From 52f970930033b1fad155b30c5b945e52f4f1258f Mon Sep 17 00:00:00 2001 From: Christian Stenger Date: Mon, 12 Feb 2024 09:37:45 +0100 Subject: [PATCH 001/243] QtKeychain: Build lib with qbs Change-Id: Ief16859fd26b130aef474c6caae64f2faacbe7f3 Reviewed-by: Christian Kandeler --- src/libs/3rdparty/qtkeychain/qtkeychain.qbs | 86 +++++++++++++++++++++ src/libs/libs.qbs | 1 + 2 files changed, 87 insertions(+) create mode 100644 src/libs/3rdparty/qtkeychain/qtkeychain.qbs diff --git a/src/libs/3rdparty/qtkeychain/qtkeychain.qbs b/src/libs/3rdparty/qtkeychain/qtkeychain.qbs new file mode 100644 index 00000000000..4a532363f0b --- /dev/null +++ b/src/libs/3rdparty/qtkeychain/qtkeychain.qbs @@ -0,0 +1,86 @@ +QtcLibrary { + name: "qtkeychain" + + property bool useWinCredentialsStore: qbs.targetOS.contains("windows") + + Depends { name: "cpp" } + Depends { name: "Qt.core" } + Depends { name: "Qt.dbus"; condition: qbs.targetOS.contains("linux") } + Depends { name: "libsecret-1"; required: false } + + cpp.defines: base.concat(["QTKEYCHAIN_LIBRARY"]) + + Properties { + condition: useWinCredentialsStore + cpp.defines: outer.concat(["USE_CREDENTIAL_STORE=1"]) + cpp.dynamicLibraries: ["advapi32"] + } + + Properties { + condition: qbs.targetOS.contains("windows") && !useWinCredentialsStore + cpp.dynamicLibraries: ["crypt32"] + } + + Properties { + condition: qbs.targetOS.contains("macos") + cpp.frameworks: [ "Foundation", "Security" ] + } + + files: [ + "keychain.cpp", + "keychain.h", + "keychain_p.h", + "qkeychain_export.h", + ] + + Group { + name: "qtkeychain Windows files" + condition: qbs.targetOS.contains("windows") + files: [ + "keychain_win.cpp", + "plaintextstore_p.h", + ] + + Group { + name: "qtkeychain Windows no credentials store" + condition: !product.useWinCredentialsStore + files: [ "plaintextstore.cpp" ] + } + } + + Group { + name: "qtkeychain macOS files" + condition: qbs.targetOS.contains("macos") + files: [ "keychain_apple.mm" ] + } + + Group { + name: "qtkeychain Linux files" + condition: qbs.targetOS.contains("linux") + + Group { + name: "qtkeychain libsecret support" + condition: "libsecret-1".present + cpp.defines: outer.concat(["HAVE_LIBSECRET=1"]) + } + Group { + name: "dbus sources" + fileTags: "qt.dbus.interface" + files: ["org.kde.KWallet.xml"] + } + + Group { + name: "qtkeychain dbus support" + cpp.defines: outer.concat(["KEYCHAIN_DBUS=1"]) + files: [ + "gnomekeyring.cpp", + "gnomekeyring_p.h", + "keychain_unix.cpp", + "libsecret.cpp", + "libsecret_p.h", + "plaintextstore.cpp", + "plaintextstore_p.h", + ] + } + } +} diff --git a/src/libs/libs.qbs b/src/libs/libs.qbs index ffc3017cba0..a6426d4ae47 100644 --- a/src/libs/libs.qbs +++ b/src/libs/libs.qbs @@ -26,6 +26,7 @@ Project { "utils/utils.qbs", "3rdparty/libptyqt/ptyqt.qbs", "3rdparty/libvterm/vterm.qbs", + "3rdparty/qtkeychain/qtkeychain.qbs", "3rdparty/syntax-highlighting/syntax-highlighting.qbs", "3rdparty/winpty/winpty.qbs", "3rdparty/yaml-cpp/yaml-cpp.qbs", From 0d1831b4629a1ff062be22d66515a00857c75b82 Mon Sep 17 00:00:00 2001 From: Jarek Kobus Date: Wed, 14 Feb 2024 11:49:30 +0100 Subject: [PATCH 002/243] Mercurial: Remove unused lambda captures Change-Id: I5b308dc57b10624d140ed506a17ed41b3ec49491 Reviewed-by: Orgad Shaneh --- src/plugins/mercurial/mercurialplugin.cpp | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/src/plugins/mercurial/mercurialplugin.cpp b/src/plugins/mercurial/mercurialplugin.cpp index 8e4d90f045c..76c8f2ba8c8 100644 --- a/src/plugins/mercurial/mercurialplugin.cpp +++ b/src/plugins/mercurial/mercurialplugin.cpp @@ -148,7 +148,7 @@ public: Constants::FILELOG_ID, VcsBase::Tr::tr("Mercurial File Log Editor"), Constants::LOGAPP, - [this] { return new MercurialEditorWidget; }, + [] { return new MercurialEditorWidget; }, std::bind(&MercurialPluginPrivate::vcsDescribe, this, _1, _2) }}; @@ -157,7 +157,7 @@ public: Constants::ANNOTATELOG_ID, VcsBase::Tr::tr("Mercurial Annotation Editor"), Constants::ANNOTATEAPP, - [this] { return new MercurialEditorWidget; }, + [] { return new MercurialEditorWidget; }, std::bind(&MercurialPluginPrivate::vcsDescribe, this, _1, _2) }}; @@ -166,7 +166,7 @@ public: Constants::DIFFLOG_ID, VcsBase::Tr::tr("Mercurial Diff Editor"), Constants::DIFFAPP, - [this] { return new MercurialEditorWidget; }, + [] { return new MercurialEditorWidget; }, std::bind(&MercurialPluginPrivate::vcsDescribe, this, _1, _2) }}; }; From 090fd0e5f5de4ccdf59eb3e520112f69bfd2ea0c Mon Sep 17 00:00:00 2001 From: hjk Date: Tue, 13 Feb 2024 17:15:28 +0100 Subject: [PATCH 003/243] Utils: Merge NamesValueModel and EnvironmentModel (1/2) The abstraction is nowhere used (anymore?) In order to keep the diff small, this here merges environmentmodel.{h,cpp} into namevaluemodel.{h,cpp} which will be renamed back to env* in a second step. Change-Id: I1e7c14012ec3d3f54d8557f4b737a59ede2283e7 Reviewed-by: Christian Kandeler --- src/libs/utils/CMakeLists.txt | 1 - src/libs/utils/environmentfwd.h | 3 - src/libs/utils/environmentmodel.cpp | 20 ------- src/libs/utils/environmentmodel.h | 19 ------- src/libs/utils/namevaluemodel.cpp | 56 ++++++++++--------- src/libs/utils/namevaluemodel.h | 17 +++--- src/libs/utils/namevaluevalidator.cpp | 2 +- src/libs/utils/namevaluevalidator.h | 6 +- src/libs/utils/utils.qbs | 2 - .../projectexplorer/environmentwidget.cpp | 2 +- 10 files changed, 42 insertions(+), 86 deletions(-) delete mode 100644 src/libs/utils/environmentmodel.cpp delete mode 100644 src/libs/utils/environmentmodel.h diff --git a/src/libs/utils/CMakeLists.txt b/src/libs/utils/CMakeLists.txt index 9f11f3fc83c..dc3322456e5 100644 --- a/src/libs/utils/CMakeLists.txt +++ b/src/libs/utils/CMakeLists.txt @@ -44,7 +44,6 @@ add_qtc_library(Utils environment.cpp environment.h environmentdialog.cpp environmentdialog.h environmentfwd.h - environmentmodel.cpp environmentmodel.h execmenu.cpp execmenu.h expected.h externalterminalprocessimpl.cpp externalterminalprocessimpl.h diff --git a/src/libs/utils/environmentfwd.h b/src/libs/utils/environmentfwd.h index 8a2c444cc42..deb78279b5c 100644 --- a/src/libs/utils/environmentfwd.h +++ b/src/libs/utils/environmentfwd.h @@ -19,7 +19,4 @@ class PreprocessorMacroDictionary; using PreprocessorMacroItem = NameValueItem; using PreprocessorMacroItems = NameValueItems; -class NameValueModel; -class EnvironmentModel; - } // namespace Utils diff --git a/src/libs/utils/environmentmodel.cpp b/src/libs/utils/environmentmodel.cpp deleted file mode 100644 index 13329597846..00000000000 --- a/src/libs/utils/environmentmodel.cpp +++ /dev/null @@ -1,20 +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 "environmentmodel.h" - -#include "environment.h" - -namespace Utils { - -Environment EnvironmentModel::baseEnvironment() const -{ - return Environment(baseNameValueDictionary()); -} - -void EnvironmentModel::setBaseEnvironment(const Environment &env) -{ - setBaseNameValueDictionary(env.toDictionary()); -} - -} // namespace Utils diff --git a/src/libs/utils/environmentmodel.h b/src/libs/utils/environmentmodel.h deleted file mode 100644 index 82bf98d43f5..00000000000 --- a/src/libs/utils/environmentmodel.h +++ /dev/null @@ -1,19 +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 "utils_global.h" - -#include "namevaluemodel.h" - -namespace Utils { - -class QTCREATOR_UTILS_EXPORT EnvironmentModel : public NameValueModel -{ -public: - Environment baseEnvironment() const; - void setBaseEnvironment(const Environment &env); -}; - -} // namespace Utils diff --git a/src/libs/utils/namevaluemodel.cpp b/src/libs/utils/namevaluemodel.cpp index 57327c4ebed..400824763f8 100644 --- a/src/libs/utils/namevaluemodel.cpp +++ b/src/libs/utils/namevaluemodel.cpp @@ -4,6 +4,7 @@ #include "namevaluemodel.h" #include "algorithm.h" +#include "environment.h" #include "hostosinfo.h" #include "namevaluedictionary.h" #include "namevalueitem.h" @@ -20,7 +21,7 @@ namespace Utils { namespace Internal { -class NameValueModelPrivate +class EnvironmentModelPrivate { public: void updateResultNameValueDictionary() @@ -78,21 +79,22 @@ public: } // namespace Internal -NameValueModel::NameValueModel(QObject *parent) +EnvironmentModel::EnvironmentModel(QObject *parent) : QAbstractTableModel(parent) - , d(std::make_unique()) + , d(std::make_unique()) {} -NameValueModel::~NameValueModel() = default; +EnvironmentModel::~EnvironmentModel() = default; -QString NameValueModel::indexToVariable(const QModelIndex &index) const +QString EnvironmentModel::indexToVariable(const QModelIndex &index) const { const auto it = std::next(d->m_resultNameValueDictionary.constBegin(), index.row()); return d->m_resultNameValueDictionary.key(it); } -void NameValueModel::setBaseNameValueDictionary(const NameValueDictionary &dictionary) +void EnvironmentModel::setBaseEnvironment(const Environment &env) { + const NameValueDictionary dictionary = env.toDictionary(); if (d->m_baseNameValueDictionary == dictionary) return; beginResetModel(); @@ -101,14 +103,14 @@ void NameValueModel::setBaseNameValueDictionary(const NameValueDictionary &dicti endResetModel(); } -int NameValueModel::rowCount(const QModelIndex &parent) const +int EnvironmentModel::rowCount(const QModelIndex &parent) const { if (parent.isValid()) return 0; return d->m_resultNameValueDictionary.size(); } -int NameValueModel::columnCount(const QModelIndex &parent) const +int EnvironmentModel::columnCount(const QModelIndex &parent) const { if (parent.isValid()) return 0; @@ -116,17 +118,17 @@ int NameValueModel::columnCount(const QModelIndex &parent) const return 2; } -bool NameValueModel::changes(const QString &name) const +bool EnvironmentModel::changes(const QString &name) const { return d->findInChanges(name) >= 0; } -const NameValueDictionary &NameValueModel::baseNameValueDictionary() const +Environment EnvironmentModel::baseEnvironment() const { - return d->m_baseNameValueDictionary; + return Environment(d->m_baseNameValueDictionary); } -QVariant NameValueModel::data(const QModelIndex &index, int role) const +QVariant EnvironmentModel::data(const QModelIndex &index, int role) const { if (!index.isValid()) return QVariant(); @@ -176,13 +178,13 @@ QVariant NameValueModel::data(const QModelIndex &index, int role) const return QVariant(); } -Qt::ItemFlags NameValueModel::flags(const QModelIndex &index) const +Qt::ItemFlags EnvironmentModel::flags(const QModelIndex &index) const { Q_UNUSED(index) return Qt::ItemIsSelectable | Qt::ItemIsEnabled; } -QVariant NameValueModel::headerData(int section, Qt::Orientation orientation, int role) const +QVariant EnvironmentModel::headerData(int section, Qt::Orientation orientation, int role) const { if (orientation == Qt::Vertical || role != Qt::DisplayRole) return QVariant(); @@ -192,7 +194,7 @@ QVariant NameValueModel::headerData(int section, Qt::Orientation orientation, in /// ***************** /// Utility functions /// ***************** -QModelIndex NameValueModel::variableToIndex(const QString &name) const +QModelIndex EnvironmentModel::variableToIndex(const QString &name) const { int row = d->findInResult(name); if (row == -1) @@ -200,7 +202,7 @@ QModelIndex NameValueModel::variableToIndex(const QString &name) const return index(row, 0); } -bool NameValueModel::setData(const QModelIndex &index, const QVariant &value, int role) +bool EnvironmentModel::setData(const QModelIndex &index, const QVariant &value, int role) { if (!index.isValid() || role != Qt::EditRole) return false; @@ -262,12 +264,12 @@ bool NameValueModel::setData(const QModelIndex &index, const QVariant &value, in return false; } -QModelIndex NameValueModel::addVariable() +QModelIndex EnvironmentModel::addVariable() { return addVariable(NameValueItem("NEWVAR", "VALUE")); } -QModelIndex NameValueModel::addVariable(const NameValueItem &item) +QModelIndex EnvironmentModel::addVariable(const NameValueItem &item) { // Return existing index if the name is already in the result set: int pos = d->findInResult(item.name); @@ -298,7 +300,7 @@ QModelIndex NameValueModel::addVariable(const NameValueItem &item) return index(insertPos, 0, QModelIndex()); } -void NameValueModel::resetVariable(const QString &name) +void EnvironmentModel::resetVariable(const QString &name) { int rowInChanges = d->findInChanges(name); if (rowInChanges < 0) @@ -323,7 +325,7 @@ void NameValueModel::resetVariable(const QString &name) } } -void NameValueModel::unsetVariable(const QString &name) +void EnvironmentModel::unsetVariable(const QString &name) { // This does not change the number of rows as we will display a // in place of the original variable! @@ -347,7 +349,7 @@ void NameValueModel::unsetVariable(const QString &name) emit userChangesChanged(); } -void NameValueModel::toggleVariable(const QModelIndex &idx) +void EnvironmentModel::toggleVariable(const QModelIndex &idx) { const QString name = indexToVariable(idx); const auto newIt = d->m_resultNameValueDictionary.constFind(name); @@ -371,28 +373,28 @@ void NameValueModel::toggleVariable(const QModelIndex &idx) emit userChangesChanged(); } -bool NameValueModel::isUnset(const QString &name) +bool EnvironmentModel::isUnset(const QString &name) { const int pos = d->findInChanges(name); return pos == -1 ? false : d->m_items.at(pos).operation == NameValueItem::Unset; } -bool NameValueModel::isEnabled(const QString &name) const +bool EnvironmentModel::isEnabled(const QString &name) const { return d->m_resultNameValueDictionary.isEnabled(d->m_resultNameValueDictionary.constFind(name)); } -bool NameValueModel::canReset(const QString &name) +bool EnvironmentModel::canReset(const QString &name) { return d->m_baseNameValueDictionary.hasKey(name); } -NameValueItems NameValueModel::userChanges() const +NameValueItems EnvironmentModel::userChanges() const { return d->m_items; } -void NameValueModel::setUserChanges(const NameValueItems &items) +void EnvironmentModel::setUserChanges(const NameValueItems &items) { NameValueItems filtered = Utils::filtered(items, [](const NameValueItem &i) { return i.name != "export " && !i.name.contains('='); @@ -421,7 +423,7 @@ void NameValueModel::setUserChanges(const NameValueItems &items) emit userChangesChanged(); } -bool NameValueModel::currentEntryIsPathList(const QModelIndex ¤t) const +bool EnvironmentModel::currentEntryIsPathList(const QModelIndex ¤t) const { if (!current.isValid()) return false; diff --git a/src/libs/utils/namevaluemodel.h b/src/libs/utils/namevaluemodel.h index 84c1f2cece9..55f53ed59e6 100644 --- a/src/libs/utils/namevaluemodel.h +++ b/src/libs/utils/namevaluemodel.h @@ -13,17 +13,15 @@ namespace Utils { -namespace Internal { -class NameValueModelPrivate; -} +namespace Internal { class EnvironmentModelPrivate; } -class QTCREATOR_UTILS_EXPORT NameValueModel : public QAbstractTableModel +class QTCREATOR_UTILS_EXPORT EnvironmentModel : public QAbstractTableModel { Q_OBJECT public: - explicit NameValueModel(QObject *parent = nullptr); - ~NameValueModel() override; + explicit EnvironmentModel(QObject *parent = nullptr); + ~EnvironmentModel() override; int rowCount(const QModelIndex &parent) const override; int columnCount(const QModelIndex &parent) const override; @@ -34,6 +32,9 @@ public: Qt::Orientation orientation, int role = Qt::DisplayRole) const override; + Environment baseEnvironment() const; + void setBaseEnvironment(const Environment &env); + QModelIndex addVariable(); QModelIndex addVariable(const NameValueItem &item); void resetVariable(const QString &name); @@ -45,8 +46,6 @@ public: QString indexToVariable(const QModelIndex &index) const; QModelIndex variableToIndex(const QString &name) const; bool changes(const QString &key) const; - const NameValueDictionary &baseNameValueDictionary() const; - void setBaseNameValueDictionary(const NameValueDictionary &dictionary); NameValueItems userChanges() const; void setUserChanges(const NameValueItems &items); bool currentEntryIsPathList(const QModelIndex ¤t) const; @@ -59,7 +58,7 @@ signals: void focusIndex(const QModelIndex &index); private: - std::unique_ptr d; + std::unique_ptr d; }; } // namespace Utils diff --git a/src/libs/utils/namevaluevalidator.cpp b/src/libs/utils/namevaluevalidator.cpp index ef2ccbc9a08..e64c1528939 100644 --- a/src/libs/utils/namevaluevalidator.cpp +++ b/src/libs/utils/namevaluevalidator.cpp @@ -10,7 +10,7 @@ namespace Utils { NameValueValidator::NameValueValidator(QWidget *parent, - NameValueModel *model, + EnvironmentModel *model, QTreeView *view, const QModelIndex &index, const QString &toolTipText) diff --git a/src/libs/utils/namevaluevalidator.h b/src/libs/utils/namevaluevalidator.h index bf0f1b27f74..e06560f1896 100644 --- a/src/libs/utils/namevaluevalidator.h +++ b/src/libs/utils/namevaluevalidator.h @@ -16,13 +16,13 @@ QT_END_NAMESPACE namespace Utils { -class NameValueModel; +class EnvironmentModel; class QTCREATOR_UTILS_EXPORT NameValueValidator : public QValidator { public: NameValueValidator(QWidget *parent, - NameValueModel *model, + EnvironmentModel *model, QTreeView *view, const QModelIndex &index, const QString &toolTipText); @@ -33,7 +33,7 @@ public: private: const QString m_toolTipText; - NameValueModel *m_model; + EnvironmentModel *m_model; QTreeView *m_view; QPersistentModelIndex m_index; mutable QTimer m_hideTipTimer; diff --git a/src/libs/utils/utils.qbs b/src/libs/utils/utils.qbs index d7ccd1d6761..d062400ee1c 100644 --- a/src/libs/utils/utils.qbs +++ b/src/libs/utils/utils.qbs @@ -101,8 +101,6 @@ QtcLibrary { "environment.h", "environmentdialog.cpp", "environmentdialog.h", - "environmentmodel.cpp", - "environmentmodel.h", "execmenu.cpp", "execmenu.h", "externalterminalprocessimpl.cpp", diff --git a/src/plugins/projectexplorer/environmentwidget.cpp b/src/plugins/projectexplorer/environmentwidget.cpp index 9a63d789ece..4331dbb06f1 100644 --- a/src/plugins/projectexplorer/environmentwidget.cpp +++ b/src/plugins/projectexplorer/environmentwidget.cpp @@ -12,7 +12,7 @@ #include #include #include -#include +#include #include #include #include From 83eaeda954bb7194f2a8673b1174552322966737 Mon Sep 17 00:00:00 2001 From: hjk Date: Tue, 13 Feb 2024 17:23:04 +0100 Subject: [PATCH 004/243] Utils: Merge NamesValueModel and EnvironmentModel (2/2) Rename namevaluemodel.{h,cpp} back to environmentmodel.{h,cpp} Change-Id: Idfa528b0c1c307ef4cd9dd5869f18993647b98bc Reviewed-by: Christian Kandeler --- src/libs/utils/CMakeLists.txt | 6 +----- src/libs/utils/{namevaluemodel.cpp => environmentmodel.cpp} | 2 +- src/libs/utils/{namevaluemodel.h => environmentmodel.h} | 0 src/libs/utils/namevaluevalidator.cpp | 3 ++- src/libs/utils/utils.qbs | 4 ++-- src/plugins/projectexplorer/environmentwidget.cpp | 2 +- 6 files changed, 7 insertions(+), 10 deletions(-) rename src/libs/utils/{namevaluemodel.cpp => environmentmodel.cpp} (99%) rename src/libs/utils/{namevaluemodel.h => environmentmodel.h} (100%) diff --git a/src/libs/utils/CMakeLists.txt b/src/libs/utils/CMakeLists.txt index dc3322456e5..eb2eaed9ddc 100644 --- a/src/libs/utils/CMakeLists.txt +++ b/src/libs/utils/CMakeLists.txt @@ -43,6 +43,7 @@ add_qtc_library(Utils elidinglabel.cpp elidinglabel.h environment.cpp environment.h environmentdialog.cpp environmentdialog.h + environmentmodel.cpp environmentmodel.h environmentfwd.h execmenu.cpp execmenu.h expected.h @@ -102,12 +103,7 @@ add_qtc_library(Utils namevaluedictionary.cpp namevaluedictionary.h namevaluedictionary.cpp namevaluedictionary.h namevalueitem.cpp namevalueitem.h - namevalueitem.cpp namevalueitem.h - namevaluemodel.cpp namevaluemodel.h - namevaluemodel.cpp namevaluemodel.h namevaluesdialog.cpp namevaluesdialog.h - namevaluesdialog.cpp namevaluesdialog.h - namevaluevalidator.cpp namevaluevalidator.h namevaluevalidator.cpp namevaluevalidator.h navigationtreeview.cpp navigationtreeview.h networkaccessmanager.cpp networkaccessmanager.h diff --git a/src/libs/utils/namevaluemodel.cpp b/src/libs/utils/environmentmodel.cpp similarity index 99% rename from src/libs/utils/namevaluemodel.cpp rename to src/libs/utils/environmentmodel.cpp index 400824763f8..c21470808d7 100644 --- a/src/libs/utils/namevaluemodel.cpp +++ b/src/libs/utils/environmentmodel.cpp @@ -1,7 +1,7 @@ // 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 "namevaluemodel.h" +#include "environmentmodel.h" #include "algorithm.h" #include "environment.h" diff --git a/src/libs/utils/namevaluemodel.h b/src/libs/utils/environmentmodel.h similarity index 100% rename from src/libs/utils/namevaluemodel.h rename to src/libs/utils/environmentmodel.h diff --git a/src/libs/utils/namevaluevalidator.cpp b/src/libs/utils/namevaluevalidator.cpp index e64c1528939..620adc137c3 100644 --- a/src/libs/utils/namevaluevalidator.cpp +++ b/src/libs/utils/namevaluevalidator.cpp @@ -2,7 +2,8 @@ // SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only WITH Qt-GPL-exception-1.0 #include "namevaluevalidator.h" -#include "namevaluemodel.h" + +#include "environmentmodel.h" #include "tooltip/tooltip.h" #include diff --git a/src/libs/utils/utils.qbs b/src/libs/utils/utils.qbs index d062400ee1c..7bf55d8f247 100644 --- a/src/libs/utils/utils.qbs +++ b/src/libs/utils/utils.qbs @@ -101,6 +101,8 @@ QtcLibrary { "environment.h", "environmentdialog.cpp", "environmentdialog.h", + "environmentmodel.cpp", + "environmentmodel.h", "execmenu.cpp", "execmenu.h", "externalterminalprocessimpl.cpp", @@ -196,8 +198,6 @@ QtcLibrary { "namevaluedictionary.h", "namevalueitem.cpp", "namevalueitem.h", - "namevaluemodel.cpp", - "namevaluemodel.h", "namevaluesdialog.cpp", "namevaluesdialog.h", "namevaluevalidator.cpp", diff --git a/src/plugins/projectexplorer/environmentwidget.cpp b/src/plugins/projectexplorer/environmentwidget.cpp index 4331dbb06f1..9a63d789ece 100644 --- a/src/plugins/projectexplorer/environmentwidget.cpp +++ b/src/plugins/projectexplorer/environmentwidget.cpp @@ -12,7 +12,7 @@ #include #include #include -#include +#include #include #include #include From 5639c141ff153fa8d06ef0adf61d6a309790ff65 Mon Sep 17 00:00:00 2001 From: Leena Miettinen Date: Tue, 13 Feb 2024 18:04:27 +0100 Subject: [PATCH 005/243] Doc: Describe Qt Translation File wizard Task-number: QTCREATORBUG-30209 Change-Id: I9a5d04d59e836cb08dd3eafd9d4ea22106aea4a0 Reviewed-by: Christian Stenger Reviewed-by: --- .../images/qtcreator-new-file-ts.webp | Bin 0 -> 4784 bytes .../src/howto/creator-external-tools.qdoc | 35 +++++++++++++----- .../howto/creator-only/creator-how-tos.qdoc | 2 +- .../creator-only/creator-files-creating.qdoc | 8 ++-- .../creator-how-to-create-ts-files.qdoc | 30 +++++++++++++++ doc/qtcreator/src/qtcreator-toc.qdoc | 2 +- 6 files changed, 61 insertions(+), 16 deletions(-) create mode 100644 doc/qtcreator/images/qtcreator-new-file-ts.webp create mode 100644 doc/qtcreator/src/projects/creator-only/creator-how-to-create-ts-files.qdoc diff --git a/doc/qtcreator/images/qtcreator-new-file-ts.webp b/doc/qtcreator/images/qtcreator-new-file-ts.webp new file mode 100644 index 0000000000000000000000000000000000000000..3ad21a25d919e7042c399fc4f445d33bc4ade3a4 GIT binary patch literal 4784 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 S+}M@7`PQpF|0nR9F#rGz0Zb(T literal 0 HcmV?d00001 diff --git a/doc/qtcreator/src/howto/creator-external-tools.qdoc b/doc/qtcreator/src/howto/creator-external-tools.qdoc index 3f29dfc57bf..dda7eeb62ae 100644 --- a/doc/qtcreator/src/howto/creator-external-tools.qdoc +++ b/doc/qtcreator/src/howto/creator-external-tools.qdoc @@ -134,18 +134,30 @@ \title Use Qt Linguist + Most of the text to translate in an application consists of either single + words or short phrases. These typically appear as window titles, menu items, + tooltips, and labels to buttons, checkboxes, and radio buttons. + + You mark the phrases as translatable in the QML and C++ source code. Qt + localization tools provide context information for each of the phrases to + help the translator understand their meaning. You can add comments to the + phrases. + + Translation files contain all the user-visible text and keyboard shortcuts + in an application and translations of that text. + When you \l{Creating Projects}{create a new project}, you can automatically - generate a translation source file (TS) for one language. You can add other - languages later by editing the project file. + generate a translation source file (TS) for one language. To add other + languages, edit the project file or go to \uicontrol File > + \uicontrol {New File}. To open TS files in Qt Linguist, right-click a TS file in the - \uicontrol Projects or \uicontrol {File System} view and select + \uicontrol Projects or \uicontrol {File System} view and go to \uicontrol {Open With} > \uicontrol {Qt Linguist} in the context menu. - For more information about Qt Linguist, see \l{Qt Linguist Manual}. \section1 Use lupdate and lrelease - You can use the Qt Linguist release manager tools, lupdate and lrelease, + Use the Qt Linguist release manager tools, lupdate and lrelease, directly from \QC. The lupdate tool synchronizes source code and translations. The lrelease tool creates run-time translation files for use by the released application. @@ -156,22 +168,27 @@ {Qt6::LinguistTools}. By default, the project .pro file is passed to the tools as an argument. To - specify other command-line arguments for the tools, select \uicontrol Tools > + specify other command-line arguments for the tools, go to \uicontrol Tools > \uicontrol External > \uicontrol Configure. \section2 Synchronize TS files To synchronize TS files from a translator with the - application code, select \uicontrol Tools > \uicontrol External > + application code, go to \uicontrol Tools > \uicontrol External > \uicontrol Linguist > \uicontrol {Update Translations (lupdate)}. \section2 Generate QM files To generate from the TS files Qt message (QM) files that can be used by an - application, select \uicontrol Tools > \uicontrol External > + application, go to \uicontrol Tools > \uicontrol External > \uicontrol Linguist > \uicontrol {Release Translations (lrelease)}. - \sa {Use external tools} + \if defined(qtcreator) + \sa {Add translation files} + \endif + + \sa {Use external tools}, {Internationalization with Qt}, + {Qt Linguist Manual} */ /*! 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 6c3fc7fd84e..0643c3a1525 100644 --- a/doc/qtcreator/src/howto/creator-only/creator-how-tos.qdoc +++ b/doc/qtcreator/src/howto/creator-only/creator-how-tos.qdoc @@ -77,7 +77,7 @@ \generatelist creator-how-to-projects-create - \section2 Create Files + \section2 Add Files \generatelist creator-how-to-projects-files diff --git a/doc/qtcreator/src/projects/creator-only/creator-files-creating.qdoc b/doc/qtcreator/src/projects/creator-only/creator-files-creating.qdoc index 6b953d4401d..d03263d4625 100644 --- a/doc/qtcreator/src/projects/creator-only/creator-files-creating.qdoc +++ b/doc/qtcreator/src/projects/creator-only/creator-files-creating.qdoc @@ -43,8 +43,8 @@ \li \uicontrol {Qt} \li Source and header files for item, table, or list models, \QD forms and a matching classes for Qt Widgets - projects, Qt resource files, as well as QML and JavaScript files - for Qt Quick projects. + projects, Qt resource and translation files, as well as QML and + JavaScript files for Qt Quick projects. \row \li \uicontrol {Compiler Explorer} \li Example setup for using Compiler Explorer to compile C++ or Python @@ -74,9 +74,7 @@ \li Empty Nim source and script files. \endtable - \sa {Create compiler explorer sessions}, {Create C++ classes}, - {Create OpenGL fragment and vertex shaders}, {Create resource files}, - {Create UML-style models}, {Create vcpkg manifest files}, + \sa {Add Files}{How To: Add Files}, {Create UML-style models}, {Use project wizards} */ diff --git a/doc/qtcreator/src/projects/creator-only/creator-how-to-create-ts-files.qdoc b/doc/qtcreator/src/projects/creator-only/creator-how-to-create-ts-files.qdoc new file mode 100644 index 00000000000..cb4471aeb5d --- /dev/null +++ b/doc/qtcreator/src/projects/creator-only/creator-how-to-create-ts-files.qdoc @@ -0,0 +1,30 @@ +// Copyright (C) 2024 The Qt Company Ltd. +// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GFDL-1.3-no-invariants-only + +/*! + \page creator-how-to-add-ts-files.html + \previouspage creator-how-tos.html + + \ingroup creator-how-to-projects-files + + \title Add translation files + + When you \l{Creating Projects}{create a new project}, you can automatically + generate a translation source file (TS) for one language. To add other + languages later, use a file wizard. + + To create a translation source (TS) file for a language: + + \list 1 + \li Go to \uicontrol File > \uicontrol {New File}. + \li Select \uicontrol Qt > \uicontrol {Qt Translation File} > + \uicontrol Choose. + \li In \uicontrol Language, select a language and territory (\e locale). + \image qtcreator-new-file-ts.webp {Select language for a TS file} + \endlist + + You can see the file name in \uicontrol {Translation file}. + + \sa {Create files}, {Use project wizards}, {Use Qt Linguist}, + {Internationalization with Qt}, {Qt Linguist Manual} +*/ diff --git a/doc/qtcreator/src/qtcreator-toc.qdoc b/doc/qtcreator/src/qtcreator-toc.qdoc index 5f2daf2737f..ec8408795fc 100644 --- a/doc/qtcreator/src/qtcreator-toc.qdoc +++ b/doc/qtcreator/src/qtcreator-toc.qdoc @@ -157,7 +157,7 @@ \list \li Create Projects \generatelist creator-how-to-projects-create - \li Create Files + \li Add Files \generatelist creator-how-to-projects-files \li Configure Projects \generatelist creator-how-to-projects-configure From 91c1c244a1256b2dc9979edb1a3ce83c28ef5636 Mon Sep 17 00:00:00 2001 From: Jarek Kobus Date: Mon, 19 Apr 2021 14:50:51 +0200 Subject: [PATCH 006/243] ModelManagerInterface: Cancel all running threads on session switch On session switch we cancel all the running tasks. We connect to the SessionManager::aboutToLoadSession() signal, as this one is emitted just before loading new session's projects. We don't connect to SessionManager::aboutToUnloadSession(), since after this signal is emitted the unloading may be canceled due to e.g. showing the dialog asking for saving changed files in the unloaded session (the user may cancel the process of unloading). In contrast to what we do on shutdown, we don't wait for futures being finished here - it's just enough we cancel all of them. Fixes: QTCREATORBUG-25583 Change-Id: I01eeca00d150f6e98a80a050c6a19efb848b9954 Reviewed-by: hjk --- src/libs/qmljs/qmljsmodelmanagerinterface.cpp | 10 ++++++++++ src/libs/qmljs/qmljsmodelmanagerinterface.h | 2 +- src/plugins/qmljstools/qmljsmodelmanager.cpp | 3 +++ 3 files changed, 14 insertions(+), 1 deletion(-) diff --git a/src/libs/qmljs/qmljsmodelmanagerinterface.cpp b/src/libs/qmljs/qmljsmodelmanagerinterface.cpp index aac0de9ab1e..a525c6c3054 100644 --- a/src/libs/qmljs/qmljsmodelmanagerinterface.cpp +++ b/src/libs/qmljs/qmljsmodelmanagerinterface.cpp @@ -317,6 +317,16 @@ void ModelManagerInterface::setDefaultProject(const ModelManagerInterface::Proje }); } +void ModelManagerInterface::cancelAllThreads() +{ + m_cppQmlTypesUpdater.cancel(); + // Don't execute the scheduled updates for the old session anymore + m_updateCppQmlTypesTimer->stop(); + m_asyncResetTimer->stop(); + QMutexLocker locker(&m_futuresMutex); + m_futureSynchronizer.cancelAllFutures(); +} + Snapshot ModelManagerInterface::snapshot() const { return m_syncedData.readLocked()->m_validSnapshot; diff --git a/src/libs/qmljs/qmljsmodelmanagerinterface.h b/src/libs/qmljs/qmljsmodelmanagerinterface.h index c57cba7e46e..ae3d8e0e6c4 100644 --- a/src/libs/qmljs/qmljsmodelmanagerinterface.h +++ b/src/libs/qmljs/qmljsmodelmanagerinterface.h @@ -238,7 +238,7 @@ protected: void updateImportPaths(); void loadQmlTypeDescriptionsInternal(const QString &path); void setDefaultProject(const ProjectInfo &pInfo, ProjectExplorer::Project *p); - + void cancelAllThreads(); private: void joinAllThreads(bool cancelOnWait = false); void iterateQrcFiles(ProjectExplorer::Project *project, diff --git a/src/plugins/qmljstools/qmljsmodelmanager.cpp b/src/plugins/qmljstools/qmljsmodelmanager.cpp index c8265d73544..36d0e657cf5 100644 --- a/src/plugins/qmljstools/qmljsmodelmanager.cpp +++ b/src/plugins/qmljstools/qmljsmodelmanager.cpp @@ -10,6 +10,7 @@ #include #include #include +#include #include @@ -281,6 +282,8 @@ void ModelManager::delayedInitialization() this, &ModelManager::removeProjectInfo); connect(ProjectManager::instance(), &ProjectManager::startupProjectChanged, this, &ModelManager::updateDefaultProjectInfo); + connect(SessionManager::instance(), &SessionManager::aboutToLoadSession, + this, &ModelManager::cancelAllThreads); ViewerContext qbsVContext; qbsVContext.language = Dialect::QmlQbs; From 0a1783d656964df60f1ec462f81c56ea38100dc5 Mon Sep 17 00:00:00 2001 From: hjk Date: Tue, 13 Feb 2024 18:01:32 +0100 Subject: [PATCH 007/243] Utils: Rename NameValueItem to EnvironmentItem (1/2) Only used in Environments nowadays. Change-Id: I64a645ebebd5cb57c50d5d8f72a5e4dba40e122f Reviewed-by: Christian Kandeler --- src/libs/utils/environment.cpp | 6 +- src/libs/utils/environment.h | 6 +- src/libs/utils/environmentfwd.h | 12 +--- src/libs/utils/environmentmodel.cpp | 38 ++++++------ src/libs/utils/environmentmodel.h | 6 +- src/libs/utils/namevaluedictionary.cpp | 22 +++---- src/libs/utils/namevaluedictionary.h | 4 +- src/libs/utils/namevalueitem.cpp | 60 +++++++++---------- src/libs/utils/namevalueitem.h | 26 ++++---- src/libs/utils/namevaluesdialog.cpp | 6 +- src/libs/utils/namevaluesdialog.h | 10 ++-- src/plugins/debugger/gdb/gdbengine.cpp | 2 +- src/plugins/mcusupport/mcukitaspect.cpp | 12 ++-- src/plugins/mcusupport/mcukitaspect.h | 4 +- src/plugins/mcusupport/mcukitmanager.cpp | 2 +- .../projectexplorer/environmentwidget.cpp | 8 +-- .../projectexplorer/environmentwidget.h | 2 +- src/plugins/projectexplorer/project.cpp | 4 +- .../cmakegen/generatecmakelists.cpp | 2 +- tests/auto/environment/tst_environment.cpp | 26 ++++---- 20 files changed, 126 insertions(+), 132 deletions(-) diff --git a/src/libs/utils/environment.cpp b/src/libs/utils/environment.cpp index b1143c7fab4..be43f2a2062 100644 --- a/src/libs/utils/environment.cpp +++ b/src/libs/utils/environment.cpp @@ -50,7 +50,7 @@ Environment::Environment(const NameValueDictionary &dict) m_changeItems.append(dict); } -NameValueItems Environment::diff(const Environment &other, bool checkAppendPrepend) const +EnvironmentItems Environment::diff(const Environment &other, bool checkAppendPrepend) const { const NameValueDictionary &dict = resolved(); const NameValueDictionary &otherDict = other.resolved(); @@ -393,7 +393,7 @@ void Environment::unset(const QString &key) addItem(Item{std::in_place_index_t(), key}); } -void Environment::modify(const NameValueItems &items) +void Environment::modify(const EnvironmentItems &items) { addItem(Item{std::in_place_index_t(), items}); } @@ -485,7 +485,7 @@ const NameValueDictionary &Environment::resolved() const break; } case Modify: { - NameValueItems items = std::get(item); + EnvironmentItems items = std::get(item); m_dict.modify(items); break; } diff --git a/src/libs/utils/environment.h b/src/libs/utils/environment.h index 542343aa2a9..1b6b7d2c0e0 100644 --- a/src/libs/utils/environment.h +++ b/src/libs/utils/environment.h @@ -37,7 +37,7 @@ public: void set(const QString &key, const QString &value, bool enabled = true); void setFallback(const QString &key, const QString &value); void unset(const QString &key); - void modify(const NameValueItems &items); + void modify(const EnvironmentItems &items); bool hasChanges() const; @@ -79,7 +79,7 @@ public: QStringList expandVariables(const QStringList &input) const; NameValueDictionary toDictionary() const; // FIXME: avoid - NameValueItems diff(const Environment &other, bool checkAppendPrepend = false) const; // FIXME: avoid + EnvironmentItems diff(const Environment &other, bool checkAppendPrepend = false) const; // FIXME: avoid struct Entry { QString key; QString value; bool enabled; }; using FindResult = std::optional; @@ -117,7 +117,7 @@ public: QString, // UnsetValue (key) std::tuple, // PrependOrSet (key, value, separator) std::tuple, // AppendOrSet (key, value, separator) - NameValueItems, // Modify + EnvironmentItems, // Modify std::monostate, // SetupEnglishOutput FilePath // SetupSudoAskPass (file path of qtc-askpass or ssh-askpass) >; diff --git a/src/libs/utils/environmentfwd.h b/src/libs/utils/environmentfwd.h index deb78279b5c..376d1ea08c5 100644 --- a/src/libs/utils/environmentfwd.h +++ b/src/libs/utils/environmentfwd.h @@ -7,16 +7,10 @@ namespace Utils { -class NameValueDictionary; -class NameValueItem; -using NameValueItems = QList; - class Environment; -using EnvironmentItem = NameValueItem; -using EnvironmentItems = NameValueItems; +class EnvironmentItem; +using EnvironmentItems = QList; -class PreprocessorMacroDictionary; -using PreprocessorMacroItem = NameValueItem; -using PreprocessorMacroItems = NameValueItems; +class NameValueDictionary; } // namespace Utils diff --git a/src/libs/utils/environmentmodel.cpp b/src/libs/utils/environmentmodel.cpp index c21470808d7..6ac9b356406 100644 --- a/src/libs/utils/environmentmodel.cpp +++ b/src/libs/utils/environmentmodel.cpp @@ -30,8 +30,8 @@ public: m_resultNameValueDictionary.modify(m_items); // Add removed variables again and mark them as "" so // that the user can actually see those removals: - for (const NameValueItem &item : std::as_const(m_items)) { - if (item.operation == NameValueItem::Unset) + for (const EnvironmentItem &item : std::as_const(m_items)) { + if (item.operation == EnvironmentItem::Unset) m_resultNameValueDictionary.set(item.name, Tr::tr("")); } } @@ -74,7 +74,7 @@ public: NameValueDictionary m_baseNameValueDictionary; NameValueDictionary m_resultNameValueDictionary; - NameValueItems m_items; + EnvironmentItems m_items; }; } // namespace Internal @@ -145,7 +145,7 @@ QVariant EnvironmentModel::data(const QModelIndex &index, int role) const // Do not return "" when editing a previously unset variable: if (role == Qt::EditRole) { int pos = d->findInChanges(indexToVariable(index)); - if (pos != -1 && d->m_items.at(pos).operation == NameValueItem::Unset) + if (pos != -1 && d->m_items.at(pos).operation == EnvironmentItem::Unset) return QString(); } QString value = d->m_resultNameValueDictionary.value(resultIterator); @@ -225,7 +225,7 @@ bool EnvironmentModel::setData(const QModelIndex &index, const QVariant &value, if (d->m_resultNameValueDictionary.hasKey(newName) || newName.isEmpty()) return false; - NameValueItem newVariable(newName, oldValue); + EnvironmentItem newVariable(newName, oldValue); if (changesPos != -1) resetVariable(oldName); // restore the original base variable again @@ -249,12 +249,12 @@ bool EnvironmentModel::setData(const QModelIndex &index, const QVariant &value, } else { // ... and changed it again d->m_items[changesPos].value = stringValue; - if (d->m_items[changesPos].operation == NameValueItem::Unset) - d->m_items[changesPos].operation = NameValueItem::SetEnabled; + if (d->m_items[changesPos].operation == EnvironmentItem::Unset) + d->m_items[changesPos].operation = EnvironmentItem::SetEnabled; } } else { // Add a new change item: - d->m_items.append(NameValueItem(oldName, stringValue)); + d->m_items.append(EnvironmentItem(oldName, stringValue)); } d->updateResultNameValueDictionary(); emit dataChanged(index, index); @@ -266,10 +266,10 @@ bool EnvironmentModel::setData(const QModelIndex &index, const QVariant &value, QModelIndex EnvironmentModel::addVariable() { - return addVariable(NameValueItem("NEWVAR", "VALUE")); + return addVariable(EnvironmentItem("NEWVAR", "VALUE")); } -QModelIndex EnvironmentModel::addVariable(const NameValueItem &item) +QModelIndex EnvironmentModel::addVariable(const EnvironmentItem &item) { // Return existing index if the name is already in the result set: int pos = d->findInResult(item.name); @@ -283,7 +283,7 @@ QModelIndex EnvironmentModel::addVariable(const NameValueItem &item) Q_ASSERT(changePos >= 0); // Do not insert a line here as we listed the variable as before! Q_ASSERT(d->m_items.at(changePos).name == item.name); - Q_ASSERT(d->m_items.at(changePos).operation == NameValueItem::Unset); + Q_ASSERT(d->m_items.at(changePos).operation == EnvironmentItem::Unset); Q_ASSERT(d->m_items.at(changePos).value.isEmpty()); d->m_items[changePos] = item; emit dataChanged(index(insertPos, 0, QModelIndex()), index(insertPos, 1, QModelIndex())); @@ -336,14 +336,14 @@ void EnvironmentModel::unsetVariable(const QString &name) // look in d->m_items for the variable int pos = d->findInChanges(name); if (pos != -1) { - d->m_items[pos].operation = NameValueItem::Unset; + d->m_items[pos].operation = EnvironmentItem::Unset; d->m_items[pos].value.clear(); d->updateResultNameValueDictionary(); emit dataChanged(index(row, 0, QModelIndex()), index(row, 1, QModelIndex())); emit userChangesChanged(); return; } - d->m_items.append(NameValueItem(name, QString(), NameValueItem::Unset)); + d->m_items.append(EnvironmentItem(name, QString(), EnvironmentItem::Unset)); d->updateResultNameValueDictionary(); emit dataChanged(index(row, 0, QModelIndex()), index(row, 1, QModelIndex())); emit userChangesChanged(); @@ -355,7 +355,7 @@ void EnvironmentModel::toggleVariable(const QModelIndex &idx) const auto newIt = d->m_resultNameValueDictionary.constFind(name); QTC_ASSERT(newIt != d->m_resultNameValueDictionary.constEnd(), return); const auto op = d->m_resultNameValueDictionary.isEnabled(newIt) - ? NameValueItem::SetDisabled : NameValueItem::SetEnabled; + ? EnvironmentItem::SetDisabled : EnvironmentItem::SetEnabled; const int changesPos = d->findInChanges(name); if (changesPos != -1) { const auto oldIt = d->m_baseNameValueDictionary.constFind(name); @@ -376,7 +376,7 @@ void EnvironmentModel::toggleVariable(const QModelIndex &idx) bool EnvironmentModel::isUnset(const QString &name) { const int pos = d->findInChanges(name); - return pos == -1 ? false : d->m_items.at(pos).operation == NameValueItem::Unset; + return pos == -1 ? false : d->m_items.at(pos).operation == EnvironmentItem::Unset; } bool EnvironmentModel::isEnabled(const QString &name) const @@ -389,14 +389,14 @@ bool EnvironmentModel::canReset(const QString &name) return d->m_baseNameValueDictionary.hasKey(name); } -NameValueItems EnvironmentModel::userChanges() const +EnvironmentItems EnvironmentModel::userChanges() const { return d->m_items; } -void EnvironmentModel::setUserChanges(const NameValueItems &items) +void EnvironmentModel::setUserChanges(const EnvironmentItems &items) { - NameValueItems filtered = Utils::filtered(items, [](const NameValueItem &i) { + EnvironmentItems filtered = Utils::filtered(items, [](const EnvironmentItem &i) { return i.name != "export " && !i.name.contains('='); }); // We assume nobody is reordering the items here. @@ -404,7 +404,7 @@ void EnvironmentModel::setUserChanges(const NameValueItems &items) return; beginResetModel(); d->m_items = filtered; - for (NameValueItem &item : d->m_items) { + for (EnvironmentItem &item : d->m_items) { QString &name = item.name; name = name.trimmed(); if (name.startsWith("export ")) diff --git a/src/libs/utils/environmentmodel.h b/src/libs/utils/environmentmodel.h index 55f53ed59e6..07670bd13fc 100644 --- a/src/libs/utils/environmentmodel.h +++ b/src/libs/utils/environmentmodel.h @@ -36,7 +36,7 @@ public: void setBaseEnvironment(const Environment &env); QModelIndex addVariable(); - QModelIndex addVariable(const NameValueItem &item); + QModelIndex addVariable(const EnvironmentItem &item); void resetVariable(const QString &name); void unsetVariable(const QString &name); void toggleVariable(const QModelIndex &index); @@ -46,8 +46,8 @@ public: QString indexToVariable(const QModelIndex &index) const; QModelIndex variableToIndex(const QString &name) const; bool changes(const QString &key) const; - NameValueItems userChanges() const; - void setUserChanges(const NameValueItems &items); + EnvironmentItems userChanges() const; + void setUserChanges(const EnvironmentItems &items); bool currentEntryIsPathList(const QModelIndex ¤t) const; signals: diff --git a/src/libs/utils/namevaluedictionary.cpp b/src/libs/utils/namevaluedictionary.cpp index 05ff4761dd1..d93298b3f15 100644 --- a/src/libs/utils/namevaluedictionary.cpp +++ b/src/libs/utils/namevaluedictionary.cpp @@ -97,34 +97,34 @@ int NameValueDictionary::size() const return m_values.size(); } -void NameValueDictionary::modify(const NameValueItems &items) +void NameValueDictionary::modify(const EnvironmentItems &items) { NameValueDictionary resultKeyValueDictionary = *this; - for (const NameValueItem &item : items) + for (const EnvironmentItem &item : items) item.apply(&resultKeyValueDictionary); *this = resultKeyValueDictionary; } -NameValueItems NameValueDictionary::diff(const NameValueDictionary &other, bool checkAppendPrepend) const +EnvironmentItems NameValueDictionary::diff(const NameValueDictionary &other, bool checkAppendPrepend) const { NameValueMap::const_iterator thisIt = constBegin(); NameValueMap::const_iterator otherIt = other.constBegin(); - NameValueItems result; + EnvironmentItems result; while (thisIt != constEnd() || otherIt != other.constEnd()) { if (thisIt == constEnd()) { result.append({other.key(otherIt), other.value(otherIt), - otherIt.value().second ? NameValueItem::SetEnabled : NameValueItem::SetDisabled}); + otherIt.value().second ? EnvironmentItem::SetEnabled : EnvironmentItem::SetDisabled}); ++otherIt; } else if (otherIt == other.constEnd()) { - result.append(NameValueItem(key(thisIt), QString(), NameValueItem::Unset)); + result.append(EnvironmentItem(key(thisIt), QString(), EnvironmentItem::Unset)); ++thisIt; } else if (thisIt.key() < otherIt.key()) { - result.append(NameValueItem(key(thisIt), QString(), NameValueItem::Unset)); + result.append(EnvironmentItem(key(thisIt), QString(), EnvironmentItem::Unset)); ++thisIt; } else if (thisIt.key() > otherIt.key()) { result.append({other.key(otherIt), otherIt.value().first, - otherIt.value().second ? NameValueItem::SetEnabled : NameValueItem::SetDisabled}); + otherIt.value().second ? EnvironmentItem::SetEnabled : EnvironmentItem::SetDisabled}); ++otherIt; } else { const QString &oldValue = thisIt.value().first; @@ -137,16 +137,16 @@ NameValueItems NameValueDictionary::diff(const NameValueDictionary &other, bool QString appended = newValue.right(newValue.size() - oldValue.size()); if (appended.startsWith(OsSpecificAspects::pathListSeparator(osType()))) appended.remove(0, 1); - result.append(NameValueItem(other.key(otherIt), appended, NameValueItem::Append)); + result.append(EnvironmentItem(other.key(otherIt), appended, EnvironmentItem::Append)); } else if (checkAppendPrepend && newValue.endsWith(oldValue) && oldEnabled == newEnabled) { QString prepended = newValue.left(newValue.size() - oldValue.size()); if (prepended.endsWith(OsSpecificAspects::pathListSeparator(osType()))) prepended.chop(1); - result.append(NameValueItem(other.key(otherIt), prepended, NameValueItem::Prepend)); + result.append(EnvironmentItem(other.key(otherIt), prepended, EnvironmentItem::Prepend)); } else { result.append({other.key(otherIt), newValue, newEnabled - ? NameValueItem::SetEnabled : NameValueItem::SetDisabled}); + ? EnvironmentItem::SetEnabled : EnvironmentItem::SetDisabled}); } } ++otherIt; diff --git a/src/libs/utils/namevaluedictionary.h b/src/libs/utils/namevaluedictionary.h index 722558f8912..87d81249704 100644 --- a/src/libs/utils/namevaluedictionary.h +++ b/src/libs/utils/namevaluedictionary.h @@ -48,9 +48,9 @@ public: QString value(const QString &key) const; void set(const QString &key, const QString &value, bool enabled = true); void unset(const QString &key); - void modify(const NameValueItems &items); + void modify(const EnvironmentItems &items); /// Return the KeyValueDictionary changes necessary to modify this into the other environment. - NameValueItems diff(const NameValueDictionary &other, bool checkAppendPrepend = false) const; + EnvironmentItems diff(const NameValueDictionary &other, bool checkAppendPrepend = false) const; bool hasKey(const QString &key) const; OsType osType() const; Qt::CaseSensitivity nameCaseSensitivity() const; diff --git a/src/libs/utils/namevalueitem.cpp b/src/libs/utils/namevalueitem.cpp index adc7ff5afc9..3f4cdbd4b2c 100644 --- a/src/libs/utils/namevalueitem.cpp +++ b/src/libs/utils/namevalueitem.cpp @@ -10,34 +10,34 @@ namespace Utils { -void NameValueItem::sort(NameValueItems *list) +void EnvironmentItem::sort(EnvironmentItems *list) { - Utils::sort(*list, &NameValueItem::name); + Utils::sort(*list, &EnvironmentItem::name); } -NameValueItems NameValueItem::fromStringList(const QStringList &list) +EnvironmentItems EnvironmentItem::fromStringList(const QStringList &list) { - NameValueItems result; + EnvironmentItems result; for (const QString &string : list) { int pos = string.indexOf("+="); if (pos != -1) { - result.append({string.left(pos), string.mid(pos + 2), NameValueItem::Append}); + result.append({string.left(pos), string.mid(pos + 2), EnvironmentItem::Append}); continue; } pos = string.indexOf("=+"); if (pos != -1) { - result.append({string.left(pos), string.mid(pos + 2), NameValueItem::Prepend}); + result.append({string.left(pos), string.mid(pos + 2), EnvironmentItem::Prepend}); continue; } pos = string.indexOf('=', 1); if (pos == -1) { - result.append(NameValueItem(string, QString(), NameValueItem::Unset)); + result.append(EnvironmentItem(string, QString(), EnvironmentItem::Unset)); continue; } const int hashPos = string.indexOf('#'); if (hashPos != -1 && hashPos < pos) { result.append({string.mid(hashPos + 1, pos - hashPos - 1), string.mid(pos + 1), - NameValueItem::SetDisabled}); + EnvironmentItem::SetDisabled}); } else { result.append({string.left(pos), string.mid(pos + 1)}); } @@ -45,49 +45,49 @@ NameValueItems NameValueItem::fromStringList(const QStringList &list) return result; } -QStringList NameValueItem::toStringList(const NameValueItems &list) +QStringList EnvironmentItem::toStringList(const EnvironmentItems &list) { - return Utils::transform(list, [](const NameValueItem &item) { + return Utils::transform(list, [](const EnvironmentItem &item) { switch (item.operation) { - case NameValueItem::Unset: + case EnvironmentItem::Unset: return item.name; - case NameValueItem::Append: + case EnvironmentItem::Append: return QString(item.name + "+=" + item.value); - case NameValueItem::Prepend: + case EnvironmentItem::Prepend: return QString(item.name + "=+" + item.value); - case NameValueItem::SetDisabled: + case EnvironmentItem::SetDisabled: return QString('#' + item.name + '=' + item.value); - case NameValueItem::SetEnabled: + case EnvironmentItem::SetEnabled: return QString(item.name + '=' + item.value); } return QString(); }); } -NameValueItems NameValueItem::itemsFromVariantList(const QVariantList &list) +EnvironmentItems EnvironmentItem::itemsFromVariantList(const QVariantList &list) { - return Utils::transform(list, [](const QVariant &item) { + return Utils::transform(list, [](const QVariant &item) { return itemFromVariantList(item.toList()); }); } -QVariantList NameValueItem::toVariantList(const NameValueItems &list) +QVariantList EnvironmentItem::toVariantList(const EnvironmentItems &list) { - return Utils::transform(list, [](const NameValueItem &item) { + return Utils::transform(list, [](const EnvironmentItem &item) { return QVariant(toVariantList(item)); }); } -NameValueItem NameValueItem::itemFromVariantList(const QVariantList &list) +EnvironmentItem EnvironmentItem::itemFromVariantList(const QVariantList &list) { - QTC_ASSERT(list.size() == 3, return NameValueItem("", "")); + QTC_ASSERT(list.size() == 3, return EnvironmentItem("", "")); QString key = list.value(0).toString(); Operation operation = Operation(list.value(1).toInt()); QString value = list.value(2).toString(); - return NameValueItem(key, value, operation); + return EnvironmentItem(key, value, operation); } -QVariantList NameValueItem::toVariantList(const NameValueItem &item) +QVariantList EnvironmentItem::toVariantList(const EnvironmentItem &item) { return QVariantList() << item.name << item.operation << item.value; } @@ -118,7 +118,7 @@ static QString expand(const NameValueDictionary *dictionary, QString value) return value; } -void NameValueItem::apply(NameValueDictionary *dictionary, Operation op) const +void EnvironmentItem::apply(NameValueDictionary *dictionary, Operation op) const { switch (op) { case SetEnabled: @@ -173,26 +173,26 @@ void NameValueItem::apply(NameValueDictionary *dictionary, Operation op) const } } -QDebug operator<<(QDebug debug, const NameValueItem &i) +QDebug operator<<(QDebug debug, const EnvironmentItem &i) { QDebugStateSaver saver(debug); debug.noquote(); debug.nospace(); debug << "KeyValueItem("; switch (i.operation) { - case NameValueItem::SetEnabled: + case EnvironmentItem::SetEnabled: debug << "set \"" << i.name << "\" to \"" << i.value << '"'; break; - case NameValueItem::SetDisabled: + case EnvironmentItem::SetDisabled: debug << "set \"" << i.name << "\" to \"" << i.value << '"' << "[disabled]"; break; - case NameValueItem::Unset: + case EnvironmentItem::Unset: debug << "unset \"" << i.name << '"'; break; - case NameValueItem::Prepend: + case EnvironmentItem::Prepend: debug << "prepend to \"" << i.name << "\":\"" << i.value << '"'; break; - case NameValueItem::Append: + case EnvironmentItem::Append: debug << "append to \"" << i.name << "\":\"" << i.value << '"'; break; } diff --git a/src/libs/utils/namevalueitem.h b/src/libs/utils/namevalueitem.h index 62ba9d25baf..6ad5ed03791 100644 --- a/src/libs/utils/namevalueitem.h +++ b/src/libs/utils/namevalueitem.h @@ -13,12 +13,12 @@ namespace Utils { -class QTCREATOR_UTILS_EXPORT NameValueItem +class QTCREATOR_UTILS_EXPORT EnvironmentItem { public: enum Operation : char { SetEnabled, Unset, Prepend, Append, SetDisabled }; - NameValueItem() = default; - NameValueItem(const QString &key, const QString &value, Operation operation = SetEnabled) + EnvironmentItem() = default; + EnvironmentItem(const QString &key, const QString &value, Operation operation = SetEnabled) : name(key) , value(value) , operation(operation) @@ -26,25 +26,25 @@ public: void apply(NameValueDictionary *dictionary) const { apply(dictionary, operation); } - static void sort(NameValueItems *list); - static NameValueItems fromStringList(const QStringList &list); - static QStringList toStringList(const NameValueItems &list); - static NameValueItems itemsFromVariantList(const QVariantList &list); - static QVariantList toVariantList(const NameValueItems &list); - static NameValueItem itemFromVariantList(const QVariantList &list); - static QVariantList toVariantList(const NameValueItem &item); + static void sort(EnvironmentItems *list); + static EnvironmentItems fromStringList(const QStringList &list); + static QStringList toStringList(const EnvironmentItems &list); + static EnvironmentItems itemsFromVariantList(const QVariantList &list); + static QVariantList toVariantList(const EnvironmentItems &list); + static EnvironmentItem itemFromVariantList(const QVariantList &list); + static QVariantList toVariantList(const EnvironmentItem &item); - friend bool operator==(const NameValueItem &first, const NameValueItem &second) + friend bool operator==(const EnvironmentItem &first, const EnvironmentItem &second) { return first.operation == second.operation && first.name == second.name && first.value == second.value; } - friend bool operator!=(const NameValueItem &first, const NameValueItem &second) + friend bool operator!=(const EnvironmentItem &first, const EnvironmentItem &second) { return !(first == second); } - friend QTCREATOR_UTILS_EXPORT QDebug operator<<(QDebug debug, const NameValueItem &i); + friend QTCREATOR_UTILS_EXPORT QDebug operator<<(QDebug debug, const EnvironmentItem &i); public: QString name; diff --git a/src/libs/utils/namevaluesdialog.cpp b/src/libs/utils/namevaluesdialog.cpp index 4f9537655ef..43511fe57f0 100644 --- a/src/libs/utils/namevaluesdialog.cpp +++ b/src/libs/utils/namevaluesdialog.cpp @@ -70,7 +70,7 @@ NameValueItemsWidget::NameValueItemsWidget(QWidget *parent) layout->addWidget(new QLabel(helpText, this)); const auto checkForItemChange = [this] { - const NameValueItems newItems = environmentItems(); + const EnvironmentItems newItems = environmentItems(); if (newItems != m_originalItems) { m_originalItems = newItems; emit userChangedItems(newItems); @@ -190,8 +190,8 @@ void NameValuesDialog::setPlaceholderText(const QString &text) m_editor->setPlaceholderText(text); } -std::optional NameValuesDialog::getNameValueItems(QWidget *parent, - const NameValueItems &initial, +std::optional NameValuesDialog::getNameValueItems(QWidget *parent, + const EnvironmentItems &initial, const QString &placeholderText, Polisher polisher, const QString &windowTitle) diff --git a/src/libs/utils/namevaluesdialog.h b/src/libs/utils/namevaluesdialog.h index af847bb5a1d..a1e884fe5b5 100644 --- a/src/libs/utils/namevaluesdialog.h +++ b/src/libs/utils/namevaluesdialog.h @@ -34,20 +34,20 @@ signals: private: Internal::TextEditHelper *m_editor; - NameValueItems m_originalItems; + EnvironmentItems m_originalItems; }; class QTCREATOR_UTILS_EXPORT NameValuesDialog : public QDialog { public: - void setNameValueItems(const NameValueItems &items); - NameValueItems nameValueItems() const; + void setNameValueItems(const EnvironmentItems &items); + EnvironmentItems nameValueItems() const; void setPlaceholderText(const QString &text); using Polisher = std::function; - static std::optional getNameValueItems(QWidget *parent = nullptr, - const NameValueItems &initial = {}, + static std::optional getNameValueItems(QWidget *parent = nullptr, + const EnvironmentItems &initial = {}, const QString &placeholderText = {}, Polisher polish = {}, const QString &windowTitle = {}); diff --git a/src/plugins/debugger/gdb/gdbengine.cpp b/src/plugins/debugger/gdb/gdbengine.cpp index 406b5524473..9efc98f24c3 100644 --- a/src/plugins/debugger/gdb/gdbengine.cpp +++ b/src/plugins/debugger/gdb/gdbengine.cpp @@ -4093,7 +4093,7 @@ void GdbEngine::setEnvironmentVariables() Environment baseEnv = runParameters().debugger.environment; Environment runEnv = runParameters().inferior.environment; - const NameValueItems items = baseEnv.diff(runEnv); + const EnvironmentItems items = baseEnv.diff(runEnv); for (const EnvironmentItem &item : items) { // imitate the weird windows gdb behavior of setting the case of the path environment // variable name to an all uppercase PATH diff --git a/src/plugins/mcusupport/mcukitaspect.cpp b/src/plugins/mcusupport/mcukitaspect.cpp index f53dcacfd04..8d497f209dd 100644 --- a/src/plugins/mcusupport/mcukitaspect.cpp +++ b/src/plugins/mcusupport/mcukitaspect.cpp @@ -32,19 +32,19 @@ Utils::Id McuDependenciesKitAspect::id() return "PE.Profile.McuCMakeDependencies"; } -Utils::NameValueItems McuDependenciesKitAspect::dependencies(const Kit *kit) +Utils::EnvironmentItems McuDependenciesKitAspect::dependencies(const Kit *kit) { if (kit) - return Utils::NameValueItem::fromStringList( + return Utils::EnvironmentItem::fromStringList( kit->value(McuDependenciesKitAspect::id()).toStringList()); - return Utils::NameValueItems(); + return Utils::EnvironmentItems(); } -void McuDependenciesKitAspect::setDependencies(Kit *k, const Utils::NameValueItems &dependencies) +void McuDependenciesKitAspect::setDependencies(Kit *k, const Utils::EnvironmentItems &dependencies) { if (k) k->setValue(McuDependenciesKitAspect::id(), - Utils::NameValueItem::toStringList(dependencies)); + Utils::EnvironmentItem::toStringList(dependencies)); } Utils::NameValuePairs McuDependenciesKitAspect::configuration(const Kit *kit) @@ -108,7 +108,7 @@ public: if (!variant.isNull() && !variant.canConvert(QVariant::List)) { qWarning("Kit \"%s\" has a wrong mcu dependencies value set.", qPrintable(kit->displayName())); - McuDependenciesKitAspect::setDependencies(kit, Utils::NameValueItems()); + McuDependenciesKitAspect::setDependencies(kit, Utils::EnvironmentItems()); } } diff --git a/src/plugins/mcusupport/mcukitaspect.h b/src/plugins/mcusupport/mcukitaspect.h index a86841a72aa..46256213488 100644 --- a/src/plugins/mcusupport/mcukitaspect.h +++ b/src/plugins/mcusupport/mcukitaspect.h @@ -11,8 +11,8 @@ class McuDependenciesKitAspect final { public: static Utils::Id id(); - static Utils::NameValueItems dependencies(const ProjectExplorer::Kit *kit); - static void setDependencies(ProjectExplorer::Kit *kit, const Utils::NameValueItems &dependencies); + static Utils::EnvironmentItems dependencies(const ProjectExplorer::Kit *kit); + static void setDependencies(ProjectExplorer::Kit *kit, const Utils::EnvironmentItems &dependencies); static Utils::NameValuePairs configuration(const ProjectExplorer::Kit *kit); }; diff --git a/src/plugins/mcusupport/mcukitmanager.cpp b/src/plugins/mcusupport/mcukitmanager.cpp index 456bdbdcdfc..08c9c8abb09 100644 --- a/src/plugins/mcusupport/mcukitmanager.cpp +++ b/src/plugins/mcusupport/mcukitmanager.cpp @@ -180,7 +180,7 @@ public: const McuTarget *mcuTarget, const McuPackagePtr &qtForMCUsSdkPackage) { - NameValueItems dependencies; + EnvironmentItems dependencies; auto processPackage = [&dependencies](const McuPackagePtr &package) { const auto cmakeVariableName = package->cmakeVariableName(); diff --git a/src/plugins/projectexplorer/environmentwidget.cpp b/src/plugins/projectexplorer/environmentwidget.cpp index 9a63d789ece..a34f8bc256e 100644 --- a/src/plugins/projectexplorer/environmentwidget.cpp +++ b/src/plugins/projectexplorer/environmentwidget.cpp @@ -481,25 +481,25 @@ void EnvironmentWidget::unsetEnvironmentButtonClicked() d->m_editor.setEnvironmentItems(d->m_model->userChanges()); } -void EnvironmentWidget::amendPathList(Utils::NameValueItem::Operation op) +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")); if (dir.isEmpty()) return; - Utils::NameValueItems changes = d->m_model->userChanges(); + Utils::EnvironmentItems changes = d->m_model->userChanges(); changes.append({varName, dir.toUserOutput(), op}); setUserChanges(changes); } void EnvironmentWidget::appendPathButtonClicked() { - amendPathList(Utils::NameValueItem::Append); + amendPathList(Utils::EnvironmentItem::Append); } void EnvironmentWidget::prependPathButtonClicked() { - amendPathList(Utils::NameValueItem::Prepend); + amendPathList(Utils::EnvironmentItem::Prepend); } void EnvironmentWidget::environmentCurrentIndexChanged(const QModelIndex ¤t) diff --git a/src/plugins/projectexplorer/environmentwidget.h b/src/plugins/projectexplorer/environmentwidget.h index a00e45bcda7..b1a26b036b3 100644 --- a/src/plugins/projectexplorer/environmentwidget.h +++ b/src/plugins/projectexplorer/environmentwidget.h @@ -57,7 +57,7 @@ private: void linkActivated(const QString &link); using PathListModifier = std::function; - void amendPathList(Utils::NameValueItem::Operation op); + void amendPathList(Utils::EnvironmentItem::Operation op); class Private; const std::unique_ptr d; diff --git a/src/plugins/projectexplorer/project.cpp b/src/plugins/projectexplorer/project.cpp index cd46c2a521c..7f2eee43db7 100644 --- a/src/plugins/projectexplorer/project.cpp +++ b/src/plugins/projectexplorer/project.cpp @@ -1063,13 +1063,13 @@ void Project::setNamedSettings(const Key &name, const QVariant &value) void Project::setAdditionalEnvironment(const EnvironmentItems &envItems) { - setNamedSettings(PROJECT_ENV_KEY, NameValueItem::toStringList(envItems)); + setNamedSettings(PROJECT_ENV_KEY, EnvironmentItem::toStringList(envItems)); emit environmentChanged(); } EnvironmentItems Project::additionalEnvironment() const { - return NameValueItem::fromStringList(namedSettings(PROJECT_ENV_KEY).toStringList()); + return EnvironmentItem::fromStringList(namedSettings(PROJECT_ENV_KEY).toStringList()); } bool Project::needsConfiguration() const diff --git a/src/plugins/qmlprojectmanager/cmakegen/generatecmakelists.cpp b/src/plugins/qmlprojectmanager/cmakegen/generatecmakelists.cpp index 524150db41b..50d8596ae36 100644 --- a/src/plugins/qmlprojectmanager/cmakegen/generatecmakelists.cpp +++ b/src/plugins/qmlprojectmanager/cmakegen/generatecmakelists.cpp @@ -286,7 +286,7 @@ const QString projectEnvironmentVariable(const QString &key) if (auto buildSystem = getBuildSystem()) { auto envItems = buildSystem->environment(); - auto confEnv = std::find_if(envItems.begin(), envItems.end(), [key](NameValueItem &item) { + auto confEnv = std::find_if(envItems.begin(), envItems.end(), [key](EnvironmentItem &item) { return item.name == key; }); if (confEnv != envItems.end()) diff --git a/tests/auto/environment/tst_environment.cpp b/tests/auto/environment/tst_environment.cpp index 64dfe426487..3cf9c127a22 100644 --- a/tests/auto/environment/tst_environment.cpp +++ b/tests/auto/environment/tst_environment.cpp @@ -262,11 +262,11 @@ void tst_Environment::expansion() void tst_Environment::incrementalChanges() { const Environment origEnv({{"VAR1", "VALUE1"}, {"VAR2", "VALUE2"}, {"PATH", "/usr/bin"}}); - const NameValueItems changes({ - {"VAR1", QString(), NameValueItem::Unset}, - {"VAR2", "VALUE2", NameValueItem::SetDisabled}, - {"PATH", "/usr/local/bin", NameValueItem::Append}, - {"PATH", "/tmp", NameValueItem::Prepend}}); + const EnvironmentItems changes({ + {"VAR1", QString(), EnvironmentItem::Unset}, + {"VAR2", "VALUE2", EnvironmentItem::SetDisabled}, + {"PATH", "/usr/local/bin", EnvironmentItem::Append}, + {"PATH", "/tmp", EnvironmentItem::Prepend}}); // Check values after change application. Environment newEnv = origEnv; @@ -281,8 +281,8 @@ void tst_Environment::incrementalChanges() QString("/tmp").append(sep).append("/usr/bin").append(sep).append("/usr/local/bin")); // Check apply/diff round-trips. - const NameValueItems diff = origEnv.diff(newEnv); - const NameValueItems reverseDiff = newEnv.diff(origEnv); + const EnvironmentItems diff = origEnv.diff(newEnv); + const EnvironmentItems reverseDiff = newEnv.diff(origEnv); Environment newEnv2 = origEnv; newEnv2.modify(diff); QCOMPARE(newEnv, newEnv2); @@ -290,12 +290,12 @@ void tst_Environment::incrementalChanges() QCOMPARE(newEnv2, origEnv); // Check conversion round-trips. - QCOMPARE(NameValueItem::fromStringList(NameValueItem::toStringList(changes)), changes); - QCOMPARE(NameValueItem::fromStringList(NameValueItem::toStringList(diff)), diff); - QCOMPARE(NameValueItem::fromStringList(NameValueItem::toStringList(reverseDiff)), reverseDiff); - QCOMPARE(NameValueItem::itemsFromVariantList(NameValueItem::toVariantList(changes)), changes); - QCOMPARE(NameValueItem::itemsFromVariantList(NameValueItem::toVariantList(diff)), diff); - QCOMPARE(NameValueItem::itemsFromVariantList(NameValueItem::toVariantList(reverseDiff)), + QCOMPARE(EnvironmentItem::fromStringList(EnvironmentItem::toStringList(changes)), changes); + QCOMPARE(EnvironmentItem::fromStringList(EnvironmentItem::toStringList(diff)), diff); + QCOMPARE(EnvironmentItem::fromStringList(EnvironmentItem::toStringList(reverseDiff)), reverseDiff); + QCOMPARE(EnvironmentItem::itemsFromVariantList(EnvironmentItem::toVariantList(changes)), changes); + QCOMPARE(EnvironmentItem::itemsFromVariantList(EnvironmentItem::toVariantList(diff)), diff); + QCOMPARE(EnvironmentItem::itemsFromVariantList(EnvironmentItem::toVariantList(reverseDiff)), reverseDiff); } From c38c0fc863153883cf1305881230210cc60b602f Mon Sep 17 00:00:00 2001 From: Leena Miettinen Date: Wed, 14 Feb 2024 13:00:41 +0100 Subject: [PATCH 008/243] Doc: Describe highlighting source lines matching assembly code ...in Compiler Explorer Task-number: QTCREATORBUG-30209 Change-Id: I91d9e82ee8fac0ddb3196a39f9f5f0baf1cac184 Reviewed-by: Marcus Tillmanns --- ...r-how-to-create-compiler-explorer-setup.qdoc | 17 ++++++++++------- 1 file changed, 10 insertions(+), 7 deletions(-) diff --git a/doc/qtcreator/src/projects/creator-only/creator-how-to-create-compiler-explorer-setup.qdoc b/doc/qtcreator/src/projects/creator-only/creator-how-to-create-compiler-explorer-setup.qdoc index 08bc4764434..b35df2e6707 100644 --- a/doc/qtcreator/src/projects/creator-only/creator-how-to-create-compiler-explorer-setup.qdoc +++ b/doc/qtcreator/src/projects/creator-only/creator-how-to-create-compiler-explorer-setup.qdoc @@ -1,20 +1,20 @@ -// Copyright (C) 2023 The Qt Company Ltd. +// Copyright (C) 2024 The Qt Company Ltd. // SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GFDL-1.3-no-invariants-only /*! \page creator-how-to-create-compiler-explorer-sessions.html \previouspage creator-how-tos.html - \ingroup creator-how-to-projects-files + \ingroup creator-how-to-analyze \title Create compiler explorer sessions To create a compiler explorer session for a C++ or Python project: \list 1 - \li Select \uicontrol File > \uicontrol {New File} > - \uicontrol {Compiler Explorer} > \uicontrol C++ or \uicontrol Python - > \uicontrol Choose. + \li Go to \uicontrol File > \uicontrol {New File}. + \li Select \uicontrol {Compiler Explorer} > \uicontrol C++ or + \uicontrol Python > \uicontrol Choose. \li Follow the instructions of the wizard to create an example compiler explorer session as a JSON-based \c .qtce file and to open it. @@ -29,7 +29,7 @@ \page creator-how-to-explore-compiler-code.html \previouspage creator-how-tos.html - \ingroup creator-how-to-build + \ingroup creator-how-to-analyze \title Explore compiler code @@ -45,7 +45,7 @@ To check how a compiler sees C++ or Python code: \list 1 - \li Select \uicontrol Tools > \uicontrol {Compiler Explorer} > + \li Go to \uicontrol Tools > \uicontrol {Compiler Explorer} > \uicontrol {Open Compiler Explorer}. \li In the \uicontrol Language field, select the language to compile. \li In the \uicontrol Compiler field, select a compiler to see the @@ -53,6 +53,9 @@ \li Enter code to see the resulting assembly code. \endlist + Hover the mouse over the assembly code, to have the matching source lines + highlighted. + You can also see the application status and output. To explore several compilers, select \uicontrol {Add Compiler}. From 9f155ecc822a6819fa014dd20c30d66438a88947 Mon Sep 17 00:00:00 2001 From: Leena Miettinen Date: Wed, 14 Feb 2024 12:29:04 +0100 Subject: [PATCH 009/243] Doc: Describe the Enclose in QByteArrayLiteral() quick fix Task-number: QTCREATORBUG-30209 Change-Id: If802af529a12ce9729fddd4d3f37372b593fc47e Reviewed-by: Christian Kandeler --- .../creator-only/creator-cpp-quick-fixes.qdoc | 13 +++++++++++++ 1 file changed, 13 insertions(+) diff --git a/doc/qtcreator/src/editors/creator-only/creator-cpp-quick-fixes.qdoc b/doc/qtcreator/src/editors/creator-only/creator-cpp-quick-fixes.qdoc index 0651d02ae38..7df63851dc7 100644 --- a/doc/qtcreator/src/editors/creator-only/creator-cpp-quick-fixes.qdoc +++ b/doc/qtcreator/src/editors/creator-only/creator-cpp-quick-fixes.qdoc @@ -328,7 +328,20 @@ \endcode \li String literal + \row + \li Enclose in QByteArrayLiteral() + \li Converts a string to a byte array. For example, rewrites + \code + "abcd" + \endcode + as + + \code + QByteArrayLiteral("abcd") + \endcode + + \li String literal \row \li Mark as Translatable \li Marks a string translatable. For example, rewrites \c "abcd" From 7c86b0d2cb7ecfd04c3089911265d0d69813bc11 Mon Sep 17 00:00:00 2001 From: Leena Miettinen Date: Wed, 14 Feb 2024 15:16:37 +0100 Subject: [PATCH 010/243] Doc: Update info about iOS 17 support Task-number: QTCREATORBUG-30209 Change-Id: I7ba61e3626d268bf21b659afa3a2f87891bf2c8e Reviewed-by: Eike Ziller --- doc/qtcreator/src/ios/creator-ios-dev.qdoc | 12 +++++++++--- 1 file changed, 9 insertions(+), 3 deletions(-) diff --git a/doc/qtcreator/src/ios/creator-ios-dev.qdoc b/doc/qtcreator/src/ios/creator-ios-dev.qdoc index 6c9ca24dfea..203ab0ff126 100644 --- a/doc/qtcreator/src/ios/creator-ios-dev.qdoc +++ b/doc/qtcreator/src/ios/creator-ios-dev.qdoc @@ -1,4 +1,4 @@ -// Copyright (C) 2019 The Qt Company Ltd. +// Copyright (C) 2024 The Qt Company Ltd. // SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GFDL-1.3-no-invariants-only /*! @@ -11,8 +11,6 @@ You can connect iOS devices to your local machine with a USB cable to run applications built for them from \QC. - \note Deployment, running, and debugging on iOS 17 devices are not supported. - To be able to use \QC on \macos, you must install Xcode, and therefore, you already have the tool chain for building applications for iOS. \QC automatically detects the tool chain and creates the necessary @@ -22,6 +20,14 @@ You only need Qt libraries that are built for iOS. You can install them as part of Qt 5.2, or later. + \section1 iOS 17 Devices + + \QC detects iOS 17 devices, and you can deploy and run applications on them. + + However, \QC cannot access application output. Also, debugging and + profiling are not supported because of limitations of the Apple tool for + accessing devices with iOS 17, and later. + \section1 Configuring Devices The connections between \QC and an iOS device are protected by using a From d6b2c205ad816c1e57b73fded98de41c34431661 Mon Sep 17 00:00:00 2001 From: Leena Miettinen Date: Fri, 9 Feb 2024 17:25:48 +0100 Subject: [PATCH 011/243] Doc: Describe how to navigate QML code F2 now lets users move to the C++ implementation of a QML type. Task-number: QTCREATORBUG-30209 Change-Id: If364451d7e94fcd18da82321839dede18bf704a4 Reviewed-by: Reviewed-by: Eike Ziller --- .../images/qtcreator-locator-m-filter.webp | Bin 0 -> 3032 bytes .../src/editors/creator-code-refactoring.qdoc | 7 --- .../howto/creator-only/creator-how-tos.qdoc | 41 +++++++++++++++--- 3 files changed, 36 insertions(+), 12 deletions(-) create mode 100644 doc/qtcreator/images/qtcreator-locator-m-filter.webp diff --git a/doc/qtcreator/images/qtcreator-locator-m-filter.webp b/doc/qtcreator/images/qtcreator-locator-m-filter.webp new file mode 100644 index 0000000000000000000000000000000000000000..9b681b38c00c70364d06547f4c00a3652893f2d3 GIT binary patch literal 3032 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 \uicontrol {QML/JS} > - \uicontrol {Find References to Symbol Under Cursor} or press - \key {Ctrl+Shift+U}. - \section1 Viewing Search Results \QC searches from the following locations: 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 0643c3a1525..c82cdcfa91c 100644 --- a/doc/qtcreator/src/howto/creator-only/creator-how-tos.qdoc +++ b/doc/qtcreator/src/howto/creator-only/creator-how-tos.qdoc @@ -224,17 +224,48 @@ */ /*! - \page creator-how-to-jump-to-functions-in-qml-code.html + \page creator-how-to-navigate-qml-code.html \previouspage creator-how-tos.html \ingroup creator-how-to-edit - \title Jump to a function in QML code + \title Move in QML code - Open the \uicontrol Locator with \key {Ctrl+K} and type m, followed by a space. - You can now go directly to any QML method in the file. + Find QML methods and types, and move to the C++ implementation of a QML type. - \sa {Edit Code}{How To: Edit Code}, {Edit Mode} + \section1 Locate QML methods + + To locate a QML method: + + \list 1 + \li Press \key {Ctrl+K} to activate the locator. + \li Type m, followed by a space. + \image qtcreator-locator-m-filter.webp {The m filter in the locator} + \li Double-click a QML method in the list to move to it in the editor. + \endlist + + \section1 Find QML types + + To find instances of a QML type in a project, place the cursor on + the type and and do one of the following: + + \list + \li Press \key {Ctrl+Shift+U}. + \li Go to \uicontrol Tools > \uicontrol {QML/JS} > + \uicontrol {Find References to Symbol Under Cursor}. + \endlist + + \section1 Move between QML and C++ + + To move to the C++ implementation of a QML type in the code editor, place the + cursor on the type and do one of the following: + + \list + \li Press \key F2. + \li Go to \uicontrol {Follow Symbol Under Cursor} in the context menu. + \endlist + + \sa {Edit Code}{How To: Edit Code}, {Edit Mode}, {Searching with the Locator} */ /*! From e1b3c3e35762df83e68b02c657ef69289cf72224 Mon Sep 17 00:00:00 2001 From: Christian Kandeler Date: Tue, 13 Feb 2024 17:51:23 +0100 Subject: [PATCH 012/243] ProjectExplorer: Warn against "special" characters in build directories There are still tools around that have problems with such setups, so we turn this warning on by default and let the user opt out. Fixes: QTCREATORBUG-20834 Change-Id: I01a2e0fa931bec74add43b37cb042712635f3175 Reviewed-by: Christian Kandeler --- src/plugins/projectexplorer/buildaspects.cpp | 84 ++++++++++++++++--- src/plugins/projectexplorer/buildaspects.h | 3 +- .../projectexplorer/projectexplorer.cpp | 8 ++ .../projectexplorersettings.cpp | 10 +++ .../projectexplorer/projectexplorersettings.h | 2 + 5 files changed, 93 insertions(+), 14 deletions(-) diff --git a/src/plugins/projectexplorer/buildaspects.cpp b/src/plugins/projectexplorer/buildaspects.cpp index a108558f360..18f7fe2b851 100644 --- a/src/plugins/projectexplorer/buildaspects.cpp +++ b/src/plugins/projectexplorer/buildaspects.cpp @@ -8,10 +8,13 @@ #include "devicesupport/idevice.h" #include "kitaspects.h" #include "projectexplorerconstants.h" +#include "projectexplorer.h" +#include "projectexplorersettings.h" #include "projectexplorertr.h" #include "target.h" #include +#include #include #include @@ -19,6 +22,8 @@ #include #include +#include + using namespace Utils; namespace ProjectExplorer { @@ -31,8 +36,11 @@ public: FilePath sourceDir; Target * const target; FilePath savedShadowBuildDir; - QString problem; - QPointer problemLabel; + QString specialProblem; + QLabel *genericProblemSpacer; + QLabel *specialProblemSpacer; + QPointer genericProblemLabel; + QPointer specialProblemLabel; }; BuildDirectoryAspect::BuildDirectoryAspect(AspectContainer *container, const BuildConfiguration *bc) @@ -48,6 +56,10 @@ BuildDirectoryAspect::BuildDirectoryAspect(AspectContainer *container, const Bui if (!fixedDir.isEmpty()) text = fixedDir.toUserOutput(); + const QString problem = updateProblemLabelsHelper(text); + if (!problem.isEmpty()) + return QtFuture::makeReadyFuture(expected_str(make_unexpected(problem))); + const FilePath newPath = FilePath::fromUserInput(text); const auto buildDevice = BuildDeviceKitAspect::device(d->target->kit()); @@ -56,12 +68,16 @@ BuildDirectoryAspect::BuildDirectoryAspect(AspectContainer *container, const Bui return QtFuture::makeReadyFuture((Utils::expected_str(make_unexpected( Tr::tr("The build directory is not reachable from the build device."))))); } + return pathChooser()->defaultValidationFunction()(text); }); setOpenTerminalHandler([this, bc] { Core::FileUtils::openTerminal(expandedValue(), bc->environment()); }); + + connect(ProjectExplorerPlugin::instance(), &ProjectExplorerPlugin::settingsChanged, + this, &BuildDirectoryAspect::validateInput); } BuildDirectoryAspect::~BuildDirectoryAspect() @@ -83,8 +99,8 @@ bool BuildDirectoryAspect::isShadowBuild() const void BuildDirectoryAspect::setProblem(const QString &description) { - d->problem = description; - updateProblemLabel(); + d->specialProblem = description; + validateInput(); } void BuildDirectoryAspect::toMap(Store &map) const @@ -110,10 +126,18 @@ void BuildDirectoryAspect::fromMap(const Store &map) void BuildDirectoryAspect::addToLayout(Layouting::LayoutItem &parent) { FilePathAspect::addToLayout(parent); - d->problemLabel = new InfoLabel({}, InfoLabel::Warning); - d->problemLabel->setElideMode(Qt::ElideNone); - parent.addItems({Layouting::br, Layouting::empty, d->problemLabel.data()}); - updateProblemLabel(); + d->genericProblemSpacer = new QLabel; + d->specialProblemSpacer = new QLabel; + d->genericProblemLabel = new InfoLabel({}, InfoLabel::Warning); + d->genericProblemLabel->setElideMode(Qt::ElideNone); + connect(d->genericProblemLabel, &QLabel::linkActivated, this, [] { + Core::ICore::showOptionsDialog(Constants::BUILD_AND_RUN_SETTINGS_PAGE_ID); + }); + d->specialProblemLabel = new InfoLabel({}, InfoLabel::Warning); + d->specialProblemLabel->setElideMode(Qt::ElideNone); + parent.addItems({Layouting::br, d->genericProblemSpacer, d->genericProblemLabel.data()}); + parent.addItems({Layouting::br, d->specialProblemSpacer, d->specialProblemLabel.data()}); + updateProblemLabels(); if (!d->sourceDir.isEmpty()) { connect(this, &StringAspect::checkedChanged, this, [this] { if (isChecked()) { @@ -153,13 +177,47 @@ FilePath BuildDirectoryAspect::fixupDir(const FilePath &dir) return {}; } -void BuildDirectoryAspect::updateProblemLabel() +void BuildDirectoryAspect::updateProblemLabels() { - if (!d->problemLabel) - return; + updateProblemLabelsHelper(value()); +} - d->problemLabel->setText(d->problem); - d->problemLabel->setVisible(!d->problem.isEmpty()); +QString BuildDirectoryAspect::updateProblemLabelsHelper(const QString &value) +{ + if (!d->genericProblemLabel) + return {}; + QTC_ASSERT(d->specialProblemLabel, return {}); + + QString genericProblem; + QString genericProblemLabelString; + if (ProjectExplorerPlugin::projectExplorerSettings().warnAgainstNonAsciiBuildDir) { + const auto isInvalid = [](QChar c) { return c.isSpace() || !isascii(c.toLatin1()); }; + if (const auto invalidChar = Utils::findOr(value, std::nullopt, isInvalid)) { + genericProblem = Tr::tr( + "Build directory contains potentially problematic character '%1'.") + .arg(*invalidChar); + genericProblemLabelString + = genericProblem + + Tr::tr(" This warning can be suppressed here."); + } + } + + auto updateRow = [](const QString &text, InfoLabel *label, QLabel *spacer) { + label->setText(text); + label->setVisible(!text.isEmpty()); + spacer->setVisible(!text.isEmpty()); + }; + + updateRow(genericProblemLabelString, d->genericProblemLabel, d->genericProblemSpacer); + updateRow(d->specialProblem, d->specialProblemLabel, d->specialProblemSpacer); + + if (genericProblem.isEmpty() && d->specialProblem.isEmpty()) + return {}; + if (genericProblem.isEmpty()) + return d->specialProblem; + if (d->specialProblem.isEmpty()) + return genericProblem; + return genericProblem + '\n' + d->specialProblem; } SeparateDebugInfoAspect::SeparateDebugInfoAspect(AspectContainer *container) diff --git a/src/plugins/projectexplorer/buildaspects.h b/src/plugins/projectexplorer/buildaspects.h index f159cd9d37b..f19cc393858 100644 --- a/src/plugins/projectexplorer/buildaspects.h +++ b/src/plugins/projectexplorer/buildaspects.h @@ -31,7 +31,8 @@ private: void toMap(Utils::Store &map) const override; void fromMap(const Utils::Store &map) override; - void updateProblemLabel(); + void updateProblemLabels(); + QString updateProblemLabelsHelper(const QString &value); class Private; Private * const d; diff --git a/src/plugins/projectexplorer/projectexplorer.cpp b/src/plugins/projectexplorer/projectexplorer.cpp index 4a9d1ef8aae..cf82aa6e739 100644 --- a/src/plugins/projectexplorer/projectexplorer.cpp +++ b/src/plugins/projectexplorer/projectexplorer.cpp @@ -281,6 +281,7 @@ const char CLEAR_ISSUES_ON_REBUILD_SETTINGS_KEY[] = "ProjectExplorer/Settings/Cl const char ABORT_BUILD_ALL_ON_ERROR_SETTINGS_KEY[] = "ProjectExplorer/Settings/AbortBuildAllOnError"; const char LOW_BUILD_PRIORITY_SETTINGS_KEY[] = "ProjectExplorer/Settings/LowBuildPriority"; +const char WARN_AGAINST_NON_ASCII_BUILD_DIR_SETTINGS_KEY[] = "ProjectExplorer/Settings/LowBuildPriority"; const char APP_ENV_CHANGES_SETTINGS_KEY[] = "ProjectExplorer/Settings/AppEnvChanges"; const char CUSTOM_PARSER_COUNT_KEY[] = "ProjectExplorer/Settings/CustomParserCount"; @@ -1696,6 +1697,10 @@ bool ProjectExplorerPlugin::initialize(const QStringList &arguments, QString *er dd->m_projectExplorerSettings.lowBuildPriority = s->value(Constants::LOW_BUILD_PRIORITY_SETTINGS_KEY, defaultSettings.lowBuildPriority) .toBool(); + dd->m_projectExplorerSettings.warnAgainstNonAsciiBuildDir + = s->value(Constants::WARN_AGAINST_NON_ASCII_BUILD_DIR_SETTINGS_KEY, + defaultSettings.warnAgainstNonAsciiBuildDir) + .toBool(); dd->m_projectExplorerSettings.appEnvChanges = EnvironmentItem::fromStringList( s->value(Constants::APP_ENV_CHANGES_SETTINGS_KEY).toStringList()); @@ -2258,6 +2263,9 @@ void ProjectExplorerPluginPrivate::savePersistentSettings() s->setValueWithDefault(Constants::LOW_BUILD_PRIORITY_SETTINGS_KEY, dd->m_projectExplorerSettings.lowBuildPriority, defaultSettings.lowBuildPriority); + s->setValueWithDefault(Constants::WARN_AGAINST_NON_ASCII_BUILD_DIR_SETTINGS_KEY, + dd->m_projectExplorerSettings.warnAgainstNonAsciiBuildDir, + defaultSettings.warnAgainstNonAsciiBuildDir); s->setValueWithDefault(Constants::AUTO_CREATE_RUN_CONFIGS_SETTINGS_KEY, dd->m_projectExplorerSettings.automaticallyCreateRunConfigurations, defaultSettings.automaticallyCreateRunConfigurations); diff --git a/src/plugins/projectexplorer/projectexplorersettings.cpp b/src/plugins/projectexplorer/projectexplorersettings.cpp index aa60eb49926..6cd79ce8f0b 100644 --- a/src/plugins/projectexplorer/projectexplorersettings.cpp +++ b/src/plugins/projectexplorer/projectexplorersettings.cpp @@ -70,6 +70,7 @@ private: QCheckBox *m_clearIssuesCheckBox; QCheckBox *m_abortBuildAllOnErrorCheckBox; QCheckBox *m_lowBuildPriorityCheckBox; + QCheckBox *m_warnAgainstNonAsciiBuildDirCheckBox; QComboBox *m_buildBeforeDeployComboBox; QComboBox *m_stopBeforeBuildComboBox; QComboBox *m_terminalModeComboBox; @@ -95,6 +96,12 @@ ProjectExplorerSettingsWidget::ProjectExplorerSettingsWidget() m_clearIssuesCheckBox = new QCheckBox(Tr::tr("Clear issues list on new build")); m_abortBuildAllOnErrorCheckBox = new QCheckBox(Tr::tr("Abort on error when building all projects")); m_lowBuildPriorityCheckBox = new QCheckBox(Tr::tr("Start build processes with low priority")); + m_warnAgainstNonAsciiBuildDirCheckBox = new QCheckBox( + Tr::tr("Warn against build directories with spaces or non-ASCII characters")); + m_warnAgainstNonAsciiBuildDirCheckBox->setToolTip( + Tr::tr("Some legacy build tools do not deal well with paths that contain \"special\" " + "characters such as spaces, potentially resulting in spurious build errors.

" + "Uncheck this option if you do not work with such tools.")); m_buildBeforeDeployComboBox = new QComboBox; m_buildBeforeDeployComboBox->addItem(Tr::tr("Do Not Build Anything"), int(BuildBeforeRunMode::Off)); @@ -172,6 +179,7 @@ ProjectExplorerSettingsWidget::ProjectExplorerSettingsWidget() m_clearIssuesCheckBox, m_abortBuildAllOnErrorCheckBox, m_lowBuildPriorityCheckBox, + m_warnAgainstNonAsciiBuildDirCheckBox, Form { appEnvDescriptionLabel, Row{m_appEnvLabel, appEnvButton, st}, br, Tr::tr("Build before deploying:"), m_buildBeforeDeployComboBox, br, @@ -219,6 +227,7 @@ ProjectExplorerSettings ProjectExplorerSettingsWidget::settings() const m_settings.clearIssuesOnRebuild = m_clearIssuesCheckBox->isChecked(); m_settings.abortBuildAllOnError = m_abortBuildAllOnErrorCheckBox->isChecked(); m_settings.lowBuildPriority = m_lowBuildPriorityCheckBox->isChecked(); + m_settings.warnAgainstNonAsciiBuildDir = m_warnAgainstNonAsciiBuildDirCheckBox->isChecked(); m_settings.appEnvChanges = m_appEnvChanges; return m_settings; } @@ -242,6 +251,7 @@ void ProjectExplorerSettingsWidget::setSettings(const ProjectExplorerSettings & m_clearIssuesCheckBox->setChecked(m_settings.clearIssuesOnRebuild); m_abortBuildAllOnErrorCheckBox->setChecked(m_settings.abortBuildAllOnError); m_lowBuildPriorityCheckBox->setChecked(m_settings.lowBuildPriority); + m_warnAgainstNonAsciiBuildDirCheckBox->setChecked(m_settings.warnAgainstNonAsciiBuildDir); } FilePath ProjectExplorerSettingsWidget::projectsDirectory() const diff --git a/src/plugins/projectexplorer/projectexplorersettings.h b/src/plugins/projectexplorer/projectexplorersettings.h index 244d4c76f87..dbec8ea2aef 100644 --- a/src/plugins/projectexplorer/projectexplorersettings.h +++ b/src/plugins/projectexplorer/projectexplorersettings.h @@ -36,6 +36,7 @@ public: && p1.clearIssuesOnRebuild == p2.clearIssuesOnRebuild && p1.abortBuildAllOnError == p2.abortBuildAllOnError && p1.appEnvChanges == p2.appEnvChanges + && p1.warnAgainstNonAsciiBuildDir == p2.warnAgainstNonAsciiBuildDir && p1.lowBuildPriority == p2.lowBuildPriority; } @@ -50,6 +51,7 @@ public: bool clearIssuesOnRebuild = true; bool abortBuildAllOnError = true; bool lowBuildPriority = false; + bool warnAgainstNonAsciiBuildDir = true; StopBeforeBuild stopBeforeBuild = Utils::HostOsInfo::isWindowsHost() ? StopBeforeBuild::SameProject : StopBeforeBuild::None; From e059b62421b0a2ba58856eb4a5ce37f2e913ec1a Mon Sep 17 00:00:00 2001 From: Jarek Kobus Date: Wed, 14 Feb 2024 23:05:38 +0100 Subject: [PATCH 013/243] TaskTree: Fix progress reporting with LoopUntil(false) Advance the progress value by the group's children count when LoopUntil handler returns false on the first iteration. Add a test for it. Change-Id: I3783dd295dfaa16c09c5eda299f365ff981b3be7 Reviewed-by: Reviewed-by: Qt CI Bot Reviewed-by: hjk --- src/libs/solutions/tasking/tasktree.cpp | 1 + tests/auto/solutions/tasking/tst_tasking.cpp | 13 ++++++++++++- 2 files changed, 13 insertions(+), 1 deletion(-) diff --git a/src/libs/solutions/tasking/tasktree.cpp b/src/libs/solutions/tasking/tasktree.cpp index 67a6f36817d..58fb43b3a5e 100644 --- a/src/libs/solutions/tasking/tasktree.cpp +++ b/src/libs/solutions/tasking/tasktree.cpp @@ -1850,6 +1850,7 @@ SetupResult TaskTreePrivate::start(RuntimeContainer *container) && (containerNode.m_children.empty() || (containerNode.m_loop && !invokeLoopHandler(container)))) { startAction = toSetupResult(container->m_successBit); + advanceProgress(containerNode.m_taskCount); } return continueStart(container, startAction); } diff --git a/tests/auto/solutions/tasking/tst_tasking.cpp b/tests/auto/solutions/tasking/tst_tasking.cpp index 1d708405a9d..64b407fce99 100644 --- a/tests/auto/solutions/tasking/tst_tasking.cpp +++ b/tests/auto/solutions/tasking/tst_tasking.cpp @@ -2807,7 +2807,7 @@ void tst_Tasking::testTree_data() } { - LoopUntil loop([](int index) { return index < 3; }); + const LoopUntil loop([](int index) { return index < 3; }); const auto onSetupContinue = [storage, loop](int taskId) { return [storage, loop, taskId](TaskObject &) { @@ -2901,6 +2901,17 @@ void tst_Tasking::testTree_data() << TestData{storage, rootParallelLimit, logParallelLimit, 2, DoneWith::Success}; } + { + // Check if task tree finishes with the right progress value when LoopUntil(false). + const Group root { + storage, + LoopUntil([](int) { return false; }), + createSuccessTask(1) + }; + QTest::newRow("ProgressWithLoopUntilFalse") + << TestData{storage, root, {}, 1, DoneWith::Success}; + } + { const auto createRoot = [=](DoneResult doneResult, CallDoneIf callDoneIf) { return Group { From bc4c3b87df8ed80bfa0b7c57fcd9627edd8ce6b3 Mon Sep 17 00:00:00 2001 From: Jarek Kobus Date: Sun, 11 Feb 2024 12:44:09 +0100 Subject: [PATCH 014/243] Axivion: Add Username field Change-Id: Icafedc1c79ceb48349975576b99a7da7dd39f353 Reviewed-by: hjk Reviewed-by: --- src/plugins/axivion/axivionsettings.cpp | 30 +++++++++++++++---------- src/plugins/axivion/axivionsettings.h | 5 +---- 2 files changed, 19 insertions(+), 16 deletions(-) diff --git a/src/plugins/axivion/axivionsettings.cpp b/src/plugins/axivion/axivionsettings.cpp index 3d95673b9c0..f742f0c5626 100644 --- a/src/plugins/axivion/axivionsettings.cpp +++ b/src/plugins/axivion/axivionsettings.cpp @@ -25,17 +25,9 @@ using namespace Utils; namespace Axivion::Internal { -AxivionServer::AxivionServer(const Id &id, const QString &dashboard, - const QString &description, const QString &token) - : id(id) - , dashboard(dashboard) - , description(description) - , token(token) -{} - bool AxivionServer::operator==(const AxivionServer &other) const { - return id == other.id && dashboard == other.dashboard + return id == other.id && dashboard == other.dashboard && username == other.username && description == other.description && token == other.token; } @@ -49,6 +41,7 @@ QJsonObject AxivionServer::toJson() const QJsonObject result; result.insert("id", id.toString()); result.insert("dashboard", dashboard); + result.insert("username", username); result.insert("description", description); result.insert("token", token); return result; @@ -63,14 +56,17 @@ AxivionServer AxivionServer::fromJson(const QJsonObject &json) const QJsonValue dashboard = json.value("dashboard"); if (dashboard == QJsonValue::Undefined) return invalidServer; + const QJsonValue username = json.value("username"); + if (username == QJsonValue::Undefined) + return invalidServer; const QJsonValue description = json.value("description"); if (description == QJsonValue::Undefined) return invalidServer; const QJsonValue token = json.value("token"); if (token == QJsonValue::Undefined) return invalidServer; - return { Id::fromString(id.toString()), dashboard.toString(), - description.toString(), token.toString() }; + return {Id::fromString(id.toString()), dashboard.toString(), username.toString(), + description.toString(), token.toString()}; } static FilePath tokensFilePath() @@ -164,6 +160,7 @@ private: Mode m_mode = Display; Id m_id; StringAspect m_dashboardUrl; + StringAspect m_username; StringAspect m_description; StringAspect m_token; BoolAspect m_valid; @@ -176,9 +173,14 @@ DashboardSettingsWidget::DashboardSettingsWidget(Mode mode, QWidget *parent, QPu auto labelStyle = mode == Display ? StringAspect::LabelDisplay : StringAspect::LineEditDisplay; m_dashboardUrl.setLabelText(Tr::tr("Dashboard URL:")); m_dashboardUrl.setDisplayStyle(labelStyle); - m_dashboardUrl.setValidationFunction([](FancyLineEdit *edit, QString *){ + m_dashboardUrl.setValidationFunction([](FancyLineEdit *edit, QString *) { return isUrlValid(edit->text()); }); + + m_username.setLabelText(Tr::tr("Username:")); + m_username.setDisplayStyle(labelStyle); + m_username.setPlaceHolderText(Tr::tr("User name")); + m_description.setLabelText(Tr::tr("Description:")); m_description.setDisplayStyle(labelStyle); m_description.setPlaceHolderText(Tr::tr("Non-empty description")); @@ -192,6 +194,7 @@ DashboardSettingsWidget::DashboardSettingsWidget(Mode mode, QWidget *parent, QPu Form { m_dashboardUrl, br, + m_username, br, m_description, br, m_token, br, mode == Edit ? normalMargin : noMargin @@ -204,6 +207,7 @@ DashboardSettingsWidget::DashboardSettingsWidget(Mode mode, QWidget *parent, QPu ok->setEnabled(m_valid()); }; connect(&m_dashboardUrl, &BaseAspect::changed, this, checkValidity); + connect(&m_username, &BaseAspect::changed, this, checkValidity); connect(&m_description, &BaseAspect::changed, this, checkValidity); connect(&m_token, &BaseAspect::changed, this, checkValidity); } @@ -217,6 +221,7 @@ AxivionServer DashboardSettingsWidget::dashboardServer() const else result.id = m_mode == Edit ? Id::fromName(QUuid::createUuid().toByteArray()) : m_id; result.dashboard = m_dashboardUrl(); + result.username = m_username(); result.description = m_description(); result.token = m_token(); return result; @@ -226,6 +231,7 @@ void DashboardSettingsWidget::setDashboardServer(const AxivionServer &server) { m_id = server.id; m_dashboardUrl.setValue(server.dashboard); + m_username.setValue(server.username); m_description.setValue(server.description); m_token.setValue(server.token); } diff --git a/src/plugins/axivion/axivionsettings.h b/src/plugins/axivion/axivionsettings.h index 5f0beb55522..00a93843816 100644 --- a/src/plugins/axivion/axivionsettings.h +++ b/src/plugins/axivion/axivionsettings.h @@ -17,10 +17,6 @@ namespace Axivion::Internal { class AxivionServer { public: - AxivionServer() = default; - AxivionServer(const Utils::Id &id, const QString &dashboardUrl, - const QString &description, const QString &token); - bool operator==(const AxivionServer &other) const; bool operator!=(const AxivionServer &other) const; @@ -29,6 +25,7 @@ public: Utils::Id id; QString dashboard; + QString username; QString description; QString token; From 61cf8702a3cfa4c281d9e0dcb62e7a86b7deaaa2 Mon Sep 17 00:00:00 2001 From: Jarek Kobus Date: Sun, 11 Feb 2024 18:01:48 +0100 Subject: [PATCH 015/243] Axivion: Separate fetching Dto data from credential handing Change-Id: Ibddafa055c73614797235921ba5cb62096b5980f Reviewed-by: Reviewed-by: Qt CI Bot Reviewed-by: hjk --- src/plugins/axivion/axivionplugin.cpp | 76 +++++++++++++++++---------- 1 file changed, 48 insertions(+), 28 deletions(-) diff --git a/src/plugins/axivion/axivionplugin.cpp b/src/plugins/axivion/axivionplugin.cpp index cd8fca0a0c5..1deb0280d7d 100644 --- a/src/plugins/axivion/axivionplugin.cpp +++ b/src/plugins/axivion/axivionplugin.cpp @@ -319,35 +319,31 @@ static Group fetchHtmlRecipe(const QUrl &url, const std::function -static Group fetchDataRecipe(const QUrl &url, - const std::function &handler) +template +struct GetDtoStorage { - struct StorageData - { - QByteArray credentials; - QByteArray serializableData; - }; + QByteArray credential; + QUrl url; + std::optional dtoData; +}; - const Storage storage; +template +static Group getDtoRecipe(const Storage> &dtoStorage) +{ + const Storage storage; - const auto onCredentialSetup = [storage] { - storage->credentials = QByteArrayLiteral("AxToken ") + settings().server.token.toUtf8(); - }; - - const auto onNetworkQuerySetup = [storage, url](NetworkQuery &query) { - QNetworkRequest request(url); + const auto onNetworkQuerySetup = [dtoStorage](NetworkQuery &query) { + QNetworkRequest request(dtoStorage->url); request.setRawHeader("Accept", s_jsonContentType); - request.setRawHeader("Authorization", storage->credentials); + request.setRawHeader("Authorization", dtoStorage->credential); const QByteArray ua = "Axivion" + QCoreApplication::applicationName().toUtf8() + "Plugin/" + QCoreApplication::applicationVersion().toUtf8(); request.setRawHeader("X-Axivion-User-Agent", ua); query.setRequest(request); query.setNetworkAccessManager(&dd->m_networkAccessManager); - return SetupResult::Continue; }; - const auto onNetworkQueryDone = [storage, url](const NetworkQuery &query, DoneWith doneWith) { + const auto onNetworkQueryDone = [storage](const NetworkQuery &query, DoneWith doneWith) { QNetworkReply *reply = query.reply(); const QNetworkReply::NetworkError error = reply->error(); const int statusCode = reply->attribute(QNetworkRequest::HttpStatusCodeAttribute).toInt(); @@ -359,7 +355,7 @@ static Group fetchDataRecipe(const QUrl &url, .toLower(); if (doneWith == DoneWith::Success && statusCode == httpStatusCodeOk && contentType == s_jsonContentType) { - storage->serializableData = reply->readAll(); + *storage = reply->readAll(); return DoneResult::Success; } @@ -385,25 +381,49 @@ static Group fetchDataRecipe(const QUrl &url, return DoneResult::Error; }; - const auto onDeserializeSetup = [storage](Async &task) { - const auto deserialize = [](QPromise &promise, const QByteArray &input) { - promise.addResult(SerializableType::deserialize(input)); + const auto onDeserializeSetup = [storage](Async &task) { + const auto deserialize = [](QPromise &promise, const QByteArray &input) { + promise.addResult(DtoType::deserialize(input)); }; task.setFutureSynchronizer(ExtensionSystem::PluginManager::futureSynchronizer()); - task.setConcurrentCallData(deserialize, storage->serializableData); + task.setConcurrentCallData(deserialize, *storage); }; - const auto onDeserializeDone = [handler](const Async &task, - DoneWith doneWith) { + const auto onDeserializeDone = [dtoStorage](const Async &task, DoneWith doneWith) { if (doneWith == DoneWith::Success) - handler(task.future().result()); + dtoStorage->dtoData = task.future().result(); }; const Group recipe { storage, - Sync(onCredentialSetup), NetworkQueryTask(onNetworkQuerySetup, onNetworkQueryDone), - AsyncTask(onDeserializeSetup, onDeserializeDone) + AsyncTask(onDeserializeSetup, onDeserializeDone) + }; + return recipe; +}; + +template +static Group fetchDataRecipe(const QUrl &url, const std::function &handler) +{ + const Storage> dtoStorage; + + const auto onCredentialSetup = [dtoStorage, url] { + dtoStorage->credential = QByteArrayLiteral("AxToken ") + settings().server.token.toUtf8(); + dtoStorage->url = url; + }; + + const auto onDtoDone = [dtoStorage, handler] { + if (dtoStorage->dtoData) + handler(*dtoStorage->dtoData); + }; + + const Group recipe { + dtoStorage, + Sync(onCredentialSetup), + Group { + getDtoRecipe(dtoStorage), + onGroupDone(onDtoDone) + } }; return recipe; From 046ae752f663db8870508c65ba37b80357d78b39 Mon Sep 17 00:00:00 2001 From: Eike Ziller Date: Wed, 14 Feb 2024 15:54:11 +0100 Subject: [PATCH 016/243] Fix ODR violation with Spinner Spinner is already added to and exported by the Utils library. Do not add it again to more (plugin) libraries. Fixes: QTCREATORBUG-30368 Change-Id: I6ddf43f8bf1c4972b786b82dbafd3201bc8e0a0e Reviewed-by: Reviewed-by: Jarek Kobus Reviewed-by: Tim Blechmann Reviewed-by: Qt CI Bot --- src/plugins/compilerexplorer/CMakeLists.txt | 2 +- src/plugins/screenrecorder/CMakeLists.txt | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/src/plugins/compilerexplorer/CMakeLists.txt b/src/plugins/compilerexplorer/CMakeLists.txt index 55368044706..361bba8ec76 100644 --- a/src/plugins/compilerexplorer/CMakeLists.txt +++ b/src/plugins/compilerexplorer/CMakeLists.txt @@ -1,6 +1,6 @@ add_qtc_plugin(CompilerExplorer PLUGIN_DEPENDS Core ProjectExplorer TextEditor - DEPENDS Qt::Network TerminalLib Spinner + DEPENDS Qt::Network TerminalLib SOURCES api/config.h api/compile.cpp diff --git a/src/plugins/screenrecorder/CMakeLists.txt b/src/plugins/screenrecorder/CMakeLists.txt index a16e316b2c8..838eed9ab6d 100644 --- a/src/plugins/screenrecorder/CMakeLists.txt +++ b/src/plugins/screenrecorder/CMakeLists.txt @@ -1,6 +1,6 @@ add_qtc_plugin(ScreenRecorder PLUGIN_DEPENDS Core - DEPENDS Spinner + DEPENDS Utils SOURCES cropandtrim.cpp cropandtrim.h export.cpp export.h From 65fcb9b746de2cbb9d126ff2d4f169e6fb425f2e Mon Sep 17 00:00:00 2001 From: Eike Ziller Date: Tue, 6 Feb 2024 09:24:00 +0100 Subject: [PATCH 017/243] Help: Update litehtml to v0.9 MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit And adapt the attributions to use the attribution.json from the qlitehtml repository, so it is automatically in sync. Fixes: QTCREATORBUG-29169 Change-Id: I96343162880b6aa0e38ee356b3b5f98db4a85cc3 Reviewed-by: Kai Köhne Reviewed-by: --- cmake/QtCreatorDocumentation.cmake | 2 +- doc/CMakeLists.txt | 8 ++++++ .../overview/creator-acknowledgements.qdoc | 2 +- qt_attributions.json | 28 ------------------- src/libs/qlitehtml | 2 +- 5 files changed, 11 insertions(+), 31 deletions(-) diff --git a/cmake/QtCreatorDocumentation.cmake b/cmake/QtCreatorDocumentation.cmake index 1ef9030a43a..9587a77e0b1 100644 --- a/cmake/QtCreatorDocumentation.cmake +++ b/cmake/QtCreatorDocumentation.cmake @@ -283,7 +283,7 @@ function(add_qtc_doc_attribution target attribution_file output_file qdocconf_fi file(MAKE_DIRECTORY ${output_dir}) # add target add_custom_target(${target} - Qt6::qtattributionsscanner -o "${output_file}" ${attribution_file} + Qt6::qtattributionsscanner -o "${output_file}" --basedir "${PROJECT_SOURCE_DIR}" ${attribution_file} COMMENT "Create attributions ${output_file} from ${attribution_file}" DEPENDS "${attribution_file}" SOURCES "${attribution_file}" diff --git a/doc/CMakeLists.txt b/doc/CMakeLists.txt index 00786024dfd..f78240e4fb0 100644 --- a/doc/CMakeLists.txt +++ b/doc/CMakeLists.txt @@ -43,6 +43,14 @@ function(_add_doc _doc_file _dev_doc_file) "${GENERATED_ATTRIBUTIONS_DIR}/creator-attributions.qdoc" ${_doc_file} ) + set(litehtml_attributions "${CMAKE_CURRENT_SOURCE_DIR}/../src/libs/qlitehtml/src/3rdparty/qt_attribution.json") + if(EXISTS "${litehtml_attributions}") + add_qtc_doc_attribution(doc_attributions_litehtml + "${litehtml_attributions}" + "${GENERATED_ATTRIBUTIONS_DIR}/creator-attributions-litehtml.qdoc" + ${_doc_file} + ) + endif() if (BUILD_DEVELOPER_DOCS) _find_all_includes(_all_includes _framework_paths) add_qtc_documentation(${_dev_doc_file} diff --git a/doc/qtcreator/src/overview/creator-acknowledgements.qdoc b/doc/qtcreator/src/overview/creator-acknowledgements.qdoc index f70c2dc9d3f..e69626b35cf 100644 --- a/doc/qtcreator/src/overview/creator-acknowledgements.qdoc +++ b/doc/qtcreator/src/overview/creator-acknowledgements.qdoc @@ -31,7 +31,7 @@ \QC contains the following third-party components: - \generatelist{groupsbymodule attributions-qtcreator-tools} + \generatelist{groupsbymodule attributions-tools} The following third-party components are shipped with binary packages of \QC: diff --git a/qt_attributions.json b/qt_attributions.json index 2d18d2f51bc..2a2a866b110 100644 --- a/qt_attributions.json +++ b/qt_attributions.json @@ -375,34 +375,6 @@ "LicenseFile": "src/libs/3rdparty/json/LICENSE.MIT", "Copyright": "Copyright 2013-2022 Niels Lohmann" }, - { - "Id": "litehtml-gumbo", - "Name": "Gumbo", - "QDocModule": "qtcreator", - "QtParts": ["tools"], - "QtUsage": "Used by litehtml.", - "Path": "src/libs/qlitehtml/src/3rdparty/litehtml/src/gumbo", - "Description": "Gumbo is an implementation of the HTML5 parsing algorithm implemented as a pure C99 library with no outside dependencies.", - "Homepage": "https://github.com/google/gumbo-parser", - "Version": "0.10.1", - "License": "Apache License 2.0 AND MIT", - "LicenseFile": "src/libs/qlitehtml/src/3rdparty/litehtml/src/gumbo/LICENSE", - "CopyrightFile": "src/libs/qlitehtml/src/3rdparty/GUMBO-AUTHORS.txt" - }, - { - "Id": "litehtml", - "Name": "litehtml", - "QDocModule": "qtcreator", - "QtParts": ["tools"], - "QtUsage": "Used for the help viewer.", - "Path": "src/libs/qlitehtml/src/3rdparty/litehtml", - "Description": "litehtml is the lightweight HTML rendering engine with CSS2/CSS3 support.", - "Homepage": "https://github.com/litehtml/litehtml", - "Version": "v0.5-64-gdb7f59d", - "License": "BSD 3-Clause \"New\" or \"Revised\" License", - "LicenseFile": "src/libs/qlitehtml/src/3rdparty/litehtml/LICENSE", - "Copyright": "Copyright (c) 2013, Yuri Kobets (tordex)" - }, { "Id": "conan.cmake", "Name": "conan.cmake", diff --git a/src/libs/qlitehtml b/src/libs/qlitehtml index b8f6617f22a..ce2baa83078 160000 --- a/src/libs/qlitehtml +++ b/src/libs/qlitehtml @@ -1 +1 @@ -Subproject commit b8f6617f22a7bd0bf3da2e75d1613e1346b974f0 +Subproject commit ce2baa83078dcc2723be497831e2314b02eacbf9 From 4c4d297d1500a555ea120eb41dcfbf39f6eae407 Mon Sep 17 00:00:00 2001 From: hjk Date: Mon, 5 Feb 2024 18:18:56 +0100 Subject: [PATCH 018/243] Core: Use ActionBuilder in a few more places Change-Id: If578ea89fd8af9aca9d5f137dab5c4dbebfaa2e8 Reviewed-by: Eike Ziller --- src/plugins/coreplugin/coreplugin.cpp | 14 ++++++------- src/plugins/coreplugin/locator/locator.cpp | 14 ++++++------- src/plugins/coreplugin/outputpanemanager.cpp | 21 ++++++++++---------- 3 files changed, 24 insertions(+), 25 deletions(-) diff --git a/src/plugins/coreplugin/coreplugin.cpp b/src/plugins/coreplugin/coreplugin.cpp index 49ca2fec8af..76a808d9a60 100644 --- a/src/plugins/coreplugin/coreplugin.cpp +++ b/src/plugins/coreplugin/coreplugin.cpp @@ -283,13 +283,13 @@ static void registerActionsForOptions() const Id commandId = generateOpenPageCommandId(page); if (!commandId.isValid()) continue; - const QString actionTitle = Tr::tr("%1 > %2 Preferences...") - .arg(categoryDisplay.value(page->category()), page->displayName()); - auto action = new QAction(actionTitle, m_instance); - QObject::connect(action, &QAction::triggered, m_instance, [id = page->id()] { - ICore::showOptionsDialog(id); - }); - ActionManager::registerAction(action, commandId); + + ActionBuilder(m_instance, commandId) + .setText(Tr::tr("%1 > %2 Preferences...") + .arg(categoryDisplay.value(page->category()), page->displayName())) + .addOnTriggered(m_instance, [id = page->id()] { + ICore::showOptionsDialog(id); + }); } } diff --git a/src/plugins/coreplugin/locator/locator.cpp b/src/plugins/coreplugin/locator/locator.cpp index 95b8dc5be8f..55aa984c08d 100644 --- a/src/plugins/coreplugin/locator/locator.cpp +++ b/src/plugins/coreplugin/locator/locator.cpp @@ -213,17 +213,15 @@ void Locator::updateFilterActions() if (filter->shortcutString().isEmpty() || filter->isHidden()) continue; Id filterId = filter->id(); - Id actionId = filter->actionId(); QAction *action = nullptr; if (!actionCopy.contains(filterId)) { // register new action - action = new QAction(filter->displayName(), this); - Command *cmd = ActionManager::registerAction(action, actionId); - cmd->setAttribute(Command::CA_UpdateText); - cmd->setDefaultKeySequence(filter->defaultKeySequence()); - connect(action, &QAction::triggered, this, [filter] { - LocatorManager::showFilter(filter); - }); + ActionBuilder(this, filter->actionId()) + .setText(filter->displayName()) + .bindContextAction(&action) + .setCommandAttribute(Command::CA_UpdateText) + .setDefaultKeySequence(filter->defaultKeySequence()) + .addOnTriggered(this, [filter] { LocatorManager::showFilter(filter); }); } else { action = actionCopy.take(filterId); action->setText(filter->displayName()); diff --git a/src/plugins/coreplugin/outputpanemanager.cpp b/src/plugins/coreplugin/outputpanemanager.cpp index a6e83474cf7..48ba6224182 100644 --- a/src/plugins/coreplugin/outputpanemanager.cpp +++ b/src/plugins/coreplugin/outputpanemanager.cpp @@ -230,16 +230,17 @@ void IOutputPane::setupContext(const Context &context, QWidget *widget) m_context->setWidget(widget); ICore::addContextObject(m_context); - const auto zoomInAction = new QAction(this); - Core::ActionManager::registerAction(zoomInAction, Constants::ZOOM_IN, m_context->context()); - connect(zoomInAction, &QAction::triggered, this, [this] { emit zoomInRequested(1); }); - const auto zoomOutAction = new QAction(this); - Core::ActionManager::registerAction(zoomOutAction, Constants::ZOOM_OUT, m_context->context()); - connect(zoomOutAction, &QAction::triggered, this, [this] { emit zoomOutRequested(1); }); - const auto resetZoomAction = new QAction(this); - Core::ActionManager::registerAction(resetZoomAction, Constants::ZOOM_RESET, - m_context->context()); - connect(resetZoomAction, &QAction::triggered, this, &IOutputPane::resetZoomRequested); + ActionBuilder(this, Constants::ZOOM_IN) + .setContext(context) + .addOnTriggered(this, [this] { emit zoomInRequested(1); }); + + ActionBuilder(this, Constants::ZOOM_OUT) + .setContext(context) + .addOnTriggered(this, [this] { emit zoomOutRequested(1); }); + + ActionBuilder(this, Constants::ZOOM_RESET) + .setContext(context) + .addOnTriggered(this, &IOutputPane::resetZoomRequested); } void IOutputPane::setZoomButtonsEnabled(bool enabled) From a5c4c34c9ab49a21aefa42456b5a8cc04e7fbff1 Mon Sep 17 00:00:00 2001 From: Christian Stenger Date: Wed, 14 Feb 2024 12:57:15 +0100 Subject: [PATCH 019/243] Raise minimum supported libclang ClangFormat needs 14.0+ nowadays. Change-Id: Ib5e38c79c5ec629fed4e5d8da5435769a71b2626 Reviewed-by: Eike Ziller Reviewed-by: Christian Kandeler --- README.md | 4 +-- qbs/modules/libclang/functions.js | 2 +- src/plugins/clangformat/CMakeLists.txt | 2 +- .../clangformat/clangformatbaseindenter.cpp | 4 --- src/plugins/clangformat/clangformatutils.cpp | 35 +------------------ 5 files changed, 5 insertions(+), 42 deletions(-) diff --git a/README.md b/README.md index 32b53aacb53..9f4b6f1457d 100644 --- a/README.md +++ b/README.md @@ -44,11 +44,11 @@ Prerequisites: * Qt WebEngine module for QtWebEngine based help viewer * On Windows: * MinGW with GCC 9 or Visual Studio 2019 or later - * Python 3.5 or later (optional, needed for the python enabled debug helper) + * 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 Mac OS X: latest Xcode * On Linux: GCC 9 or later -* LLVM/Clang 10 or later (optional, LLVM/Clang 14 is recommended. +* 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. The ClangFormat plugin uses the LLVM C++ API. diff --git a/qbs/modules/libclang/functions.js b/qbs/modules/libclang/functions.js index c1cd5c237e9..0d3c5afb87a 100644 --- a/qbs/modules/libclang/functions.js +++ b/qbs/modules/libclang/functions.js @@ -1,7 +1,7 @@ var Environment = require("qbs.Environment") var File = require("qbs.File") var FileInfo = require("qbs.FileInfo") -var MinimumLLVMVersion = "8.0.0" // CLANG-UPGRADE-CHECK: Adapt minimum version numbers. +var MinimumLLVMVersion = "14.0.0" // CLANG-UPGRADE-CHECK: Adapt minimum version numbers. var Process = require("qbs.Process") var Utilities = require("qbs.Utilities") diff --git a/src/plugins/clangformat/CMakeLists.txt b/src/plugins/clangformat/CMakeLists.txt index f1dc569333f..30bc50dd2c3 100644 --- a/src/plugins/clangformat/CMakeLists.txt +++ b/src/plugins/clangformat/CMakeLists.txt @@ -1,5 +1,5 @@ add_qtc_plugin(ClangFormat - CONDITION TARGET ${CLANG_FORMAT_LIB} AND LLVM_PACKAGE_VERSION VERSION_GREATER_EQUAL 10.0.0 AND (QTC_CLANG_BUILDMODE_MATCH OR CLANGTOOLING_LINK_CLANG_DYLIB) + CONDITION TARGET ${CLANG_FORMAT_LIB} AND LLVM_PACKAGE_VERSION VERSION_GREATER_EQUAL 14.0.0 AND (QTC_CLANG_BUILDMODE_MATCH OR CLANGTOOLING_LINK_CLANG_DYLIB) DEPENDS Utils Qt::Widgets ${CLANG_FORMAT_LIB} PLUGIN_DEPENDS Core TextEditor CppEditor ProjectExplorer SOURCES diff --git a/src/plugins/clangformat/clangformatbaseindenter.cpp b/src/plugins/clangformat/clangformatbaseindenter.cpp index 2de357b1124..1d5dc2730c3 100644 --- a/src/plugins/clangformat/clangformatbaseindenter.cpp +++ b/src/plugins/clangformat/clangformatbaseindenter.cpp @@ -42,11 +42,7 @@ static void adjustFormatStyleForLineBreak(clang::format::FormatStyle &style, ReplacementsToKeep replacementsToKeep) { style.MaxEmptyLinesToKeep = 100; -#if LLVM_VERSION_MAJOR >= 13 style.SortIncludes = clang::format::FormatStyle::SI_Never; -#else - style.SortIncludes = false; -#endif #if LLVM_VERSION_MAJOR >= 16 style.SortUsingDeclarations = clang::format::FormatStyle::SUD_Never; #else diff --git a/src/plugins/clangformat/clangformatutils.cpp b/src/plugins/clangformat/clangformatutils.cpp index 6d16ebe9aa1..4036d34f6dc 100644 --- a/src/plugins/clangformat/clangformatutils.cpp +++ b/src/plugins/clangformat/clangformatutils.cpp @@ -42,37 +42,22 @@ clang::format::FormatStyle calculateQtcStyle() #if LLVM_VERSION_MAJOR >= 15 style.AlignConsecutiveAssignments = {false, false, false, false, false}; style.AlignConsecutiveDeclarations = {false, false, false, false, false}; -#elif LLVM_VERSION_MAJOR >= 12 +#else style.AlignConsecutiveAssignments = FormatStyle::ACS_None; style.AlignConsecutiveDeclarations = FormatStyle::ACS_None; -#else - style.AlignConsecutiveAssignments = false; - style.AlignConsecutiveDeclarations = false; #endif style.AlignEscapedNewlines = FormatStyle::ENAS_DontAlign; -#if LLVM_VERSION_MAJOR >= 11 style.AlignOperands = FormatStyle::OAS_Align; -#else - style.AlignOperands = true; -#endif #if LLVM_VERSION_MAJOR >= 16 style.AlignTrailingComments = {FormatStyle::TCAS_Always, 0}; #else style.AlignTrailingComments = true; #endif style.AllowAllParametersOfDeclarationOnNextLine = true; -#if LLVM_VERSION_MAJOR >= 10 style.AllowShortBlocksOnASingleLine = FormatStyle::SBS_Never; -#else - style.AllowShortBlocksOnASingleLine = false; -#endif style.AllowShortCaseLabelsOnASingleLine = false; style.AllowShortFunctionsOnASingleLine = FormatStyle::SFS_Inline; -#if LLVM_VERSION_MAJOR >= 9 style.AllowShortIfStatementsOnASingleLine = FormatStyle::SIS_Never; -#else - style.AllowShortIfStatementsOnASingleLine = false; -#endif style.AllowShortLoopsOnASingleLine = false; style.AlwaysBreakAfterReturnType = FormatStyle::RTBS_None; style.AlwaysBreakBeforeMultilineStrings = false; @@ -80,11 +65,7 @@ clang::format::FormatStyle calculateQtcStyle() style.BinPackArguments = false; style.BinPackParameters = false; style.BraceWrapping.AfterClass = true; -#if LLVM_VERSION_MAJOR >= 10 style.BraceWrapping.AfterControlStatement = FormatStyle::BWACS_Never; -#else - style.BraceWrapping.AfterControlStatement = false; -#endif style.BraceWrapping.AfterEnum = false; style.BraceWrapping.AfterFunction = true; style.BraceWrapping.AfterNamespace = false; @@ -119,11 +100,7 @@ clang::format::FormatStyle calculateQtcStyle() style.ExperimentalAutoDetectBinPacking = false; style.FixNamespaceComments = true; style.ForEachMacros = {"forever", "foreach", "Q_FOREACH", "BOOST_FOREACH"}; -#if LLVM_VERSION_MAJOR >= 12 style.IncludeStyle.IncludeCategories = {{"^= 13 style.SortIncludes = FormatStyle::SI_CaseSensitive; -#else - style.SortIncludes = true; -#endif #if LLVM_VERSION_MAJOR >= 16 style.SortUsingDeclarations = FormatStyle::SUD_Lexicographic; #else @@ -166,11 +139,7 @@ clang::format::FormatStyle calculateQtcStyle() style.SpaceInEmptyParentheses = false; #endif style.SpacesBeforeTrailingComments = 1; -#if LLVM_VERSION_MAJOR >= 13 style.SpacesInAngles = FormatStyle::SIAS_Never; -#else - style.SpacesInAngles = false; -#endif style.SpacesInContainerLiterals = false; #if LLVM_VERSION_MAJOR >= 17 style.SpacesInParens = FormatStyle::SIPO_Never; @@ -225,9 +194,7 @@ void fromCppCodeStyleSettings(clang::format::FormatStyle &style, style.BreakBeforeBraces = FormatStyle::BS_Custom; style.IndentCaseLabels = settings.indentSwitchLabels; -#if LLVM_VERSION_MAJOR >= 11 style.IndentCaseBlocks = settings.indentBlocksRelativeToSwitchLabels; -#endif if (settings.extraPaddingForConditionsIfConfusingAlign) style.BreakBeforeBinaryOperators = FormatStyle::BOS_All; From f6ad82a0eb29d67447d4dda20a99884e22c5e742 Mon Sep 17 00:00:00 2001 From: Marcus Tillmanns Date: Thu, 15 Feb 2024 08:33:04 +0100 Subject: [PATCH 020/243] CompilerExplorer: Use global network access manager Change-Id: I03589a1b5abd42b36281c1c733adf20fcb51d272 Reviewed-by: hjk --- src/plugins/compilerexplorer/api/compile.h | 8 ++------ src/plugins/compilerexplorer/api/compiler.h | 2 -- src/plugins/compilerexplorer/api/language.h | 1 - src/plugins/compilerexplorer/api/library.h | 1 - src/plugins/compilerexplorer/compilerexplorereditor.cpp | 1 - src/plugins/compilerexplorer/compilerexplorersettings.cpp | 2 -- src/plugins/compilerexplorer/compilerexplorersettings.h | 8 ++------ 7 files changed, 4 insertions(+), 19 deletions(-) diff --git a/src/plugins/compilerexplorer/api/compile.h b/src/plugins/compilerexplorer/api/compile.h index ce346fe2bde..8caefff83bc 100644 --- a/src/plugins/compilerexplorer/api/compile.h +++ b/src/plugins/compilerexplorer/api/compile.h @@ -6,16 +6,12 @@ #include "compiler.h" #include "config.h" -#include "../compilerexploreraspects.h" - -#include -#include - #include #include #include #include -#include +#include +#include namespace CompilerExplorer::Api { diff --git a/src/plugins/compilerexplorer/api/compiler.h b/src/plugins/compilerexplorer/api/compiler.h index 070817206e2..5e728ae19ca 100644 --- a/src/plugins/compilerexplorer/api/compiler.h +++ b/src/plugins/compilerexplorer/api/compiler.h @@ -6,9 +6,7 @@ #include "config.h" #include -#include #include -#include #include #include diff --git a/src/plugins/compilerexplorer/api/language.h b/src/plugins/compilerexplorer/api/language.h index 85780b7466a..431f01d8d36 100644 --- a/src/plugins/compilerexplorer/api/language.h +++ b/src/plugins/compilerexplorer/api/language.h @@ -6,7 +6,6 @@ #include "config.h" #include -#include #include #include diff --git a/src/plugins/compilerexplorer/api/library.h b/src/plugins/compilerexplorer/api/library.h index 07e8a117341..e63ccaf4874 100644 --- a/src/plugins/compilerexplorer/api/library.h +++ b/src/plugins/compilerexplorer/api/library.h @@ -7,7 +7,6 @@ #include #include -#include #include #include diff --git a/src/plugins/compilerexplorer/compilerexplorereditor.cpp b/src/plugins/compilerexplorer/compilerexplorereditor.cpp index 9b9eb242ed9..0defb331636 100644 --- a/src/plugins/compilerexplorer/compilerexplorereditor.cpp +++ b/src/plugins/compilerexplorer/compilerexplorereditor.cpp @@ -36,7 +36,6 @@ #include #include #include -#include #include #include #include diff --git a/src/plugins/compilerexplorer/compilerexplorersettings.cpp b/src/plugins/compilerexplorer/compilerexplorersettings.cpp index defa10ff698..291624aac40 100644 --- a/src/plugins/compilerexplorer/compilerexplorersettings.cpp +++ b/src/plugins/compilerexplorer/compilerexplorersettings.cpp @@ -12,7 +12,6 @@ #include #include -#include namespace CompilerExplorer { @@ -306,7 +305,6 @@ CompilerExplorerSettings::CompilerExplorerSettings() { setAutoApply(false); setSettingsKey("CompilerExplorer"); - m_networkAccessManager = std::make_unique(); compilerExplorerUrl.setSettingsKey("CompilerExplorerUrl"); compilerExplorerUrl.setLabelText(Tr::tr("Compiler Explorer URL:")); diff --git a/src/plugins/compilerexplorer/compilerexplorersettings.h b/src/plugins/compilerexplorer/compilerexplorersettings.h index e196249d117..4b3ac849a2c 100644 --- a/src/plugins/compilerexplorer/compilerexplorersettings.h +++ b/src/plugins/compilerexplorer/compilerexplorersettings.h @@ -7,11 +7,10 @@ #include "compilerexploreraspects.h" #include +#include #include -#include - namespace CompilerExplorer { class SourceSettings; class CompilerSettings; @@ -40,11 +39,8 @@ public: Api::Config apiConfig() const { - return Api::Config(m_networkAccessManager.get(), compilerExplorerUrl()); + return Api::Config(Utils::NetworkAccessManager::instance(), compilerExplorerUrl()); } - -private: - std::unique_ptr m_networkAccessManager; }; class SourceSettings : public Utils::AspectContainer, From c2f25f72a76ecfa683dc23eb80aed0e471813580 Mon Sep 17 00:00:00 2001 From: Christian Stenger Date: Thu, 15 Feb 2024 09:27:38 +0100 Subject: [PATCH 021/243] Update qlitehtml to latest master Fixes the qbs build. Change-Id: I0860acd2d63cf727696dfdb4f35ee2dd83c51dbe Reviewed-by: Eike Ziller --- src/libs/qlitehtml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/libs/qlitehtml b/src/libs/qlitehtml index ce2baa83078..9248bd827b3 160000 --- a/src/libs/qlitehtml +++ b/src/libs/qlitehtml @@ -1 +1 @@ -Subproject commit ce2baa83078dcc2723be497831e2314b02eacbf9 +Subproject commit 9248bd827b3859e6898860c15a63c6cd57ca5434 From e24ce364ce626572bad6758b5a397835ec6bf56f Mon Sep 17 00:00:00 2001 From: Christian Kandeler Date: Wed, 14 Feb 2024 17:46:49 +0100 Subject: [PATCH 022/243] QbsProjectManager: Do not create language client without build system A session without a build system can happen via the project importer. Change-Id: I04e77a790e595e9a5249b27569a0e79033fddad1 Reviewed-by: Reviewed-by: Christian Stenger --- src/plugins/qbsprojectmanager/qbssession.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/plugins/qbsprojectmanager/qbssession.cpp b/src/plugins/qbsprojectmanager/qbssession.cpp index 99c37cfd8d4..69dd6a7b2e1 100644 --- a/src/plugins/qbsprojectmanager/qbssession.cpp +++ b/src/plugins/qbsprojectmanager/qbssession.cpp @@ -453,7 +453,7 @@ void QbsSession::handlePacket(const QJsonObject &packet) setError(Error::VersionMismatch); return; } - if (packet.value("api-level").toInt() > 4) { + if (parent() && packet.value("api-level").toInt() > 4) { const QString lspSocket = packet.value("lsp-socket").toString(); if (!lspSocket.isEmpty()) d->languageClient = new QbsLanguageClient(lspSocket, From c6aeb2cde1f992f2e0044f5c10f0652818af8da3 Mon Sep 17 00:00:00 2001 From: hjk Date: Thu, 15 Feb 2024 09:25:18 +0100 Subject: [PATCH 023/243] TextEditor: Fix initial loading of settings Amends e784b1e58b8a. Done-with: Orgad Shaneh Change-Id: I727983a96ac9aae204974adfabfa7a794bf99907 Reviewed-by: Orgad Shaneh Reviewed-by: --- src/plugins/texteditor/texteditorplugin.cpp | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/src/plugins/texteditor/texteditorplugin.cpp b/src/plugins/texteditor/texteditorplugin.cpp index 6bb36d1c23c..04f11bcbb0b 100644 --- a/src/plugins/texteditor/texteditorplugin.cpp +++ b/src/plugins/texteditor/texteditorplugin.cpp @@ -95,11 +95,13 @@ void TextEditorPlugin::initialize() addTestCreator(createSnippetParserTest); #endif - setupTextEditorSettings(); setupBehaviorSettings(); setupExtraEncodingSettings(); setupStorageSettings(); setupTypingSettings(); + // Currently needed after the previous four lines. + // FIXME: This kind of dependency should not exist. + setupTextEditorSettings(); setupTextMarkRegistry(this); setupOutlineFactory(); From 41131eadaa73d5a70620d0056e14d26005291b55 Mon Sep 17 00:00:00 2001 From: hjk Date: Thu, 15 Feb 2024 09:38:15 +0100 Subject: [PATCH 024/243] TextEditor: Drop TextEditorSettings::m_instance This can be null when accessed too early. Using the function-static global instance directly ensures initialization. There is more simplification potential in this area, but I'd leave that for master. Change-Id: Ide35f4119e9fbcb392d1abac180ef46c02c16b87 Reviewed-by: Orgad Shaneh Reviewed-by: --- src/plugins/texteditor/texteditorsettings.cpp | 9 ++------- 1 file changed, 2 insertions(+), 7 deletions(-) diff --git a/src/plugins/texteditor/texteditorsettings.cpp b/src/plugins/texteditor/texteditorsettings.cpp index ca499f613b6..e3f96fa1676 100644 --- a/src/plugins/texteditor/texteditorsettings.cpp +++ b/src/plugins/texteditor/texteditorsettings.cpp @@ -418,12 +418,9 @@ FormatDescriptions TextEditorSettingsPrivate::initialFormats() static TextEditorSettingsPrivate *d = nullptr; -static TextEditorSettings *m_instance = nullptr; TextEditorSettings::TextEditorSettings() { - QTC_ASSERT(!m_instance, return); - m_instance = this; d = new Internal::TextEditorSettingsPrivate; // Note: default background colors are coming from FormatDescription::background() @@ -453,13 +450,11 @@ TextEditorSettings::TextEditorSettings() TextEditorSettings::~TextEditorSettings() { delete d; - - m_instance = nullptr; } TextEditorSettings *TextEditorSettings::instance() { - return m_instance; + return &textEditorSettings(); } const FontSettings &TextEditorSettings::fontSettings() @@ -578,7 +573,7 @@ static void setFontZoom(int zoom) { d->m_fontSettings.setFontZoom(zoom); d->m_fontSettings.toSettings(Core::ICore::settings()); - emit m_instance->fontSettingsChanged(d->m_fontSettings); + emit textEditorSettings().fontSettingsChanged(d->m_fontSettings); } int TextEditorSettings::increaseFontZoom(int step) From 029ac3c4a1f6de15110ed182dcff6bc0f49afa19 Mon Sep 17 00:00:00 2001 From: Orgad Shaneh Date: Thu, 15 Feb 2024 08:34:54 +0200 Subject: [PATCH 025/243] TextEditor: Simplify settings initialization * Consolidate and simplify behaviorSettingsChanged callbacks. * Do not call the callbacks during initialization, they are called later. Change-Id: Ica4b601e091de2112c7737047cbffa8a98fc9f70 Reviewed-by: hjk --- src/plugins/texteditor/texteditorsettings.cpp | 17 ++++------------- 1 file changed, 4 insertions(+), 13 deletions(-) diff --git a/src/plugins/texteditor/texteditorsettings.cpp b/src/plugins/texteditor/texteditorsettings.cpp index e3f96fa1676..1d7dd89386a 100644 --- a/src/plugins/texteditor/texteditorsettings.cpp +++ b/src/plugins/texteditor/texteditorsettings.cpp @@ -431,20 +431,11 @@ TextEditorSettings::TextEditorSettings() connect(this, &TextEditorSettings::fontSettingsChanged, this, updateGeneralMessagesFontSettings); updateGeneralMessagesFontSettings(); - auto updateGeneralMessagesBehaviorSettings = []() { - bool wheelZoom = d->m_behaviorSettingsPage.behaviorSettings().m_scrollWheelZooming; - Core::MessageManager::setWheelZoomEnabled(wheelZoom); - }; connect(this, &TextEditorSettings::behaviorSettingsChanged, - this, updateGeneralMessagesBehaviorSettings); - updateGeneralMessagesBehaviorSettings(); - - auto updateCamelCaseNavigation = [] { - FancyLineEdit::setCamelCaseNavigationEnabled(globalBehaviorSettings().m_camelCaseNavigation); - }; - connect(this, &TextEditorSettings::behaviorSettingsChanged, - this, updateCamelCaseNavigation); - updateCamelCaseNavigation(); + this, [](const BehaviorSettings &bs) { + Core::MessageManager::setWheelZoomEnabled(bs.m_scrollWheelZooming); + FancyLineEdit::setCamelCaseNavigationEnabled(bs.m_camelCaseNavigation); + }); } TextEditorSettings::~TextEditorSettings() From 02ac5deb4ae31a586f6d98462ac9e19f2083d7fd Mon Sep 17 00:00:00 2001 From: Jarek Kobus Date: Thu, 15 Feb 2024 08:17:31 +0100 Subject: [PATCH 026/243] TaskTree: Fix progress reporting with nested LoopUntil(false) Fix also a case when parent iteration isn't progressive. Add a test for it. Amends e059b62421b0a2ba58856eb4a5ce37f2e913ec1a Change-Id: Ic2f8c047d413ab2e2b98af4592f7cb60185bea06 Reviewed-by: hjk --- src/libs/solutions/tasking/tasktree.cpp | 3 ++- tests/auto/solutions/tasking/tst_tasking.cpp | 14 ++++++++++++++ 2 files changed, 16 insertions(+), 1 deletion(-) diff --git a/src/libs/solutions/tasking/tasktree.cpp b/src/libs/solutions/tasking/tasktree.cpp index 58fb43b3a5e..2bbb745b527 100644 --- a/src/libs/solutions/tasking/tasktree.cpp +++ b/src/libs/solutions/tasking/tasktree.cpp @@ -1849,8 +1849,9 @@ SetupResult TaskTreePrivate::start(RuntimeContainer *container) if (startAction == SetupResult::Continue && (containerNode.m_children.empty() || (containerNode.m_loop && !invokeLoopHandler(container)))) { + if (isProgressive(container)) + advanceProgress(containerNode.m_taskCount); startAction = toSetupResult(container->m_successBit); - advanceProgress(containerNode.m_taskCount); } return continueStart(container, startAction); } diff --git a/tests/auto/solutions/tasking/tst_tasking.cpp b/tests/auto/solutions/tasking/tst_tasking.cpp index 64b407fce99..6c67d2f01a2 100644 --- a/tests/auto/solutions/tasking/tst_tasking.cpp +++ b/tests/auto/solutions/tasking/tst_tasking.cpp @@ -2912,6 +2912,20 @@ void tst_Tasking::testTree_data() << TestData{storage, root, {}, 1, DoneWith::Success}; } + { + // Check if task tree finishes with the right progress value when nested LoopUntil(false). + const Group root { + storage, + LoopUntil([](int index) { return index < 2; }), + Group { + LoopUntil([](int) { return false; }), + createSuccessTask(1) + } + }; + QTest::newRow("ProgressWithNestedLoopUntilFalse") + << TestData{storage, root, {}, 1, DoneWith::Success}; + } + { const auto createRoot = [=](DoneResult doneResult, CallDoneIf callDoneIf) { return Group { From 0b3b5b892cf920a3d56c05341c57ad339076e5e2 Mon Sep 17 00:00:00 2001 From: Jarek Kobus Date: Thu, 15 Feb 2024 08:20:06 +0100 Subject: [PATCH 027/243] TaskTree: Add a test for progress reporting with onGroupSetup(false) Also for the case when parent iteration isn't progressive. Change-Id: I831b86de68d504a1e5e189d2be2b12ffc7d97c60 Reviewed-by: hjk --- tests/auto/solutions/tasking/tst_tasking.cpp | 25 ++++++++++++++++++++ 1 file changed, 25 insertions(+) diff --git a/tests/auto/solutions/tasking/tst_tasking.cpp b/tests/auto/solutions/tasking/tst_tasking.cpp index 6c67d2f01a2..477dd57a460 100644 --- a/tests/auto/solutions/tasking/tst_tasking.cpp +++ b/tests/auto/solutions/tasking/tst_tasking.cpp @@ -2926,6 +2926,31 @@ void tst_Tasking::testTree_data() << TestData{storage, root, {}, 1, DoneWith::Success}; } + { + // Check if task tree finishes with the right progress value when onGroupSetup(false). + const Group root { + storage, + onGroupSetup([] { return SetupResult::StopWithSuccess; }), + createSuccessTask(1) + }; + QTest::newRow("ProgressWithGroupSetupFalse") + << TestData{storage, root, {}, 1, DoneWith::Success}; + } + + { + // Check if task tree finishes with the right progress value when nested LoopUntil(false). + const Group root { + storage, + LoopUntil([](int index) { return index < 2; }), + Group { + onGroupSetup([] { return SetupResult::StopWithSuccess; }), + createSuccessTask(1) + } + }; + QTest::newRow("ProgressWithNestedGroupSetupFalse") + << TestData{storage, root, {}, 1, DoneWith::Success}; + } + { const auto createRoot = [=](DoneResult doneResult, CallDoneIf callDoneIf) { return Group { From 035e9485367274fd0db0fbde55d1d8fdc0b86024 Mon Sep 17 00:00:00 2001 From: Jarek Kobus Date: Wed, 14 Feb 2024 08:18:49 +0100 Subject: [PATCH 028/243] Axivion: Introduce postDtoRecipe() For posting dto data to the server. Change-Id: Id519c311f13e7c42c85b758f97fefd79fa2c41e9 Reviewed-by: Qt CI Bot Reviewed-by: hjk --- src/plugins/axivion/axivionplugin.cpp | 88 +++++++++++++++++++++++++++ 1 file changed, 88 insertions(+) diff --git a/src/plugins/axivion/axivionplugin.cpp b/src/plugins/axivion/axivionplugin.cpp index 1deb0280d7d..9b333af7c3e 100644 --- a/src/plugins/axivion/axivionplugin.cpp +++ b/src/plugins/axivion/axivionplugin.cpp @@ -402,6 +402,94 @@ static Group getDtoRecipe(const Storage> &dtoStorage) return recipe; }; +template +struct PostDtoStorage +{ + QByteArray credential; + QUrl url; + QByteArray csrfToken; + QByteArray writeData; + std::optional dtoData; +}; + +template +static Group postDtoRecipe(const Storage> &dtoStorage) +{ + const Storage storage; + + const auto onNetworkQuerySetup = [dtoStorage](NetworkQuery &query) { + QNetworkRequest request(dtoStorage->url); + request.setRawHeader("Accept", s_jsonContentType); + request.setRawHeader("Authorization", dtoStorage->credential); + const QByteArray ua = "Axivion" + QCoreApplication::applicationName().toUtf8() + + "Plugin/" + QCoreApplication::applicationVersion().toUtf8(); + request.setRawHeader("X-Axivion-User-Agent", ua); + request.setRawHeader("AX-CSRF-Token", dtoStorage->csrfToken); + query.setRequest(request); + query.setWriteData(dtoStorage->writeData); + query.setOperation(NetworkOperation::Post); + query.setNetworkAccessManager(&dd->m_networkAccessManager); + }; + + const auto onNetworkQueryDone = [storage](const NetworkQuery &query, DoneWith doneWith) { + QNetworkReply *reply = query.reply(); + const QNetworkReply::NetworkError error = reply->error(); + const int statusCode = reply->attribute(QNetworkRequest::HttpStatusCodeAttribute).toInt(); + const QString contentType = reply->header(QNetworkRequest::ContentTypeHeader) + .toString() + .split(';') + .constFirst() + .trimmed() + .toLower(); + if (doneWith == DoneWith::Success && statusCode == httpStatusCodeOk + && contentType == s_jsonContentType) { + *storage = reply->readAll(); + return DoneResult::Success; + } + + const auto getError = [&]() -> Error { + if (contentType == s_jsonContentType) { + try { + return DashboardError(reply->url(), statusCode, + reply->attribute(QNetworkRequest::HttpReasonPhraseAttribute).toString(), + Dto::ErrorDto::deserialize(reply->readAll())); + } catch (const Dto::invalid_dto_exception &) { + // ignore + } + } + if (statusCode != 0) { + return HttpError(reply->url(), statusCode, + reply->attribute(QNetworkRequest::HttpReasonPhraseAttribute).toString(), + QString::fromUtf8(reply->readAll())); // encoding? + } + return NetworkError(reply->url(), error, reply->errorString()); + }; + + MessageManager::writeFlashing(QStringLiteral("Axivion: %1").arg(getError().message())); + return DoneResult::Error; + }; + + const auto onDeserializeSetup = [storage](Async &task) { + const auto deserialize = [](QPromise &promise, const QByteArray &input) { + promise.addResult(DtoType::deserialize(input)); + }; + task.setFutureSynchronizer(ExtensionSystem::PluginManager::futureSynchronizer()); + task.setConcurrentCallData(deserialize, *storage); + }; + + const auto onDeserializeDone = [dtoStorage](const Async &task, DoneWith doneWith) { + if (doneWith == DoneWith::Success) + dtoStorage->dtoData = task.future().result(); + }; + + const Group recipe { + storage, + NetworkQueryTask(onNetworkQuerySetup, onNetworkQueryDone), + AsyncTask(onDeserializeSetup, onDeserializeDone) + }; + return recipe; +}; + template static Group fetchDataRecipe(const QUrl &url, const std::function &handler) { From 27df099c152f3ebcd6788829d387120707126c2a Mon Sep 17 00:00:00 2001 From: Jarek Kobus Date: Sun, 11 Feb 2024 11:54:12 +0100 Subject: [PATCH 029/243] Axivion: Introduce CredentialQuery Accompanied by CredentialQueryTask, to be used in Axivion recipes. It wraps QKeychain::Job subclasses into one asynchronous task. Change-Id: I78a06255d880b02cba657c822976ef09454ac261 Reviewed-by: Reviewed-by: hjk Reviewed-by: Qt CI Bot --- src/plugins/axivion/CMakeLists.txt | 3 +- src/plugins/axivion/axivion.qbs | 5 ++- src/plugins/axivion/credentialquery.cpp | 51 +++++++++++++++++++++++++ src/plugins/axivion/credentialquery.h | 42 ++++++++++++++++++++ 4 files changed, 99 insertions(+), 2 deletions(-) create mode 100644 src/plugins/axivion/credentialquery.cpp create mode 100644 src/plugins/axivion/credentialquery.h diff --git a/src/plugins/axivion/CMakeLists.txt b/src/plugins/axivion/CMakeLists.txt index faba40706c8..a71b984520f 100644 --- a/src/plugins/axivion/CMakeLists.txt +++ b/src/plugins/axivion/CMakeLists.txt @@ -1,7 +1,7 @@ add_qtc_plugin(Axivion PLUGIN_DEPENDS Core ProjectExplorer TextEditor - DEPENDS Qt::Network Qt::Widgets ExtensionSystem Utils + DEPENDS Qt::Network Qt::Widgets ExtensionSystem Utils qtkeychain SOURCES axivion.qrc axivionoutputpane.cpp axivionoutputpane.h @@ -9,6 +9,7 @@ add_qtc_plugin(Axivion axivionprojectsettings.h axivionprojectsettings.cpp axivionsettings.cpp axivionsettings.h axiviontr.h + credentialquery.h credentialquery.cpp dashboard/dto.cpp dashboard/dto.h dashboard/concat.cpp dashboard/concat.h dashboard/error.h dashboard/error.cpp diff --git a/src/plugins/axivion/axivion.qbs b/src/plugins/axivion/axivion.qbs index 7d215259b8e..7b8034c26c4 100644 --- a/src/plugins/axivion/axivion.qbs +++ b/src/plugins/axivion/axivion.qbs @@ -4,10 +4,11 @@ QtcPlugin { name: "Axivion" Depends { name: "Core" } + Depends { name: "ExtensionSystem" } Depends { name: "ProjectExplorer" } Depends { name: "TextEditor" } - Depends { name: "ExtensionSystem" } Depends { name: "Utils" } + Depends { name: "qtkeychain" } Depends { name: "Qt.widgets" } Depends { name: "Qt.network" } @@ -22,6 +23,8 @@ QtcPlugin { "axivionsettings.cpp", "axivionsettings.h", "axiviontr.h", + "credentialquery.h", + "credentialquery.cpp", ] cpp.includePaths: base.concat(["."]) // needed for the generated stuff below diff --git a/src/plugins/axivion/credentialquery.cpp b/src/plugins/axivion/credentialquery.cpp new file mode 100644 index 00000000000..7393845819a --- /dev/null +++ b/src/plugins/axivion/credentialquery.cpp @@ -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 + +#include "credentialquery.h" + +#include + +using namespace QKeychain; +using namespace Tasking; + +namespace Axivion::Internal { + +CredentialQueryTaskAdapter::~CredentialQueryTaskAdapter() = default; + +void CredentialQueryTaskAdapter::start() +{ + Job *job = nullptr; + ReadPasswordJob *reader = nullptr; + + switch (task()->m_operation) { + case CredentialOperation::Get: { + job = reader = new ReadPasswordJob(task()->m_service); + break; + } + case CredentialOperation::Set: { + WritePasswordJob *writer = new WritePasswordJob(task()->m_service); + writer->setBinaryData(task()->m_data); + job = writer; + break; + } + case CredentialOperation::Delete: + job = new DeletePasswordJob(task()->m_service); + break; + } + + job->setAutoDelete(false); + job->setKey(task()->m_key); + m_guard.reset(job); + + connect(job, &Job::finished, this, [this, reader](Job *job) { + if (job->error() != NoError) + task()->m_errorString = job->errorString(); + else if (reader) + task()->m_data = reader->binaryData(); + emit done(toDoneResult(job->error() == NoError)); + m_guard.release()->deleteLater(); + }); + job->start(); +} + +} // Axivion::Internal diff --git a/src/plugins/axivion/credentialquery.h b/src/plugins/axivion/credentialquery.h new file mode 100644 index 00000000000..6440cd51043 --- /dev/null +++ b/src/plugins/axivion/credentialquery.h @@ -0,0 +1,42 @@ +// 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 Axivion::Internal { + +enum class CredentialOperation { Get, Set, Delete }; + +class CredentialQuery +{ +public: + void setOperation(CredentialOperation operation) { m_operation = operation; } + void setService(const QString &service) { m_service = service; } + void setKey(const QString &key) { m_key = key; } + void setData(const QByteArray &data) { m_data = data; } + + QByteArray data() const { return m_data; } + QString errorString() const { return m_errorString; } + +private: + CredentialOperation m_operation = CredentialOperation::Get; + QString m_service; + QString m_key; + QByteArray m_data; // Used for input when Set and for output when Get. + QString m_errorString; + friend class CredentialQueryTaskAdapter; +}; + +class CredentialQueryTaskAdapter : public Tasking::TaskAdapter +{ +private: + ~CredentialQueryTaskAdapter(); + void start() final; + std::unique_ptr m_guard; +}; + +using CredentialQueryTask = Tasking::CustomTask; + +} // Axivion::Internal From b9671bcffc295a16e1d948dabe534d9b5eaeb3be Mon Sep 17 00:00:00 2001 From: Christian Stenger Date: Wed, 14 Feb 2024 10:43:24 +0100 Subject: [PATCH 030/243] Axivion: Fix disabling filters Enabling and disabling a layout does not do so for its child components which had been assumed. Explicitly disable or enable filters to avoid crashes when accessing them without a project info. Fixes: QTCREATORBUG-30371 Change-Id: I56633dad4b3ffbb1c0c7c7d154c2af5d3c3cde6b Reviewed-by: Jarek Kobus --- src/plugins/axivion/axivionoutputpane.cpp | 15 +++++++++++++-- 1 file changed, 13 insertions(+), 2 deletions(-) diff --git a/src/plugins/axivion/axivionoutputpane.cpp b/src/plugins/axivion/axivionoutputpane.cpp index a9fb3a4e3f4..6cdf6121089 100644 --- a/src/plugins/axivion/axivionoutputpane.cpp +++ b/src/plugins/axivion/axivionoutputpane.cpp @@ -227,6 +227,7 @@ private: void onSearchParameterChanged(); void updateBasicProjectInfo(std::optional info); void updateTableView(); + void setFiltersEnabled(bool enabled); IssueListSearch searchFromUi() const; void fetchIssues(const IssueListSearch &search); void fetchMoreIssues(); @@ -337,7 +338,7 @@ IssuesWidget::IssuesWidget(QWidget *parent) void IssuesWidget::updateUi() { - m_filtersLayout->setEnabled(false); + setFiltersEnabled(false); std::optional projectInfo = Internal::projectInfo(); updateBasicProjectInfo(projectInfo); @@ -347,7 +348,7 @@ void IssuesWidget::updateUi() if (info.versions.empty()) // add some warning/information? return; - m_filtersLayout->setEnabled(true); + setFiltersEnabled(true); // avoid refetching existing data if (!m_currentPrefix.isEmpty() || m_issuesModel->rowCount()) return; @@ -555,6 +556,16 @@ void IssuesWidget::updateTableView() m_taskTreeRunner.start(tableInfoRecipe(m_currentPrefix, tableHandler), setupHandler, doneHandler); } +void IssuesWidget::setFiltersEnabled(bool enabled) +{ + m_addedFilter->setEnabled(enabled); + m_removedFilter->setEnabled(enabled); + m_ownerFilter->setEnabled(enabled); + m_versionStart->setEnabled(enabled); + m_versionEnd->setEnabled(enabled); + m_pathGlobFilter->setEnabled(enabled); +} + IssueListSearch IssuesWidget::searchFromUi() const { IssueListSearch search; From 6849c173c1321a8006089d8804a7db545ac05c7a Mon Sep 17 00:00:00 2001 From: Christian Stenger Date: Thu, 15 Feb 2024 13:12:46 +0100 Subject: [PATCH 031/243] QtKeychain: Fix export for includes Fixes the qbs build. Change-Id: I8dc3427b35468685d03adfbf6bfffef9936015c6 Reviewed-by: Christian Kandeler --- src/libs/3rdparty/qtkeychain/qtkeychain.qbs | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/src/libs/3rdparty/qtkeychain/qtkeychain.qbs b/src/libs/3rdparty/qtkeychain/qtkeychain.qbs index 4a532363f0b..6a1073a953e 100644 --- a/src/libs/3rdparty/qtkeychain/qtkeychain.qbs +++ b/src/libs/3rdparty/qtkeychain/qtkeychain.qbs @@ -83,4 +83,9 @@ QtcLibrary { ] } } + + Export { + Depends { name: "cpp" } + cpp.includePaths: project.ide_source_tree + "/src/libs/3rdparty/" + } } From 4329b67c7476f21b3b7f46f139a384dc4712039f Mon Sep 17 00:00:00 2001 From: Marcus Tillmanns Date: Thu, 15 Feb 2024 12:49:39 +0100 Subject: [PATCH 032/243] Clangd: Fix version check to use (remote) executable Fixes: QTCREATORBUG-30374 Change-Id: I4a98a82ea24bb55a2ab3eed72f13d3d6f648df8a Reviewed-by: Christian Kandeler --- src/plugins/clangcodemodel/clangdclient.cpp | 4 ++-- src/plugins/cppeditor/cppcodemodelsettings.cpp | 2 +- src/plugins/cppeditor/cppcodemodelsettings.h | 1 - 3 files changed, 3 insertions(+), 4 deletions(-) diff --git a/src/plugins/clangcodemodel/clangdclient.cpp b/src/plugins/clangcodemodel/clangdclient.cpp index e5e5142370d..46aa5848f7c 100644 --- a/src/plugins/clangcodemodel/clangdclient.cpp +++ b/src/plugins/clangcodemodel/clangdclient.cpp @@ -207,11 +207,11 @@ static BaseClientInterface *clientInterface(Project *project, const Utils::FileP "--clang-tidy=0"}}; if (settings.workerThreadLimit() != 0) cmd.addArg("-j=" + QString::number(settings.workerThreadLimit())); - if (indexingEnabled && settings.clangdVersion() >= QVersionNumber(15)) { + if (indexingEnabled && Utils::clangdVersion(clangdExePath) >= QVersionNumber(15)) { cmd.addArg("--background-index-priority=" + ClangdSettings::priorityToString(indexingPriority)); } - if (settings.clangdVersion() >= QVersionNumber(16)) + if (Utils::clangdVersion(clangdExePath) >= QVersionNumber(16)) cmd.addArg("--rename-file-limit=0"); if (!jsonDbDir.isEmpty()) cmd.addArg("--compile-commands-dir=" + clangdExePath.withNewMappedPath(jsonDbDir).path()); diff --git a/src/plugins/cppeditor/cppcodemodelsettings.cpp b/src/plugins/cppeditor/cppcodemodelsettings.cpp index db6231cfe99..bac28694f52 100644 --- a/src/plugins/cppeditor/cppcodemodelsettings.cpp +++ b/src/plugins/cppeditor/cppcodemodelsettings.cpp @@ -273,7 +273,7 @@ ClangdSettings::ClangdSettings() bool ClangdSettings::useClangd() const { - return m_data.useClangd && clangdVersion() >= QVersionNumber(14); + return m_data.useClangd && Utils::clangdVersion(clangdFilePath()) >= QVersionNumber(14); } void ClangdSettings::setUseClangd(bool use) { instance().m_data.useClangd = use; } diff --git a/src/plugins/cppeditor/cppcodemodelsettings.h b/src/plugins/cppeditor/cppcodemodelsettings.h index b4f8ac7269d..6b491855107 100644 --- a/src/plugins/cppeditor/cppcodemodelsettings.h +++ b/src/plugins/cppeditor/cppcodemodelsettings.h @@ -182,7 +182,6 @@ public: void setData(const Data &data); Data data() const { return m_data; } - QVersionNumber clangdVersion() const { return Utils::clangdVersion(clangdFilePath()); } Utils::FilePath clangdIncludePath() const; static Utils::FilePath clangdUserConfigFilePath(); From 9d3b154ca8197d3c738aadfbc95e79f4aa56deb3 Mon Sep 17 00:00:00 2001 From: Leena Miettinen Date: Fri, 2 Feb 2024 17:44:36 +0100 Subject: [PATCH 033/243] Doc: Describe new search options - Restructure the "Finding and Replacing" topic. Task-number: QTCREATORBUG-30209 Task-number: QTCREATORBUG-29361 Change-Id: I107f366d99877a80a0ed8973c9156e46ee0ab312 Reviewed-by: Eike Ziller --- .../qtcreator-find-from-current-file.webp | Bin 0 -> 12472 bytes .../images/qtcreator-find-incremental.png | Bin 2618 -> 0 bytes .../images/qtcreator-search-all-projects.webp | Bin 0 -> 5606 bytes .../images/qtcreator-search-allprojects.png | Bin 8271 -> 0 bytes .../images/qtcreator-search-file-system.webp | Bin 0 -> 7504 bytes .../images/qtcreator-search-filesystem.png | Bin 11041 -> 0 bytes .../images/qtcreator-search-reg-exp.webp | Bin 0 -> 5794 bytes .../qtcreator-search-results-matches.webp | Bin 6534 -> 10992 bytes .../qtcreator-search-results-reg-exp.webp | Bin 0 -> 11060 bytes .../images/qtcreator-search-results.webp | Bin 7250 -> 0 bytes .../creator-projects-cmake-building.qdoc | 4 +- .../src/editors/creator-code-refactoring.qdoc | 2 +- doc/qtcreator/src/editors/creator-coding.qdoc | 5 +- .../src/editors/creator-diff-editor.qdoc | 2 +- .../src/editors/creator-finding.qdoc | 51 --- .../src/editors/creator-locator.qdoc | 6 +- .../editors/creator-only/creator-scxml.qdoc | 2 +- doc/qtcreator/src/editors/creator-search.qdoc | 302 ++++++++---------- .../creator-how-to-silver-searcher.qdoc | 53 +++ .../howto/creator-only/creator-how-tos.qdoc | 47 ++- .../creator-projects-creating.qdoc | 4 +- doc/qtcreator/src/qtcreator-toc.qdoc | 7 +- doc/qtcreator/src/qtcreator.qdoc | 1 - .../creator-file-system-view.qdoc | 2 +- .../creator-how-to-view-output.qdoc | 4 +- .../creator-reference-terminal-view.qdoc | 3 +- .../user-interface/creator-projects-view.qdoc | 2 +- .../creator-reference-output-views.qdoc | 86 ++++- .../src/overviews/studio-finding.qdoc | 39 +++ .../src/qtdesignstudio-toc.qdoc | 3 +- 30 files changed, 360 insertions(+), 265 deletions(-) create mode 100644 doc/qtcreator/images/qtcreator-find-from-current-file.webp delete mode 100644 doc/qtcreator/images/qtcreator-find-incremental.png create mode 100644 doc/qtcreator/images/qtcreator-search-all-projects.webp delete mode 100644 doc/qtcreator/images/qtcreator-search-allprojects.png create mode 100644 doc/qtcreator/images/qtcreator-search-file-system.webp delete mode 100644 doc/qtcreator/images/qtcreator-search-filesystem.png create mode 100644 doc/qtcreator/images/qtcreator-search-reg-exp.webp create mode 100644 doc/qtcreator/images/qtcreator-search-results-reg-exp.webp delete mode 100644 doc/qtcreator/images/qtcreator-search-results.webp delete mode 100644 doc/qtcreator/src/editors/creator-finding.qdoc create mode 100644 doc/qtcreator/src/howto/creator-only/creator-how-to-silver-searcher.qdoc create mode 100644 doc/qtdesignstudio/src/overviews/studio-finding.qdoc diff --git a/doc/qtcreator/images/qtcreator-find-from-current-file.webp b/doc/qtcreator/images/qtcreator-find-from-current-file.webp new file mode 100644 index 0000000000000000000000000000000000000000..d9296f04ac0c280b30452d3e9addf7c230222726 GIT binary patch literal 12472 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 literal 0 HcmV?d00001 diff --git a/doc/qtcreator/images/qtcreator-find-incremental.png b/doc/qtcreator/images/qtcreator-find-incremental.png deleted file mode 100644 index 3bb17a1a41fb0130c1422be985421a83c189b875..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 2618 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 NP;|3?-b5C81^_oh(-Qyy literal 0 HcmV?d00001 diff --git a/doc/qtcreator/images/qtcreator-search-allprojects.png b/doc/qtcreator/images/qtcreator-search-allprojects.png deleted file mode 100644 index c442572f99653a82df593e017f8bdf430baeba92..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 8271 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 F2>?jm6Dj}z diff --git a/doc/qtcreator/images/qtcreator-search-file-system.webp b/doc/qtcreator/images/qtcreator-search-file-system.webp new file mode 100644 index 0000000000000000000000000000000000000000..31494d1a17f6a4de8bc43a449765fe34a809cfeb GIT binary patch literal 7504 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 literal 0 HcmV?d00001 diff --git a/doc/qtcreator/images/qtcreator-search-filesystem.png b/doc/qtcreator/images/qtcreator-search-filesystem.png deleted file mode 100644 index df344a79e33f74b67b7f15189ef9b1c0c10cf55c..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 11041 zcmeAS@N?(olHy`uVBq!ia0y~yU|P$-z$n4N#K6Gt^J2tu1_rGco-U3d6}R5b&7Lgd zzH`C(_z1CxmIK9%$M~2o+}$*DqI>b3tjs*yO*MkkRO731CYV?Y+TB>tTsY^2qQptF zZ7H)qu*p0T>N)gdhApGaZ|RG2Z|>S3c>YiHxA3>M)nRF2rKP2%=S$9hKJvP-G%WPm z(%r9WwTyRv^who=~1`-zsY~{c^DWNzR6WEFfcI4frtu*H${5!`_6bWFfiCK z@V_{8-PR(xVQtYRh7S$4<(mbVD}KM-o_}vo->d)s_vq21huis2$Iq<$eAfK?CawvWF8z2i+2115z)G&*WtsYeZ%d1|sha+K zd-Z0|PQ$;sM%B*MkN9@y-?zKZoU&-jTdy`@&WOm!m&+$TeVQ8B$aI!d_0!+?_5Xi9 zpKs3lpjA9>#>|t5&$xcir>;G3iWlGieeb)9uidvB z$&VjD{(HsP(D37n#ry{-QxQ{&wVel;*|f-OKb|lSr0E= zy7cz;_N#~HerZ@Jz4;;IC(jV$vU<<&N4D@2StPDJm-3^#AX4 zuXFS5^+mn5vi8|p{jrPwdelRu@^`kUw(CRZ$!QFd!Ub<`Y<#h3YOwCh|FiG^c{cz5 zpXWvF={;N6V|Ew3eQa_5+w>ClNt@VTGtR$pfcZcbbN!Qv?*D#W-+$^p)AzS4+%1?t z@0)T>|AF14*X11BCn{Xb$uE)Jv3=_8?f=F0T?_k=XEnXa=<&D7Is6@IucfzMwaoVY z@8#aSd&S1@SHCvs*S_?Q|8YqC-|Tju6Q^x_ox|Sk{eCZfer=fCbk&VhOF4q3hG<;% zdTL!~^n1_GQ=+PG8GGFhe`m1V_*&jhK{4s$?)!i9u2(piER18l#k%NR&$@{(y8bh@#F{1~_QVFr`RHqA5izTO!9u=;(i%)V=3 z9H~dOHSco#Yv;9LxTNynxc$FEL(vbm4)6Z_zuPwD`xC~Gv5tF{T`H|Af3Ds>J411^ z|E1mUk8o$bys<+&(p-zR^Q)1~fr9Rd=l<`^7vs14u^_F!{QW&sRm11Ux%p4H$^BiL z`}q6*|9{Q*edPVG^u^ZUmh`;3UoRJa=boXW-=a6&-@{G0Pi_AE z&!0aV)xNv4b6&`S{a1g_y!Xdwvz7UB_9I3UYUYFmmDW5r{It&Mkb-u)bn#?o;V->a zs;6e{v~`HzI7?39{rA)Q``0Y}6aVLt_@@sSw`OYedVS-b@|1DXzx%b{V7e0Xrs zFu!8id&b{3WoLgde0}7#vu2Wb&WtZxUu*Aqvpd#9Q%=D4eY@&M@?4nb8uq)tSaqTU!`3Wg_n7wg#p3=gQ}pMvNgnxk zRKLz}ccun&{hSAn`|aa;3!B3DXUv}6UGwN+yZpJE8$O=1et+WRpLgZ^UoWpWZu>F0 zuksh`CH?vDnCbuy-_H%6 zhLy8DzgW)NE}gyKL66_#WyXb2hkV

1UONj4erC(M2uuD6VK3tU|GK`6-NSs( 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 diff --git a/doc/qtcreator/images/qtcreator-search-reg-exp.webp b/doc/qtcreator/images/qtcreator-search-reg-exp.webp new file mode 100644 index 0000000000000000000000000000000000000000..a56f9b18d421feb04cd823526a1e917b8e1f6dec GIT binary patch literal 5794 zcmWIYbaR^}#=sEn>J$(bVBymz#=xMz)5)CS>Vw_??iWgV{y+En1mpP?#U(+{XGTsE zuy}YbMQwBC^$WFpvp-+jTxpqZHS?y7W&2cf-*ew}3*W#0zIt`gRI$5!$C{Kx0*huI z&1w|B(R*N$>D^sIP2Vo;+LoIeVr#+Uex~J=2j6eise*I<)yd3SxuhvCGjgR|?%#a| z?|n13ZQI)W<<9ZOV{<*Ha^~OPyT*)_UQapNE-n?kvZli9?{wGOVKdyGuQXob zS=A_T@l|Zf$M1HVclGLfg#TTT^SGDMhWXmFxD^fj3%@Hj&sfngMd_(oh5e+iyBf!1 zLeleCJhMWLg0!Y^O<2k_Mf7*VK_{ORpA-W^b>^7Fv2x!HTk0HIsQ+u3;lxe+{-<3| zd}O$C=C+c17J0t{Wavuh(t%37ZwVQ`l>%>F)qef5s=8fBHl+zdIJlJYTe1#s6vi zcfR+3Rhx5o55AQWKYwG_T%+F3lj7DpL$1y$-f`p0zuaWgMKUaz-|I%uvkgK~5%P(w)e=M*@p_X3Y3A z_wxD!JDb-o?bdvL)N#?*?zwknp4hh{((q}zp~;+2ah&TnO3roRUo@%3#_6(1%%uuB zpRB#COCq{$KPY~5+-SVj{SEtvH!9`+9{05_W~eTBn<6k*xRYgTqq6iny@1k-Q`J6v z-+OAWy>I(+7t_+Yim$rERn{8>UiG=pw|3d=MY1KL=P&(p76^FK-K?V7@OAIa(rJ#o z`eDVB`NVHO6gE&g>a{!ORqLg%td{!{@BQp(*l3*9VLbQR2DNRISGcK9j^Pn7v{{LE^!{zeXuqfYn^LdlBj}+c`bL6)}SH4uAJl}!1j^oBLje;LqE|yM2f-KK93ZxNZ;S{$n&RP3B#N-x3=a>d_Cqk;j!6|JwMtms@`u)dGX6ceCi~YyQUYL z#r$VRDjb#g;?tp}Z8`T|$+nqMEK`yc`3^jPa_PTRliOt`9pj(hbq`hUR~F*;UgW6b zd8gm;&wqJ_$Uk@LpS}NYJMU4pJ4=ACOOhGu4yz?)8A~;fD={lM_@tQ+2Gy7tkNeD3gV-H<)!fNgr9{)ex31D5J`OSKl6@jehW3px4N zL9T|oIQq4?^?_IQg%cDs#U9mJbnee%(@&bq%&_rf{9I;*YrjoS+;RNP?EO?C&e|v^ z`$H4ox~R&wAtl5ZhSC%pKxa1+jgOk+$lR^-?UaFZWHM5 z_qVwCA;0|hgUKHP1=c6o^OZZ!IbPvnpf6Z=W#RJF?}>*SJ=WLS{CT>+HF>7Me$89| z-{#%pN>w}hLCj#&MV^`E`}e0eOxkp^`HR`t4;vmP%=mbm3b|#S@gG*^S)A5>;ZFgS@lpxd8Wgd}54^~KXHJ)FjEKr&pCVPRiUGdei7OMr!e2!OogU)#WUVYu?l23KKc<|3#C11C? z9kp~hV#hz<*J_>+(~b1ZvnD+kYs$8!?oRZX8u;~hbl98cdy{@YR4>kGXA`)%lgmHT zVryvnEz<+7Y>zIU+wxdb&pGG&p_JlR3-T&Xu-qwroM!sAojc6qxy{0+Ond(=E3SrdF!d{JzR=URqhMltZOn>&HFn?gJ-+YM)hf?lI#CoeLY99 zhBH3F<$j8E*Q?K$Kki#1Gr!OJ@TMDO1rwLdySPmvrEFW(oS)FoWk4ZWHD_KTKhT4KSOkx+Trk*>KAtLgk7xcQVZmM`Q_xt zXZ@Fz&OYw{{PyIMHL9^0xm#_f`Yk_NR^h+)^be-VGk#qQ(^lbNtAT9|)Pvif8md{g-Cu=-Tf+pgwQHHJw$GX(yMAFug;{`ua1y*$2eCp^+`2FOl1n|kbm&d1&2 z0_%1^`xw32;F!s758)Z7PdKgC`gVQY0nR<&FSbVX%~Lov@AwBa`9OAbA@ZPxZU-Tryw41I<*&h0{-95Xi>CrN*w^gMKN;l|F7 zNtfR!Ei_fJ$yMjFJY@H2js7vwx%msbjV7O|T*oN+#YbUEb6!!>#8(@X1rHqbpWYe& zpwj5o9hs2DejoNclG)TIvR-JWRKXu{^Nup3>5URIJgepze%KOgq_ReCbBmRt^|5~k zeP(ceeyfz<=PI<&>(fCIp>Bm>!*9;B7ldaD9-EOS-nm9`;!2YVNj!;ameVKte-JOv zFucZXeP$A;X6ez?4HjniFV6QY@9tQ$s8lY}`O~^@340}V1diKp>NjDU>3OPIit!eY z@VT^OuNJ(yQDvN8KDWba!~gs5?%Z=1|52MFT=&RxWpVK%b;GZ3jh@W;wq(PO?kA=v z@9lbi_L<>LgL8M?UiG9LyI`Lqx?fW-zU6NM9@AI=ieb{y| zp6Bg6``=Hj!k)}Jc)acnh#hsYi2F}ZN9n_THg~q4cWIa@e`|8*g7w$Vr`nu9t9*Xd z2H7<>%DIUgT-|Ix(qDRa7#&(vl#yq4c3s~@y?bV&c9TdY%Dth3c(e#9Jg_nH-_8FXyAQ*mG1GN-jkWMPrQr+1Pc zc%puXz7+dV$GEnXtKVf+jBu-rR@e+np@2OK_d_n~|Jt?NHD25#%GGP*Y<2AuD+2EP z;rPjT>sO|`JwQ0-n{LtH|Ml}a*$jXD0x>iH~;OA zM^7bIdYWWTNnSN)(+&5I6T1b=56)k_^&gJiRUb#?Wl9qr2Cu;`dii@rOh0Du7Zh9m7JNx*? z9-fvDvy(ORxMNDclpPmOW|^4GS#YnncrSn4q-)o%^>H=Z2~F^srp+Qci{-#m0p`{u zmr%u{JMtV#B^*Sqc9a>1H=kXwcK-85Jtixrja*DCx|dk2NZXL{%yyk|Ou%K4cUi2< z_O9n{+r+h`<$PD_Uk&%$9EYVU+@+)x5wr`>@h3>jPvi*=VPs5Wb zBEzEi(U*tkxEoF@GG#h<%7iLd#+dK03Rrkys>vc&o7?kr9i#2T4^Q{}5IHBLk-_T# zx4OpDG)?{~vnPE>J9>J1&b*A;DWM9gdv?rYJgw=g@O^K8OVOLk2*J+jXT7K92`sbc z-LUsk{&yLLdrEj9H5X0BG>gE0)^VS<#@8ObItF%($2}?M;mdLJ2ZYyqR z)KBZriPXE^-}rN_A8 z7Y!e$r*(Qiw*22?$p19sr+%sE3DFztVm^m>*KjOZ#}qkJsZ{jDDUp?{9m1BKh+*Ai z<@!o%!c@(m@WwSh6L(FE``nl;esOQV-h=H)${aG8aT0PhOV%8TapO%a;Am(3b*!x7 z!Ng~t&8eC!OV%;n+?Ft%{pEp8B1}QyjWUK4T-g(K+GXA~bk2Ek>`VNgzzbIWy2N7ZLj!eF0UlVWus40t*N_g4DCUd zXL2N4mgF8h;KJ8@t4TB9(8GBlEJ4>VNrS|n2(kM-S>d9X-r~b_qx`AH!wml=I;pIw zI_$BJ8aib@oDx30aAMq#0|(zaK8&yzUm-PN7gx&aKX1?dN&Y3SYWeWVyiKW3KWw*N zx!R#mBPzR_$t`@9%!FOj?qz&^P^ra|`pZ)u9G)JrtecEL;d%A#_NVr3c76W8-z!$$ zs^>pxo>$=^HS@Vdl&%EdLw{4H+YU;fmzsQGE$3dSWuvlKdDS83pn0>C6zUT!e7`(6 zlG6SmeO-IXkpNY>Nu5p4*sUaHiI?Oonjm{W87&kfpFuv|= zRJ4MF-*fXs*+cO=|f}ZFFSn|LI@GQU9#UW0hWn+S=0hi{~G7_*Y~2L8+UPxyR+aoGFE1`$AYuFC@t=c#?l^7S zmtUDR|7Kj|tz->`w7RsyYchW-&p&V06}G?mXXekB{~k@5@m5s&%sH<&=bP=%&1$;6 zr@t~bR)`P7P63)bELzNF?#d&=s=UlTK`^!?6$^YY(k zTN-dR+#o$F+$!v$=Bn(kXZ(DpKDixu`C!sHo(*eOF+`mXH0W8PBoSm58XwecTY5%$ z+tfIIwZ+EFi??25UMCl}$u!~d*X>P;9KOeVF4?Y|bK}*``EeHxZ&Fz-vi#W@7oXmf zKP+aQnc8?V>NR6{Uvp+01Q$A*)uVm3;AIT_}@IQq@Y+}|-KD+Ue5bK@0Y`LmhI2+#_@mR$)5Dr{S&ZM8Et&kILHnZ2dY|L2 zmmQ*7%`6mk0!%FxbzEH?ykG80xS28EJ!kQ|B_3iX_D$P&Z4Ss@w(xFgsbb>ghifJ7*dzE-ziWpgOPu+4 z-f!ci+566xrr%g19@N6OjzMR7_p^ja?;g6ye5mz2s9wyvty^{5TT6#7#@46OF=F%2 z&fxXpyAl<_mfOx8s(kdcWvN5(%UcO6SMa{vaV_~|%4?fvCpX>_X!*2}&(%3&?X@M* zsgwUL4>;HP#7#p$>q!#VWtA+(GxtwLNclbU(*2w(+x6>0Si-sR2V2&0u*pN1 zaK);%ACCVF(|>k3;MDH!$_1v|3xbl@J_n@*Uyjp{SSQTY)@oSh;JaaIlBVC8Z(Xd5 z+Di5=z1n7Ot*zCN&V2P?&_YKMWr52xLQGxMOn5XF%__0o!)fZdlJQUnhw#M!HJjL7 zS~r3U74zobjFSvy_)%|dAG2#?N$Q5yq=$cYZ=3mcYD}g1xAga)zDzuNb76elswXSs zxA~lT(Jr1|9lrcZ&iaV@vM`YY+n;_HTmJ9J$(bVBvFHi-AFZ`yp!vrQGw|Y$xCLh=0z1rsj0zlY<3EmK8sF z;t^EYT%0sxj`GQQtmgh|FVCKvrm@xR{U_$_yqk7fmeoEv{~-Rt=a}!c_U}LMyIQqd zWcuoDueQ2&6f9~ud39^&y_h*Rlhn8SZb{E(6x^a-&U~9$V*&eHkF{Y}4&`#>I3+e4 zEWGey+Qlu^PTl$4mt!_%Tw&o;uxy&l(!R`jawyyBjSTF(sT(z;Z!dGpE8EvJXN^Rg zciN=DXIak0)iYM@jLvn-ba0d`F$xfUcBR3~v2}59t5j znDr;uPR~7|oWyurI?9G%i5x%nr_ZK^9AMoL}Z>HK#qg_qP10 z{uj=_(_L?eT@CBLR_!aiyQ0ISXw~1^<-EI-w`FcQCg<wtvdyZEj8YEcO21E9;y| zJG3LyCP~)Dn-rIRd;dS@$L#(8|F%Axx^D)j`EAoLUVdOFMZx* z_Oe>x{*UbadG`xz-YNH|y)!ZVfBmn${Exp?^Zg&m+gD4v)=b+b#wg>Kko!gS+LVj4 zgdQGzD?3ff#e(nfhs_q*tDc4C?U`%Y^|o)v-GiCO?e4PedF`ElHuwMeW$VR$v|M(7 zXSB8BPHI->nVE~-;{P%|{uKZ7ru@#-|Gs4g+XLKxyXE=*yBfdE{{J)8&-#3J3?hQ; zQ#;o0-dm_qKMG@>9*qXD~nYh?KaJBp6@oTl%-2Jk)KW<+=Wg16l?%V;+Ol<*SAINOUiXk!jn}jLjJw?FyNM-X#m7J1?6;bCdPc!% z+vNJU)8AVA>)vycJ)2^5bGMKF->dO|e3$iH`(f#~;fPtzZSuw@J)M4K9YSRbZyTp;kW&A(y?+w z?eBxE@0J@kSnONBtGxcr%*A_W`ux|ua`Cp@jGEBxnuqy0ru5V&JT5M|^+K$6{tb(- z-PXSaDwph)|83ve7Ir7={f)ytKPO#Gm|1#d*1BcqA9bzMkDd6?DE6x0k4nDdr|Jtn zruVMX%@cXi_u+x}oUI%W3R2BWV~UsNi7sBRpmz4 zS;!t+TwQ5>yV2@$@qrFs6}9Ov=3cSb`jLPC_oK(`Hurz6fBtWAeEt7mZkMmB9p+2}culi;LClwzoL{_we!a^VVLv|4V(( z&2*5t%Gp{U{%ANe_SzXUX=7KBI{~D(nc^!@Z^0)K0x!LM-6`y^6UEMeP`+qT+DMxCZ z-t+CPI{w1+_m0my@443hxxLSI`78f+ZN7)!@4P!4wp}e`wS4)ffc%?gSx37ztvwld z`$hDM#ce$6&g|IOFe~|0dB0u8p>rSie~k!?D7fma6}z1^?LFt=r8XK$(G&OZp6ARn zNn7FCc6p&(F_X^J`NFp8+B0GnraLX&^>f{2?^U{Y3vJJvEY<NoQuw#dwIWj zeYp3#|Gp7_^38nBSI=v69woRvSYDt1_;B9d{70|C`TqRs65Vh2;Z&XSzrRN12eNK8 z+dtM_I(7GQ+ho4NDPf>s?Z|QcG)y5yoG&b>0g3zDt3+*oA%=;quR^J0S)m;bB(@?~dt z>yw(JQn&xTV2{67b$`b%l?wZnjqAVP+`QxB@3SYmzw9q+SQh^6`h-1`M1n-l&wq3K z-u+(H2M=dGIwqDS@*wxuyrst{Y(4Vx)$yPX{;s>nl7Aih@!h?9eTBPT@t^X{7^|{7 z{a*x+m)-TdU0rPYZ0(l`{Pw%F!;ZPj-2FQ7xZR#~&tF%rS>`YO|83%N`xsH>$7Sr_ z?=4pGTQm1Zv+|zpmtN=n*eD@6y=GJ0Gk%`>cU!-F@=i*v*;M!IJAdu7ty{iE^w$J^ z{_&z0<#Q@4sATiPus-aETDa$@(6e-%=f*RL+ge!QyFtLt7yR;o_6UjE?=wqrBnj1c>u5gzd|8SRNIx7efaB=cTA*m||&Ma?C58TG;)t^Dnwk*_Cn z#k<~`EB;Ap{nuO{zr`F2%(Iq-|MgnYyZV^Umm_J{68(28UtVk&=5p(8vE1%Q-S&@i zHat4`_FJ>-^VWV-kGctkFI`lRZf4k;;n%-ohGSj?AH&^~d2805Wm~?#(#kc_B38}M zUY{r3abs@HF0qLgXEY{8uA47u9?ddy+qTHf5jQvNT%@#U>Nno&+g|GWPB%^6_+2UW z;7bF!<@3uq-yPo~F;{Zekt4S{n?E@$|Fq|OLWb-WmiyWB_)f*&|Juo8z-K&r?#xeD zvd{mEYkyg~FSpRD;AYA8FwJbekI#GghQ zey4~0wvtGeKgZwfec|fWe=*VK*ySUx*|$~ZNbWk)lJ)gKOyqLr;;$VCjGuV!UFv^k zs~*4d16hmsx;qa)Tk!C=|9V_kasA<<&o9iJyX{(o2}d4{|5=Hq*B-dCK~iLBu+s5qJ<7 zr^k}6=cU=D9|OA0{MxHRy#6dQGqf}+>Ha8M;joS6Wy713|0VoNy?fbHUJIJfIpWnD zy!qaxV{W=1?9WH9N^y9!$IF5JinqA^uZEwKw#}a6I#uZJjr}W99`)Si^N_|gLPF3g+rG@{m#;S&%+9UY;WoSiCyP1Dg0@KS&8|}>+ zx5SI7Zu-t9C-QKuPEp*_FZvS;lV0d;(2x0dD*lr7{;Xe#70d4NO4VyB?aeNjf1y8n zU-`6>~d*c-{pl-)wg_q#S3p~ z@tfY79lPLd=?9U_)c39rBd4xA->kH0>bI-MdqWc=n(q4jopSu;0``h;Te$rTGhXn0 z*XaJel-tVJb1~=fSgxE;)&JgCpG&@La6S$?UMe+xmsI5OL<{b9b}v022cLVISaEcR$eNgAiK;oF z>)Ibr@Bd$uVq0VJ$|uf#9q)lhp6h4pEi5||`*F$1m1_;==*?YjJ4bLyn$_LKDnHzR z$cgPrd!yAU^zHI$r>%xex0%l~9nslf|4nQC>&*V5J6`#{C)O5jKAtM?wbtV8UXE{9 zRy=#>nwaxxhM(dR`OUNVW*?mTpl7X&@t2>^4LAR^;g>Cbwn94djO5B9&h|tWv*TxE zOiQaW*7V$#x$*bxcKNxWw)LK=lkV4K_4M#tZ+cvID|&zahN9^&TX*~ES84t|leu{7 zcDp|>`nE;fJic;zh4$Q8`PO|2QX40VTxws??_SD#Z%4L4+ANh*yJkphJ8!(Kvhnq? zQweWOWN%Loj6I{#8kjj{lJzB*&&ppeDJxrO9h_5gNn@$e{LIB&XFRQZeNEziU7CJR zdzA)rR?(-LwkaoEj?H9LtSQz!iWS+ZWK>gAsm8>e&ZEvZ|QxwEtD+okD# zUyGt9`#u)2xS#z-)za|HLhfmNT&E)3zkTT1bNS2U*BksE-S+#Wf3oHI`R@VCtM0i> zzIb-0u$KS!CqJxKJgZO-zW>eO^K!e}H`F%q&fdJKtNd1O$v54*`L7h-m(HtS!d@@( zTBUNy%^RIvF)#ozo=yYbUSV-n*x(?p}?5_Q6@f8p69RKByPD8~s?E#Qx_{ zY1Q${e_6Y4Y%h_Y@ZHLOXYaL>+}D53J{tOCrDpJpf;CE^m06J!`ATOkSRpzwWZHt$ zQ*v4}`%GUN)Eqn0!Q4C3HN9(lz|lFYPGtTUGtdm)p_R7kdG30HxteidtN(7A6sRQZ zv+`8&Ep>w`uR}Tc`L3;D0o7U2)uBu5YJNN4zAc~ssNZt7!(#xFEIa%ZaeJ z?6da&shBeVWuXdpu#M-9OPQ&ze$$y!PKlnLFy)#^aHy)QN=N?h$Ih>~XU*YzywUKV zuG~a^XSc_yxjwy(XTSevT041pSVfS)uc;v|{C_#8C|XH$FX2+0nrL+)lPO5sX{F{3 zJJ*!v1TM4mHkph$#lDh{R;{qSwt(5da%q=U=)%p5wL(sF)Ov}Ap62*IZS#}~mn@&E z`{mx+_jp#qZ~wVVMdM;r&$vdZZT5)FyME2>UqZ0xtnQ|nM|QG_oC?@>$UuByh=9iB zw<+GDhxV|U`v2_YoWgf5(ra6bBvbW?DcaMvY|*=_+A4J9`_a-X-|vS=^ogaENc3-X z+xC;|{0Vl(tO=`>qAw}sTXtXJ)c7$qkB};nG^Ezi|O)=7-zmF$?E! zXTGgcDKjTc=sDNX?$s@ulaKd#$NxE$edf>9EB`c_0DyF=UD@I)M$WYaEuGcWd&juOr|*ZPT?MbCr3LnKKp`X3Z;WF_>pmaEoV^4Xg3zmd4A^TG_TQ zUB191?UbnZ!YwOUI#%@v-@k7e`n$-g=QvN2ed+<>PXSIV99MPaWF|OVXIeSA@v1vV z;m3w}Pc@!3^VHvL&EBqeEy39?_wB8%`!_n8{@8kdp>N1j?TIHBEqV28%Ub2aXIHkm zx118ZB9Jk|v3G0s`~|uW|EgDlz*cCNJG}dRZ7u^?#{Y$^1#pg zh7V>7T>k05(D%2wnSt7~&es9#GQX_7{fw7aJLN}4eg4|8=kcmZSv}w0T{!zg_0+Bx zwSkwuZqe5|zjXEd1eMu)<}RE3?BT)<`hL68U#?nT{ps5(uXP*s53Rm@*eI|*cXGX_ zP-<+**<<@OYIj_mBW<=nGcV%ybd|fCORipbt^7Sh<^GY`Zu_R@bkAJ2XmQD+?v)Y3 zOIDUYx)!u?+qAyr&9%SW?29+V<(=Fvp<=O2b#11RX;O05wzqzdmMl_S(f3u*D$`|^ zRT(q${3~xH`aCAF`P^E;uDaFD;CuOzHU4W9R`i80TX)2FMpb&%zW3*<>~t5L>NuaS zJKH(rr?KwNKa2Hn6JN2e0p8*fdRkfO~%LUcjeRz z1J2%kb)z?Zp)zmNApxgbnQ_%irmFp9bDPaPKZX74aycHajaw2l-(S?Py+r5Bwxx>sY~pAc{3`Oa;8 zWd=ioVed-@#y>9#8Eq{R?&rMJT50-pzINOP^YAc)1_Aj&V^=n@ePYt{aH2t zyGy~s+7qW{etez1`iB1-t}V94T`McXl$P(x$@yRT;&?G%#>+fo6}p5i}V<;=$A`ZQGaRGXU;Ww zQdJ^{>)CmWbe7+=+TJ9$rrulp)iS0J*VL^({N?(vE3WpyZK*5l`_AUGho3(3?wtPN zAIp|%KfL$z=?&SR6=LVM9*uhb`GR?X*T&nG85^atu6(QgBe10;ZLz4)`Xk>rWtZ+$ zebdbOi&vuH+03&$IObg6aV#>Xg>&7L^&G-lLPt*Ph;zm@&Rjn8oMT$ip+CPv5>Ifg zbh$WpidWf>n0XO-C);_r4hZX8MK8$P*7AMZ-Ik+2pQh}4yvE<cE(_{UzxXCccb%Z3?D$>i|*Icf3ddcQr=O>_3A##Tn&U>EkUDV5sa=%BT5R;THX zpXSpFRqIRaCi1>&+kB^Te-M{q^)lNNg-YQ%QEex8+^?PSPMv2-bFgThq28n4tLH~w zXBK;;bV5h&4_n@oeiNsg-JSmf4s^6{yDc)aWQood<(Dk7*Dvf4m?bYIKZ&d0-*S#= z-T{wJsZKr3?zqUKCUd9Zy&c)Vi(c*9<-Fatx=?Ue@pfTx#fMJ+W}J)tw&$Lh0D24Iw$YKrZ-1jSDbuo_DCru=A?XY?)1GLf7p4o`#1*O^Du|W$ zR){@(zV&MDSCiXXPv6TPK9Jz}+4=bEJ_bu2ajxgxKmLi9*<=~(F_}NH&~vJ}(fda< zc!%Q2?j!XN@|d_x+^Z(6-TP(Dw`uDtru|Ba;ds(syS?X4;O#R^HSM2waB$xK`Itq>^=5bX|Ay@b)i^XU;TtfI(uZ!2S)dA{!sL%xn=re%Ov$eG1u}*%ONbihc7GoZg|dV z^*-7ACvwjDVB;f^GP9HZEy?$H=l*-8&|Tppzunwv=iXdoH`&)T=f{n=LhJS|^mw3P_S!T-Y z>5p{E*8aQxt5AQk7LOs*k;AMd#?6-bK7Uwd?6~mm?#c311}X27g_rGlQRADQKef8G zP2u1Tqp#0Cl{#m!WYnD#{53Hetj1l!~156&s=QrP5imw%@gLD{zm@o(`KI(ocrs-?}|x} zERNiD?E2lnHeYFS_mNN29)~U|^kvvmvT(N^&&HU_`_ufE)hE5u?OG>&=*nz?Xr{&D9P^I+d?dkQwWSuK}i3EsI!)9Qas4SO&D#lHbfGZ{4w z|9o~bx8~)qv{z>@U*|P!=?y+u^jYYY9EN zqO4L(!INZH9+Gry`gO^It$A_o^*1+GP0MroxukN<@7pKMb^W6+lpPd4FBK-P=&P}; z$Ur|>PrbQfYEs~idbz#R3*2LVR-E{GsOgG%eE!9vy8?1LOrd%Anv4yOZIIdFcaXvC z-vJ|^Jap<+-JbI@D=*e$Cf<$7w4CYi`!-AL3GIU4bJS+&{HXf;s?=E~*!<1a zqiU)NnXPj5J1sb7wkaI{VW``>E%;Sp%O}yymr8pjwzmE*Tl7)5L9{+|&vTReL6y%G z=0C^`;5%|(Ktqt(KPrxw@fmlWQ0S>5OV2{Jm_M9H+9N8s#GfnKw65L$VrL%5HEG4U z+DSVrnbh_r3D0}C;j58aUDGi`j}L|1nr3y4vs1d|V(u`v{wn(5o+R|#;27J5f(JkR z4ZoWo_1fpT?}OdK9YvE*HGWR7f5&-1zxSwawb9RuO_q88C!hB0F;0ABZD8keYeMAC zpm?q;=F$1z=M^u0x=Yb#??nsIpghyhKc8;-Yo7BsGI)NBp;xfhyshsu*X~)gVBccJ zeMc{zPc;3%r=v|FJ^J#Jc{hJ>_9yI@c~c#wye%k0A+g{O>{OH-=Yh91~`lMaF)35z`K1bt_!oIz#w;x`Q{QlT`+MBe0 zc^uyb>-hIwnRLeQVppNir<(fD@ixl84eIqA?beLslMx`iC$$tip$pin_;x@ zxgS@(c}w-@{jrW+lLel9(s4QAFs}ol-rc@rj?X`C?%>HYn=hh% z@P}~59=4nEmij{d3h(Umj_?P(IV#xkST)ftH}ORN;_#OJ(udNv$1N#r4RP65*DO#z z@zEpk7Zz=?Pkh66)SUb%8Drx#%X--kA$x}n67C6R2NkD&o_&M2VR^lI%h#Wi*{&xq zxSnsY|9q`gz5Ue7x@L0=xMr_!b7<&v&){HLbDTdQrbBsws*BgDo=A?-lc$oi3Q6oorjzkfhzWVB5jSr_=Vh{n@R!#xG}; z^f|74^$D-dXXt9E_@(slE&mwui{1a6Roltwwrh^_3+NmZoU#6gcTSzr{d2!gU$Sg| zZFu3exktfA#xsBZX07}GM`HGw`_|W1@4Tm&DDdCmlk0coYuc*6GPuRpwKGQaDHnX3 zlG46D?QXyR#mwEM88VGEwroFt@&2(`xS_fK^o87=1}+Of|9<*|eU`qZU9-}kNk!u8 z+7G_X`u2$9gme>|^r0W!5=VbNElE7l{gL_Gb61NW+at~#S6ZNcWRHY>g8bohGS^kv#k3Q-E9I>o`oO!IU%K;{Zne%tOXw>>Pr4SDcjMnW?t~~7t1}zIr$hr8 z6sovCHmp%Q^Hinc#aF(Jn5L5do>N}zv}?RstK(S4^De$qDQ^A21O1)16(+Z7+&ej) zrC0sy%$%rAPvYlmIIk~vcr4Viqg_OC)jEHL`^P8A9C!Skn6trh*_|`*i#_+8S96#? z`}fbHvi*50=kUiis(;dcQpJ9zlvktlaAc##PP@i~wK{F?B#nO#qHCX_<5o9uj`+<;@&sxwqs;{ ztZK37`7f3~rJPZ_d?q~BU-H_tqi)NQ8?S8y_Ds@ee;@qYt8DEt4ep0_vvyR7ONl!^ z7HN4c<#O@9cw&*fcaaQx@BRhPm7lyeJyG|m*6d-|^iQge=1=~g*RTHni=|C_UeE0h zuQnV!x&NQM`Fj6=;)H_vzJU&_3__%5oPYf2D`ytplixXAeLrosKKVIW{l(mOUek`0 zuliD{@{V`Dh~+_6wI@eH0yc?%Q2o`Nzw+qTc&!BsO@AtQtoT0j$mHO2b)g;bp~H?n zodH_y?|GIB@9Ubm=4kDN%gah9=LDHQ7n+%I)aQ%$^ffMuURi1X&a6yL>{Hm{k~&rI zCTQ5u_TrVxs{BFb7A@+Br2WqQ((>DR>dhX9yL(kNCjIPl4ed3!nSVf!?@#BQ9KQA= zd=~RBTl?K@hVI&sRi^X!gI9s>6lge=*&;N(jKIo(*x{uAQeTPAIgzPLMa?xMVc z6YC8vTpGjXI0bRu@cqPDV{!9h(Alr;2Q;L!_8Uy$7pmH~AZ&&7wc4H6&ZsBo8-7Sn zvwERF>D!^eGm~}CP77l)eYmdoQHu8r#SQH~JCi)Uy-%unUKG5)EAdtLp zxxD60JpPemVp!;nf=?2&Ltb1yVVCV1RiNBq!#!&P+x+XY;dUGwd?y`0s2Lk{z~)QL z-A>M%^DWslgtLOp1D-JWUM+dIHu^OC`3r|7Gu%?VecHCzrkvvSUb#hrQ{zKP=Z~b1 z#a366x0Tqc#4jmrec^Qd$7=mKMN>cSnO@>4$G_ZLM&W9~rVb95 zff0Xm+ToMQIUnrL&B%TIn!VlPiCf3aqJu#?x)U~dTwnjR%hmtH>vgRAxw z=C4!lQd90*$I>*j=xC6JuG^xe++|FO8KB9vmo68jKiz6;EPMAQasRY0ihB)~D14ov zwBKDp_Q`_9ZE~5jbXKnN7d^+ZD!IID&Ht7yJIuE?Em)%KU_br({yhhd%s;8{&Td!! z;`X0HnRcazKUiGNREu6DskO{=S5nVw(i$1jruh$B@a&j;heox->N$H!GY;pS-J1F&dvMV)K{+X zYCMd--fK*{Cx+4IWNX1+-F4rthiQzVBbag(+(1m+yb0+mgY1vNMq{c0)-(z%i>$?F#y7H@U8V zd-Xh5_sHy8#qa+M=KjC2Q()KHSC#Rb4!nMLhs$(LbkQF1TV8vnX7+%G`OoH9XB~UC zX3e9u+oJT+PVHOzd%>RS%;!uWxON@B8FgcCf@0KT?nL{t_&cXU-o<3Rdam2D+cUTL zt<>3bb>K06?wa)qWe0rsRvo{2Ghh7ow0F#(t_kjL&F24V`}NYYxOk4g2g-O&660N7 zo7QR6*hj?QU+u%OTR-nw*2iB}cZ=&!Hhq8pD*CF%VoA|ijdTC6`?q{@)tbv$kNPcV z-`;5*v43lWiRtBQS6XIvZ(menfAY}62b|HrUNT4f#&S*24A-M+t0l-`QLkkQ*CNnwq95w<#O3yeQT3cg46BD#X5=lh9BL}MK0d&aZB*{G__4j zSp`fNKbv>(n(p;^&f5?}?Nz0o3t2wi{TcFV_3vigXbIV4k1vaF>5ks`#WS(^l~Y&% z*b#E)N+h$tEtzar2+rJUVkU~b`&RA~t!p@J<|)U%ykfOedH>hF*8gKSzd0|%yu~wE zU)HRkVOdsCar8yW+k8i6$(?iftQ4JOwB)T~a9)Jh(xV;@jmM)q^~LO$JKKsmOh4i5 zc>2|m=9RWV+$r82dNIAfn(S-3ZXVt>sr945jDm(M@3K?N;(1Cgm+MEV)~7Wtm~%?| z^M-37P4o9%sQI*5T<6Z;FVnWKO<=ezVi>F!(Y2ISNKDdZyZCG72UpK3Y;A~EI!Mp8KqSZKsKvRg8P` z+La|=E0WjMZ?Eh=*^#_K@}SSoB+V&e9tPTXJr7TPr}9`Z|Cv{O*mEo1U6*l{qH`%Xxul|Wc6JC*5fPBJw7olqix#}Q0BjLcAD5!2Ip9v zE8)}gw3j!_J=nR`fj@kY75`N=kO%ddKcwz6Gc~=utoEE#)}tT0qdsh(68pJ!r}ax+ z@9cf&p2%Kr3Xuet0(VbZ-t+somi4=i?eo_{U*5`Cd<@oZtJMCseDb@~x* VosnyGu-@;(eBnROXM}Vy000VNA?*MF literal 6534 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 diff --git a/doc/qtcreator/images/qtcreator-search-results-reg-exp.webp b/doc/qtcreator/images/qtcreator-search-results-reg-exp.webp new file mode 100644 index 0000000000000000000000000000000000000000..7b2c9aab7a4de0a365e98669eb52f7cd72a7bbaf GIT binary patch literal 11060 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 H{TUemk$f~( literal 0 HcmV?d00001 diff --git a/doc/qtcreator/images/qtcreator-search-results.webp b/doc/qtcreator/images/qtcreator-search-results.webp deleted file mode 100644 index d36ec5e2851f7b72dce81254c1b953c1c7c53e56..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 7250 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 F0{}CnBxnEt diff --git a/doc/qtcreator/src/cmake/creator-projects-cmake-building.qdoc b/doc/qtcreator/src/cmake/creator-projects-cmake-building.qdoc index 90ffd7cd809..a51d6623f88 100644 --- a/doc/qtcreator/src/cmake/creator-projects-cmake-building.qdoc +++ b/doc/qtcreator/src/cmake/creator-projects-cmake-building.qdoc @@ -180,7 +180,7 @@ case-sensitivity. Select \uicontrol {Show Non-matching Lines} to hide the lines that match the filter. - Press \key {Ctrl+F} to \l{Finding and Replacing}{search} for a string from + Press \key {Ctrl+F} to \l{Search in current file}{search} for a string in the output. To increase or decrease the output text size, select \inlineimage icons/plus.png @@ -188,7 +188,7 @@ (\uicontrol {Zoom Out}), or press \key Ctrl++ or \key Ctrl+-. To hide the output, select the \inlineimage icons/rightsidebaricon.png - (\uicontrol {Hide/Show Right Sidebar}) button or press \key {Alt+Shift+0}. + (\uicontrol {Hide Right Sidebar}) button or press \key {Alt+Shift+0}. \section1 CLICOLOR_FORCE Environment Variable diff --git a/doc/qtcreator/src/editors/creator-code-refactoring.qdoc b/doc/qtcreator/src/editors/creator-code-refactoring.qdoc index f286d18f85c..285c36166bd 100644 --- a/doc/qtcreator/src/editors/creator-code-refactoring.qdoc +++ b/doc/qtcreator/src/editors/creator-code-refactoring.qdoc @@ -64,7 +64,7 @@ \endif \endlist - \l{Search Results} shows the location and number of search hits in the + \l{Search Results View} shows the location and number of search hits in the current project. \if defined(qtcreator) diff --git a/doc/qtcreator/src/editors/creator-coding.qdoc b/doc/qtcreator/src/editors/creator-coding.qdoc index 67f8b6ac44d..38c6f3f5963 100644 --- a/doc/qtcreator/src/editors/creator-coding.qdoc +++ b/doc/qtcreator/src/editors/creator-coding.qdoc @@ -36,12 +36,15 @@ key components of \QC. You can use the code editor in the \uicontrol Edit mode. \endif + + \if defined(qtdesignstudio) \li \l{Finding} - Use the incremental and advanced search to search from currently + Use the incremental and advanced search to search in currently open projects or files on the file system or use the locator to browse through projects, files, classes, functions, documentation and file systems. + \endif \li \l{Refactoring} diff --git a/doc/qtcreator/src/editors/creator-diff-editor.qdoc b/doc/qtcreator/src/editors/creator-diff-editor.qdoc index dfeb7f5b4ac..8557cd8bffb 100644 --- a/doc/qtcreator/src/editors/creator-diff-editor.qdoc +++ b/doc/qtcreator/src/editors/creator-diff-editor.qdoc @@ -11,7 +11,7 @@ \page creator-diff-editor.html \if defined(qtdesignstudio) \previouspage qt-quick-toolbars.html - \nextpage creator-finding-overview.html + \nextpage studio-finding.html \else \previouspage creator-macros.html \nextpage creator-clang-codemodel.html diff --git a/doc/qtcreator/src/editors/creator-finding.qdoc b/doc/qtcreator/src/editors/creator-finding.qdoc deleted file mode 100644 index 2ebf1ad0a94..00000000000 --- a/doc/qtcreator/src/editors/creator-finding.qdoc +++ /dev/null @@ -1,51 +0,0 @@ -// Copyright (C) 2018 The Qt Company Ltd. -// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GFDL-1.3-no-invariants-only - -// ********************************************************************** -// NOTE: the sections are not ordered by their logical order to avoid -// reshuffling the file each time the index order changes (i.e., often). -// Run the fixnavi.pl script to adjust the links to the index order. -// ********************************************************************** - -/*! - \page creator-finding-overview.html - \if defined(qtdesignstudio) - \previouspage creator-diff-editor.html - \else - \previouspage creator-clang-codemodel.html - \endif - - \nextpage creator-editor-finding.html - - \title Finding - - \list - - \li \l{Finding and Replacing} - - The incremental search highlights the matching strings in the - window while typing and the advanced search enables you to - search from currently open projects or files on the file system. - You can conduct incremental and advanced searches in parallel. - - In addition, you can search for symbols when you want to - refactor code. - - \li \l{Searching with the Locator} - - Use the locator to browse - through projects, files, classes, functions, documentation and - file systems. - - \if defined(qtdesignstudio) - \li \l{Jump to the Code} - - Jump to the code for a specific component directly from - the \uicontrol {2D} view or \uicontrol {Navigator} view. - You can also jump to the code of a particular - \uicontrol {State} or \uicontrol {Connection} from their - corresponding views. - \endif - \endlist - -*/ diff --git a/doc/qtcreator/src/editors/creator-locator.qdoc b/doc/qtcreator/src/editors/creator-locator.qdoc index bcdc5278757..292b35ff30c 100644 --- a/doc/qtcreator/src/editors/creator-locator.qdoc +++ b/doc/qtcreator/src/editors/creator-locator.qdoc @@ -2,9 +2,13 @@ // SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GFDL-1.3-no-invariants-only /*! - \previouspage creator-editor-finding.html \page creator-editor-locator.html + \previouspage creator-how-to-advanced-search.html + \if defined(qtdesignstudio) \nextpage creator-jump-to-the-code.html + \else + \nextpage creator-how-tos.html + \endif \title Searching with the Locator diff --git a/doc/qtcreator/src/editors/creator-only/creator-scxml.qdoc b/doc/qtcreator/src/editors/creator-only/creator-scxml.qdoc index 5c1c32810e1..eac59c47407 100644 --- a/doc/qtcreator/src/editors/creator-only/creator-scxml.qdoc +++ b/doc/qtcreator/src/editors/creator-only/creator-scxml.qdoc @@ -98,7 +98,7 @@ state chart. \endtable - To search from the state chart, select \uicontrol {Search} and start typing + To search in the state chart, select \uicontrol {Search} and start typing in the \uicontrol Filter field. The search checks the whole SCXML tree for attributes that match the search criteria. diff --git a/doc/qtcreator/src/editors/creator-search.qdoc b/doc/qtcreator/src/editors/creator-search.qdoc index a5fd8c9e15a..42ca482a5f3 100644 --- a/doc/qtcreator/src/editors/creator-search.qdoc +++ b/doc/qtcreator/src/editors/creator-search.qdoc @@ -1,29 +1,40 @@ -// Copyright (C) 2022 The Qt Company Ltd. +// Copyright (C) 2024 The Qt Company Ltd. // SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GFDL-1.3-no-invariants-only /*! - \previouspage creator-finding-overview.html \page creator-editor-finding.html - \nextpage creator-editor-locator.html + \if defined(qtdesignstudio) + \previouspage studio-finding.html + \nextpage creator-how-to-advanced-search.html + \else + \previouspage creator-how-tos.html + \endif - \title Finding and Replacing + \ingroup creator-how-to-search + + \title Search in current file + + The incremental search highlights the matching strings in the editor while + you type. To search through the currently open file: \list 1 - \li Press \key {Ctrl+F} or select \uicontrol Edit > + \li Press \key {Ctrl+F} or go to \uicontrol Edit > \uicontrol {Find/Replace} > \uicontrol {Find/Replace}. \li In \uicontrol Find, enter the text you are looking for. - \image qtcreator-find-incremental.png + \image qtcreator-find-from-current-file.webp {Search hits highlighted in editor} - If the text is found, all occurrences are highlighted as you type. + All occurrences of the text are highlighted in the editor as you + type. - \li To go to the next occurrence, click \inlineimage icons/next.png - (\uicontrol {Find Next}), or press \key F3. To go to the previous - occurrence click \inlineimage icons/prev.png + \li To go to the next occurrence, select \inlineimage icons/next.png + (\uicontrol {Find Next}), or press \key F3. + + \li To go to the previous occurrence, select \inlineimage icons/prev.png (\uicontrol {Find Previous}), or press \key {Shift+F3}. \li To select all found occurrences in a file, select @@ -31,9 +42,13 @@ \endlist - You can restrict the search in the \uicontrol Find field by selecting - \inlineimage icons/qtcreator-new-search-icon.png - . Select one or several search criteria: + \note Select text before selecting \uicontrol {Find/Replace} to search only + from the selection. + + \section1 Set search criteria + + To restrict the search in the \uicontrol Find box, select + \inlineimage icons/qtcreator-new-search-icon.png and set search criteria: \list @@ -42,38 +57,33 @@ \li To search only whole words, select \uicontrol {Whole Words Only}. - \li To search using regular expressions, select + \li To search using \l{QRegularExpression}{regular expressions}, select \uicontrol {Use Regular Expressions}. Regular expressions used in \QC - are modeled on Perl regular expressions. For more information on - using regular expressions, see the documentation for the - QRegularExpression Class. + are modeled on Perl regular expressions \endlist - \note If you have selected text before selecting \uicontrol {Find/Replace}, the - search is conducted within the selection. + \section1 Replace text - To replace occurrences of the existing text, enter the new text in the - \uicontrol {Replace with} field. + To replace occurrences of the existing text, enter the new text in + \uicontrol {Replace with}. \list - + \li To replace the selected occurrence, select \uicontrol {Replace}. \li To replace the selected occurrence and move to the next one, - click \uicontrol {Find Next} or press \key {Ctrl+=}. - - \li To replace the selected occurrence and move to the previous one, - click \uicontrol {Find Previous}. - - \li To replace all occurrences in the file, click + select \uicontrol {Replace & Find}. + \li To replace all occurrences in the file, select \uicontrol {Replace All}. - \endlist - The \uicontrol {Preserve Case when Replacing} option can be selected to - preserve the case of the original text when replacing. This option is not - compatible with the \uicontrol {Use Regular Expressions} search option, and will - thus be disabled when regular expressions are used. When the option is used, - the case of the occurrence will be conserved, according to the following + \section1 Preserve case when replacing + + To preserve the case of the original text when replacing, select + \inlineimage icons/qtcreator-new-search-icon.png and then select + \uicontrol {Preserve Case when Replacing}. You cannot use this option + together with \uicontrol {Use Regular Expressions}. + + The case of the of the occurrence is preserved according to the following rules: \list @@ -88,163 +98,127 @@ \li Other occurrences are replaced with the new text as entered. \li If an occurrence and the new text have the same prefix or suffix, - then the case of the prefix and/or suffix are preserved, and the - other rules are applied on the rest of the occurrence only. + the case of the prefix and suffix are preserved, and the + other rules are applied to the rest of the occurrence. \endlist + \section1 Highlight search hits + The locations of search hits, breakpoints, and bookmarks in your document are highlighted on the editor scroll bar. To turn highlighting off, select \preferences > \uicontrol {Text Editor} > \uicontrol Display > \uicontrol {Highlight search results on the scrollbar}. - To search using more advanced options, select \uicontrol Advanced. + \image qtcreator-options-text-editor-display.png {Text Editor Display preferences} - \section1 Advanced Search + \section1 Search globally - To search through projects, files on a file system, files in all project - directories, or currently open files: + Select \uicontrol Advanced to open the \uicontrol {Search Results} view where + you can search in currently open projects or files on the file system. Or, + search for symbols to refactor code. + + \if defined(qtcreator) + \sa {Search}{How To: Search} + \else + \sa {Search in projects or file systems} + \endif + + \sa {Search Results View} +*/ + +/*! + \page creator-how-to-advanced-search.html + \if defined(qtdesignstudio) + \previouspage creator-editor-finding.html + \nextpage creator-editor-locator.html + \else + \previouspage creator-how-tos.html + \endif + + \ingroup creator-how-to-search + + \title Search in projects or file systems + + The search scope and search criteria determine where \QC looks for the search + string, how it matches the string with text, and which results it shows. + + \section1 Search in all projects \list 1 - - \li Press \key {Ctrl+Shift+F} or select \uicontrol Edit > + \li Press \key {Ctrl+Shift+F} or go to \uicontrol Edit > \uicontrol {Find/Replace} > \uicontrol {Advanced Find} > \uicontrol {Open Advanced Find}. - - \li Select the scope of your search: - - \list - - \li \uicontrol {All Projects} searches from all currently open - projects. - - \image qtcreator-search-allprojects.png - - \if defined(qtcreator) - If you cannot find some files, see - \l{Specify project contents} for how - to declare them as a part of the project. - \endif - - \li \uicontrol {Current Project} searches from the project you - are currently editing. - - \li \uicontrol {Files in All Project Directories} searches from - all project directories. - - \li \uicontrol {Files in File System} recursively searches from - the selected directory. - - \image qtcreator-search-filesystem.png - - In the \uicontrol {Search engine} field, select the search - engine to use: - - \list - \li Select \uicontrol Internal to use the \QC search - engine. - - \li Select \uicontrol {Git Grep} to use Git to only - search tracked files in the Git work tree. To - restrict the search to the HEAD, a tag, a local or - remote branch, or a commit hash, enter a reference. - Leave the field empty to search through the file - system. - - \if defined(qtcreator) - \li Select \uicontrol {Silver Searcher} to use the - experimental Silver Searcher plugin. For more - information, see \l{Enabling Silver Searcher}. - \endif - - \endlist - - \li \uicontrol {Current File} searches only from the current - file. - - \li \uicontrol {Open Documents} searches from all open files. - - \endlist - - \li In the \uicontrol {File pattern} field, specify file patterns to + \li In \uicontrol Scope, select \uicontrol {All Projects}. + \image qtcreator-search-all-projects.webp {Search Results view} + \li In \uicontrol {Search for}, enter the string you are looking for. + \li Select options to make the search case sensitive, search only whole + words, or use regular expressions. + \li In \uicontrol {File pattern}, specify file patterns to restrict the search to files that match the pattern. For example, to search for a string only in \c {.cpp} and \c {.h} files, enter \c {*.cpp,*.h}. - - \li In the \uicontrol {Exclusion pattern} field, specify file patterns + \li In \uicontrol {Exclusion pattern}, specify file patterns to omit files from the search. - - \li Enter the text you are looking for and click \uicontrol Search. - - \image qtcreator-search-results-matches.webp {Found matches in Search Results} - - \l {Search Results} shows a list of files that have the searched text. - - \list - - \li To see all occurrences in a file, double-click the file name - in the list. - - \li To go to an occurrence, double-click it. - - \li To repeat the search after you have made changes to the - listed files, for example, select - \uicontrol {Search Again}. - - \endlist - + \li Select \uicontrol Search. \endlist - The search results are stored in the search history from which you can - select earlier searches. - - To clear the search results, select the \inlineimage icons/clean_pane_small.png - (\uicontrol Clear) button. - - To expand and collapse the search results, select the - \uicontrol {Expand All} button. - - To start a new search, select the \inlineimage icons/qtcreator-new-search-icon.png - (\uicontrol {New Search}) button. - - \note You can use \uicontrol {Advanced Find} also to search for symbols. For - more information, see \if defined(qtcreator) - \l{Finding Symbols}. - \else - \l{Finding QML Types}. + If you cannot find some files, see \l{Specify project contents} for + how to declare them as a part of the project. \endif - \if defined(qtcreator) - \section1 Enabling Silver Searcher + \section1 Search in the file system - You can use Silver Searcher as a search engine in \QC if you install - Silver Searcher on the development PC. - - \note Enable the SilverSearcher plugin to use it. - - To use Silver Searcher: + In addition to the options available for searching from all projects, you can + select the search engine to use and the directory to search in. \list 1 - - \li Download and install Silver Searcher from - \l {https://geoff.greer.fm/ag/}{The Silver Searcher} or - \l {https://github.com/ggreer/the_silver_searcher}{GitHub}. - - You might have to build Silver Searcher from sources for some - platforms. - - \li When searching, select \uicontrol {Silver Searcher} in the - \uicontrol {Search engine} field. - - \li If Silver Searcher is not found, you might have installed it in a - location that is not found via the \c{PATH} environment variable. - Select \preferences > \uicontrol Environment > \uicontrol System, - then select \uicontrol Change in the \uicontrol Environment field, - and add the entry \c{PATH=/path/to/bin:${PATH}}. - + \li In \uicontrol Scope, select \uicontrol {Files in File System}. + \image qtcreator-search-file-system.webp {Search Results view} + \li In \uicontrol {Search for}, enter the string you are looking for. + \li In \uicontrol {Search engine}, select the search engine to use: + \list + \li Select \uicontrol Internal to use the \QC search + engine. + \li Select \uicontrol {Git Grep} to use Git to only + search tracked files in the Git work tree. To + restrict the search to the HEAD, a tag, a local or + remote branch, or a commit hash, enter a reference. + Leave the field empty to search through the file + system. + \if defined(qtcreator) + \li Select \uicontrol {Silver Searcher} to use the + experimental Silver Searcher plugin. + \endif + \endlist + \li In \uicontrol Directory, select the directory to search in. + Select \uicontrol Browse to locate the directory or + \uicontrol Current to search in the directory where the currently + active file is. + \li Select \uicontrol Search. \endlist - \sa {Enable and disable plugins} + \section1 Search and replace + + To replace occurrences of the existing text: + + \list 1 + \li Select \uicontrol {Search & Replace}. + \image qtcreator-search-results-reg-exp.webp {Search results when searching and replacing} + \li Enter the new text in \uicontrol {Replace with}. + \li Select \uicontrol Replace. + \endlist + + To preserve the case of the original text when replacing, + select \uicontrol {Preserve case}. The rules listed in + \l {Preserve case when replacing} apply here as well. + + \if defined(qtcreator) + \sa {Search}{How To: Search}, {Finding Symbols}, {Turn on Silver Searcher} + \else + \sa {Search in current file} \endif + + \sa {Search Results View} */ diff --git a/doc/qtcreator/src/howto/creator-only/creator-how-to-silver-searcher.qdoc b/doc/qtcreator/src/howto/creator-only/creator-how-to-silver-searcher.qdoc new file mode 100644 index 00000000000..b632145832d --- /dev/null +++ b/doc/qtcreator/src/howto/creator-only/creator-how-to-silver-searcher.qdoc @@ -0,0 +1,53 @@ +// Copyright (C) 2024 The Qt Company Ltd. +// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GFDL-1.3-no-invariants-only + +/*! + \page creator-how-to-silver-searcher.html + \previouspage creator-how-tos.html + + \ingroup creator-how-to-search + + \title Turn on Silver Searcher + + You can use Silver Searcher as a search engine in \QC if you install + Silver Searcher on the computer. + + \image qtcreator-search-file-system.webp {Files in File System scope in Search Results view} + + \note Enable the SilverSearcher plugin to use it. + + To use Silver Searcher: + + \list 1 + \li Download and install Silver Searcher from + \l {https://geoff.greer.fm/ag/}{The Silver Searcher} or + \l {https://github.com/ggreer/the_silver_searcher}{GitHub}. + + You might have to build Silver Searcher from sources for some + platforms. + \li When searching, select \uicontrol {Silver Searcher} in + \uicontrol {Search engine}. + \endlist + + If \QC cannot find Silver Searcher, you might have installed it in a + location that is not set in the \c{PATH} environment variable. + + \section1 Set location of Silver Searcher + + To tell \QC where Silver Searcher is: + + \list 1 + \li Go to \preferences > \uicontrol Environment > \uicontrol System. + \image qtcreator-preferences-environment-system.webp {System preferences} + \li In \uicontrol Environment, select \uicontrol Change. + \li In \uicontrol {Edit Environment}, add the path to the Silver Searcher + executable: + \badcode + PATH=:${PATH} + \endcode + \image qtcreator-edit-environment.webp {Edit Environment dialog} + \endlist + + \sa {Enable and disable plugins}, {Search}{How To: Search}, + {Batch edit environment settings} +*/ 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 c82cdcfa91c..3696b292635 100644 --- a/doc/qtcreator/src/howto/creator-only/creator-how-tos.qdoc +++ b/doc/qtcreator/src/howto/creator-only/creator-how-tos.qdoc @@ -65,6 +65,10 @@ \generatelist creator-how-to-lsp + \section2 Search + + \generatelist creator-how-to-search + \section1 Manage Kits \generatelist creator-how-to-manage-kits @@ -404,34 +408,43 @@ /*! \page creator-how-to-search-and-replace-using-regexp.html - \previouspage creator-how-to-move-between-open-files.html + \previouspage creator-how-tos.html - \ingroup creator-how-to-edit + \ingroup creator-how-to-search - \title Search and replace across files using a regular expression + \title Search and replace using a regular expression - As an example, say you want to replace equality checks (\c {foo == bar}) - with a function (\c {foo.equals(bar)}): + Search and replace across files using regular expressions in the + \uicontrol {Search Results} view. + + Regular expressions used in \QC are modeled on Perl regular expressions. + For more information about using regular expressions, see + \l QRegularExpression. + + For example, to replace equality checks (\c {foo == bar}) with a function + (\c {foo.equals(bar)}): \list 1 - \li Ensure that any work you have done is committed to version control, - as the changes cannot be undone. - \li Press \key {Ctrl+Shift+F} to bring up the \uicontrol {Advanced Find} - form. - \li Change the scope to whatever is appropriate for your search. - \li Under the \uicontrol {Search for} text field, select - the \uicontrol {Use regular expressions} check box. - \li Enter the following text in the \uicontrol {Search for} text field: + \li Commit your changes to version control, as you cannot undo the + replace action. + \li Press \key {Ctrl+Shift+F} or go to \uicontrol Edit > + \uicontrol {Find/Replace} > \uicontrol {Advanced Find} > + \uicontrol {Open Advanced Find} to open \uicontrol {Search Results}. + \image qtcreator-search-reg-exp.webp {Regular expression in Search Results view} + \li In \uicontrol Scope, select whatever is appropriate for your search. + \li Select \uicontrol {Use regular expressions}. + \li Enter the following text in \uicontrol {Search for}: \badcode if \((.*) == (.*)\) \endcode - \li Press \uicontrol {Search & Replace} to see a list of search results. - \li In the \uicontrol {Replace with} text field, enter the following text: + \li Select \uicontrol {Search & Replace} to see a list of search results. + \image qtcreator-search-results-reg-exp.webp {Search results for the regular expression} + \li In \uicontrol {Replace with}, enter the following text: \badcode if (\1.strictlyEquals(\2)) \endcode - \li Press \uicontrol Replace to replace all instances of the text. + \li Select \uicontrol Replace to replace all instances of the text. \endlist - \sa {Advanced Search}, {Edit Code}{How To: Edit Code}, {Edit Mode} + \sa {Edit Code}{How To: Edit Code}, {Search}{How To: Search}, {Edit Mode} */ diff --git a/doc/qtcreator/src/projects/creator-only/creator-projects-creating.qdoc b/doc/qtcreator/src/projects/creator-only/creator-projects-creating.qdoc index 569342b26e3..60fb9686fd6 100644 --- a/doc/qtcreator/src/projects/creator-only/creator-projects-creating.qdoc +++ b/doc/qtcreator/src/projects/creator-only/creator-projects-creating.qdoc @@ -198,8 +198,8 @@ directory in the \l {File System} view. Declaring files as a part of the project also makes them visible to the - \l{Searching with the Locator}{locator} and \l{Advanced Search} - {project-wide search}. + \l{Searching with the Locator}{locator} and + \l{Search in projects or file systems}{project-wide search}. \section1 CMake Projects diff --git a/doc/qtcreator/src/qtcreator-toc.qdoc b/doc/qtcreator/src/qtcreator-toc.qdoc index ec8408795fc..60f8248b38c 100644 --- a/doc/qtcreator/src/qtcreator-toc.qdoc +++ b/doc/qtcreator/src/qtcreator-toc.qdoc @@ -36,11 +36,6 @@ \li \l{Using Text Editing Macros} \li \l{Comparing Files} \endlist - \li \l{Finding} - \list - \li \l{Finding and Replacing} - \li \l{Searching with the Locator} - \endlist \li \l{Refactoring} \li \l{Configuring the Editor} \li \l{Using GitHub Copilot} @@ -149,6 +144,8 @@ \generatelist creator-how-to-configure-editors \li Manage Language Servers \generatelist creator-how-to-lsp + \li Search + \generatelist creator-how-to-search \endlist \li Manage Kits \generatelist creator-how-to-manage-kits diff --git a/doc/qtcreator/src/qtcreator.qdoc b/doc/qtcreator/src/qtcreator.qdoc index 7c2d8ce775e..aefa86c3946 100644 --- a/doc/qtcreator/src/qtcreator.qdoc +++ b/doc/qtcreator/src/qtcreator.qdoc @@ -50,7 +50,6 @@ \li \b {\l{Coding}} \list \li \l{Writing Code} - \li \l{Finding} \li \l{Refactoring} \li \l{Configuring the Editor} \endlist diff --git a/doc/qtcreator/src/user-interface/creator-file-system-view.qdoc b/doc/qtcreator/src/user-interface/creator-file-system-view.qdoc index 2b4ddbdb942..3b8a7d59cf7 100644 --- a/doc/qtcreator/src/user-interface/creator-file-system-view.qdoc +++ b/doc/qtcreator/src/user-interface/creator-file-system-view.qdoc @@ -68,7 +68,7 @@ To use an \l{Terminal} {internal terminal}, select \preferences > \uicontrol Terminal > \uicontrol {Use internal terminal}. \endif - \li Search from the selected directory. + \li Search in the selected directory. \li View file properties, such as name, path, MIME type, default editor, line endings, indentation, owner, size, last read and modified dates, and permissions. diff --git a/doc/qtcreator/src/user-interface/creator-how-to-view-output.qdoc b/doc/qtcreator/src/user-interface/creator-how-to-view-output.qdoc index b83a54dbe39..95de069becb 100644 --- a/doc/qtcreator/src/user-interface/creator-how-to-view-output.qdoc +++ b/doc/qtcreator/src/user-interface/creator-how-to-view-output.qdoc @@ -60,9 +60,9 @@ \section1 Find and filter output - To search from output, press \key {Ctrl+F} when the view is active. Enter + To search in output, press \key {Ctrl+F} when the view is active. Enter search criteria in the \uicontrol Find field. For more information, see - \l{Finding and Replacing}. + \l{Search in current file}. To filter output, enter a string in the \uicontrol Filter field. diff --git a/doc/qtcreator/src/user-interface/creator-only/creator-reference-terminal-view.qdoc b/doc/qtcreator/src/user-interface/creator-only/creator-reference-terminal-view.qdoc index 2be2fd8a2c3..0f09a773d47 100644 --- a/doc/qtcreator/src/user-interface/creator-only/creator-reference-terminal-view.qdoc +++ b/doc/qtcreator/src/user-interface/creator-only/creator-reference-terminal-view.qdoc @@ -44,7 +44,8 @@ \li To open links in a browser, files in the editor, or folders in the \l Projects view, hover the mouse over them, and press \key Ctrl. - \li To \l{Finding and Replacing}{search} through the output, press \key {Ctrl+F}. + \li To \l{Search in current file}{search} through the output, press + \key {Ctrl+F}. \li To make the font larger or smaller, select the \inlineimage icons/plus.png and \inlineimage icons/minus.png diff --git a/doc/qtcreator/src/user-interface/creator-projects-view.qdoc b/doc/qtcreator/src/user-interface/creator-projects-view.qdoc index b0a66c421cc..99e3b469cc1 100644 --- a/doc/qtcreator/src/user-interface/creator-projects-view.qdoc +++ b/doc/qtcreator/src/user-interface/creator-projects-view.qdoc @@ -89,7 +89,7 @@ \li Add and remove subprojects. \li Find unused functions. \endif - \li Search from the selected directory. + \li Search in the selected directory. \li Open a terminal window in the project directory. To specify the terminal to use on Linux and \macos, select \preferences > diff --git a/doc/qtcreator/src/user-interface/creator-reference-output-views.qdoc b/doc/qtcreator/src/user-interface/creator-reference-output-views.qdoc index 06ee12f0c33..60b8b72d5af 100644 --- a/doc/qtcreator/src/user-interface/creator-reference-output-views.qdoc +++ b/doc/qtcreator/src/user-interface/creator-reference-output-views.qdoc @@ -1,4 +1,4 @@ -// Copyright (C) 2023 The Qt Company Ltd. +// Copyright (C) 2024 The Qt Company Ltd. // SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GFDL-1.3-no-invariants-only // ********************************************************************** @@ -78,25 +78,87 @@ \ingroup creator-reference-output-views \ingroup studio-reference-output-views - \title Search Results + \title Search Results View - \brief Lets you search through projects, files on a file system or the - currently open files. + \brief Search through projects, files on a file system or the + currently open files and view search results. - The search history (1) stores the search results. You can select earlier - searches from the history. + The search scope determines where \QC searches for the search string: - \image qtcreator-search-results.webp {Search Results - criteria} + \list + \li \uicontrol {All Projects} searches in all projects. + \li \uicontrol {Current Project} searches in the currently active + project. + \li \uicontrol {Files in All Project Directories} recursively searches + in all project directories. + \li \uicontrol {Files in File System} recursively searches in + the selected directory. + \li \uicontrol {Current File} searches only from the current + file. + \li \uicontrol {Open Documents} searches in all open files. + \endlist - The figure below shows an example search result for all - occurrences of the search string in the specified directory. + In \uicontrol {File pattern} and \uicontrol {Exclusion pattern}, specify + file patterns to further restrict the search scope. - \image qtcreator-search-results-matches.webp {Search Results - matches found} + The search criteria determine how \QC matches the search + string with text and which results it shows: - For more information about the different search options, see - \l {Finding and Replacing}. + \list + + \li To consider case, select \uicontrol {Case sensitive}. + \li To search only whole words, select \uicontrol {Whole words only}. + \li To search using \l{QRegularExpression}{regular expressions}, select + \uicontrol {Use regular expressions}. + \endlist + + \image qtcreator-search-file-system.webp {Search Results view with search options} + + \section1 Viewing Search Results + + After you select \uicontrol Search or \uicontrol {Search & Replace}, the view + shows a list of files that have search hits. + + \image qtcreator-search-results-matches.webp {Found matches in Search Results} + + To show search hits in the editor: + + \list + + \li To see all occurrences in a file, double-click the file name + in the list. + + \li To go to an occurrence, double-click it. + \endlist + + To repeat the search after you have made changes to the listed files, + for example, select \uicontrol {Search Again}. + + \section1 Search Results View Toolbar + + The toolbar contains options for searching again and navigating search + results: + + \list + \li To clear the search results, select + \inlineimage icons/clean_pane_small.png (\uicontrol Clear). + \li To expand and collapse the search results, select + \inlineimage icons/qtcreator-expand.png (\uicontrol {Expand All}). + \li To start a new search, select + \inlineimage icons/qtcreator-new-search-icon.png + (\uicontrol {New Search}). + \li If the active project has long paths, select \uicontrol {../} + (\uicontrol {Show Paths in Relation to Active Project}) to show + relative paths. + \li To show the results of earlier searches, select them in + \uicontrol History. + \endlist \sa {View output} + + \if defined(qtcreator) + \sa {Search}{How To: Search} + \endif */ /*! diff --git a/doc/qtdesignstudio/src/overviews/studio-finding.qdoc b/doc/qtdesignstudio/src/overviews/studio-finding.qdoc new file mode 100644 index 00000000000..bd1e24a5053 --- /dev/null +++ b/doc/qtdesignstudio/src/overviews/studio-finding.qdoc @@ -0,0 +1,39 @@ +// Copyright (C) 2024 The Qt Company Ltd. +// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GFDL-1.3-no-invariants-only + +/*! + \page studio-finding.html + \previouspage creator-diff-editor.html + \nextpage creator-editor-finding.html + + \title Finding + + \list + + \li \l{Search in current file} + + The incremental search highlights the matching strings in the + editor while you type. + + \li \l{Search in projects or file systems} + + With advanced search, you can search in currently open projects or + files on the file system. + + \li \l{Searching with the Locator} + + Use the locator to browse + through projects, files, classes, functions, documentation and + file systems. + + \li \l{Jump to the Code} + + Jump to the code for a specific component directly from + the \uicontrol {2D} view or \uicontrol {Navigator} view. + You can also jump to the code of a particular + \uicontrol {State} or \uicontrol {Connection} from their + corresponding views. + + \endlist + +*/ diff --git a/doc/qtdesignstudio/src/qtdesignstudio-toc.qdoc b/doc/qtdesignstudio/src/qtdesignstudio-toc.qdoc index 29ef0a9b240..f18a71fb65a 100644 --- a/doc/qtdesignstudio/src/qtdesignstudio-toc.qdoc +++ b/doc/qtdesignstudio/src/qtdesignstudio-toc.qdoc @@ -211,7 +211,8 @@ \endlist \li \l{Finding} \list - \li \l{Finding and Replacing} + \li \l{Search in current file} + \li \l{Search in projects or file systems} \li \l{Searching with the Locator} \li \l{Jump to the Code} \endlist From 75fa962eb4f9965a71fe885f6b4ad72bf541bde4 Mon Sep 17 00:00:00 2001 From: Leena Miettinen Date: Thu, 8 Feb 2024 15:30:10 +0100 Subject: [PATCH 034/243] Doc: Update info about QML live preview Task-number: QTCREATORBUG-30209 Change-Id: I0c4717a192e7fd94924fa573994bc27d7687d1d3 Reviewed-by: Reviewed-by: Mats Honkamaa --- doc/qtcreator/images/icons/live-preview.png | Bin 0 -> 239 bytes .../images/qtcreator-editor-toolbar-qml.webp | Bin 0 -> 8078 bytes .../images/qtcreator-live-preview.png | Bin 46355 -> 0 bytes .../images/qtcreator-live-preview.webp | Bin 0 -> 28496 bytes .../creator-coding-edit-mode.qdoc | 10 +++- .../qtquick/qtquick-live-preview-desktop.qdoc | 44 +++++++++--------- .../src/qtquick/qtquick-live-preview.qdoc | 44 ++++++++---------- .../images/studio-run-settings.png | Bin 18057 -> 0 bytes .../images/studio-run-settings.webp | Bin 0 -> 8376 bytes 9 files changed, 51 insertions(+), 47 deletions(-) create mode 100644 doc/qtcreator/images/icons/live-preview.png create mode 100644 doc/qtcreator/images/qtcreator-editor-toolbar-qml.webp delete mode 100644 doc/qtcreator/images/qtcreator-live-preview.png create mode 100644 doc/qtcreator/images/qtcreator-live-preview.webp delete mode 100644 doc/qtdesignstudio/images/studio-run-settings.png create mode 100644 doc/qtdesignstudio/images/studio-run-settings.webp diff --git a/doc/qtcreator/images/icons/live-preview.png b/doc/qtcreator/images/icons/live-preview.png new file mode 100644 index 0000000000000000000000000000000000000000..62feef8122cd3b035fe87904c64c3a3002028e48 GIT binary patch literal 239 zcmeAS@N?(olHy`uVBq!ia0y~yU=RRd4i*LmhONKMUokK+Z1Z$+4AD5>dw!u83!@0@ z1!Fz#?hV3hh87RxJA4DWFWPUo`G@ne@4wdig!09?2UE6iSf5gRta5$o)|`M6xA=;u zvhSXLoPW|gZ&#l5>)IK|=ae%`>^`-GKj6mc;7hy-Pn0g(G3=iCbQixt$*gv}3!xLO zwuVpDoqBLR=ggbi48AP$`fU90T3T6;=&37iGi%tjkBeojF{vp3BDzH{IBJ>c_WXI* uj8s{l+%!plJGGs~AhSZ#E9>RgTR)2}tF7RN>x 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

&z5TD}~`u;T-K_j68>B+!e)NFD~C>HvQkpgYka+ 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

SEn5;V!bpJ>%K6%^$h8 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 \uicontrol {QML Preview}. - - \image qtcreator-live-preview.png - \else To preview the currently active QML file on the desktop: \list + \if defined(qtcreator) + \li Select \inlineimage icons/live-preview.png (\uicontrol {Live Preview}) + on the \l{Edit Mode}{editor} toolbar. + \image qtcreator-live-preview.webp {Application running on top of the editor view} + \li Select \uicontrol Build > \uicontrol {QML Preview}. + \endlist + \else \li Select the \uicontrol {Live Preview} button on the top toolbar. \li Press \key {Alt+P}. + \image studio-live-preview.webp \endlist - \image studio-live-preview.webp - \endif + To preview any QML file in the project: - To preview any QML file that belongs to the project, \list \li Select the \uicontrol {Live Preview} button on the top toolbar. - \li Right-click the - filename in the \l Projects view, and select \uicontrol {Preview File}. + \li Right-click the filename in the \l Projects view, and select + \uicontrol {Preview File}. \endlist - \if defined(qtdesignstudio) To preview the whole UI, select \uicontrol {Live Preview} when viewing the main QML file of the project. - To view the UI in different sizes, select the zooming level on the toolbar. + \section1 Overriding the Preview Tool - \section1 Selecting the Preview Tool + By default, the QML runtime is used for previewing. - By default, the QML runtime is used for previewing. To use some - other tool, specify it in the \uicontrol {QML viewer} field in the run - settings of the project in the Projects mode. + To use some other tool: - \note Click \inlineimage icons/settings.png - to access the setting options. - - \image studio-run-settings.png "Run settings" + \list 1 + \li Select \inlineimage icons/settings.png to go to + \uicontrol {Run Settings}. + \image studio-run-settings.webp {Run Settings} + \li In \uicontrol {Override device QML viewer}, select the folder where + the preview tool executable is located. + \endlist \endif */ diff --git a/doc/qtcreator/src/qtquick/qtquick-live-preview.qdoc b/doc/qtcreator/src/qtquick/qtquick-live-preview.qdoc index b292540c3f2..95aac0fc527 100644 --- a/doc/qtcreator/src/qtquick/qtquick-live-preview.qdoc +++ b/doc/qtcreator/src/qtquick/qtquick-live-preview.qdoc @@ -1,4 +1,4 @@ -// Copyright (C) 2021 The Qt Company Ltd. +// Copyright (C) 2024 The Qt Company Ltd. // SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GFDL-1.3-no-invariants-only /*! @@ -12,38 +12,35 @@ \title Validating with Target Hardware - You can use the live preview feature to preview a UI file or the entire - UI on the desktop, as well as on embedded Linux - devices. The changes you make to the UI are instantly visible - to you in the preview. While the preview is available on Android devices, - it does not instantly reflect the changes made to the UI in the editor. It - shows the snapshot of your project from the moment you start the preview on - the device. + Preview a UI file or the entire UI on the desktop, as well as on embedded + Linux devices to instantly view the changes you make to the UI. On Android + devices, the preview shows the snapshot of your project from the moment + you start the preview on the device, not your changes. - In addition, you can use \QDV to run + \if defined(qtcreator) + \image qtcreator-live-preview.webp {Application running on top of the editor} + \else + \image studio-live-preview.webp + \endif + + Or, use \QDV to run \if defined(qtcreator) \l{Create Qt Quick UI Prototypes}{Qt Quick UI projects} \else applications \endif - in most widely-used web browsers on the desktop and in mobile devices This - enables you to easily share your designs with reviewers who don't have \QC. - - \if defined(qtcreator) - \image qtcreator-live-preview.png - \else - \image studio-live-preview.webp - \endif + in most widely-used web browsers on the desktop and in mobile devices and + share your designs with reviewers who don't have \QC. \list \li \l{Previewing on Desktop} - You can preview individual QML files or the whole UI. + Preview individual QML files or the whole UI. \li \l{Previewing on Devices} \if defined(qtcreator) - You can preview Qt Quick applications on devices that you have - connected to the development PC. For more information, see + Preview Qt Quick applications on devices that you + connect to the development PC. For more information, see \l {Connecting Devices}. \else When you install \QDS, everything you need for previewing on @@ -54,17 +51,16 @@ \if defined(qtdesignstudio) \li \l{Previewing Android applications} - You can preview Android applications live using an Android - emulator. + Preview Android applications live using an Android emulator. \li \l{Sharing Applications Online} - You can share applications online and view them in a web browser. + Share applications online and view them in a web browser. \else \li \l{Previewing in Browsers} - You can open \l{https://designviewer.qt.io/}{\QDV} + Open \l{https://designviewer.qt.io/}{\QDV} in a browser and load applications to it. \endif \endlist diff --git a/doc/qtdesignstudio/images/studio-run-settings.png b/doc/qtdesignstudio/images/studio-run-settings.png deleted file mode 100644 index 0a8fa23612dff554d97188d1b42ad344a05de208..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 18057 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 OFnGH9xvXJ$(bVBxb^fq_B)$4aVyT&MZl>AE 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 Date: Thu, 15 Feb 2024 11:48:30 +0100 Subject: [PATCH 035/243] Update change log with documentation links and missing item Change-Id: I5260192b2b07fba0d915b1fa1e0625be60b671ae Reviewed-by: Leena Miettinen Reviewed-by: --- dist/changelog/changes-13.0.0.md | 9 ++++++++- 1 file changed, 8 insertions(+), 1 deletion(-) diff --git a/dist/changelog/changes-13.0.0.md b/dist/changelog/changes-13.0.0.md index 793e47e97f2..f1199018f8b 100644 --- a/dist/changelog/changes-13.0.0.md +++ b/dist/changelog/changes-13.0.0.md @@ -18,7 +18,7 @@ What's new? ### Qt Application Manager Adds support for Qt 6 based applications with CMake for creating, building, -deploying, running, and debugging on devices that use the +deploying, running, and debugging for devices that use the [Qt Application Manager](https://doc.qt.io/QtApplicationManager/). ([Documentation](https://doc.qt.io/qtcreator/creator-overview-qtasam.html)) @@ -63,6 +63,7 @@ Editing ([QTCREATORBUG-21826](https://bugreports.qt.io/browse/QTCREATORBUG-21826)) * Improved the coding style settings by separating Clang Format and other coding style settings, and using a plain text editor for custom Clang Format settings + ([Documentation](https://doc-snapshots.qt.io/qtcreator-13.0/creator-preferences-cpp-code-style.html)) * Fixed that the class wizards used the class name for the include guard instead of the file name ([QTCREATORBUG-30140](https://bugreports.qt.io/browse/QTCREATORBUG-30140)) @@ -96,6 +97,7 @@ Editing * Added automatic setup up of language servers for `YAML`, `JSON`, and `Bash` (requires `npm`) + ([Documentation](https://doc-snapshots.qt.io/qtcreator-13.0/creator-language-servers.html#adding-language-servers)) ### Widget Designer @@ -123,6 +125,7 @@ Projects * Added a section `Vanished Targets` to `Projects` mode in case the project was configured for kits that have vanished, as a replacement for the automatic creation of "Replacement" kits + ([Documentation](https://doc-snapshots.qt.io/qtcreator-13.0/creator-how-to-activate-kits.html#copy-custom-settings-from-vanished-targets)) * Added the status of devices to the device lists ([QTCREATORBUG-20941](https://bugreports.qt.io/browse/QTCREATORBUG-20941)) * Added the `Preferences > Build & Run > General > Application environment` @@ -130,6 +133,8 @@ Projects ([QTCREATORBUG-29530](https://bugreports.qt.io/browse/QTCREATORBUG-29530)) * Added a file wizard for Qt translation (`.ts`) files ([QTCREATORBUG-29775](https://bugreports.qt.io/browse/QTCREATORBUG-29775)) +* Improved the environment settings by making the changes explicit in a + separate, text-based editor * Increased the maximum width of the target selector ([QTCREATORBUG-30038](https://bugreports.qt.io/browse/QTCREATORBUG-30038)) * Fixed that the `Left` cursor key did not always collapse the current item @@ -164,6 +169,7 @@ Projects * Added `Generate Kit` to the Python interpreter preferences for generating a Python kit with this interpreter + ([Documentation](https://doc-snapshots.qt.io/qtcreator-13.0/creator-python-development.html#create-kits-for-python-interpreters)) * Added the target setup page when loading unconfigured Python projects * Added a `requirements.txt` file to the application wizard * Fixed that the same Python interpreter could be auto-detected multiple times @@ -244,6 +250,7 @@ Platforms * Fixed deployment and running applications for iOS 17 devices (application output, debugging, and profiling are not supported) ([QTCREATORBUG-29682](https://bugreports.qt.io/browse/QTCREATORBUG-29682)) + ([Documentation](https://doc-snapshots.qt.io/qtcreator-13.0/creator-developing-ios.html)) ### Remote Linux From 3e7ef867dd55e17c9a1ccf73f3b32cdb4db883a5 Mon Sep 17 00:00:00 2001 From: Jarek Kobus Date: Thu, 15 Feb 2024 15:57:56 +0100 Subject: [PATCH 036/243] QmlJSPluginDumper: Prevent potential crash when no results in QFuture Ensure we don't reference non-existing QFuture's result. Change-Id: I57668390e6ca83ae30c0b1de3e3a083a344ddbaa Reviewed-by: Christian Kandeler --- src/libs/qmljs/qmljsplugindumper.cpp | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/src/libs/qmljs/qmljsplugindumper.cpp b/src/libs/qmljs/qmljsplugindumper.cpp index d2407bb1137..b2591fbf0ab 100644 --- a/src/libs/qmljs/qmljsplugindumper.cpp +++ b/src/libs/qmljs/qmljsplugindumper.cpp @@ -427,6 +427,10 @@ QFuture PluginDumper::loadDependencies(const FileP Utils::onFinished(loadQmlTypeDescription(dependenciesPaths), const_cast(this), [this, iface, visited](const QFuture &typesFuture) { + if (typesFuture.resultCount() == 0 || typesFuture.isCanceled()) { + iface->reportCanceled(); + return; + } PluginDumper::QmlTypeDescription typesResult = typesFuture.result(); FilePaths newDependencies = FileUtils::toFilePathList(typesResult.dependencies); From a6374bc5a9790b6784964a2175f5b44ca3fc8fc4 Mon Sep 17 00:00:00 2001 From: Jarek Kobus Date: Thu, 15 Feb 2024 16:49:29 +0100 Subject: [PATCH 037/243] ProjectManager: Add a hint on how to run the testSessionSwitch() Change-Id: I4852d15bb3f17dd9f2495f44376f62e85046db36 Reviewed-by: Christian Kandeler --- src/plugins/projectexplorer/projectmanager.cpp | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/src/plugins/projectexplorer/projectmanager.cpp b/src/plugins/projectexplorer/projectmanager.cpp index fe1e69aac02..e0cb5e2ca52 100644 --- a/src/plugins/projectexplorer/projectmanager.cpp +++ b/src/plugins/projectexplorer/projectmanager.cpp @@ -740,7 +740,8 @@ void ProjectExplorerTest::testSessionSwitch() = ProjectExplorerPlugin::openProject( FilePath::fromString(sessionSpec.projectFile.fileName())); if (openResult.errorMessage().contains("text/plain")) - QSKIP("This test requires the presence of QmakeProjectManager to be fully functional"); + QSKIP("This test requires the presence of QmakeProjectManager to be fully functional. " + "Hint: run this test with \"-load QmakeProjectManager\" option."); QVERIFY(openResult); QCOMPARE(openResult.projects().count(), 1); QVERIFY(openResult.project()); From 01f106b279845780d5fe858c46cc50177b5ea9b4 Mon Sep 17 00:00:00 2001 From: Jarek Kobus Date: Thu, 15 Feb 2024 16:50:58 +0100 Subject: [PATCH 038/243] DebuggerRunConfigurationAspect: Don't leak m_pythonAspect Change-Id: Icef93f08d0d24306c5f187c25cc4ca8d809a4c9f Reviewed-by: hjk --- src/plugins/debugger/debuggerrunconfigurationaspect.cpp | 1 + 1 file changed, 1 insertion(+) diff --git a/src/plugins/debugger/debuggerrunconfigurationaspect.cpp b/src/plugins/debugger/debuggerrunconfigurationaspect.cpp index e5a8aeb5eb6..814ca0e81b5 100644 --- a/src/plugins/debugger/debuggerrunconfigurationaspect.cpp +++ b/src/plugins/debugger/debuggerrunconfigurationaspect.cpp @@ -150,6 +150,7 @@ DebuggerRunConfigurationAspect::~DebuggerRunConfigurationAspect() { delete m_cppAspect; delete m_qmlAspect; + delete m_pythonAspect; delete m_multiProcessAspect; delete m_overrideStartupAspect; } From e3b62d0aa51dc5324ba32cb58138b0017cb97566 Mon Sep 17 00:00:00 2001 From: hjk Date: Thu, 15 Feb 2024 17:10:32 +0100 Subject: [PATCH 039/243] Debugger: Make DebuggerRunConfig sub-aspects direct members Change-Id: I53979892598164b26c8fc1977b1366b0a56fa152 Reviewed-by: Jarek Kobus --- src/libs/utils/aspects.cpp | 17 ++- src/libs/utils/aspects.h | 8 +- .../debuggerrunconfigurationaspect.cpp | 123 ++++++++---------- .../debugger/debuggerrunconfigurationaspect.h | 10 +- 4 files changed, 82 insertions(+), 76 deletions(-) diff --git a/src/libs/utils/aspects.cpp b/src/libs/utils/aspects.cpp index 2098c68d1c0..b72fc2060e3 100644 --- a/src/libs/utils/aspects.cpp +++ b/src/libs/utils/aspects.cpp @@ -2518,9 +2518,20 @@ TriStateAspect::TriStateAspect(AspectContainer *container, { setDisplayStyle(DisplayStyle::ComboBox); setDefaultValue(TriState::Default); - addOption(onString.isEmpty() ? Tr::tr("Enable") : onString); - addOption(offString.isEmpty() ? Tr::tr("Disable") : offString); - addOption(defaultString.isEmpty() ? Tr::tr("Leave at Default") : defaultString); + SelectionAspect::addOption({}); + SelectionAspect::addOption({}); + SelectionAspect::addOption({}); + setOptionTexts(onString, offString, defaultString); +} + +void TriStateAspect::setOptionTexts(const QString &onString, + const QString &offString, + const QString &defaultString) +{ + QTC_ASSERT(d->m_options.size() == 3, return); + d->m_options[0].displayName = onString.isEmpty() ? Tr::tr("Enable") : onString; + d->m_options[1].displayName = offString.isEmpty() ? Tr::tr("Disable") : offString; + d->m_options[2].displayName = defaultString.isEmpty() ? Tr::tr("Leave at Default") : defaultString; } TriState TriStateAspect::value() const diff --git a/src/libs/utils/aspects.h b/src/libs/utils/aspects.h index d4d1f704e02..cb885cc495a 100644 --- a/src/libs/utils/aspects.h +++ b/src/libs/utils/aspects.h @@ -554,7 +554,6 @@ protected: void bufferToGui() override; bool guiToBuffer() override; -private: std::unique_ptr d; }; @@ -812,6 +811,13 @@ public: TriState defaultValue() const; void setDefaultValue(TriState setting); + + void setOptionTexts(const QString &onString, + const QString &offString, + const QString &defaultString); +private: + void addOption(const QString &displayName, const QString &toolTip = {}) = delete; + void addOption(const Option &option) = delete; }; class QTCREATOR_UTILS_EXPORT StringListAspect : public TypedAspect diff --git a/src/plugins/debugger/debuggerrunconfigurationaspect.cpp b/src/plugins/debugger/debuggerrunconfigurationaspect.cpp index 814ca0e81b5..1b44afd821b 100644 --- a/src/plugins/debugger/debuggerrunconfigurationaspect.cpp +++ b/src/plugins/debugger/debuggerrunconfigurationaspect.cpp @@ -26,10 +26,8 @@ #include #include -#include #include #include -#include using namespace ProjectExplorer; using namespace Utils; @@ -79,26 +77,26 @@ DebuggerRunConfigurationAspect::DebuggerRunConfigurationAspect(Target *target) const auto setSummaryText = [this, details] { QStringList items; - if (m_cppAspect->value() == TriState::Enabled) + if (m_cppAspect() == TriState::Enabled) items.append(Tr::tr("Enable C++ debugger.")); - else if (m_cppAspect->value() == TriState::Default) + else if (m_cppAspect() == TriState::Default) items.append(Tr::tr("Try to determine need for C++ debugger.")); - if (m_qmlAspect->value() == TriState::Enabled) + if (m_qmlAspect() == TriState::Enabled) items.append(Tr::tr("Enable QML debugger.")); - else if (m_qmlAspect->value() == TriState::Default) + else if (m_qmlAspect() == TriState::Default) items.append(Tr::tr("Try to determine need for QML debugger.")); - items.append(m_overrideStartupAspect->value().isEmpty() + items.append(m_overrideStartupAspect().isEmpty() ? Tr::tr("Without additional startup commands.") : Tr::tr("With additional startup commands.")); details->setSummaryText(items.join(" ")); }; setSummaryText(); - connect(m_cppAspect, &BaseAspect::changed, this, setSummaryText); - connect(m_qmlAspect, &BaseAspect::changed, this, setSummaryText); - connect(m_overrideStartupAspect, &BaseAspect::changed, this, setSummaryText); + connect(&m_cppAspect, &BaseAspect::changed, this, setSummaryText); + connect(&m_qmlAspect, &BaseAspect::changed, this, setSummaryText); + connect(&m_overrideStartupAspect, &BaseAspect::changed, this, setSummaryText); return details; }); @@ -109,63 +107,54 @@ DebuggerRunConfigurationAspect::DebuggerRunConfigurationAspect(Target *target) addDataExtractor(this, &DebuggerRunConfigurationAspect::useMultiProcess, &Data::useMultiProcess); addDataExtractor(this, &DebuggerRunConfigurationAspect::overrideStartup, &Data::overrideStartup); - m_cppAspect = new TriStateAspect(nullptr, Tr::tr("Enabled"), Tr::tr("Disabled"), Tr::tr("Automatic")); - m_cppAspect->setLabelText(Tr::tr("C++ debugger:")); - m_cppAspect->setSettingsKey("RunConfiguration.UseCppDebugger"); + m_cppAspect.setSettingsKey("RunConfiguration.UseCppDebugger"); + m_cppAspect.setLabelText(Tr::tr("C++ debugger:")); + m_cppAspect.setOptionTexts(Tr::tr("Enabled"), Tr::tr("Disabled"), Tr::tr("Automatic")); - m_qmlAspect = new TriStateAspect(nullptr, Tr::tr("Enabled"), Tr::tr("Disabled"), Tr::tr("Automatic")); - m_qmlAspect->setLabelText(Tr::tr("QML debugger:")); - m_qmlAspect->setSettingsKey("RunConfiguration.UseQmlDebugger"); + m_qmlAspect.setSettingsKey("RunConfiguration.UseQmlDebugger"); + m_qmlAspect.setLabelText(Tr::tr("QML debugger:")); + m_qmlAspect.setOptionTexts(Tr::tr("Enabled"), Tr::tr("Disabled"), Tr::tr("Automatic")); - m_pythonAspect = new TriStateAspect(nullptr, Tr::tr("Enabled"), Tr::tr("Disabled"), Tr::tr("Automatic")); - m_pythonAspect->setLabelText(Tr::tr("Python debugger:")); - m_pythonAspect->setSettingsKey("RunConfiguration.UsePythonDebugger"); + m_pythonAspect.setSettingsKey("RunConfiguration.UsePythonDebugger"); + m_pythonAspect.setLabelText(Tr::tr("Python debugger:")); + m_pythonAspect.setOptionTexts(Tr::tr("Enabled"), Tr::tr("Disabled"), Tr::tr("Automatic")); // Make sure at least one of the debuggers is set to be active. - connect(m_cppAspect, &TriStateAspect::changed, this, [this]{ - if (Utils::allOf({m_cppAspect, m_qmlAspect, m_pythonAspect}, &isDisabled)) - m_qmlAspect->setValue(TriState::Default); + connect(&m_cppAspect, &TriStateAspect::changed, this, [this] { + if (Utils::allOf({&m_cppAspect, &m_qmlAspect, &m_pythonAspect}, &isDisabled)) + m_qmlAspect.setValue(TriState::Default); }); - connect(m_qmlAspect, &TriStateAspect::changed, this, [this]{ - if (Utils::allOf({m_cppAspect, m_qmlAspect, m_pythonAspect}, &isDisabled)) - m_cppAspect->setValue(TriState::Default); + connect(&m_qmlAspect, &TriStateAspect::changed, this, [this] { + if (Utils::allOf({&m_cppAspect, &m_qmlAspect, &m_pythonAspect}, &isDisabled)) + m_cppAspect.setValue(TriState::Default); }); - connect(m_qmlAspect, &TriStateAspect::changed, this, [this] { - if (Utils::allOf({m_cppAspect, m_qmlAspect, m_pythonAspect}, &isDisabled)) - m_cppAspect->setValue(TriState::Default); + connect(&m_qmlAspect, &TriStateAspect::changed, this, [this] { + if (Utils::allOf({&m_cppAspect, &m_qmlAspect, &m_pythonAspect}, &isDisabled)) + m_cppAspect.setValue(TriState::Default); }); - m_multiProcessAspect = new BoolAspect; - m_multiProcessAspect->setSettingsKey("RunConfiguration.UseMultiProcess"); - m_multiProcessAspect->setLabel(Tr::tr("Enable Debugging of Subprocesses"), + m_multiProcessAspect.setSettingsKey("RunConfiguration.UseMultiProcess"); + m_multiProcessAspect.setLabel(Tr::tr("Enable Debugging of Subprocesses"), BoolAspect::LabelPlacement::AtCheckBox); - m_overrideStartupAspect = new StringAspect; - m_overrideStartupAspect->setSettingsKey("RunConfiguration.OverrideDebuggerStartup"); - m_overrideStartupAspect->setDisplayStyle(StringAspect::TextEditDisplay); - m_overrideStartupAspect->setLabelText(Tr::tr("Additional startup commands:")); + m_overrideStartupAspect.setSettingsKey("RunConfiguration.OverrideDebuggerStartup"); + m_overrideStartupAspect.setDisplayStyle(StringAspect::TextEditDisplay); + m_overrideStartupAspect.setLabelText(Tr::tr("Additional startup commands:")); } -DebuggerRunConfigurationAspect::~DebuggerRunConfigurationAspect() -{ - delete m_cppAspect; - delete m_qmlAspect; - delete m_pythonAspect; - delete m_multiProcessAspect; - delete m_overrideStartupAspect; -} +DebuggerRunConfigurationAspect::~DebuggerRunConfigurationAspect() = default; void DebuggerRunConfigurationAspect::setUseQmlDebugger(bool value) { - m_qmlAspect->setValue(value ? TriState::Enabled : TriState::Disabled); + m_qmlAspect.setValue(value ? TriState::Enabled : TriState::Disabled); } bool DebuggerRunConfigurationAspect::useCppDebugger() const { - if (m_cppAspect->value() == TriState::Default) + if (m_cppAspect() == TriState::Default) return m_target->project()->projectLanguages().contains( ProjectExplorer::Constants::CXX_LANGUAGE_ID); - return m_cppAspect->value() == TriState::Enabled; + return m_cppAspect() == TriState::Enabled; } static bool projectHasQmlDefines(ProjectExplorer::Project *project) @@ -185,7 +174,7 @@ static bool projectHasQmlDefines(ProjectExplorer::Project *project) bool DebuggerRunConfigurationAspect::useQmlDebugger() const { - if (m_qmlAspect->value() == TriState::Default) { + if (m_qmlAspect() == TriState::Default) { const Core::Context languages = m_target->project()->projectLanguages(); if (!languages.contains(ProjectExplorer::Constants::QMLJS_LANGUAGE_ID)) return projectHasQmlDefines(m_target->project()); @@ -199,31 +188,31 @@ bool DebuggerRunConfigurationAspect::useQmlDebugger() const return !languages.contains(ProjectExplorer::Constants::CXX_LANGUAGE_ID); } - return m_qmlAspect->value() == TriState::Enabled; + return m_qmlAspect() == TriState::Enabled; } bool DebuggerRunConfigurationAspect::usePythonDebugger() const { - if (m_pythonAspect->value() == TriState::Default) { + if (m_pythonAspect() == TriState::Default) { const Core::Context languages = m_target->project()->projectLanguages(); return languages.contains(ProjectExplorer::Constants::PYTHON_LANGUAGE_ID); } - return m_pythonAspect->value() == TriState::Enabled; + return m_pythonAspect() == TriState::Enabled; } bool DebuggerRunConfigurationAspect::useMultiProcess() const { - return m_multiProcessAspect->value(); + return m_multiProcessAspect(); } void DebuggerRunConfigurationAspect::setUseMultiProcess(bool value) { - m_multiProcessAspect->setValue(value); + m_multiProcessAspect.setValue(value); } QString DebuggerRunConfigurationAspect::overrideStartup() const { - return m_overrideStartupAspect->value(); + return m_overrideStartupAspect(); } int DebuggerRunConfigurationAspect::portsUsedByDebugger() const @@ -238,31 +227,31 @@ int DebuggerRunConfigurationAspect::portsUsedByDebugger() const void DebuggerRunConfigurationAspect::toMap(Store &map) const { - m_cppAspect->toMap(map); - m_qmlAspect->toMap(map); - m_pythonAspect->toMap(map); - m_multiProcessAspect->toMap(map); - m_overrideStartupAspect->toMap(map); + m_cppAspect.toMap(map); + m_qmlAspect.toMap(map); + m_pythonAspect.toMap(map); + m_multiProcessAspect.toMap(map); + m_overrideStartupAspect.toMap(map); // compatibility to old settings - map.insert("RunConfiguration.UseCppDebuggerAuto", m_cppAspect->value() == TriState::Default); - map.insert("RunConfiguration.UseQmlDebuggerAuto", m_qmlAspect->value() == TriState::Default); + map.insert("RunConfiguration.UseCppDebuggerAuto", m_cppAspect() == TriState::Default); + map.insert("RunConfiguration.UseQmlDebuggerAuto", m_qmlAspect() == TriState::Default); } void DebuggerRunConfigurationAspect::fromMap(const Store &map) { - m_cppAspect->fromMap(map); - m_qmlAspect->fromMap(map); - m_pythonAspect->fromMap(map); + m_cppAspect.fromMap(map); + m_qmlAspect.fromMap(map); + m_pythonAspect.fromMap(map); // respect old project settings if (map.value("RunConfiguration.UseCppDebuggerAuto", false).toBool()) - m_cppAspect->setValue(TriState::Default); + m_cppAspect.setValue(TriState::Default); if (map.value("RunConfiguration.UseQmlDebuggerAuto", false).toBool()) - m_qmlAspect->setValue(TriState::Default); + m_qmlAspect.setValue(TriState::Default); - m_multiProcessAspect->fromMap(map); - m_overrideStartupAspect->fromMap(map); + m_multiProcessAspect.fromMap(map); + m_overrideStartupAspect.fromMap(map); } } // namespace Debugger diff --git a/src/plugins/debugger/debuggerrunconfigurationaspect.h b/src/plugins/debugger/debuggerrunconfigurationaspect.h index 16bcce9f5de..5dcbbce7a5f 100644 --- a/src/plugins/debugger/debuggerrunconfigurationaspect.h +++ b/src/plugins/debugger/debuggerrunconfigurationaspect.h @@ -40,11 +40,11 @@ public: }; private: - Utils::TriStateAspect *m_cppAspect; - Utils::TriStateAspect *m_qmlAspect; - Utils::TriStateAspect *m_pythonAspect; - Utils::BoolAspect *m_multiProcessAspect; - Utils::StringAspect *m_overrideStartupAspect; + Utils::TriStateAspect m_cppAspect; + Utils::TriStateAspect m_qmlAspect; + Utils::TriStateAspect m_pythonAspect; + Utils::BoolAspect m_multiProcessAspect; + Utils::StringAspect m_overrideStartupAspect; ProjectExplorer::Target *m_target; }; From d95fa019d4bff2bbdcf148c0096970f8aca4b585 Mon Sep 17 00:00:00 2001 From: Jarek Kobus Date: Thu, 15 Feb 2024 17:59:57 +0100 Subject: [PATCH 040/243] PythonSettings: Don't leak running watchers Detected by memory analyzer. When shutdown comes while pythonsFromRegistry() or pythonsFromPath() is still running, the corresponding QFutureWatcher is leaked. Employ TaskTreeRunner instead. It handles the cancellation of the running tasks automatically on its destruction. Make pythonsFromRegistry() and pythonsFromPath() cancelable, by providing QPromise as a parameter and check for canceled state on every iteration. Change-Id: Iae7c7d1ed764646b8203bd7ca8b9580cb999b80c Reviewed-by: David Schulz --- src/plugins/python/pythonsettings.cpp | 81 +++++++++++++-------------- src/plugins/python/pythonsettings.h | 3 + 2 files changed, 43 insertions(+), 41 deletions(-) diff --git a/src/plugins/python/pythonsettings.cpp b/src/plugins/python/pythonsettings.cpp index f2f5975ff40..d9f5f74e9ff 100644 --- a/src/plugins/python/pythonsettings.cpp +++ b/src/plugins/python/pythonsettings.cpp @@ -53,9 +53,9 @@ #include #include +using namespace Layouting; using namespace ProjectExplorer; using namespace Utils; -using namespace Layouting; namespace Python::Internal { @@ -645,12 +645,15 @@ void PythonSettings::disableOutdatedPyls() } } -static QList pythonsFromRegistry() +static void pythonsFromRegistry(QPromise> &promise) { QList pythons; QSettings pythonRegistry("HKEY_LOCAL_MACHINE\\SOFTWARE\\Python\\PythonCore", QSettings::NativeFormat); for (const QString &versionGroup : pythonRegistry.childGroups()) { + if (promise.isCanceled()) + return; + pythonRegistry.beginGroup(versionGroup); QString name = pythonRegistry.value("DisplayName").toString(); QVariant regVal = pythonRegistry.value("InstallPath/ExecutablePath"); @@ -671,14 +674,17 @@ static QList pythonsFromRegistry() } pythonRegistry.endGroup(); } - return pythons; + promise.addResult(pythons); } -static QList pythonsFromPath() +static void pythonsFromPath(QPromise> &promise) { QList pythons; if (HostOsInfo::isWindowsHost()) { for (const FilePath &executable : FilePath("python").searchAllInPath()) { + if (promise.isCanceled()) + return; + // Windows creates empty redirector files that may interfere if (executable.toFileInfo().size() == 0) continue; @@ -695,6 +701,9 @@ static QList pythonsFromPath() for (const FilePath &path : dirs) { const QDir dir(path.toString()); for (const QFileInfo &fi : dir.entryInfoList(filters)) { + if (promise.isCanceled()) + return; + const FilePath executable = FilePath::fromUserInput(fi.canonicalFilePath()); if (!used.contains(executable) && executable.exists()) { used.insert(executable); @@ -703,7 +712,7 @@ static QList pythonsFromPath() } } } - return pythons; + promise.addResult(pythons); } static QString idForPythonFromPath(const QList &pythons) @@ -732,41 +741,6 @@ static bool alreadyRegistered(const Interpreter &candidate) }); } -static void scanPath() -{ - auto watcher = new QFutureWatcher>(); - QObject::connect(watcher, &QFutureWatcher>::finished, [watcher]() { - for (const Interpreter &interpreter : watcher->result()) { - if (!alreadyRegistered(interpreter)) - settingsInstance->addInterpreter(interpreter); - } - watcher->deleteLater(); - }); - watcher->setFuture(Utils::asyncRun(pythonsFromPath)); -} - -static void scanRegistry() -{ - auto watcher = new QFutureWatcher>(); - QObject::connect(watcher, &QFutureWatcher>::finished, [watcher]() { - for (const Interpreter &interpreter : watcher->result()) { - if (!alreadyRegistered(interpreter)) - settingsInstance->addInterpreter(interpreter); - } - watcher->deleteLater(); - scanPath(); - }); - watcher->setFuture(Utils::asyncRun(pythonsFromRegistry)); -} - -static void scanSystemForInterpreters() -{ - if (Utils::HostOsInfo::isWindowsHost()) - scanRegistry(); - else - scanPath(); -} - PythonSettings::PythonSettings() { QTC_ASSERT(!settingsInstance, return); @@ -777,7 +751,32 @@ PythonSettings::PythonSettings() initFromSettings(Core::ICore::settings()); - scanSystemForInterpreters(); + const auto onRegistrySetup = [](Async> &task) { + task.setFutureSynchronizer(ExtensionSystem::PluginManager::futureSynchronizer()); + task.setConcurrentCallData(pythonsFromRegistry); + }; + const auto onPathSetup = [](Async> &task) { + task.setFutureSynchronizer(ExtensionSystem::PluginManager::futureSynchronizer()); + task.setConcurrentCallData(pythonsFromPath); + }; + const auto onTaskDone = [](const Async> &task) { + if (!task.isResultAvailable()) + return; + + const auto interpreters = task.result(); + for (const Interpreter &interpreter : interpreters) { + if (!alreadyRegistered(interpreter)) + settingsInstance->addInterpreter(interpreter); + } + }; + + const Tasking::Group recipe { + Tasking::finishAllAndSuccess, + Utils::HostOsInfo::isWindowsHost() + ? AsyncTask>(onRegistrySetup, onTaskDone) : Tasking::GroupItem({}), + AsyncTask>(onPathSetup, onTaskDone) + }; + m_taskTreeRunner.start(recipe); if (m_defaultInterpreterId.isEmpty()) m_defaultInterpreterId = idForPythonFromPath(m_interpreters); diff --git a/src/plugins/python/pythonsettings.h b/src/plugins/python/pythonsettings.h index 892069431d5..ab5d092a5ff 100644 --- a/src/plugins/python/pythonsettings.h +++ b/src/plugins/python/pythonsettings.h @@ -5,6 +5,8 @@ #include +#include + #include namespace Python::Internal { @@ -69,6 +71,7 @@ private: QString m_defaultInterpreterId; bool m_pylsEnabled = true; QString m_pylsConfiguration; + Tasking::TaskTreeRunner m_taskTreeRunner; static void saveSettings(); }; From 36241b4462f7a61ffadd3e51d6ea24ece2dbd4c9 Mon Sep 17 00:00:00 2001 From: Jarek Kobus Date: Thu, 15 Feb 2024 22:44:50 +0100 Subject: [PATCH 041/243] TaskTree: Add global nullItem This might be useful when using conditional operator. Might also be used in place of the default c'tor for GroupItem. Add a test for it. Change-Id: I622e5d3d94f7020dc294cf5bca643c53a0813d8a Reviewed-by: David Schulz Reviewed-by: --- src/libs/solutions/tasking/tasktree.cpp | 2 ++ src/libs/solutions/tasking/tasktree.h | 2 ++ tests/auto/solutions/tasking/tst_tasking.cpp | 19 +++++++++++++++++++ 3 files changed, 23 insertions(+) diff --git a/src/libs/solutions/tasking/tasktree.cpp b/src/libs/solutions/tasking/tasktree.cpp index 2bbb745b527..255fe5243a8 100644 --- a/src/libs/solutions/tasking/tasktree.cpp +++ b/src/libs/solutions/tasking/tasktree.cpp @@ -1178,6 +1178,8 @@ GroupItem workflowPolicy(WorkflowPolicy policy) return Group::workflowPolicy(policy); } +const GroupItem nullItem = GroupItem({}); + const GroupItem sequential = parallelLimit(1); const GroupItem parallel = parallelLimit(0); diff --git a/src/libs/solutions/tasking/tasktree.h b/src/libs/solutions/tasking/tasktree.h index 181f91e85d1..7295c47e1ea 100644 --- a/src/libs/solutions/tasking/tasktree.h +++ b/src/libs/solutions/tasking/tasktree.h @@ -366,6 +366,8 @@ static GroupItem onGroupDone(Handler &&handler, CallDoneIf callDoneIf = CallDone TASKING_EXPORT GroupItem parallelLimit(int limit); TASKING_EXPORT GroupItem workflowPolicy(WorkflowPolicy policy); +TASKING_EXPORT extern const GroupItem nullItem; + TASKING_EXPORT extern const GroupItem sequential; TASKING_EXPORT extern const GroupItem parallel; diff --git a/tests/auto/solutions/tasking/tst_tasking.cpp b/tests/auto/solutions/tasking/tst_tasking.cpp index 477dd57a460..2c20ce14d30 100644 --- a/tests/auto/solutions/tasking/tst_tasking.cpp +++ b/tests/auto/solutions/tasking/tst_tasking.cpp @@ -2951,6 +2951,25 @@ void tst_Tasking::testTree_data() << TestData{storage, root, {}, 1, DoneWith::Success}; } + { + const auto recipe = [storage, createSuccessTask](bool withTask) { + return Group { + storage, + withTask ? createSuccessTask(1) : nullItem + }; + }; + + const Log withTaskLog { + {1, Handler::Setup}, + {1, Handler::Success} + }; + + QTest::newRow("RecipeWithTask") + << TestData{storage, recipe(true), withTaskLog, 1, DoneWith::Success}; + QTest::newRow("RecipeWithNull") + << TestData{storage, recipe(false), {}, 0, DoneWith::Success}; + } + { const auto createRoot = [=](DoneResult doneResult, CallDoneIf callDoneIf) { return Group { From f1f4422dcea46d982feaca177c7b18aedd79486a Mon Sep 17 00:00:00 2001 From: Jarek Kobus Date: Thu, 15 Feb 2024 22:54:03 +0100 Subject: [PATCH 042/243] PythonSettings: Reuse Tasking::nullItem Change-Id: I50675730fa7a7e228b151213610996456a8eacf4 Reviewed-by: Reviewed-by: David Schulz --- src/plugins/python/pythonsettings.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/plugins/python/pythonsettings.cpp b/src/plugins/python/pythonsettings.cpp index d9f5f74e9ff..b144f4a7e84 100644 --- a/src/plugins/python/pythonsettings.cpp +++ b/src/plugins/python/pythonsettings.cpp @@ -773,7 +773,7 @@ PythonSettings::PythonSettings() const Tasking::Group recipe { Tasking::finishAllAndSuccess, Utils::HostOsInfo::isWindowsHost() - ? AsyncTask>(onRegistrySetup, onTaskDone) : Tasking::GroupItem({}), + ? AsyncTask>(onRegistrySetup, onTaskDone) : Tasking::nullItem, AsyncTask>(onPathSetup, onTaskDone) }; m_taskTreeRunner.start(recipe); From 2ceb1e2ad7be8b4d6ec2856da97530723cde7eb8 Mon Sep 17 00:00:00 2001 From: David Schulz Date: Tue, 13 Feb 2024 05:18:33 +0100 Subject: [PATCH 043/243] TextEditor: update ksyntaxhighlighting engine to v5.249.0 Task-number: QTCREATORBUG-22558 Change-Id: I0f75fd00828992df37f596148fac98069794248e Reviewed-by: Christian Stenger --- qt_attributions.json | 28 +- .../syntax-highlighting/CMakeLists.txt | 3 +- .../ksyntaxhighlighting_version.h | 14 +- .../src/lib/ksyntaxhighlighting_export.h | 115 +- .../data/generators/Pipfile | 1 + .../data/generators/cmake.xml.tpl | 27 +- .../data/generators/cmake.yaml | 354 ++- .../data/generators/generate-cmake-syntax.py | 242 +- .../data/generators/generate-html.pl | 143 ++ .../data/generators/generate-nginx-lists.rb | 55 + .../data/generators/generate-php.pl | 78 - .../data/generators/spdx-comments.xml.tpl | 2 +- .../data/generators/update_css_and_scss.py | 498 ++++ .../data/generators/update_less.py | 45 + .../data/schema/language.xsd | 103 +- .../data/schema/validatehl.sh | 3 +- .../syntax-highlighting/data/syntax/alert.xml | 6 +- .../syntax-highlighting/data/syntax/bash.xml | 50 +- .../syntax-highlighting/data/syntax/cmake.xml | 355 ++- .../data/syntax/comments.xml | 2 +- .../syntax-highlighting/data/syntax/css.xml | 2028 +++++++++-------- .../data/syntax/doxygen.xml | 7 +- .../syntax-highlighting/data/syntax/dtd.xml | 2 +- .../data/syntax/gnuassembler.xml | 2 +- .../syntax-highlighting/data/syntax/html.xml | 190 +- .../syntax-highlighting/data/syntax/ini.xml | 4 +- .../syntax-highlighting/data/syntax/java.xml | 40 +- .../data/syntax/javadoc.xml | 4 +- .../syntax-highlighting/data/syntax/json.xml | 22 +- .../data/syntax/markdown.xml | 123 +- .../data/syntax/modelines.xml | 2 +- .../syntax-highlighting/data/syntax/perl.xml | 2 +- .../data/syntax/powershell.xml | 276 ++- .../data/syntax/qdocconf.xml | 2 +- .../syntax-highlighting/data/syntax/ruby.xml | 12 +- .../data/syntax/spdx-comments.xml | 2 +- .../syntax-highlighting/data/syntax/toml.xml | 183 ++ .../data/syntax/valgrind-suppression.xml | 2 +- .../syntax-highlighting/data/syntax/xml.xml | 4 +- .../syntax-highlighting/data/syntax/yacc.xml | 2 +- .../syntax-highlighting/data/syntax/yaml.xml | 642 ++++++ .../data/themes/default.theme | 174 -- .../data/themes/theme-data.qrc | 50 +- .../syntax-highlighting/src/CMakeLists.txt | 4 +- .../syntax-highlighting/src/Messages.sh | 2 +- .../src/cli/CMakeLists.txt | 8 +- ...highlighter.cpp => ksyntaxhighlighter.cpp} | 70 +- .../src/indexer/CMakeLists.txt | 19 +- .../src/indexer/katehighlightingindexer.cpp | 366 ++- .../src/lib/CMakeLists.txt | 50 +- .../src/lib/abstracthighlighter.cpp | 123 +- .../src/lib/abstracthighlighter.h | 24 +- .../src/lib/abstracthighlighter_p.h | 3 +- .../src/lib/ansihighlighter.cpp | 107 +- .../src/lib/ansihighlighter.h | 34 +- .../syntax-highlighting/src/lib/context.cpp | 13 +- .../syntax-highlighting/src/lib/context_p.h | 19 +- .../src/lib/definition.cpp | 85 +- .../syntax-highlighting/src/lib/definition.h | 22 +- .../src/lib/definition_p.h | 26 +- .../src/lib/definitiondownloader.cpp | 6 +- .../src/lib/definitionref_p.h | 6 +- .../src/lib/dynamicregexpcache_p.h | 39 + .../src/lib/foldingregion.cpp | 31 +- .../src/lib/foldingregion.h | 19 +- .../syntax-highlighting/src/lib/format.cpp | 2 +- .../syntax-highlighting/src/lib/format.h | 10 +- .../syntax-highlighting/src/lib/format_p.h | 11 +- .../src/lib/highlightingdata.cpp | 1 + .../src/lib/highlightingdata_p.hpp | 1 + .../src/lib/htmlhighlighter.cpp | 153 +- .../src/lib/htmlhighlighter.h | 7 +- .../src/lib/keywordlist.cpp | 7 +- .../src/lib/matchresult_p.h | 6 +- .../src/lib/repository.cpp | 76 +- .../syntax-highlighting/src/lib/repository.h | 66 +- .../src/lib/repository_p.h | 26 +- .../syntax-highlighting/src/lib/rule.cpp | 105 +- .../syntax-highlighting/src/lib/rule_p.h | 55 +- .../syntax-highlighting/src/lib/state.cpp | 81 +- .../syntax-highlighting/src/lib/state.h | 14 +- .../syntax-highlighting/src/lib/state_p.h | 56 +- .../src/lib/syntaxhighlighter.cpp | 141 +- .../src/lib/syntaxhighlighter.h | 1 + .../syntax-highlighting/src/lib/theme.cpp | 2 + .../syntax-highlighting/src/lib/theme.h | 9 +- .../syntax-highlighting/src/lib/themedata.cpp | 54 +- .../syntax-highlighting/src/lib/themedata_p.h | 11 +- .../src/lib/worddelimiters.cpp | 6 + .../src/lib/worddelimiters_p.h | 5 + .../src/quick/CMakeLists.txt | 5 +- .../src/quick/kquicksyntaxhighlighter.cpp | 14 +- .../src/quick/kquicksyntaxhighlighter.h | 10 +- .../quick/kquicksyntaxhighlightingplugin.cpp | 20 +- .../src/quick/repositorywrapper.cpp | 65 - .../src/quick/repositorywrapper.h | 45 - .../syntax-highlighting.qbs | 3 +- 97 files changed, 5300 insertions(+), 2743 deletions(-) create mode 100644 src/libs/3rdparty/syntax-highlighting/data/generators/generate-html.pl create mode 100644 src/libs/3rdparty/syntax-highlighting/data/generators/generate-nginx-lists.rb delete mode 100644 src/libs/3rdparty/syntax-highlighting/data/generators/generate-php.pl create mode 100644 src/libs/3rdparty/syntax-highlighting/data/generators/update_css_and_scss.py create mode 100644 src/libs/3rdparty/syntax-highlighting/data/generators/update_less.py create mode 100644 src/libs/3rdparty/syntax-highlighting/data/syntax/toml.xml create mode 100644 src/libs/3rdparty/syntax-highlighting/data/syntax/yaml.xml delete mode 100644 src/libs/3rdparty/syntax-highlighting/data/themes/default.theme rename src/libs/3rdparty/syntax-highlighting/src/cli/{kate-syntax-highlighter.cpp => ksyntaxhighlighter.cpp} (77%) create mode 100644 src/libs/3rdparty/syntax-highlighting/src/lib/dynamicregexpcache_p.h delete mode 100644 src/libs/3rdparty/syntax-highlighting/src/quick/repositorywrapper.cpp delete mode 100644 src/libs/3rdparty/syntax-highlighting/src/quick/repositorywrapper.h diff --git a/qt_attributions.json b/qt_attributions.json index 2a2a866b110..0a9e762dae1 100644 --- a/qt_attributions.json +++ b/qt_attributions.json @@ -258,9 +258,22 @@ "Description": "Syntax highlighting definition ruby.xml", "Homepage": "https://invent.kde.org/frameworks/syntax-highlighting/-/tree/master/data/syntax", "License": "GNU Lesser General Public License v2.0 or later", - "LicenseFile": "doc/qtcreator/src/overview/license-LGPLv2.1.txt", + "LicenseFile": "doc/qtcreator/src/overview/license-LGPLv2.0.txt", "Copyright": "Copyright (C) 2004 by Sebastian Vuorinen (sebastian dot vuorinen at helsinki dot fi). Copyright (C) 2004 by Stefan Lang (langstefan@gmx.at). Copyright (C) 2008 by Robin Pedersen (robinpeder@gmail.com). Copyright (C) 2011 by Miquel Sabaté (mikisabate@gmail.com)." }, + { + "Id": "ksyntaxhighlighting-toml", + "Name": "KSyntaxHighlighting: toml.xml", + "QDocModule": "qtcreator", + "QtParts": ["tools"], + "QtUsage": "Used for the generic highlighter for text files.", + "Path": "src/libs/3rdparty/syntax-highlighting/data/syntax", + "Description": "Syntax highlighting definition toml.xml", + "Homepage": "https://invent.kde.org/frameworks/syntax-highlighting/-/tree/master/data/syntax", + "License": "GNU Lesser General Public License v2.0", + "LicenseFile": "doc/qtcreator/src/overview/license-LGPLv2.0.txt", + "Copyright": "Copyright (C) flying-sheep@web.de" + }, { "Id": "ksyntaxhighlighting-valgrind-suppression", "Name": "KSyntaxHighlighting: valgrind-suppression.xml", @@ -300,6 +313,19 @@ "LicenseFile": "doc/qtcreator/src/overview/license-LGPLv2.1.txt", "Copyright": "Copyright (C) 2004, Jan Villat . Changes by: 2018 Nibaldo González , 2007 Sebastian Pipping ." }, + { + "Id": "ksyntaxhighlighting-yaml", + "Name": "KSyntaxHighlighting: yaml.xml", + "QDocModule": "qtcreator", + "QtParts": ["tools"], + "QtUsage": "Used for the generic highlighter for text files.", + "Path": "src/libs/3rdparty/syntax-highlighting/data/syntax", + "Description": "Syntax highlighting definition yaml.xml", + "Homepage": "https://invent.kde.org/frameworks/syntax-highlighting/-/tree/master/data/syntax", + "License": "GNU Lesser General Public License v2.1", + "LicenseFile": "doc/qtcreator/src/overview/license-LGPLv2.1.txt", + "Copyright": "Copyright (C) Dr Orlovsky MA (dr.orlovsky@gmail.com), Nibaldo González (nibgonz@gmail.com)" + }, { "Id": "std-span-martinmoene", "Name": "std::span Implementation for C++11 and Later", diff --git a/src/libs/3rdparty/syntax-highlighting/CMakeLists.txt b/src/libs/3rdparty/syntax-highlighting/CMakeLists.txt index 66c1d919512..ce22946d84f 100644 --- a/src/libs/3rdparty/syntax-highlighting/CMakeLists.txt +++ b/src/libs/3rdparty/syntax-highlighting/CMakeLists.txt @@ -26,6 +26,7 @@ add_qtc_library(KSyntaxHighlighting src/lib/definitiondownloader.cpp src/lib/definitiondownloader.h src/lib/definitionref_p.h src/lib/definition_p.h + src/lib/dynamicregexpcache_p.h src/lib/foldingregion.cpp src/lib/foldingregion.h src/lib/format.cpp src/lib/format.h src/lib/format_p.h src/lib/htmlhighlighter.cpp src/lib/htmlhighlighter.h @@ -44,7 +45,7 @@ add_qtc_library(KSyntaxHighlighting src/lib/xml_p.h ) -set(export_symbol_declaration DEFINES KF5SyntaxHighlighting_EXPORTS) +set(export_symbol_declaration DEFINES KF6SyntaxHighlighting_EXPORTS) if (QTC_STATIC_BUILD) set(export_symbol_declaration PUBLIC_DEFINES KSYNTAXHIGHLIGHTING_STATIC_DEFINE) endif() diff --git a/src/libs/3rdparty/syntax-highlighting/autogenerated/ksyntaxhighlighting_version.h b/src/libs/3rdparty/syntax-highlighting/autogenerated/ksyntaxhighlighting_version.h index 007fe4acae3..d568d1813d6 100644 --- a/src/libs/3rdparty/syntax-highlighting/autogenerated/ksyntaxhighlighting_version.h +++ b/src/libs/3rdparty/syntax-highlighting/autogenerated/ksyntaxhighlighting_version.h @@ -1,12 +1,12 @@ // This file was generated by ecm_setup_version(): DO NOT EDIT! -#ifndef SyntaxHighlighting_VERSION_H -#define SyntaxHighlighting_VERSION_H +#ifndef KSYNTAXHIGHLIGHTING_VERSION_H +#define KSYNTAXHIGHLIGHTING_VERSION_H -#define SyntaxHighlighting_VERSION_STRING "5.103.0" -#define SyntaxHighlighting_VERSION_MAJOR 5 -#define SyntaxHighlighting_VERSION_MINOR 103 -#define SyntaxHighlighting_VERSION_PATCH 0 -#define SyntaxHighlighting_VERSION ((5<<16)|(103<<8)|(0)) +#define KSYNTAXHIGHLIGHTING_VERSION_STRING "5.249.0" +#define KSYNTAXHIGHLIGHTING_VERSION_MAJOR 5 +#define KSYNTAXHIGHLIGHTING_VERSION_MINOR 249 +#define KSYNTAXHIGHLIGHTING_VERSION_PATCH 0 +#define KSYNTAXHIGHLIGHTING_VERSION ((5<<16)|(249<<8)|(0)) #endif diff --git a/src/libs/3rdparty/syntax-highlighting/autogenerated/src/lib/ksyntaxhighlighting_export.h b/src/libs/3rdparty/syntax-highlighting/autogenerated/src/lib/ksyntaxhighlighting_export.h index e376e94505e..a7b9e09afa7 100644 --- a/src/libs/3rdparty/syntax-highlighting/autogenerated/src/lib/ksyntaxhighlighting_export.h +++ b/src/libs/3rdparty/syntax-highlighting/autogenerated/src/lib/ksyntaxhighlighting_export.h @@ -2,14 +2,12 @@ #ifndef KSYNTAXHIGHLIGHTING_EXPORT_H #define KSYNTAXHIGHLIGHTING_EXPORT_H -#include - #ifdef KSYNTAXHIGHLIGHTING_STATIC_DEFINE # define KSYNTAXHIGHLIGHTING_EXPORT # define KSYNTAXHIGHLIGHTING_NO_EXPORT #else # ifndef KSYNTAXHIGHLIGHTING_EXPORT -# ifdef KF5SyntaxHighlighting_EXPORTS +# ifdef KF6SyntaxHighlighting_EXPORTS /* We are building this library */ # define KSYNTAXHIGHLIGHTING_EXPORT Q_DECL_EXPORT # else @@ -43,8 +41,6 @@ #define KSYNTAXHIGHLIGHTING_DECL_DEPRECATED_TEXT(text) __declspec(deprecated(text)) -#define ECM_GENERATEEXPORTHEADER_VERSION_VALUE(major, minor, patch) ((major<<16)|(minor<<8)|(patch)) - /* Take any defaults from group settings */ #if !defined(KSYNTAXHIGHLIGHTING_NO_DEPRECATED) && !defined(KSYNTAXHIGHLIGHTING_DISABLE_DEPRECATED_BEFORE_AND_AT) # ifdef KF_NO_DEPRECATED @@ -88,7 +84,7 @@ #define KSYNTAXHIGHLIGHTING_BUILD_DEPRECATED_SINCE(major, minor) 1 #ifdef KSYNTAXHIGHLIGHTING_NO_DEPRECATED -# define KSYNTAXHIGHLIGHTING_DISABLE_DEPRECATED_BEFORE_AND_AT 0x56700 +# define KSYNTAXHIGHLIGHTING_DISABLE_DEPRECATED_BEFORE_AND_AT KSYNTAXHIGHLIGHTING_VERSION #endif #ifdef KSYNTAXHIGHLIGHTING_NO_DEPRECATED_WARNINGS # define KSYNTAXHIGHLIGHTING_DEPRECATED_WARNINGS_SINCE 0 @@ -98,7 +94,7 @@ # ifdef KSYNTAXHIGHLIGHTING_DISABLE_DEPRECATED_BEFORE_AND_AT # define KSYNTAXHIGHLIGHTING_DEPRECATED_WARNINGS_SINCE KSYNTAXHIGHLIGHTING_DISABLE_DEPRECATED_BEFORE_AND_AT # else -# define KSYNTAXHIGHLIGHTING_DEPRECATED_WARNINGS_SINCE 0x56700 +# define KSYNTAXHIGHLIGHTING_DEPRECATED_WARNINGS_SINCE KSYNTAXHIGHLIGHTING_VERSION # endif #endif @@ -107,112 +103,9 @@ #endif #ifdef KSYNTAXHIGHLIGHTING_DEPRECATED -# define KSYNTAXHIGHLIGHTING_ENABLE_DEPRECATED_SINCE(major, minor) (ECM_GENERATEEXPORTHEADER_VERSION_VALUE(major, minor, 0) > KSYNTAXHIGHLIGHTING_DISABLE_DEPRECATED_BEFORE_AND_AT) +# define KSYNTAXHIGHLIGHTING_ENABLE_DEPRECATED_SINCE(major, minor) (((major<<16)|(minor<<8)) > KSYNTAXHIGHLIGHTING_DISABLE_DEPRECATED_BEFORE_AND_AT) #else # define KSYNTAXHIGHLIGHTING_ENABLE_DEPRECATED_SINCE(major, minor) 0 #endif -#if KSYNTAXHIGHLIGHTING_DEPRECATED_WARNINGS_SINCE >= 0x55700 -# define KSYNTAXHIGHLIGHTING_DEPRECATED_VERSION_5_87(text) KSYNTAXHIGHLIGHTING_DECL_DEPRECATED_TEXT(text) -#else -# define KSYNTAXHIGHLIGHTING_DEPRECATED_VERSION_5_87(text) -#endif -#define KSYNTAXHIGHLIGHTING_DEPRECATED_VERSION_5(minor, text) KSYNTAXHIGHLIGHTING_DEPRECATED_VERSION_5_##minor(text) -#define KSYNTAXHIGHLIGHTING_DEPRECATED_VERSION(major, minor, text) KSYNTAXHIGHLIGHTING_DEPRECATED_VERSION_##major(minor, "Since "#major"."#minor". " text) -#define KSYNTAXHIGHLIGHTING_DEPRECATED_VERSION_BELATED(major, minor, textmajor, textminor, text) KSYNTAXHIGHLIGHTING_DEPRECATED_VERSION_##major(minor, "Since "#textmajor"."#textminor". " text) -// Not yet implemented for MSVC -#define KSYNTAXHIGHLIGHTING_ENUMERATOR_DEPRECATED_VERSION(major, minor, text) -#define KSYNTAXHIGHLIGHTING_ENUMERATOR_DEPRECATED_VERSION_BELATED(major, minor, textmajor, textminor, text) - #endif /* KSYNTAXHIGHLIGHTING_EXPORT_H */ - - -#ifndef ECM_GENERATEEXPORTHEADER_KSYNTAXHIGHLIGHTING_EXPORT_H -#define ECM_GENERATEEXPORTHEADER_KSYNTAXHIGHLIGHTING_EXPORT_H - - -#define KSYNTAXHIGHLIGHTING_DECL_DEPRECATED_TEXT(text) __declspec(deprecated(text)) - -#define ECM_GENERATEEXPORTHEADER_VERSION_VALUE(major, minor, patch) ((major<<16)|(minor<<8)|(patch)) - -/* Take any defaults from group settings */ -#if !defined(KSYNTAXHIGHLIGHTING_NO_DEPRECATED) && !defined(KSYNTAXHIGHLIGHTING_DISABLE_DEPRECATED_BEFORE_AND_AT) -# ifdef KF_NO_DEPRECATED -# define KSYNTAXHIGHLIGHTING_NO_DEPRECATED -# elif defined(KF_DISABLE_DEPRECATED_BEFORE_AND_AT) -# define KSYNTAXHIGHLIGHTING_DISABLE_DEPRECATED_BEFORE_AND_AT KF_DISABLE_DEPRECATED_BEFORE_AND_AT -# endif -#endif -#if !defined(KSYNTAXHIGHLIGHTING_DISABLE_DEPRECATED_BEFORE_AND_AT) && defined(KF_DISABLE_DEPRECATED_BEFORE_AND_AT) -# define KSYNTAXHIGHLIGHTING_DISABLE_DEPRECATED_BEFORE_AND_AT KF_DISABLE_DEPRECATED_BEFORE_AND_AT -#endif - -#if !defined(KSYNTAXHIGHLIGHTING_NO_DEPRECATED_WARNINGS) && !defined(KSYNTAXHIGHLIGHTING_DEPRECATED_WARNINGS_SINCE) -# ifdef KF_NO_DEPRECATED_WARNINGS -# define KSYNTAXHIGHLIGHTING_NO_DEPRECATED_WARNINGS -# elif defined(KF_DEPRECATED_WARNINGS_SINCE) -# define KSYNTAXHIGHLIGHTING_DEPRECATED_WARNINGS_SINCE KF_DEPRECATED_WARNINGS_SINCE -# endif -#endif -#if !defined(KSYNTAXHIGHLIGHTING_DEPRECATED_WARNINGS_SINCE) && defined(KF_DEPRECATED_WARNINGS_SINCE) -# define KSYNTAXHIGHLIGHTING_DEPRECATED_WARNINGS_SINCE KF_DEPRECATED_WARNINGS_SINCE -#endif - -#if defined(KSYNTAXHIGHLIGHTING_NO_DEPRECATED) -# undef KSYNTAXHIGHLIGHTING_DEPRECATED -# define KSYNTAXHIGHLIGHTING_DEPRECATED_EXPORT KSYNTAXHIGHLIGHTING_EXPORT -# define KSYNTAXHIGHLIGHTING_DEPRECATED_NO_EXPORT KSYNTAXHIGHLIGHTING_NO_EXPORT -#elif defined(KSYNTAXHIGHLIGHTING_NO_DEPRECATED_WARNINGS) -# define KSYNTAXHIGHLIGHTING_DEPRECATED -# define KSYNTAXHIGHLIGHTING_DEPRECATED_EXPORT KSYNTAXHIGHLIGHTING_EXPORT -# define KSYNTAXHIGHLIGHTING_DEPRECATED_NO_EXPORT KSYNTAXHIGHLIGHTING_NO_EXPORT -#else -# define KSYNTAXHIGHLIGHTING_DEPRECATED KSYNTAXHIGHLIGHTING_DECL_DEPRECATED -# define KSYNTAXHIGHLIGHTING_DEPRECATED_EXPORT KSYNTAXHIGHLIGHTING_DECL_DEPRECATED_EXPORT -# define KSYNTAXHIGHLIGHTING_DEPRECATED_NO_EXPORT KSYNTAXHIGHLIGHTING_DECL_DEPRECATED_NO_EXPORT -#endif - -/* No deprecated API had been removed from build */ -#define KSYNTAXHIGHLIGHTING_EXCLUDE_DEPRECATED_BEFORE_AND_AT 0 - -#define KSYNTAXHIGHLIGHTING_BUILD_DEPRECATED_SINCE(major, minor) 1 - -#ifdef KSYNTAXHIGHLIGHTING_NO_DEPRECATED -# define KSYNTAXHIGHLIGHTING_DISABLE_DEPRECATED_BEFORE_AND_AT 0x56700 -#endif -#ifdef KSYNTAXHIGHLIGHTING_NO_DEPRECATED_WARNINGS -# define KSYNTAXHIGHLIGHTING_DEPRECATED_WARNINGS_SINCE 0 -#endif - -#ifndef KSYNTAXHIGHLIGHTING_DEPRECATED_WARNINGS_SINCE -# ifdef KSYNTAXHIGHLIGHTING_DISABLE_DEPRECATED_BEFORE_AND_AT -# define KSYNTAXHIGHLIGHTING_DEPRECATED_WARNINGS_SINCE KSYNTAXHIGHLIGHTING_DISABLE_DEPRECATED_BEFORE_AND_AT -# else -# define KSYNTAXHIGHLIGHTING_DEPRECATED_WARNINGS_SINCE 0x56700 -# endif -#endif - -#ifndef KSYNTAXHIGHLIGHTING_DISABLE_DEPRECATED_BEFORE_AND_AT -# define KSYNTAXHIGHLIGHTING_DISABLE_DEPRECATED_BEFORE_AND_AT 0 -#endif - -#ifdef KSYNTAXHIGHLIGHTING_DEPRECATED -# define KSYNTAXHIGHLIGHTING_ENABLE_DEPRECATED_SINCE(major, minor) (ECM_GENERATEEXPORTHEADER_VERSION_VALUE(major, minor, 0) > KSYNTAXHIGHLIGHTING_DISABLE_DEPRECATED_BEFORE_AND_AT) -#else -# define KSYNTAXHIGHLIGHTING_ENABLE_DEPRECATED_SINCE(major, minor) 0 -#endif - -#if KSYNTAXHIGHLIGHTING_DEPRECATED_WARNINGS_SINCE >= 0x55700 -# define KSYNTAXHIGHLIGHTING_DEPRECATED_VERSION_5_87(text) KSYNTAXHIGHLIGHTING_DECL_DEPRECATED_TEXT(text) -#else -# define KSYNTAXHIGHLIGHTING_DEPRECATED_VERSION_5_87(text) -#endif -#define KSYNTAXHIGHLIGHTING_DEPRECATED_VERSION_5(minor, text) KSYNTAXHIGHLIGHTING_DEPRECATED_VERSION_5_##minor(text) -#define KSYNTAXHIGHLIGHTING_DEPRECATED_VERSION(major, minor, text) KSYNTAXHIGHLIGHTING_DEPRECATED_VERSION_##major(minor, "Since "#major"."#minor". " text) -#define KSYNTAXHIGHLIGHTING_DEPRECATED_VERSION_BELATED(major, minor, textmajor, textminor, text) KSYNTAXHIGHLIGHTING_DEPRECATED_VERSION_##major(minor, "Since "#textmajor"."#textminor". " text) -// Not yet implemented for MSVC -#define KSYNTAXHIGHLIGHTING_ENUMERATOR_DEPRECATED_VERSION(major, minor, text) -#define KSYNTAXHIGHLIGHTING_ENUMERATOR_DEPRECATED_VERSION_BELATED(major, minor, textmajor, textminor, text) - - -#endif /* ECM_GENERATEEXPORTHEADER_KSYNTAXHIGHLIGHTING_EXPORT_H */ diff --git a/src/libs/3rdparty/syntax-highlighting/data/generators/Pipfile b/src/libs/3rdparty/syntax-highlighting/data/generators/Pipfile index 8e9c570084c..227d4cd2cca 100644 --- a/src/libs/3rdparty/syntax-highlighting/data/generators/Pipfile +++ b/src/libs/3rdparty/syntax-highlighting/data/generators/Pipfile @@ -8,4 +8,5 @@ name = "pypi" [packages] click = "~= 8.0" jinja2 = "~= 3.0" +lxml = "*" PyYAML = "*" diff --git a/src/libs/3rdparty/syntax-highlighting/data/generators/cmake.xml.tpl b/src/libs/3rdparty/syntax-highlighting/data/generators/cmake.xml.tpl index 5f57c8eeacc..48f56f7b607 100644 --- a/src/libs/3rdparty/syntax-highlighting/data/generators/cmake.xml.tpl +++ b/src/libs/3rdparty/syntax-highlighting/data/generators/cmake.xml.tpl @@ -1,5 +1,5 @@ - @@ -12,7 +12,7 @@ SPDX-FileCopyrightText: 2004 Alexander Neundorf SPDX-FileCopyrightText: 2005 Dominik Haumann SPDX-FileCopyrightText: 2007, 2008, 2013, 2014 Matthew Woehlke - SPDX-FileCopyrightText: 2013-2015, 2017-2020 Alex Turbov + SPDX-FileCopyrightText: 2013-2015, 2017-2023 Alex Turbov SPDX-License-Identifier: LGPL-2.0-or-later --> @@ -26,7 +26,7 @@ + + + + + + + @@ -135,7 +142,7 @@ - + beginRegion="" endRegion="" /> @@ -427,11 +434,22 @@ + + + + + + + + + + + @@ -460,6 +478,7 @@ + diff --git a/src/libs/3rdparty/syntax-highlighting/data/generators/cmake.yaml b/src/libs/3rdparty/syntax-highlighting/data/generators/cmake.yaml index 624299346f9..e247237dda4 100644 --- a/src/libs/3rdparty/syntax-highlighting/data/generators/cmake.yaml +++ b/src/libs/3rdparty/syntax-highlighting/data/generators/cmake.yaml @@ -1,4 +1,4 @@ -version: 44 +version: 50 global-properties: - ALLOW_DUPLICATE_CUSTOM_TARGETS @@ -112,11 +112,12 @@ target-properties: - AUTOGEN_BUILD_DIR - AUTOGEN_ORIGIN_DEPENDS # Since 3.14 - AUTOGEN_TARGET_DEPENDS - - AUTOMOC_COMPILER_PREDEFINES # Since ??? + - AUTOGEN_USE_SYSTEM_INCLUDE # Since 3.27 + - AUTOMOC_COMPILER_PREDEFINES # Since 3.10 - AUTOMOC_DEPEND_FILTERS - AUTOMOC_EXECUTABLE # Since 3.14 - AUTOMOC_MACRO_NAMES - - AUTOMOC_MOC_OPTIONS # Since ??? + - AUTOMOC_MOC_OPTIONS - AUTOMOC_PATH_PREFIX # Since 3.16 - AUTOMOC - AUTOUIC @@ -154,14 +155,23 @@ target-properties: - _POSTFIX - CROSSCOMPILING_EMULATOR - CUDA_ARCHITECTURES # Since 3.18 + - CUDA_CUBIN_COMPILATION # Since 3.27 + - CUDA_EXTENSIONS + - CUDA_FATBIN_COMPILATION # Since 3.27 + - CUDA_OPTIX_COMPILATION # Since 3.27 - CUDA_PTX_COMPILATION - CUDA_SEPARABLE_COMPILATION - CUDA_RESOLVE_DEVICE_SYMBOLS - CUDA_RUNTIME_LIBRARY # Since 3.17 - - CUDA_EXTENSIONS - CUDA_STANDARD - CUDA_STANDARD_REQUIRED - CXX_EXTENSIONS + - CXX_MODULE_DIRS # Since 3.28 + - CXX_MODULE_DIRS_ # Since 3.28 + - CXX_MODULE_SET # Since 3.28 + - CXX_MODULE_SET_ # Since 3.28 + - CXX_MODULE_SETS # Since 3.28 + - CXX_SCAN_FOR_MODULES # Since 3.28 - CXX_STANDARD - CXX_STANDARD_REQUIRED # - DEBUG_POSTFIX # NOTE: Handled by `_POSTFIX` @@ -170,6 +180,7 @@ target-properties: - DEPLOYMENT_REMOTE_DIRECTORY - DEPRECATION # Since 3.17 - DISABLE_PRECOMPILE_HEADERS # Since 3.16 + - DLL_NAME_WITH_SOVERSION # Since 3.27 - DOTNET_SDK # Since 3.23 - DOTNET_TARGET_FRAMEWORK # Since 3.17 - DOTNET_TARGET_FRAMEWORK_VERSION # Since 3.12 @@ -234,10 +245,12 @@ target-properties: - INSTALL_REMOVE_ENVIRONMENT_RPATH # Since 3.16 - INSTALL_RPATH - INSTALL_RPATH_USE_LINK_PATH + - INTERFACE_AUTOMOC_MACRO_NAMES # Since 3.27 - INTERFACE_AUTOUIC_OPTIONS - INTERFACE_COMPILE_DEFINITIONS - INTERFACE_COMPILE_FEATURES - INTERFACE_COMPILE_OPTIONS + - INTERFACE_CXX_MODULE_SETS # Since 3.28 - INTERFACE_HEADER_SETS # Since 3.23 - INTERFACE_HEADER_SETS_TO_VERIFY # Since 3.24 - INTERFACE_INCLUDE_DIRECTORIES @@ -261,6 +274,7 @@ target-properties: - JOB_POOL_LINK - LABELS - _CLANG_TIDY + - _CLANG_TIDY_EXPORT_FIXES_DIR # Since 3.26 - _COMPILER_LAUNCHER - _CPPCHECK # Since 3.10 - _CPPLINT @@ -451,18 +465,22 @@ test-properties: - FIXTURES_CLEANUP - FIXTURES_REQUIRED - FIXTURES_SETUP + - GENERATED_RESOURCE_SPEC_FILE # Since 3.28 - LABELS - MEASUREMENT - PASS_REGULAR_EXPRESSION - PROCESSOR_AFFINITY # Since 3.12 - PROCESSORS - REQUIRED_FILES + - RESOURCE_GROUPS # Since 3.16 - RESOURCE_LOCK - RUN_SERIAL - SKIP_REGULAR_EXPRESSION # Since 3.16 - SKIP_RETURN_CODE - TIMEOUT - TIMEOUT_AFTER_MATCH + - TIMEOUT_SIGNAL_GRACE_PERIOD # Since 3.27 + - TIMEOUT_SIGNAL_NAME # Since 3.27 - WILL_FAIL - WORKING_DIRECTORY @@ -473,6 +491,7 @@ source-properties: - COMPILE_DEFINITIONS - COMPILE_FLAGS - COMPILE_OPTIONS # Since 3.11 + - CXX_SCAN_FOR_MODULES # Since 3.28 - EXTERNAL_OBJECT - Fortran_FORMAT - Fortran_PREPROCESS # Since 3.18 @@ -490,6 +509,7 @@ source-properties: - SKIP_AUTOMOC - SKIP_AUTORCC - SKIP_AUTOUIC + - SKIP_LINTING # Since 3.27 - SKIP_PRECOMPILE_HEADERS # Since 3.16 - SKIP_UNITY_BUILD_INCLUSION # Since 3.16 - Swift_DEPENDENCIES_FILE # Since 3.15 @@ -535,76 +555,155 @@ install-properties: - CPACK_WIX_ACL generator-expressions: - # Boolean Generator Expressions - # * Logical Operators + # Conditional Expressions + - IF - 0 - 1 - BOOL + # Logical Operators - AND - OR - NOT - # * String Comparisons + # String Comparisons - STREQUAL - EQUAL - - IN_LIST # Since 3.12 + # Version Comparisons - VERSION_LESS - VERSION_GREATER - VERSION_EQUAL - VERSION_LESS_EQUAL - VERSION_GREATER_EQUAL - # * Path Comparisons - - PATH_EQUAL # Since 3.24 - # * Path Queries - # * Path Decomposition - # * Path Transformations - # TODO Need a bit deeper genex parsing to get sub-commands of `PATH` - - PATH # Since 3.24 - # * Variable Queries - - TARGET_EXISTS # Since 3.12 - - CONFIG - - PLATFORM_ID - - C_COMPILER_ID - - CXX_COMPILER_ID - - CUDA_COMPILER_ID # Since 3.15 - - Fortran_COMPILER_ID - - C_COMPILER_VERSION - - CXX_COMPILER_VERSION - - CUDA_COMPILER_VERSION # Since 3.15 - - Fortran_COMPILER_VERSION - - TARGET_POLICY - - COMPILE_FEATURES - - COMPILE_LANG_AND_ID # Since 3.15 - - COMPILE_LANGUAGE - - LINK_LANG_AND_ID # Since 3.18 - - LINK_LANGUAGE # Since 3.18 - - DEVICE_LINK # Since 3.18 - - HOST_LINK # Since 3.18 - - LINK_LIBRARY # Since 3.24 - - LINK_GROUP # Since 3.24 - # String-Valued Generator Expressions - # * Escaped Characters - - ANGLE-R - - COMMA - - SEMICOLON - # * Conditional Expressions - - IF - # * String Transformations + # String Transformations + - LOWER_CASE + - UPPER_CASE + - MAKE_C_IDENTIFIER + # List Expressions + # * List Comparisons + - IN_LIST # Since 3.12 + - name: LIST # Since 3.27 + subcommands: + # * List Queries + - LENGTH + - GET + - SUBLIST + - FIND + # * List Transformations + - JOIN + - APPEND + - PREPEND + - INSERT + - POP_BACK + - POP_FRONT + - REMOVE_ITEM + - REMOVE_AT + - REMOVE_DUPLICATES + - FILTER + - TRANSFORM + - FRANSFORM + # * List Ordering + - REVERSE + - SORT - JOIN - REMOVE_DUPLICATES # Since 3.15 - FILTER # Since 3.15 - - LOWER_CASE - - UPPER_CASE - - GENEX_EVAL # Since 3.12 - - TARGET_GENEX_EVAL # Since 3.12 - # * Variable Queries (NOTE Already included above) - # * Target-Dependent Queries + # Path Expressions + # * Path Comparisons + - PATH_EQUAL # Since 3.24 + - name: PATH # Since 3.24 + subcommands: + # * Path Queries + - HAS_ROOT_NAME + - HAS_ROOT_DIRECTORY + - HAS_ROOT_PATH + - HAS_FILENAME + - HAS_EXTENSION + - HAS_STEM + - HAS_RELATIVE_PART + - HAS_PARENT_PATH + - IS_ABSOLUTE + - IS_RELATIVE + - IS_PREFIX + # * Path Decomposition + - GET_ROOT_NAME + - GET_ROOT_DIRECTORY + - GET_ROOT_PATH + - GET_FILENAME + - GET_EXTENSION + - GET_STEM + - GET_RELATIVE_PART + - GET_PARENT_PATH + # * Path Transformations + - CMAKE_PATH + - APPEND + - REMOVE_FILENAME + - REPLACE_FILENAME + - REMOVE_EXTENSION + - REPLACE_EXTENSION + - NORMAL_PATH + - RELATIVE_PATH + - ABSOLUTE_PATH + # Shell Paths + - SHELL_PATH + # Configuration Expressions + - CONFIG + - OUTPUT_CONFIG # Since 3.20 + - COMMAND_CONFIG # Since 3.20 + # Toolchain And Language Expressions + # * Platform + - PLATFORM_ID + # * Compiler Version + - C_COMPILER_VERSION + - CXX_COMPILER_VERSION + - CUDA_COMPILER_VERSION # Since 3.15 + - OBJC_COMPILER_VERSION # Since 3.16 + - OBJCXX_COMPILER_VERSION # Since 3.16 + - Fortran_COMPILER_VERSION + - HIP_COMPILER_VERSION # Since 3.21 + - ISPC_COMPILER_VERSION # Since 3.19 + # * Compiler Language And ID + - C_COMPILER_ID + - CXX_COMPILER_ID + - CUDA_COMPILER_ID # Since 3.15 + - OBJC_COMPILER_ID # Since 3.16 + - OBJCXX_COMPILER_ID # Since 3.16 + - Fortran_COMPILER_ID + - HIP_COMPILER_ID # Since 3.21 + - ISPC_COMPILER_ID # Since 3.19 + - COMPILE_LANGUAGE # Since 3.3 + - COMPILE_LANG_AND_ID # Since 3.15 + # * Compile Features + - COMPILE_FEATURES + # * Compile Context + - COMPILE_ONLY # Since 3.27 + # * Linker Language And ID + - LINK_LANGUAGE # Since 3.18 + - LINK_LANG_AND_ID # Since 3.18 + # * Link Features + - LINK_LIBRARY # Since 3.24 + - LINK_GROUP # Since 3.24 + # * Link Context + - LINK_ONLY + - DEVICE_LINK # Since 3.18 + - HOST_LINK # Since 3.18 + # Target-Dependent Expressions + - TARGET_EXISTS # Since 3.12 - TARGET_NAME_IF_EXISTS # Since 3.12 + - TARGET_NAME + - TARGET_PROPERTY + - TARGET_OBJECTS + - TARGET_POLICY - TARGET_FILE - TARGET_FILE_BASE_NAME # Since 3.15 - TARGET_FILE_PREFIX # Since 3.15 - TARGET_FILE_SUFFIX # Since 3.15 - TARGET_FILE_NAME - TARGET_FILE_DIR + - TARGET_IMPORT_FILE # Since 3.27 + - TARGET_IMPORT_FILE_BASE_NAME # Since 3.27 + - TARGET_IMPORT_FILE_PREFIX # Since 3.27 + - TARGET_IMPORT_FILE_SUFFIX # Since 3.27 + - TARGET_IMPORT_FILE_NAME # Since 3.27 + - TARGET_IMPORT_FILE_DIR # Since 3.27 - TARGET_LINKER_FILE - TARGET_LINKER_FILE_BASE_NAME # Since 3.15 - TARGET_LINKER_FILE_PREFIX # Since 3.15 @@ -612,7 +711,6 @@ generator-expressions: - TARGET_LINKER_FILE_NAME - TARGET_LINKER_FILE_DIR - TARGET_SONAME_FILE - - TARGET_SONAME_FILE - TARGET_SONAME_FILE_NAME - TARGET_SONAME_FILE_DIR - TARGET_PDB_FILE @@ -622,19 +720,22 @@ generator-expressions: - TARGET_BUNDLE_DIR_NAME # Since 3.24 - TARGET_BUNDLE_DIR - TARGET_BUNDLE_CONTENT_DIR - - TARGET_PROPERTY - TARGET_RUNTIME_DLLS # Since 3.21 - - INSTALL_PREFIX - # Output-Related Expressions - - TARGET_NAME - - LINK_ONLY + - TARGET_RUNTIME_DLL_DIRS # Since 3.27 + # Export And Install Expressions - INSTALL_INTERFACE - BUILD_INTERFACE - - MAKE_C_IDENTIFIER - - TARGET_OBJECTS - - SHELL_PATH - - OUTPUT_CONFIG # Since 3.20 - - COMMAND_CONFIG # Since 3.20 + - BUILD_LOCAL_INTERFACE # Since 3.26 + - INSTALL_PREFIX + # Multi-level Expression Evaluation + - GENEX_EVAL # Since 3.12 + - TARGET_GENEX_EVAL # Since 3.12 + # Escaped Characters + - ANGLE-R + - COMMA + - SEMICOLON + # Deprecated Expressions + # - CONFIGURATION variables: # Variables that Provide Information @@ -686,6 +787,7 @@ variables: - CMAKE_JOB_POOL_LINK - CMAKE_JOB_POOLS # Since 3.11 - CMAKE__COMPILER_AR + - CMAKE__COMPILER_FRONTEND_VARIANT # Since 3.14 - CMAKE__COMPILER_RANLIB - CMAKE_LINK_LIBRARY_SUFFIX - CMAKE_LINK_SEARCH_END_STATIC @@ -735,9 +837,17 @@ variables: - CMAKE_VS_NsightTegra_VERSION - CMAKE_VS_NUGET_PACKAGE_RESTORE # Since 3.23 - CMAKE_VS_PLATFORM_NAME + - CMAKE_VS_PLATFORM_NAME_DEFAULT # Since 3.14.3 - CMAKE_VS_PLATFORM_TOOLSET - CMAKE_VS_PLATFORM_TOOLSET_CUDA - - CMAKE_VS_PLATFORM_TOOLSET_HOST_ARCHITECTURE + - CMAKE_VS_PLATFORM_TOOLSET_CUDA_CUSTOM_DIR # Since 3.16 + - CMAKE_VS_PLATFORM_TOOLSET_HOST_ARCHITECTURE # Since 3.8 + - CMAKE_VS_PLATFORM_TOOLSET_VERSION # Since 3.12 + - CMAKE_VS_TARGET_FRAMEWORK_IDENTIFIER # Since 3.22 + - CMAKE_VS_TARGET_FRAMEWORK_TARGETS_VERSION # Since 3.22 + - CMAKE_VS_TARGET_FRAMEWORK_VERSION # Since 3.22 + - CMAKE_VS_VERSION_BUILD_NUMBER # Since 3.26 + - CMAKE_VS_WINDOWS_TARGET_PLATFORM_MIN_VERSION # Since 3.27 - CMAKE_VS_WINDOWS_TARGET_PLATFORM_VERSION - CMAKE_VS_WINDOWS_TARGET_PLATFORM_VERSION_MAXIMUM # Since 3.19 - CMAKE_XCODE_BUILD_SYSTEM # Since 3.19 @@ -766,6 +876,7 @@ variables: # Variables that Change Behavior - BUILD_SHARED_LIBS - CMAKE_ABSOLUTE_DESTINATION_FILES + - CMAKE_ADD_CUSTOM_COMMAND_DEPENDS_EXPLICIT_ONLY # Since 3.27 - CMAKE_APPBUNDLE_PATH - CMAKE_AUTOMOC_RELAXED_MODE - CMAKE_BACKWARDS_COMPATIBILITY @@ -973,16 +1084,20 @@ variables: - CMAKE_ARCHIVE_OUTPUT_DIRECTORY_ - CMAKE_AUTOGEN_ORIGIN_DEPENDS # Since 3.14 - CMAKE_AUTOGEN_PARALLEL + - CMAKE_AUTOGEN_USE_SYSTEM_INCLUDE # Since 3.27 - CMAKE_AUTOGEN_VERBOSE # Since 3.13 - CMAKE_AUTOMOC - CMAKE_AUTOMOC_DEPEND_FILTERS - CMAKE_AUTOMOC_MOC_OPTIONS - CMAKE_AUTOMOC_PATH_PREFIX # Since 3.16 + - CMAKE_AUTOMOC_EXECUTABLE # Since 3.27 - CMAKE_AUTORCC - CMAKE_AUTORCC_OPTIONS + - CMAKE_AUTORCC_EXECUTABLE # Since 3.27 - CMAKE_AUTOUIC - CMAKE_AUTOUIC_OPTIONS - CMAKE_AUTOUIC_SEARCH_PATHS + - CMAKE_AUTOUIC_EXECUTABLE # Since 3.27 - CMAKE_BUILD_RPATH - CMAKE_BUILD_RPATH_USE_ORIGIN # Since 3.14 - CMAKE_BUILD_WITH_INSTALL_NAME_DIR @@ -993,14 +1108,17 @@ variables: - CMAKE__POSTFIX - CMAKE_CROSS_CONFIGS # Since 3.17 - CMAKE_CTEST_ARGUMENTS # Since 3.17 - - CMAKE_CUDA_SEPARABLE_COMPILATION # Since 3.11 - CMAKE_CUDA_RESOLVE_DEVICE_SYMBOLS # Since 3.16 - CMAKE_CUDA_RUNTIME_LIBRARY # Since 3.17 + - CMAKE_CUDA_SEPARABLE_COMPILATION # Since 3.11 + - CMAKE_CXX_SCAN_FOR_MODULES # Since 3.28 - CMAKE_DEBUG_POSTFIX - CMAKE_DEFAULT_BUILD_TYPE # Since 3.17 - CMAKE_DEFAULT_CONFIGS # Since 3.17 - CMAKE_DISABLE_PRECOMPILE_HEADERS # Since 3.17 - - CMAKE_ENABLE_EXPORTS + - CMAKE_DLL_NAME_WITH_SOVERSION # Since 3.27 + # `CMAKE_ENABLE_EXPORTS` has been moved to deprecated section + - CMAKE_EXECUTABLE_ENABLE_EXPORTS # Since 3.27 - CMAKE_EXE_LINKER_FLAGS - CMAKE_EXE_LINKER_FLAGS_ - CMAKE_EXE_LINKER_FLAGS__INIT @@ -1024,8 +1142,8 @@ variables: - CMAKE_INSTALL_RPATH_USE_LINK_PATH - CMAKE_INTERPROCEDURAL_OPTIMIZATION - CMAKE_INTERPROCEDURAL_OPTIMIZATION_ - - CMAKE_IOS_INSTALL_COMBINED - CMAKE__CLANG_TIDY + - CMAKE__CLANG_TIDY_EXPORT_FIXES_DIR # Since 3.26 - CMAKE__COMPILER_LAUNCHER - CMAKE__CPPCHECK # Since 3.10 - CMAKE__CPPLINT @@ -1044,6 +1162,9 @@ variables: - CMAKE_LIBRARY_PATH_FLAG - CMAKE_LINK_DEF_FILE_FLAG - CMAKE_LINK_DEPENDS_NO_SHARED + - CMAKE_LINK_DEPENDS_USE_LINKER # Since 3.27 + - CMAKE_LINK_GROUP_USING_ # Since 3.24 + - CMAKE_LINK_GROUP_USING__SUPPORTED # Since 3.24 - CMAKE_LINK_INTERFACE_LIBRARIES - CMAKE_LINK_LIBRARY_FILE_FLAG - CMAKE_LINK_LIBRARY_FLAG @@ -1072,9 +1193,11 @@ variables: - CMAKE_PCH_INSTANTIATE_TEMPLATES # Since 3.19 - CMAKE_PDB_OUTPUT_DIRECTORY - CMAKE_PDB_OUTPUT_DIRECTORY_ + - CMAKE_PLATFORM_NO_VERSIONED_SONAME # Since 3.1 - CMAKE_POSITION_INDEPENDENT_CODE - CMAKE_RUNTIME_OUTPUT_DIRECTORY - CMAKE_RUNTIME_OUTPUT_DIRECTORY_ + - CMAKE_SHARED_LIBRARY_ENABLE_EXPORTS # Since 3.27 - CMAKE_SHARED_LINKER_FLAGS - CMAKE_SHARED_LINKER_FLAGS_ - CMAKE_SHARED_LINKER_FLAGS__INIT @@ -1095,6 +1218,10 @@ variables: - CMAKE_USE_RELATIVE_PATHS - CMAKE_VERIFY_INTERFACE_HEADER_SETS # Since 3.24 - CMAKE_VISIBILITY_INLINES_HIDDEN + - CMAKE_VS_DEBUGGER_COMMAND # Since 3.27 + - CMAKE_VS_DEBUGGER_COMMAND_ARGUMENTS # Since 3.27 + - CMAKE_VS_DEBUGGER_ENVIRONMENT # Since 3.27 + - CMAKE_VS_DEBUGGER_WORKING_DIRECTORY # Since 3.27 - CMAKE_VS_GLOBALS # Since 3.13 - CMAKE_VS_INCLUDE_INSTALL_TO_DEFAULT_BUILD - CMAKE_VS_INCLUDE_PACKAGE_TO_DEFAULT_BUILD @@ -1137,6 +1264,7 @@ variables: - CMAKE_Fortran_MODOUT_FLAG - CMAKE_HIP_ARCHITECTURES # Since 3.21 - CMAKE_HIP_EXTENSIONS # Since 3.21 + - CMAKE_HIP_PLATFORM # Since 3.28 - CMAKE_HIP_STANDARD # Since 3.21 - CMAKE_HIP_STANDARD_REQUIRED # Since 3.21 - CMAKE_ISPC_HEADER_DIRECTORY # Since 3.19 @@ -1533,6 +1661,41 @@ variables: - CPACK_COMMAND_HDIUTIL - CPACK_COMMAND_SETFILE - CPACK_COMMAND_REZ + # [built-in]: CPack Inno Setup Generator (Since 3.27) + - CPACK_INNOSETUP_USE_CMAKE_BOOL_FORMAT + - CPACK_INNOSETUP_ARCHITECTURE + - CPACK_INNOSETUP_INSTALL_ROOT + - CPACK_INNOSETUP_ALLOW_CUSTOM_DIRECTORY + - CPACK_INNOSETUP_PROGRAM_MENU_FOLDER + - CPACK_INNOSETUP_LANGUAGES + - CPACK_INNOSETUP_IGNORE_LICENSE_PAGE + - CPACK_INNOSETUP_IGNORE_README_PAGE + - CPACK_INNOSETUP_PASSWORD + - CPACK_INNOSETUP_USE_MODERN_WIZARD + - CPACK_INNOSETUP_ICON_FILE + - CPACK_INNOSETUP_SETUP_ + - CPACK_INNOSETUP_CUSTOM_INSTALL_INSTRUCTIONS + - CPACK_INNOSETUP_MENU_LINKS + - CPACK_INNOSETUP_CREATE_UNINSTALL_LINK + - CPACK_INNOSETUP_RUN_EXECUTABLES + - CPACK_INNOSETUP__INSTALL_DIRECTORY + - CPACK_INNOSETUP_VERIFY_DOWNLOADS + - CPACK_INNOSETUP_EXECUTABLE + - CPACK_INNOSETUP_EXECUTABLE_ARGUMENTS + - CPACK_INNOSETUP_DEFINE_ + - CPACK_INNOSETUP_EXTRA_SCRIPTS + - CPACK_INNOSETUP_CODE_FILES + # [built-in]: CPack FreeBSD Generator (Since 3.10) + - CPACK_FREEBSD_PACKAGE_NAME + - CPACK_FREEBSD_PACKAGE_COMMENT + - CPACK_FREEBSD_PACKAGE_DESCRIPTION + - CPACK_FREEBSD_PACKAGE_WWW + - CPACK_FREEBSD_PACKAGE_LICENSE + - CPACK_FREEBSD_PACKAGE_LICENSE_LOGIC + - CPACK_FREEBSD_PACKAGE_MAINTAINER + - CPACK_FREEBSD_PACKAGE_ORIGIN + - CPACK_FREEBSD_PACKAGE_CATEGORIES + - CPACK_FREEBSD_PACKAGE_DEPS # -CPackExt (Since 3.13) - CPACK_EXTERNAL_REQUESTED_VERSIONS - CPACK_EXTERNAL_ENABLE_STAGING @@ -1970,6 +2133,7 @@ variables: - CUPS_INCLUDE_DIR # - FindCURL - CURL_NO_CURL_CMAKE + - CURL_USE_STATIC_LIBS # Since 3.28 # - FindCurses - CURSES_CFLAGS - CURSES_HAVE_CURSES_H @@ -1989,7 +2153,6 @@ variables: - CXXTEST_TESTGEN_EXECUTABLE - CXXTEST_TESTGEN_INTERPRETER # - FindCygwin - # - FindDart # - FindDCMTK # - FindDevIL # - FindDoxygen @@ -1997,6 +2160,7 @@ variables: # - FindEnvModules - EnvModules_COMMAND # - FindEXPAT + - EXPAT_USE_STATIC_LIBS # Since 3.28 # - FindFLEX - FLEX_EXECUTABLE # - FindFLTK @@ -2598,6 +2762,11 @@ deprecated-or-internal-variables: - CMAKE_OBJDUMP # Mentioned in "Deprecated and Removed Features" of release notes 3.21 - CMAKE_SYSTEM_ARCH + # Superseded by `CMAKE_EXECUTABLE_ENABLE_EXPORTS` + - CMAKE_ENABLE_EXPORTS + - CMAKE_IOS_INSTALL_COMBINED # Since 3.28 + + # https://cmake.org/cmake/help/latest/manual/cmake-env-variables.7.html # NOTE Added to syntax file version 14 at 3.15.0 version of CMake @@ -2614,6 +2783,7 @@ environment-variables: - CMAKE_COLOR_DIAGNOSTICS # Since 3.24 - CMAKE_CONFIGURATION_TYPES # Since 3.22 - CMAKE_CONFIG_TYPE + - CMAKE_CROSSCOMPILING_EMULATOR # Since 3.28 - CMAKE_EXPORT_COMPILE_COMMANDS # Since 3.17 - CMAKE_GENERATOR - CMAKE_GENERATOR_INSTANCE @@ -2657,11 +2827,13 @@ environment-variables: # Environment Variables for CTest - CMAKE_CONFIG_TYPE - CTEST_INTERACTIVE_DEBUG_MODE + - CTEST_NO_TESTS_ACTION # Since 3.26 - CTEST_OUTPUT_ON_FAILURE - CTEST_PARALLEL_LEVEL - CTEST_PROGRESS_OUTPUT - CTEST_USE_LAUNCHERS_DEFAULT - DASHBOARD_TEST_FROM_CTEST + # Environment Variables for the CMake curses interface - CCMAKE_COLORS # Here are the `find_package` specific variables described at the # https://cmake.org/cmake/help/latest/command/find_package.html @@ -2731,6 +2903,7 @@ scripting-commands: , OS_RELEASE , OS_VERSION , OS_PLATFORM + , MSYSTEM_PREFIX # Since 3.28 # Since 3.22 , DISTRIB_INFO , DISTRIB_ @@ -3380,6 +3553,8 @@ scripting-commands: , CHECK_START , CHECK_PASS , CHECK_FAIL + # Since 3.26 + , CONFIGURE_LOG ] - name: option @@ -3520,10 +3695,12 @@ project-commands: , COMMENT , DEPFILE , JOB_POOL # Since 3.15 + , JOB_SERVER_AWARE # Since 3.28 , VERBATIM , APPEND , USES_TERMINAL , COMMAND_EXPAND_LISTS + , DEPENDS_EXPLICIT_ONLY # Since 3.27 , TARGET , PRE_BUILD , PRE_LINK @@ -3543,6 +3720,7 @@ project-commands: , COMMENT , DEPFILE , JOB_POOL # Since 3.15 + , JOB_SERVER_AWARE # Since 3.28 , VERBATIM , APPEND , USES_TERMINAL @@ -3587,6 +3765,9 @@ project-commands: , TARGET ] has-target-name-after-kw: TARGET + - + name: cmake_file_api # Since 3.27 + named-args: [QUERY, API_VERSION, CODEMODEL, CACHE, CMAKEFILES, TOOLCHAINS] - name: create_test_sourcelist named-args: [EXTRA_INCLUDE, FUNCTION] @@ -3614,6 +3795,7 @@ project-commands: ASM , ASM-ATT , ASM_NASM + , ASM_MARMASM # Since 3.26 , ASM_MASM , C , CSharp @@ -3650,6 +3832,7 @@ project-commands: property-args: &get_target_property [target-properties] - name: get_test_property + named-args: [DIRECTORY] # Since 3.28 property-args: &get_test_property [test-properties] - name: include_directories @@ -3741,7 +3924,7 @@ project-commands: named-args: [AFTER, BEFORE] - name: link_libraries - named-args: [debug, optimized, general] + special-args: &link_libraries_sa [debug, optimized, general] - name: load_cache named-args: [READ_WITH_PREFIX, EXCLUDE, INCLUDE_INTERNALS] @@ -3793,7 +3976,10 @@ project-commands: first-args-are-targets?: true # NOTE Multiple target args - name: set_tests_properties - named-args: [PROPERTIES] + named-args: [ + DIRECTORY # Since 3.28 + , PROPERTIES + ] property-args: *get_test_property - name: source_group @@ -3888,6 +4074,7 @@ project-commands: , cuda_std_17 , cuda_std_20 , cuda_std_23 # Since 3.21 + , cuda_std_26 # Since 3.25 ] first-arg-is-target?: true - @@ -3913,6 +4100,7 @@ project-commands: - name: target_link_libraries named-args: *target_compile_definitions + special-args: *link_libraries_sa first-arg-is-target?: true - name: target_link_options @@ -3935,6 +4123,10 @@ project-commands: , BASE_DIRS , FILES ] + special-args: [ + HEADERS + , CXX_MODULES # Since 3.28 + ] first-arg-is-target?: true - name: try_compile @@ -3959,6 +4151,9 @@ project-commands: , SOURCE_FROM_CONTENT , SOURCE_FROM_VAR , SOURCE_FROM_FILE + # Since 3.26 + , LOG_DESCRIPTION + , NO_LOG ] - name: try_run @@ -3987,6 +4182,9 @@ project-commands: , NO_CACHE , RUN_OUTPUT_STDOUT_VARIABLE , RUN_OUTPUT_STDERR_VARIABLE + # Since 3.26 + , LOG_DESCRIPTION + , NO_LOG ] ctest-commands: @@ -4150,7 +4348,6 @@ modules: - CTestCoverageCollectGCOV - CTestScriptMode - CTestUseLaunchers - - Dart - DeployQt4 - ExternalData - ExternalProject @@ -4196,7 +4393,6 @@ modules: - FindCVS - FindCxxTest - FindCygwin - - FindDart - FindDCMTK - FindDevIL - FindDoxygen @@ -4339,6 +4535,7 @@ modules: - CMakeExpandImportedTargets - CMakeForceCompiler - CMakeParseArguments + - Dart # Since 3.27 - Documentation - MacroAddFileDependencies - TestCXXAcceptsFlag @@ -4350,6 +4547,7 @@ modules: - WriteCompilerDetectionHeader # Deprecated Find Modules - FindCUDA + - FindDart # Since 3.27 - FindPythonInterp - FindPythonLibs - FindQt @@ -4773,6 +4971,7 @@ standard-module-commands: - BUILD_IN_SOURCE - BUILD_ALWAYS - BUILD_BYPRODUCTS + - BUILD_JOB_SERVER_AWARE # Since 3.28 - INSTALL_COMMAND - TEST_COMMAND - TEST_BEFORE_INSTALL @@ -4800,6 +4999,7 @@ standard-module-commands: - INDEPENDENT_STEP_TARGETS - LIST_SEPARATOR - COMMAND + - INSTALL_BYPRODUCTS # Since 3.26 special-args: [IGNORED, OPTIONAL, REQUIRED, CHECKOUT, REBASE, REBASE_CHECKOUT] property-args: *get_target_property - name: ExternalProject_Get_Property @@ -4814,6 +5014,7 @@ standard-module-commands: - INDEPENDENT - BYPRODUCTS - ALWAYS + - JOB_SERVER_AWARE # Since 3.28 - EXCLUDE_FROM_MAIN - WORKING_DIRECTORY - LOG @@ -4901,7 +5102,10 @@ standard-module-commands: - UPDATE_DISCONNECTED - PATCH_COMMAND - SOURCE_SUBDIR + - OVERRIDE_FIND_PACKAGE + - FIND_PACKAGE_ARGS - SYSTEM + - EXCLUDE_FROM_ALL # Since 3.28 - name: FetchContent_Populate named-args: @@ -5169,7 +5373,12 @@ standard-module-commands: # FindDoxygen - name: doxygen_add_docs - named-args: [ALL, USE_STAMP_FILE, WORKING_DIRECTORY, COMMENT] + named-args: + - ALL + - USE_STAMP_FILE + - WORKING_DIRECTORY + - COMMENT + - CONFIG_FILE # Since 3.27 # FindEnvModules - name: env_module @@ -5248,6 +5457,7 @@ standard-module-commands: named-args: *pkgcm - name: pkg_get_variable + named-args: [DEFINE_VARIABLES] # Since 3.28 # FindProtobuf - name: protobuf_generate_cpp diff --git a/src/libs/3rdparty/syntax-highlighting/data/generators/generate-cmake-syntax.py b/src/libs/3rdparty/syntax-highlighting/data/generators/generate-cmake-syntax.py index f500061f47e..0d9597320ee 100644 --- a/src/libs/3rdparty/syntax-highlighting/data/generators/generate-cmake-syntax.py +++ b/src/libs/3rdparty/syntax-highlighting/data/generators/generate-cmake-syntax.py @@ -3,25 +3,31 @@ # # Generate Kate syntax file for CMake # -# SPDX-FileCopyrightText: 2017-2020 Alex Turbov +# SPDX-FileCopyrightText: 2017-2023 Alex Turbov # # To install prerequisites: # -# $ pip install --user click jinja2 pyyaml +# $ pip install --user click jinja2 lxml pyyaml # # To use: # # $ ./generate-cmake-syntax.py cmake.yaml > ../syntax/cmake.xml # + +from __future__ import annotations + +import functools +import re +from dataclasses import dataclass, field + import click import jinja2 -import re import yaml - +import sys from lxml import etree -_TEMPLATED_NAME = re.compile('<[^>]+>') +_TEMPLATED_NAME = re.compile(r'(?:<[^>]+>)') _PROPERTY_KEYS = [ 'global-properties' , 'directory-properties' @@ -33,7 +39,7 @@ _PROPERTY_KEYS = [ ] _KW_RE_LIST = ['kw', 're'] _VAR_KIND_LIST = ['variables', 'deprecated-or-internal-variables', 'environment-variables'] -_CONTROL_FLOW_LIST = set(( +_CONTROL_FLOW_LIST = { 'break' , 'continue' , 'elseif' @@ -45,39 +51,226 @@ _CONTROL_FLOW_LIST = set(( , 'if' , 'return' , 'while' -)) + } +_VAR_REF_ENTITY = '&var_ref_re;' + +_HEURISTICS = [ + ( + {'MAX(_(COUNT|MAJOR|MINOR|PATCH|TWEAK))?', 'MIN(_(COUNT|MAJOR|MINOR|PATCH|TWEAK))?'} + , 'M(AX|IN)(_(COUNT|MAJOR|MINOR|PATCH|TWEAK))?' + ) + , ({'OUTPUTS', 'OUTPUT_(HEADER|SOURCE)'}, 'OUTPUT(S|_(HEADER|SOURCE))') + , ({'PREFIX', 'SUFFIX'}, '(PRE|SUF)FIX') + , ({'CPPCHECK', 'CPPLINT'}, 'CPP(CHECK|LINT)') + , ({'DEPENDS', 'PREDEPENDS'}, '(PRE)?DEPENDS') + , ({'ICON', 'ICONURL'}, 'ICON(URL)?') + , ( + { + '&var%ref%re;(_INIT)?' + , 'DEBUG(_INIT)?' + , 'MINSIZEREL(_INIT)?' + , 'RELEASE(_INIT)?' + , 'RELWITHDEBINFO(_INIT)?' + } + , '(DEBUG|MINSIZEREL|REL(EASE|WITHDEBINFO)|&var%ref%re;)(_INIT)?' + ) + , ({'RELEASE', 'RELWITHDEBINFO'}, 'REL(EASE|WITHDEBINFO)') + , ({'POST', 'POSTUN', 'PRE', 'PREUN'}, 'P(RE|OST)(UN)?') + , ({'AUTOPROV', 'AUTOREQ', 'AUTOREQPROV'}, 'AUTO(PROV|REQ(PROV)?)') + , ({'DEFINITIONS', 'OPTIONS'}, '(DEFINI|OP)TIONS') + , ({'LIB_NAMES', 'LIBRARY'}, 'LIB(_NAMES|RARY)') + , ({'EXTENSIONS', 'EXTRA_FLAGS'}, 'EXT(ENSIONS|RA_FLAGS)') + , ({'DISABLED', 'DISPLAY_NAME'}, 'DIS(ABLED|PLAY_NAME)') + , ({'LIBRARIES', 'LINK_LIBRARIES', 'STATIC_LINK_LIBRARIES'}, '((STATIC_)?LINK_)?LIBRARIES') + , ({'INCLUDE_DIRS', 'LIBRARY_DIRS'}, '(INCLUDE|LIBRARY)_DIRS') + , ({'BINARY_DIR', 'SOURCE_DIR'}, '(BINARY|SOURCE)_DIR') + , ({'CFLAGS(_OTHER)?', 'LDFLAGS(_OTHER)?'}, '(C|LD)FLAGS(_OTHER)?') + , ({'INCLUDE_DIRECTORIES', 'LIBRARIES'}, '(INCLUDE_DIRECTO|LIBRA)RIES') + , ({'POSTFLIGHT_&var%ref%re;_SCRIPT', 'PREFLIGHT_&var%ref%re;_SCRIPT'}, 'P(RE|OST)FLIGHT_&var%ref%re;_SCRIPT') + , ({'DIRECTORIES', 'FRAMEWORK_DIRECTORIES'}, '(FRAMEWORK_)?DIRECTORIES') + , ({'FILE_FLAG', 'FILE'}, 'FILE(_FLAG)?') + , ({'DIR_PERMISSIONS', 'FILE_PERMISSIONS'}, '(DIR|FILE)_PERMISSIONS') + , ({'COMPILER_LAUNCHER', 'LINKER_LAUNCHER'}, '(COMPIL|LINK)ER_LAUNCHER') + , ({'COMPILER', 'COMPILE_(DEFINI|OP)TIONS'}, 'COMPILE(R|_(DEFINI|OP)TIONS)') + , ({'LICENSEURL', 'LICENSE_(EXPRESSION|FILE_NAME)'}, 'LICENSE(URL|_(EXPRESSION|FILE_NAME))') + , ({'NO_SONAME', 'SONAME'}, '(NO_)?SONAME') + , ({'CODE_SIGN_ON_COPY', 'REMOVE_HEADERS_ON_COPY'}, '(CODE_SIGN|REMOVE_HEADERS)_ON_COPY') + , ({'(REFERENCE|REFERENCEPROP_&var%ref%re;_TAG)_&var%ref%re;'}, 'REFERENCE(PROP_&var%ref%re;_TAG)?_&var%ref%re;') + , ({'DISABLE_FIND_PACKAGE', 'REQUIRE_FIND_PACKAGE'}, '(DISABLE|REQUIRE)_FIND_PACKAGE') + , ( + {'GROUP_USING_&var%ref%re;(_SUPPORTED)?', 'LIBRARY_USING_&var%ref%re;(_SUPPORTED)?'} + , '(GROUP|LIBRARY)_USING_&var%ref%re;(_SUPPORTED)?' + ) + , ( + { + 'EXE_LINKER_FLAGS_&var%ref%re;(_INIT)?' + , 'MODULE_LINKER_FLAGS_&var%ref%re;(_INIT)?' + , 'SHARED_LINKER_FLAGS_&var%ref%re;(_INIT)?' + , 'STATIC_LINKER_FLAGS_&var%ref%re;(_INIT)?' + } + , '(EXE|MODULE|SHARED|STATIC)_LINKER_FLAGS_&var%ref%re;(_INIT)?' + ) + , ( + { + 'ARCHIVE_OUTPUT_DIRECTORY' + , 'COMPILE_PDB_OUTPUT_DIRECTORY' + , 'LIBRARY_OUTPUT_DIRECTORY' + , 'PDB_OUTPUT_DIRECTORY' + , 'RUNTIME_OUTPUT_DIRECTORY' + } + , '(ARCHIVE|(COMPILE_)?PDB|LIBRARY|RUNTIME)_OUTPUT_DIRECTORY' + ) + , ( + { + 'ARCHIVE_OUTPUT_(DIRECTORY|NAME)' + , 'LIBRARY_OUTPUT_(DIRECTORY|NAME)' + , 'RUNTIME_OUTPUT_(DIRECTORY|NAME)' + } + , '(ARCHIVE|LIBRARY|RUNTIME)_OUTPUT_(DIRECTORY|NAME)' + ) + , ({'ASM&var_ref_re;', 'ASM&var_ref_re;FLAGS'}, 'ASM&var_ref_re;(FLAGS)?') + , ( + { + 'CMAKE_POLICY_DEFAULT_CMP[0-9]{4}' + , 'CMAKE_POLICY_WARNING_CMP[0-9]{4}' + } + , 'CMAKE_POLICY_(DEFAULT|WARNING)_CMP[0-9]{4}' + ) + , ({'CMAKE_ARGV[0-9]+', 'CMAKE_MATCH_[0-9]+'}, 'CMAKE_(ARGV|MATCH_)[0-9]+') + ] + +@dataclass +class RePartNode: + children: dict[str, RePartNode] = field(default_factory=dict, hash=False) + is_leaf: bool = False -def try_transform_placeholder_string_to_regex(name): +@dataclass +class RegexCollection: + special_cases: list[str] = field(default_factory=list, hash=False) + re_tree: dict[str, RePartNode] = field(default_factory=dict, hash=False) + + def add_case(self, regex: str) -> RegexCollection: + self.special_cases.append(regex) + return self + + def update_tree(self, name_parts: list[str]) -> RegexCollection: + safe_var_ref = _VAR_REF_ENTITY.replace('_', '%') + current = functools.reduce( + lambda current, part: ( + self.re_tree if current is None else current.children + ).setdefault(part, RePartNode()) + , safe_var_ref.join(name_parts).replace(f'{safe_var_ref}_{safe_var_ref}', safe_var_ref).split('_') + , None + ) + current.is_leaf = True + return self + + +def try_transform_placeholder_string_to_regex(state: RegexCollection, name: str): ''' NOTE Some placeholders are not IDs, but numbers... `CMAKE_MATCH_` 4 example ''' - m = _TEMPLATED_NAME.split(name) - if 'CMAKE_MATCH_' in m: - return 'CMAKE_MATCH_[0-9]+' + name_parts = _TEMPLATED_NAME.split(name) + match name_parts: + case ['CMAKE_MATCH_' as head, ''] | ['CMAKE_ARGV' as head, ''] | ['ARGV' as head, '']: + return state.add_case(head + '[0-9]+') - if 'CMAKE_ARGV' in m: - return 'CMAKE_ARGV[0-9]+' + case ['CMAKE_POLICY_DEFAULT_CMP' as head, ''] | ['CMAKE_POLICY_WARNING_CMP' as head, '']: + return state.add_case(head + '[0-9]{4}') - if 'CMAKE_POLICY_DEFAULT_CMP' in m: - return 'CMAKE_POLICY_DEFAULT_CMP[0-9]{4}' + case ['', '__TRYRUN_OUTPUT']: + return state.add_case(f'{_VAR_REF_ENTITY}__TRYRUN_OUTPUT') - if 'CMAKE_POLICY_WARNING_CMP' in m: - return 'CMAKE_POLICY_WARNING_CMP[0-9]{4}' + case (['ASM', ''] | ['ASM', 'FLAGS']) as asm_env: + return state.add_case(f'{asm_env[0]}{_VAR_REF_ENTITY}{asm_env[1]}') - if 'ARGV' in m: - return 'ARGV[0-9]+' + return state.update_tree(name_parts) - return '&var_ref_re;'.join(m) if 1 < len(m) else name + +def is_first_subset_of_second(first, second): + subset = set(first) + fullset = set(second) + return subset.issubset(fullset) + + +def try_optimize_known_alt_groups(groups: list[str]) -> list[str]: + for case in _HEURISTICS: + if is_first_subset_of_second(case[0], groups): + groups = sorted([*filter(lambda item: item not in case[0], groups), case[1]]) + return groups + + +def try_optimize_trailing_var_ref_regex(groups: list[str]) -> list[str]: + tail_var_ref_re = '_' + _VAR_REF_ENTITY.replace('_', '%') + candidates = [*filter(lambda s: s.endswith(tail_var_ref_re), groups)] + return sorted([ + *filter(lambda item: item not in candidates, groups) + , f'({"|".join(try_optimize_known_alt_groups([s[:-len(tail_var_ref_re)] for s in candidates]))}){tail_var_ref_re}' + ]) if len(candidates) > 1 else groups + + +def build_regex(state: list[str], kv: tuple[str, RePartNode]) -> list[str]: + name, value = kv + match (value, len(value.children)): + case (RePartNode(children={}, is_leaf=True), 0): + return [*state, name] + + case (node, sz) if sz > 0: + alt_group = try_optimize_known_alt_groups( + try_optimize_trailing_var_ref_regex( + functools.reduce(build_regex, node.children.items(), []) + ) + ) + + match (len(alt_group), node.is_leaf): + case (1, False): + return [*state, f'{name}_{alt_group[0]}'] + + case (1, True): + return [*state, f'{name}(_{alt_group[0]})?'] + + case (sz, False) if sz > 0: + return [*state, f'{name}_({"|".join(alt_group)})'] + + case (sz, True) if sz > 0: + return [*state, f'{name}(_({"|".join(alt_group)}))?'] + + case _: + raise AssertionError('Zero children?') + + case _: + raise AssertionError(f'NOT MATCHED: {name=}→{value=}') + + return state def try_placeholders_to_regex(names): if not names: return None - l = map(try_transform_placeholder_string_to_regex, names) - l = sorted(l, reverse=True) - return '\\b(?:' + '|'.join(l) + ')\\b' + + data = functools.reduce( + try_transform_placeholder_string_to_regex + , names + , RegexCollection() + ) + + return ( + '\\b(?:' + + '|'.join( + try_optimize_known_alt_groups( + try_optimize_trailing_var_ref_regex( + functools.reduce( + build_regex + , data.re_tree.items() + , data.special_cases + ) + ) + ) + ).replace('%', '_') + + ')\\b' + ) def partition_iterable(fn, iterable): @@ -287,7 +480,8 @@ def cli(input_yaml, template): del data['standard-module-commands'] # Fix node names to be accessible from Jinja template - data['generator_expressions'] = data['generator-expressions'] + data['generator_expressions'] = (ex for ex in data['generator-expressions'] if isinstance(ex, str)) + data['complex_generator_expressions'] = [ex for ex in data['generator-expressions'] if not isinstance(ex, str)] data['deprecated_or_internal_variables'] = data['deprecated-or-internal-variables'] data['environment_variables'] = data['environment-variables'] del data['generator-expressions'] diff --git a/src/libs/3rdparty/syntax-highlighting/data/generators/generate-html.pl b/src/libs/3rdparty/syntax-highlighting/data/generators/generate-html.pl new file mode 100644 index 00000000000..a5b9bc9d058 --- /dev/null +++ b/src/libs/3rdparty/syntax-highlighting/data/generators/generate-html.pl @@ -0,0 +1,143 @@ +#!/usr/bin/perl + +# This perl script read stdin and write on stdout. It shall be an XML language file. +# +# * If the name of the language is 'HTML', then it creates the language 'PHP (HTML)' +# which shall be used for PHP hl. +# +# * If the name of the language is something else (say '*'), it creates the language '*/PHP'. +# This new language is the same as the old one, but is able to detect PHP everywhere. +# +# This script will correctly set extensions & mimetype, and will replace +# by +# +# Generated languages need a language named 'PHP/PHP', which shall take care of PHP hl itself +# and which will be called every time something like +# License: LGPL + +my $file = ""; + +open(my $input, '<:encoding(UTF-8)', $ARGV[0]) + or die "Could not open file '$ARGV[0]': $!"; + +open(my $output, '>:encoding(UTF-8)', $ARGV[1]) + or die "Could not open file '$ARGV[1]': $!"; + +my $language = $ARGV[1]; +if ($language =~ /-php\.xml$/) +{ + $language = "PHP"; +} +else +{ + $language = "Twig"; +} + +while (<$input>) +{ + $file .= $_; +} + +$warning = "\n\n\n"; + +$file =~ s/(?=]+)priority="[^"]*"/]+)name="[^"]*"/]+)section="[^"]*"/]+)extensions="[^"]*"/]+)mimetype="[^"]*"/]+)*/]+)extensions="[^"]*"/]+)mimetype="[^"]*"/]+)hidden="[^"]*"/]+)section="[^"]*"/]+)mimetype="[^"]*"/]+)name="([^"]*)"/]+)extensions="[^"]*"/.*?<\/list>/$1##$syntaxName<\/include><\/list>/gs; + +$file =~ s/]+)kateversion="[^"]*"///gs; + } +} +elsif ($root == 1 || $ARGV[0] =~ /mustache.xml$/) +{ + $file =~ s/<(?:RegExpr (attribute="Processing Instruction" context="PI"|context="PI" attribute="Processing Instruction")|itemData name="Processing Instruction")[^\/]+\/>|//gs; +} + +my $find_language = "##$language/$language"; +my $language_suffix = "/$language"; +if ($language eq "PHP") +{ + $find_language = "FindPHP"; +} + +$file =~ s/]*)context="([^"#]*)##(?!Alerts|Comments|Doxygen|Modelines)([^"]+)"/]*[^>\/]>)/$1\n/g; +$file =~ s/(]*[^>\/])\s*\/>/$1>\n\n<\/context>/g; + +if ($language eq "PHP") +{ + $findphp = "\n\n\n"; + $file =~ s/(?=<\/contexts\s*>)/$findphp/; +} + +print $output $file; +print $output $warning; diff --git a/src/libs/3rdparty/syntax-highlighting/data/generators/generate-nginx-lists.rb b/src/libs/3rdparty/syntax-highlighting/data/generators/generate-nginx-lists.rb new file mode 100644 index 00000000000..577dea47c4c --- /dev/null +++ b/src/libs/3rdparty/syntax-highlighting/data/generators/generate-nginx-lists.rb @@ -0,0 +1,55 @@ +#!/usr/bin/env ruby +# +# Generates the keyword lists for directives and variables used in nginx and +# prints them to stdout, ready to be copy & pasted into nginx.xml. +# +# SPDX-FileCopyrightText: 2023 Georg Gadinger +# SPDX-License-Identifier: MIT +# +# Usage: +# % ./generate-nginx-lists.rb +# +# if you want to install the required dependencies provide `INSTALL_GEMS` in +# your ENV: +# % INSTALL_GEMS=1 ./generate-nginx-lists.rb + +require "bundler/inline" + +gemfile(ENV["INSTALL_GEMS"]) do + source "https://rubygems.org" + + gem "nokogiri", "~> 1.14" + gem "faraday", "~> 2.7" + gem "builder", "~> 3.2" +end + +def fetch_vars(url) + Faraday.get(url) + .then { Nokogiri::HTML.parse _1.body } + .css("div#content a[href]") + .map(&:text) + .reject { _1.end_with?("_") } # some vars are just a prefix, ignore those + .sort + .uniq +end + +def build_xml_list(name, url: nil, items: []) + builder = Builder::XmlMarkup.new(indent: 2) + + builder.comment! "see #{url} for a full list of #{name}" + builder.list(name:) do |b| + items.each do |item| + b.item item + end + end +end + +{ + directives: "https://nginx.org/en/docs/dirindex.html", + variables: "https://nginx.org/en/docs/varindex.html", +}.each do |name, url| + items = fetch_vars(url) + + puts build_xml_list(name, url:, items:).gsub(/^/, ' ' * 4) + puts +end diff --git a/src/libs/3rdparty/syntax-highlighting/data/generators/generate-php.pl b/src/libs/3rdparty/syntax-highlighting/data/generators/generate-php.pl deleted file mode 100644 index a516332ef2f..00000000000 --- a/src/libs/3rdparty/syntax-highlighting/data/generators/generate-php.pl +++ /dev/null @@ -1,78 +0,0 @@ -#!/usr/bin/perl - -# This perl script read stdin and write on stdout. It shall be an XML language file. -# -# * If the name of the language is 'HTML', then it creates the language 'PHP (HTML)' -# which shall be used for PHP hl. -# -# * If the name of the language is something else (say '*'), it creates the language '*/PHP'. -# This new language is the same as the old one, but is able to detect PHP everywhere. -# -# This script will correctly set extensions & mimetype, and will replace -# by -# -# Generated languages need a language named 'PHP/PHP', which shall take care of PHP hl itself -# and which will be called every time something like -# License: LGPL - -my $file = ""; - -open(my $input, '<:encoding(UTF-8)', $ARGV[0]) - or die "Could not open file '$ARGV[0]': $!"; - -open(my $output, '>:encoding(UTF-8)', $ARGV[1]) - or die "Could not open file '$ARGV[1]': $!"; - -while (<$input>) -{ - $file .= $_; -} - -$warning = "\n\n\n"; - -$file =~ s/(?=]+name="HTML"/) -{ - $root = 1; -} - -if ($root == 1) -{ - $file =~ s/]+)name="[^"]*"/]+)section="[^"]*"/]+)extensions="[^"]*"/]+)mimetype="[^"]*"/]+)*/]+hidden="[^"]*"/) { - $file =~ s/]+)name="([^"]*)"/]+)hidden="[^"]*"/]+)name="([^"]*)"/' else sep + return f'{sep}{seq}\n{end}{m[3]}' + + current_at_rules.update(item_extractor.findall(m[2])) + return m[0] + + +css_content = css_filename.read_text() +original_css_content = css_content + +names = f"{'|'.join(css_replacements)}|at-rules(?: definitions)?" +css_content = re.sub(rf'(.*?)(|)', + _css_update_and_extract_items, css_content, flags=re.DOTALL) + +_regexpr_unit_prefix = r'( None: + at_rule_added = new_at_rules - old_at_rules + at_rule_removed = old_at_rules - new_at_rules + nl = '\n ' + if at_rule_added or at_rule_removed: + print(f"""\x1b[31m{language} At-rules requires a manual update +New ({len(at_rule_added)}):\x1b[0m + {nl.join(at_rule_added)} +\x1b[31mRemoved ({len(at_rule_removed)}):\x1b[0m + {nl.join(at_rule_removed)}""") + +show_at_rule_difference('CSS', current_at_rules, at_rules) + +# +# Extract SCSS data +# + +scss_functions:list[str] = [] +scss_at_rules:set[str] = {'@content', '@return'} + +_function_list_extractor = re.compile(r'{% function (.*?) %}') +_function_extractor = re.compile(r"'([-._a-zA-Z0-9]+)\(") +_at_rule_extractor = re.compile(r'@[-a-z0-9]+') + +for md in sorted(scss_dir.glob('source/documentation/modules/**/*.md')): + func_list = _function_list_extractor.findall(md.read_text()) + func_items = set(_function_extractor.findall(''.join(func_list))) + scss_functions.append(f'\n{sep}') + scss_functions.extend(f'{sep}{func}' for func in sorted(func_items - functions)) + +for md in scss_dir.glob('source/documentation/at-rules/**/*.md'): + with open(md) as f: + f.readline() + scss_at_rules.update(_at_rule_extractor.findall(f.readline())) + +subproperties = set( + '-'.join(splitted[i:n]) + for prop in properties + for splitted in (prop.rsplit('-', prop.count('-') - 1) # '-aaa-bbb' -> ['-aaa', 'bbb'] + if prop.startswith('-') + else prop.split('-'), ) # 'aaa-bbb' -> ['aaa', 'bbb'] + for i in range(len(splitted)) + for n in range(i+1, len(splitted)+1) +) + +# +# Update SCSS +# + +scss_current_at_rules = set() + +def _scss_update_and_extract_items(m) -> str: + name = m[1] + + if name == 'functions': + return f""" + functions##CSS + + {f''.join(scss_functions)} + """ + + if name == 'at-rules': + scss_current_at_rules.update(_at_rule_extractor.findall(m[2])) + return m[0] + + # sub-properties + items = f'{sep}'.join(sorted(subproperties - properties)) + return f'{sep}{items}\n ' + +scss_content = scss_filename.read_text() +original_scss_content = scss_content + +scss_content = re.sub(r'(.*?)', + _scss_update_and_extract_items, scss_content, count=3, flags=re.DOTALL) + +scss_content = re.sub(r'', + f'', + scss_content, count=1) + +scss_content = regexpr_unit_extractor.sub('\\1' + "|".join(units), scss_content, 1) + +if original_scss_content != scss_content: + scss_content = update_version(scss_content) + scss_filename.write_text(scss_content) + +show_at_rule_difference('SCSS', scss_current_at_rules, scss_at_rules) diff --git a/src/libs/3rdparty/syntax-highlighting/data/generators/update_less.py b/src/libs/3rdparty/syntax-highlighting/data/generators/update_less.py new file mode 100644 index 00000000000..d509aeabe77 --- /dev/null +++ b/src/libs/3rdparty/syntax-highlighting/data/generators/update_less.py @@ -0,0 +1,45 @@ +#!/usr/bin/env python3 +# SPDX-FileCopyrightText: 2023 Jonathan Poelen +# SPDX-License-Identifier: MIT + +from pathlib import Path +from urllib import request +import re +import sys + + +if len(sys.argv) < 1: + print(f'{sys.argv[0]} syntax/less.xml', file=sys.stderr) + exit(1) + +# +# Extract functions +# + +data = request.urlopen('https://lesscss.org/functions/').read().decode() + +functions = re.findall(r'([-_\w\d]+)
', data, flags=re.DOTALL) +functions.append('%') + +# +# Update syntax +# + +sep = '\n ' +new_list = f""" + functions##CSS + + + {f'{sep}'.join(sorted(functions))} + """ + +less_filename = Path(sys.argv[1]) +less_content = less_filename.read_text() +original_less_content = less_content +less_content = re.sub(r'.*?', + new_list, less_content, count=1, flags=re.DOTALL) + +if original_less_content != less_content: + less_content = re.sub(' version="(\d+)" ', lambda m: f' version="{int(m[1])+1}" ', + less_content, count=1) + less_filename.write_text(less_content) diff --git a/src/libs/3rdparty/syntax-highlighting/data/schema/language.xsd b/src/libs/3rdparty/syntax-highlighting/data/schema/language.xsd index fdea0dd7521..b6402194144 100644 --- a/src/libs/3rdparty/syntax-highlighting/data/schema/language.xsd +++ b/src/libs/3rdparty/syntax-highlighting/data/schema/language.xsd @@ -6,39 +6,22 @@ SPDX-FileCopyrightText: 2005 Dominik Haumann SPDX-FileCopyrightText: 2008 Wilbert Berendsen - This file describes the XML format used for syntax highlight descriptions - for the Kate text editor (http://kate.kde.org), which is part of the KDE - desktop environment (http://www.kde.org). - You'll find the "Writing a Kate Highlighting XML File HOWTO" at - http://kate.kde.org/doc/hlhowto.php + This file describes the XML format used for syntax highlight descriptions + for the Kate text editor (https://kate-editor.org), which is part of the + KDE desktop environment (https://kde.org). + You'll find the "Working with Syntax Highlighting" at + https://docs.kde.org/stable5/en/kate/katepart/highlight.html - This format is identified using the SYSTEM identifier - SYSTEM "language.dtd" + You can validate your syntax files using "validatehl.sh yourSyntax.xml". + This needs xmllint from the libxml2 XML library. - Files using this format should include a DOCTYPE declaration like this: - - - You can validate your syntax files using "validatehl.sh yourSyntax.xml". - This needs xmllint from the libxml2 XML library. - - In any case, the katehighlightingindexer will validate all files bundled - with KTextEditor during compile time and fail on errors. - - To use your syntax file, copy it to ~/.local/share/katepart5/syntax/ in - your home directory. You have to open a new instance of kwrite/kate to use - the new syntax file. + In any case, the katehighlightingindexer will validate all files bundled + with KTextEditor during compile time and fail on errors. TODO - find a more readable way for the - -dtdvalid stuff, it's just annoying xml comments don't allow it. --> - @@ -160,6 +136,7 @@ + @@ -317,20 +294,18 @@ context specification name: The name of this context specification. Used in '*Context' attributes [optional] attribute: The name of the ItemData to be used for matching text - lineEndContext: Next context if end of line is encountered - lineEmptyContext: Next context if an empty line is encountered [optional] + lineEndContext: Next context if end of line is encountered [optional, default='#stay'] + lineEmptyContext: Next context if an empty line is encountered [optional, default=value of lineEndContext] fallthrough: Use a fallthrough context [optional] deprecated since 5.62 but preserved to maintain compatibility in older versions of KF5 - fallthroughContext: Fall through to this context [optional] + fallthroughContext: Fall through to this context [optional, default='#stay'] dynamic: Dynamic context [boolean, optional] + deprecated since always but preserved to maintain compatibility in older versions of KF5 noIndentationBasedFolding: Python uses indentation based folding. However, Python has parts where - it does not use indentation based folding (e.g. for """ strings). In this case - switch to an own context and set this attribute to true. Then the indentation - based folding will ignore this parts and not change folding markers. [optional] - - TODO: - - Explain fallthrough. - - Make lineEndContext optional, defaults to '#stay'. Reasonable? + it does not use indentation based folding (e.g. for """ strings). In this case + switch to an own context and set this attribute to true. Then the indentation + based folding will ignore this parts and not change folding markers. [optional] + stopEmptyLineContextSwitchLoop: Do not continue the context switching if an empty line is encountered. [boolean, optional, default=false] --> @@ -356,11 +331,11 @@ - + - + @@ -368,8 +343,11 @@ + + + @@ -504,12 +479,9 @@ @@ -523,9 +495,6 @@ String: The string to look for insensitive: Whether the string is matched case INsensitive. [boolean, optional, default=false] dynamic: Uses %1 .. %9 as placeholders for dynamic arguments [boolean, optional, default=false] - - TODO - - What's default of insensitive? I'm not sure... --> @@ -542,9 +511,6 @@ insensitive: Whether the string is matched case INsensitive. [boolean, optional, default=false] weakDeliminator: Add weak deliminators [optional] additionalDeliminator: Add deliminators [optional] - - TODO - - What's default of insensitive? I'm not sure... --> @@ -560,7 +526,7 @@ commonAttributes: Common attributes String: The regular expression pattern insensitive: Whether the text is matched case INsensitive. [boolean, optional, default=false] - minimal: Wheather to use minimal matching for wild cards in the pattern [boolean, optional, default='false'] + minimal: Wheather to use minimal matching for wild cards in the pattern [boolean, optional, default=false] dynamic: Uses %1 .. %9 as placeholders for dynamic arguments [boolean, optional, default=false] --> @@ -584,11 +550,8 @@ @@ -596,7 +559,7 @@ + diff --git a/src/libs/3rdparty/syntax-highlighting/data/syntax/bash.xml b/src/libs/3rdparty/syntax-highlighting/data/syntax/bash.xml index 84d0cf84183..b3e8334fdaa 100644 --- a/src/libs/3rdparty/syntax-highlighting/data/syntax/bash.xml +++ b/src/libs/3rdparty/syntax-highlighting/data/syntax/bash.xml @@ -1,5 +1,5 @@ - @@ -66,7 +66,7 @@ - + @@ -1005,13 +1005,15 @@ - + + - + + @@ -1019,7 +1021,8 @@ - + + @@ -1046,8 +1049,9 @@ - - + + + @@ -1073,7 +1077,7 @@ - + @@ -1081,27 +1085,32 @@ - + + + + + + + - + - - + - + - - + @@ -1262,6 +1271,7 @@ + @@ -1270,6 +1280,8 @@ + + @@ -1277,6 +1289,10 @@ + + + + @@ -1352,7 +1368,7 @@ - + diff --git a/src/libs/3rdparty/syntax-highlighting/data/syntax/cmake.xml b/src/libs/3rdparty/syntax-highlighting/data/syntax/cmake.xml index 053d983c343..256619d3ff8 100644 --- a/src/libs/3rdparty/syntax-highlighting/data/syntax/cmake.xml +++ b/src/libs/3rdparty/syntax-highlighting/data/syntax/cmake.xml @@ -1,5 +1,5 @@ - @@ -12,7 +12,7 @@ SPDX-FileCopyrightText: 2004 Alexander Neundorf SPDX-FileCopyrightText: 2005 Dominik Haumann SPDX-FileCopyrightText: 2007, 2008, 2013, 2014 Matthew Woehlke - SPDX-FileCopyrightText: 2013-2015, 2017-2020 Alex Turbov + SPDX-FileCopyrightText: 2013-2015, 2017-2023 Alex Turbov SPDX-License-Identifier: LGPL-2.0-or-later --> @@ -25,8 +25,8 @@ add_test aux_source_directory build_command + cmake_file_api create_test_sourcelist define_property enable_language @@ -192,6 +193,7 @@ HOST HOSTNAME IS_64BIT + MSYSTEM_PREFIX NUMBER_OF_LOGICAL_CORES NUMBER_OF_PHYSICAL_CORES OS_NAME @@ -729,6 +731,7 @@ CHECK_FAIL CHECK_PASS CHECK_START + CONFIGURE_LOG DEBUG DEPRECATION FATAL_ERROR @@ -849,9 +852,11 @@ COMMAND_EXPAND_LISTS COMMENT DEPENDS + DEPENDS_EXPLICIT_ONLY DEPFILE IMPLICIT_DEPENDS JOB_POOL + JOB_SERVER_AWARE MAIN_DEPENDENCY OUTPUT POST_BUILD @@ -873,6 +878,7 @@ DEPFILE IMPLICIT_DEPENDS JOB_POOL + JOB_SERVER_AWARE SOURCES USES_TERMINAL VERBATIM @@ -914,6 +920,14 @@ PARALLEL_LEVEL TARGET + + API_VERSION + CACHE + CMAKEFILES + CODEMODEL + QUERY + TOOLCHAINS + EXTRA_INCLUDE FUNCTION @@ -937,6 +951,7 @@ ASM ASM-ATT + ASM_MARMASM ASM_MASM ASM_NASM C @@ -965,6 +980,9 @@ DIRECTORY TARGET_DIRECTORY + + DIRECTORY + AFTER BEFORE @@ -1045,7 +1063,7 @@ AFTER BEFORE - + debug general optimized @@ -1085,6 +1103,10 @@ PROPERTIES TARGET_DIRECTORY + + DIRECTORY + PROPERTIES + FILES PREFIX @@ -1112,6 +1134,7 @@ cuda_std_17 cuda_std_20 cuda_std_23 + cuda_std_26 cxx_aggregate_default_initializers cxx_alias_templates cxx_alignas @@ -1206,6 +1229,10 @@ PUBLIC TYPE + + CXX_MODULES + HEADERS + BINARY_DIR CMAKE_FLAGS @@ -1214,7 +1241,9 @@ COPY_FILE_ERROR LINK_LIBRARIES LINK_OPTIONS + LOG_DESCRIPTION NO_CACHE + NO_LOG OUTPUT_VARIABLE PROJECT SOURCES @@ -1234,7 +1263,9 @@ COPY_FILE_ERROR LINK_LIBRARIES LINK_OPTIONS + LOG_DESCRIPTION NO_CACHE + NO_LOG OUTPUT_VARIABLE RUN_OUTPUT_STDERR_VARIABLE RUN_OUTPUT_STDOUT_VARIABLE @@ -1563,6 +1594,7 @@ BUILD_BYPRODUCTS BUILD_COMMAND BUILD_IN_SOURCE + BUILD_JOB_SERVER_AWARE CMAKE_ARGS CMAKE_CACHE_ARGS CMAKE_CACHE_DEFAULT_ARGS @@ -1601,6 +1633,7 @@ HTTP_USERNAME INACTIVITY_TIMEOUT INDEPENDENT_STEP_TARGETS + INSTALL_BYPRODUCTS INSTALL_COMMAND INSTALL_DIR LIST_SEPARATOR @@ -1666,6 +1699,7 @@ DEPENDS EXCLUDE_FROM_MAIN INDEPENDENT + JOB_SERVER_AWARE LOG USES_TERMINAL WORKING_DIRECTORY @@ -1708,6 +1742,8 @@ DOWNLOAD_NAME DOWNLOAD_NO_EXTRACT DOWNLOAD_NO_PROGRESS + EXCLUDE_FROM_ALL + FIND_PACKAGE_ARGS GIT_CONFIG GIT_PROGRESS GIT_REMOTE_NAME @@ -1725,6 +1761,7 @@ INACTIVITY_TIMEOUT NETRC NETRC_FILE + OVERRIDE_FIND_PACKAGE PATCH_COMMAND SOURCE_SUBDIR SVN_PASSWORD @@ -1946,6 +1983,7 @@ ALL COMMENT + CONFIG_FILE USE_STAMP_FILE WORKING_DIRECTORY @@ -2009,6 +2047,9 @@ REQUIRED STATIC_TARGET + + DEFINE_VARIABLES + DESCRIPTORS EXPORT_MACRO @@ -2081,6 +2122,7 @@ CABLE_INCLUDE_DIR CABLE_TCL_LIBRARY CMAKE_ABSOLUTE_DESTINATION_FILES + CMAKE_ADD_CUSTOM_COMMAND_DEPENDS_EXPLICIT_ONLY CMAKE_AIX_EXPORT_ALL_SYMBOLS CMAKE_ANDROID_ANT_ADDITIONAL_OPTIONS CMAKE_ANDROID_API @@ -2116,15 +2158,19 @@ CMAKE_ARGC CMAKE_AUTOGEN_ORIGIN_DEPENDS CMAKE_AUTOGEN_PARALLEL + CMAKE_AUTOGEN_USE_SYSTEM_INCLUDE CMAKE_AUTOGEN_VERBOSE CMAKE_AUTOMOC CMAKE_AUTOMOC_DEPEND_FILTERS + CMAKE_AUTOMOC_EXECUTABLE CMAKE_AUTOMOC_MOC_OPTIONS CMAKE_AUTOMOC_PATH_PREFIX CMAKE_AUTOMOC_RELAXED_MODE CMAKE_AUTORCC + CMAKE_AUTORCC_EXECUTABLE CMAKE_AUTORCC_OPTIONS CMAKE_AUTOUIC + CMAKE_AUTOUIC_EXECUTABLE CMAKE_AUTOUIC_OPTIONS CMAKE_AUTOUIC_SEARCH_PATHS CMAKE_BACKWARDS_COMPATIBILITY @@ -2185,6 +2231,7 @@ CMAKE_CXX_EXTENSIONS CMAKE_CXX_LINK_NO_PIE_SUPPORTED CMAKE_CXX_LINK_PIE_SUPPORTED + CMAKE_CXX_SCAN_FOR_MODULES CMAKE_CXX_STANDARD CMAKE_CXX_STANDARD_REQUIRED CMAKE_C_COMPILE_FEATURES @@ -2200,6 +2247,7 @@ CMAKE_DEPENDS_IN_PROJECT_ONLY CMAKE_DIRECTORY_LABELS CMAKE_DISABLE_PRECOMPILE_HEADERS + CMAKE_DLL_NAME_WITH_SOVERSION CMAKE_DL_LIBS CMAKE_DOTNET_SDK CMAKE_DOTNET_TARGET_FRAMEWORK @@ -2210,9 +2258,9 @@ CMAKE_ECLIPSE_RESOURCE_ENCODING CMAKE_ECLIPSE_VERSION CMAKE_EDIT_COMMAND - CMAKE_ENABLE_EXPORTS CMAKE_ERROR_DEPRECATED CMAKE_ERROR_ON_ABSOLUTE_INSTALL_DESTINATION + CMAKE_EXECUTABLE_ENABLE_EXPORTS CMAKE_EXECUTABLE_SUFFIX CMAKE_EXECUTE_PROCESS_COMMAND_ECHO CMAKE_EXE_LINKER_FLAGS @@ -2286,6 +2334,7 @@ CMAKE_HIP_EXTENSIONS CMAKE_HIP_LINK_NO_PIE_SUPPORTED CMAKE_HIP_LINK_PIE_SUPPORTED + CMAKE_HIP_PLATFORM CMAKE_HIP_STANDARD CMAKE_HIP_STANDARD_REQUIRED CMAKE_HOST_APPLE @@ -2360,7 +2409,6 @@ CMAKE_INSTALL_SYSTEM_RUNTIME_LIBS_SKIP CMAKE_INSTALL_UCRT_LIBRARIES CMAKE_INTERPROCEDURAL_OPTIMIZATION - CMAKE_IOS_INSTALL_COMBINED CMAKE_ISPC_HEADER_DIRECTORY CMAKE_ISPC_HEADER_SUFFIX CMAKE_ISPC_INSTRUCTION_SETS @@ -2378,6 +2426,7 @@ CMAKE_LIBRARY_PATH_FLAG CMAKE_LINK_DEF_FILE_FLAG CMAKE_LINK_DEPENDS_NO_SHARED + CMAKE_LINK_DEPENDS_USE_LINKER CMAKE_LINK_DIRECTORIES_BEFORE CMAKE_LINK_INTERFACE_LIBRARIES CMAKE_LINK_LIBRARIES_ONLY_TARGETS @@ -2436,6 +2485,7 @@ CMAKE_PCH_INSTANTIATE_TEMPLATES CMAKE_PCH_WARN_INVALID CMAKE_PDB_OUTPUT_DIRECTORY + CMAKE_PLATFORM_NO_VERSIONED_SONAME CMAKE_POSITION_INDEPENDENT_CODE CMAKE_PREFIX_PATH CMAKE_PROGRAM_PATH @@ -2460,6 +2510,7 @@ CMAKE_ROOT CMAKE_RUNTIME_OUTPUT_DIRECTORY CMAKE_SCRIPT_MODE_FILE + CMAKE_SHARED_LIBRARY_ENABLE_EXPORTS CMAKE_SHARED_LIBRARY_PREFIX CMAKE_SHARED_LIBRARY_SUFFIX CMAKE_SHARED_LINKER_FLAGS @@ -2520,6 +2571,10 @@ CMAKE_VERIFY_INTERFACE_HEADER_SETS CMAKE_VERSION CMAKE_VISIBILITY_INLINES_HIDDEN + CMAKE_VS_DEBUGGER_COMMAND + CMAKE_VS_DEBUGGER_COMMAND_ARGUMENTS + CMAKE_VS_DEBUGGER_ENVIRONMENT + CMAKE_VS_DEBUGGER_WORKING_DIRECTORY CMAKE_VS_DEVENV_COMMAND CMAKE_VS_GLOBALS CMAKE_VS_INCLUDE_INSTALL_TO_DEFAULT_BUILD @@ -2529,9 +2584,12 @@ CMAKE_VS_NUGET_PACKAGE_RESTORE CMAKE_VS_NsightTegra_VERSION CMAKE_VS_PLATFORM_NAME + CMAKE_VS_PLATFORM_NAME_DEFAULT CMAKE_VS_PLATFORM_TOOLSET CMAKE_VS_PLATFORM_TOOLSET_CUDA + CMAKE_VS_PLATFORM_TOOLSET_CUDA_CUSTOM_DIR CMAKE_VS_PLATFORM_TOOLSET_HOST_ARCHITECTURE + CMAKE_VS_PLATFORM_TOOLSET_VERSION CMAKE_VS_SDK_EXCLUDE_DIRECTORIES CMAKE_VS_SDK_EXECUTABLE_DIRECTORIES CMAKE_VS_SDK_INCLUDE_DIRECTORIES @@ -2539,6 +2597,11 @@ CMAKE_VS_SDK_LIBRARY_WINRT_DIRECTORIES CMAKE_VS_SDK_REFERENCE_DIRECTORIES CMAKE_VS_SDK_SOURCE_DIRECTORIES + CMAKE_VS_TARGET_FRAMEWORK_IDENTIFIER + CMAKE_VS_TARGET_FRAMEWORK_TARGETS_VERSION + CMAKE_VS_TARGET_FRAMEWORK_VERSION + CMAKE_VS_VERSION_BUILD_NUMBER + CMAKE_VS_WINDOWS_TARGET_PLATFORM_MIN_VERSION CMAKE_VS_WINDOWS_TARGET_PLATFORM_VERSION CMAKE_VS_WINDOWS_TARGET_PLATFORM_VERSION_MAXIMUM CMAKE_VS_WINRT_BY_DEFAULT @@ -2653,6 +2716,16 @@ CPACK_EXTERNAL_ENABLE_STAGING CPACK_EXTERNAL_PACKAGE_SCRIPT CPACK_EXTERNAL_REQUESTED_VERSIONS + CPACK_FREEBSD_PACKAGE_CATEGORIES + CPACK_FREEBSD_PACKAGE_COMMENT + CPACK_FREEBSD_PACKAGE_DEPS + CPACK_FREEBSD_PACKAGE_DESCRIPTION + CPACK_FREEBSD_PACKAGE_LICENSE + CPACK_FREEBSD_PACKAGE_LICENSE_LOGIC + CPACK_FREEBSD_PACKAGE_MAINTAINER + CPACK_FREEBSD_PACKAGE_NAME + CPACK_FREEBSD_PACKAGE_ORIGIN + CPACK_FREEBSD_PACKAGE_WWW CPACK_GENERATOR CPACK_IFW_ADMIN_TARGET_DIRECTORY CPACK_IFW_ARCHIVE_COMPRESSION @@ -2701,6 +2774,26 @@ CPACK_IFW_TARGET_DIRECTORY CPACK_IFW_VERBOSE CPACK_INCLUDE_TOPLEVEL_DIRECTORY + CPACK_INNOSETUP_ALLOW_CUSTOM_DIRECTORY + CPACK_INNOSETUP_ARCHITECTURE + CPACK_INNOSETUP_CODE_FILES + CPACK_INNOSETUP_CREATE_UNINSTALL_LINK + CPACK_INNOSETUP_CUSTOM_INSTALL_INSTRUCTIONS + CPACK_INNOSETUP_EXECUTABLE + CPACK_INNOSETUP_EXECUTABLE_ARGUMENTS + CPACK_INNOSETUP_EXTRA_SCRIPTS + CPACK_INNOSETUP_ICON_FILE + CPACK_INNOSETUP_IGNORE_LICENSE_PAGE + CPACK_INNOSETUP_IGNORE_README_PAGE + CPACK_INNOSETUP_INSTALL_ROOT + CPACK_INNOSETUP_LANGUAGES + CPACK_INNOSETUP_MENU_LINKS + CPACK_INNOSETUP_PASSWORD + CPACK_INNOSETUP_PROGRAM_MENU_FOLDER + CPACK_INNOSETUP_RUN_EXECUTABLES + CPACK_INNOSETUP_USE_CMAKE_BOOL_FORMAT + CPACK_INNOSETUP_USE_MODERN_WIZARD + CPACK_INNOSETUP_VERIFY_DOWNLOADS CPACK_INSTALLED_DIRECTORIES CPACK_INSTALL_CMAKE_PROJECTS CPACK_INSTALL_COMMANDS @@ -2988,6 +3081,7 @@ CUDAToolkit_NVCC_EXECUTABLE CUPS_INCLUDE_DIR CURL_NO_CURL_CMAKE + CURL_USE_STATIC_LIBS CURSES_CFLAGS CURSES_HAVE_CURSES_H CURSES_HAVE_NCURSES_CURSES_H @@ -3006,6 +3100,7 @@ DVIPDF_CONVERTER DVIPS_CONVERTER EXECUTABLE_OUTPUT_PATH + EXPAT_USE_STATIC_LIBS EnvModules_COMMAND ExternalData_BINARY_ROOT ExternalData_CUSTOM_ERROR @@ -3434,9 +3529,11 @@ + CMAKE_ENABLE_EXPORTS CMAKE_FILES_DIRECTORY CMAKE_HOME_DIRECTORY CMAKE_INTERNAL_PLATFORM_ABI + CMAKE_IOS_INSTALL_COMBINED CMAKE_NOT_USING_CONFIG_FLAGS CMAKE_OBJDUMP CMAKE_SUPPRESS_DEVELOPER_ERRORS @@ -3463,6 +3560,7 @@ CMAKE_COLOR_DIAGNOSTICS CMAKE_CONFIGURATION_TYPES CMAKE_CONFIG_TYPE + CMAKE_CROSSCOMPILING_EMULATOR CMAKE_EXPORT_COMPILE_COMMANDS CMAKE_FRAMEWORK_PATH CMAKE_GENERATOR @@ -3477,6 +3575,7 @@ CMAKE_TOOLCHAIN_FILE CSFLAGS CTEST_INTERACTIVE_DEBUG_MODE + CTEST_NO_TESTS_ACTION CTEST_OUTPUT_ON_FAILURE CTEST_PARALLEL_LEVEL CTEST_PROGRESS_OUTPUT @@ -3612,6 +3711,7 @@ AUTOGEN_BUILD_DIR AUTOGEN_ORIGIN_DEPENDS AUTOGEN_TARGET_DEPENDS + AUTOGEN_USE_SYSTEM_INCLUDE AUTOMOC AUTOMOC_COMPILER_PREDEFINES AUTOMOC_DEPEND_FILTERS @@ -3647,7 +3747,10 @@ COMPILE_WARNING_AS_ERROR CROSSCOMPILING_EMULATOR CUDA_ARCHITECTURES + CUDA_CUBIN_COMPILATION CUDA_EXTENSIONS + CUDA_FATBIN_COMPILATION + CUDA_OPTIX_COMPILATION CUDA_PTX_COMPILATION CUDA_RESOLVE_DEVICE_SYMBOLS CUDA_RUNTIME_LIBRARY @@ -3655,6 +3758,10 @@ CUDA_STANDARD CUDA_STANDARD_REQUIRED CXX_EXTENSIONS + CXX_MODULE_DIRS + CXX_MODULE_SET + CXX_MODULE_SETS + CXX_SCAN_FOR_MODULES CXX_STANDARD CXX_STANDARD_REQUIRED C_EXTENSIONS @@ -3665,6 +3772,7 @@ DEPLOYMENT_REMOTE_DIRECTORY DEPRECATION DISABLE_PRECOMPILE_HEADERS + DLL_NAME_WITH_SOVERSION DOTNET_SDK DOTNET_TARGET_FRAMEWORK DOTNET_TARGET_FRAMEWORK_VERSION @@ -3715,10 +3823,12 @@ INSTALL_REMOVE_ENVIRONMENT_RPATH INSTALL_RPATH INSTALL_RPATH_USE_LINK_PATH + INTERFACE_AUTOMOC_MACRO_NAMES INTERFACE_AUTOUIC_OPTIONS INTERFACE_COMPILE_DEFINITIONS INTERFACE_COMPILE_FEATURES INTERFACE_COMPILE_OPTIONS + INTERFACE_CXX_MODULE_SETS INTERFACE_HEADER_SETS INTERFACE_HEADER_SETS_TO_VERIFY INTERFACE_INCLUDE_DIRECTORIES @@ -3896,6 +4006,7 @@ COMPILE_DEFINITIONS COMPILE_FLAGS COMPILE_OPTIONS + CXX_SCAN_FOR_MODULES EXTERNAL_OBJECT Fortran_FORMAT Fortran_PREPROCESS @@ -3913,6 +4024,7 @@ SKIP_AUTOMOC SKIP_AUTORCC SKIP_AUTOUIC + SKIP_LINTING SKIP_PRECOMPILE_HEADERS SKIP_UNITY_BUILD_INCLUSION SYMBOLIC @@ -3952,18 +4064,22 @@ FIXTURES_CLEANUP FIXTURES_REQUIRED FIXTURES_SETUP + GENERATED_RESOURCE_SPEC_FILE LABELS MEASUREMENT PASS_REGULAR_EXPRESSION PROCESSORS PROCESSOR_AFFINITY REQUIRED_FILES + RESOURCE_GROUPS RESOURCE_LOCK RUN_SERIAL SKIP_REGULAR_EXPRESSION SKIP_RETURN_CODE TIMEOUT TIMEOUT_AFTER_MATCH + TIMEOUT_SIGNAL_GRACE_PERIOD + TIMEOUT_SIGNAL_NAME WILL_FAIL WORKING_DIRECTORY @@ -3985,6 +4101,7 @@ + IF 0 1 BOOL @@ -3993,53 +4110,69 @@ NOT STREQUAL EQUAL - IN_LIST VERSION_LESS VERSION_GREATER VERSION_EQUAL VERSION_LESS_EQUAL VERSION_GREATER_EQUAL - PATH_EQUAL - PATH - TARGET_EXISTS - CONFIG - PLATFORM_ID - C_COMPILER_ID - CXX_COMPILER_ID - CUDA_COMPILER_ID - Fortran_COMPILER_ID - C_COMPILER_VERSION - CXX_COMPILER_VERSION - CUDA_COMPILER_VERSION - Fortran_COMPILER_VERSION - TARGET_POLICY - COMPILE_FEATURES - COMPILE_LANG_AND_ID - COMPILE_LANGUAGE - LINK_LANG_AND_ID - LINK_LANGUAGE - DEVICE_LINK - HOST_LINK - LINK_LIBRARY - LINK_GROUP - ANGLE-R - COMMA - SEMICOLON - IF + LOWER_CASE + UPPER_CASE + MAKE_C_IDENTIFIER + IN_LIST JOIN REMOVE_DUPLICATES FILTER - LOWER_CASE - UPPER_CASE - GENEX_EVAL - TARGET_GENEX_EVAL + PATH_EQUAL + SHELL_PATH + CONFIG + OUTPUT_CONFIG + COMMAND_CONFIG + PLATFORM_ID + C_COMPILER_VERSION + CXX_COMPILER_VERSION + CUDA_COMPILER_VERSION + OBJC_COMPILER_VERSION + OBJCXX_COMPILER_VERSION + Fortran_COMPILER_VERSION + HIP_COMPILER_VERSION + ISPC_COMPILER_VERSION + C_COMPILER_ID + CXX_COMPILER_ID + CUDA_COMPILER_ID + OBJC_COMPILER_ID + OBJCXX_COMPILER_ID + Fortran_COMPILER_ID + HIP_COMPILER_ID + ISPC_COMPILER_ID + COMPILE_LANGUAGE + COMPILE_LANG_AND_ID + COMPILE_FEATURES + COMPILE_ONLY + LINK_LANGUAGE + LINK_LANG_AND_ID + LINK_LIBRARY + LINK_GROUP + LINK_ONLY + DEVICE_LINK + HOST_LINK + TARGET_EXISTS TARGET_NAME_IF_EXISTS + TARGET_NAME + TARGET_PROPERTY + TARGET_OBJECTS + TARGET_POLICY TARGET_FILE TARGET_FILE_BASE_NAME TARGET_FILE_PREFIX TARGET_FILE_SUFFIX TARGET_FILE_NAME TARGET_FILE_DIR + TARGET_IMPORT_FILE + TARGET_IMPORT_FILE_BASE_NAME + TARGET_IMPORT_FILE_PREFIX + TARGET_IMPORT_FILE_SUFFIX + TARGET_IMPORT_FILE_NAME + TARGET_IMPORT_FILE_DIR TARGET_LINKER_FILE TARGET_LINKER_FILE_BASE_NAME TARGET_LINKER_FILE_PREFIX @@ -4047,7 +4180,6 @@ TARGET_LINKER_FILE_NAME TARGET_LINKER_FILE_DIR TARGET_SONAME_FILE - TARGET_SONAME_FILE TARGET_SONAME_FILE_NAME TARGET_SONAME_FILE_DIR TARGET_PDB_FILE @@ -4057,18 +4189,67 @@ TARGET_BUNDLE_DIR_NAME TARGET_BUNDLE_DIR TARGET_BUNDLE_CONTENT_DIR - TARGET_PROPERTY TARGET_RUNTIME_DLLS - INSTALL_PREFIX - TARGET_NAME - LINK_ONLY + TARGET_RUNTIME_DLL_DIRS INSTALL_INTERFACE BUILD_INTERFACE - MAKE_C_IDENTIFIER - TARGET_OBJECTS - SHELL_PATH - OUTPUT_CONFIG - COMMAND_CONFIG + BUILD_LOCAL_INTERFACE + INSTALL_PREFIX + GENEX_EVAL + TARGET_GENEX_EVAL + ANGLE-R + COMMA + SEMICOLON + + + LENGTH + GET + SUBLIST + FIND + JOIN + APPEND + PREPEND + INSERT + POP_BACK + POP_FRONT + REMOVE_ITEM + REMOVE_AT + REMOVE_DUPLICATES + FILTER + TRANSFORM + FRANSFORM + REVERSE + SORT + + + HAS_ROOT_NAME + HAS_ROOT_DIRECTORY + HAS_ROOT_PATH + HAS_FILENAME + HAS_EXTENSION + HAS_STEM + HAS_RELATIVE_PART + HAS_PARENT_PATH + IS_ABSOLUTE + IS_RELATIVE + IS_PREFIX + GET_ROOT_NAME + GET_ROOT_DIRECTORY + GET_ROOT_PATH + GET_FILENAME + GET_EXTENSION + GET_STEM + GET_RELATIVE_PART + GET_PARENT_PATH + CMAKE_PATH + APPEND + REMOVE_FILENAME + REPLACE_FILENAME + REMOVE_EXTENSION + REPLACE_EXTENSION + NORMAL_PATH + RELATIVE_PATH + ABSOLUTE_PATH @@ -4126,7 +4307,6 @@ CTestCoverageCollectGCOV CTestScriptMode CTestUseLaunchers - Dart DeployQt4 ExternalData ExternalProject @@ -4171,7 +4351,6 @@ CVS CxxTest Cygwin - Dart DCMTK DevIL Doxygen @@ -4314,6 +4493,7 @@ CMakeExpandImportedTargets CMakeForceCompiler CMakeParseArguments + Dart Documentation MacroAddFileDependencies TestCXXAcceptsFlag @@ -4324,6 +4504,7 @@ WriteBasicConfigVersionFile WriteCompilerDetectionHeader FindCUDA + FindDart FindPythonInterp FindPythonLibs FindQt @@ -4432,6 +4613,7 @@ + @@ -4461,7 +4643,7 @@ - + @@ -4636,7 +4818,7 @@ - + @@ -5227,6 +5409,16 @@ + + + + + + + + + + @@ -5319,6 +5511,7 @@ + @@ -5380,7 +5573,7 @@ - + @@ -5447,7 +5640,7 @@ - + @@ -5530,6 +5723,24 @@ + + + + + + + + + + + + + + + + + + @@ -5562,6 +5773,7 @@ + @@ -6345,6 +6557,16 @@ + + + + + + + + + + @@ -6380,11 +6602,11 @@ - + - + @@ -6409,8 +6631,8 @@ - - + + @@ -6423,7 +6645,7 @@ - + @@ -6549,10 +6771,22 @@ + + + + + + + + + + + + @@ -6582,6 +6816,7 @@ + diff --git a/src/libs/3rdparty/syntax-highlighting/data/syntax/comments.xml b/src/libs/3rdparty/syntax-highlighting/data/syntax/comments.xml index cd66a4133d8..011dc8ab215 100644 --- a/src/libs/3rdparty/syntax-highlighting/data/syntax/comments.xml +++ b/src/libs/3rdparty/syntax-highlighting/data/syntax/comments.xml @@ -1,5 +1,5 @@ - + - - - + + + + + + + ]> - - - + + - + -webkit-line-clamp + -webkit-text-fill-color + -webkit-text-stroke + -webkit-text-stroke-color + -webkit-text-stroke-width accent-color + additive-symbols align-content align-items - alignment-baseline align-self all animation + animation-composition animation-delay animation-direction animation-duration @@ -60,8 +69,8 @@ Changelog: animation-play-state animation-timing-function appearance + ascent-override aspect-ratio - azimuth backdrop-filter backface-visibility background @@ -76,13 +85,8 @@ Changelog: background-position-y background-repeat background-size - baseline-shift - baseline-source - block-ellipsis + base-palette block-size - bookmark-label - bookmark-level - bookmark-state border border-block border-block-color @@ -102,7 +106,6 @@ Changelog: border-bottom-right-radius border-bottom-style border-bottom-width - border-boundary border-collapse border-color border-end-end-radius @@ -149,24 +152,15 @@ Changelog: box-decoration-break box-shadow box-sizing - box-snap break-after break-before break-inside caption-side - caret caret-color - caret-shape - chains clear - clip clip-path - clip-rule color - color-adjust - color-interpolation-filters color-scheme - columns column-count column-fill column-gap @@ -176,6 +170,7 @@ Changelog: column-rule-width column-span column-width + columns contain contain-intrinsic-block-size contain-intrinsic-height @@ -186,30 +181,15 @@ Changelog: container-name container-type content - content-visibility - continue counter-increment counter-reset counter-set - cue - cue-after - cue-before cursor + descent-override direction display - dominant-baseline - elevation empty-cells - fill - fill-break - fill-color - fill-image - fill-opacity - fill-origin - fill-position - fill-repeat - fill-rule - fill-size + fallback filter flex flex-basis @@ -219,12 +199,8 @@ Changelog: flex-shrink flex-wrap float - flood-color - flood-opacity - flow - flow-from - flow-into font + font-display font-family font-feature-settings font-kerning @@ -236,6 +212,7 @@ Changelog: font-stretch font-style font-synthesis + font-synthesis-position font-synthesis-small-caps font-synthesis-style font-synthesis-weight @@ -249,11 +226,8 @@ Changelog: font-variant-position font-variation-settings font-weight - footnote-display - footnote-policy forced-color-adjust gap - glyph-orientation-vertical grid grid-area grid-auto-columns @@ -273,18 +247,12 @@ Changelog: height hyphenate-character hyphenate-limit-chars - hyphenate-limit-last - hyphenate-limit-lines - hyphenate-limit-zone hyphens image-orientation image-rendering - image-resolution - initial-letter - initial-letter-align - initial-letter-wrap + inherits + initial-value inline-size - inline-sizing inset inset-block inset-block-end @@ -296,17 +264,11 @@ Changelog: justify-content justify-items justify-self - leading-trim left letter-spacing - lighting-color line-break - line-clamp - line-grid + line-gap-override line-height - line-height-step - line-padding - line-snap list-style list-style-image list-style-position @@ -322,11 +284,6 @@ Changelog: margin-left margin-right margin-top - margin-trim - marker-end - marker-mid - marker-side - marker-start mask mask-border mask-border-mode @@ -344,28 +301,24 @@ Changelog: mask-repeat mask-size mask-type + math-depth + math-style max-block-size max-height max-inline-size - max-lines max-width min-block-size min-height min-inline-size - min-intrinsic-sizing min-width mix-blend-mode - nav-up - nav-down - nav-left - nav-right + negative object-fit object-position offset offset-anchor offset-distance offset-path - offset-position offset-rotate opacity order @@ -383,11 +336,13 @@ Changelog: overflow-wrap overflow-x overflow-y + override-colors overscroll-behavior overscroll-behavior-block overscroll-behavior-inline overscroll-behavior-x overscroll-behavior-y + pad padding padding-block padding-block-end @@ -403,37 +358,24 @@ Changelog: page-break-after page-break-before page-break-inside + page-orientation paint-order - pause - pause-after - pause-before perspective perspective-origin - pitch - pitch-range place-content place-items place-self - play-during pointer-events position + prefix print-color-adjust quotes - region-fragment + range resize - rest - rest-after - rest-before - richness right rotate - rotation row-gap - ruby-align - ruby-merge - ruby-overhang ruby-position - running scale scroll-behavior scroll-margin @@ -465,58 +407,42 @@ Changelog: scrollbar-gutter scrollbar-width shape-image-threshold - shape-inside shape-margin shape-outside + size + size-adjust speak-as - spatial-navigation-action - spatial-navigation-contain - spatial-navigation-function - speak - speak-header - speak-numeral - speak-punctuation - speech-rate - stress - string-set + src + suffix + symbols + syntax + system tab-size table-layout - text-align-all text-align text-align-last text-combine-upright text-decoration text-decoration-color text-decoration-line - text-decoration-skip - text-decoration-skip-box text-decoration-skip-ink - text-decoration-skip-inset - text-decoration-skip-self - text-decoration-skip-spaces text-decoration-style text-decoration-thickness - text-edge text-emphasis text-emphasis-color text-emphasis-position - text-emphasis-skip text-emphasis-style - text-group-align text-indent text-justify text-orientation text-overflow text-rendering text-shadow - text-space-collapse - text-space-trim - text-spacing text-transform text-underline-offset text-underline-position - text-wrap top + touch-action transform transform-box transform-origin @@ -528,55 +454,50 @@ Changelog: transition-timing-function translate unicode-bidi + unicode-range user-select vertical-align visibility - voice-balance - voice-duration - voice-family - voice-pitch - voice-range - voice-rate - voice-stress - voice-volume - volume white-space widows width will-change - word-boundary-detection - word-boundary-expansion word-break word-spacing - word-wrap - wrap-after - wrap-before - wrap-flow - wrap-inside - wrap-through writing-mode z-index + + + alignment-baseline + baseline-shift + color-interpolation + color-interpolation-filters + dominant-baseline + fill + fill-opacity + fill-rule + flood-color + flood-opacity + marker-end + marker-mid + marker-start + shape-rendering + stop-color + stop-opacity + stroke + stroke-dasharray + stroke-dashoffset + stroke-linecap + stroke-linejoin + stroke-miterlimit + stroke-opacity + text-anchor + vector-effect + + + - -moz-animation - -moz-animation-delay - -moz-animation-direction - -moz-animation-duration - -moz-animation-fill-mode - -moz-animation-iteration-count - -moz-animation-name - -moz-animation-play-state - -moz-animation-timing-function - -moz-appearance - -moz-background-clip - -moz-background-origin - -moz-background-size - -moz-border-image - -moz-border-radius - -moz-border-radius-bottomleft - -moz-border-radius-bottomright - -moz-border-radius-topleft - -moz-border-radius-topright -moz-box-align -moz-box-direction -moz-box-flex @@ -584,80 +505,16 @@ Changelog: -moz-box-ordinal-group -moz-box-orient -moz-box-pack - -moz-box-shadow - -moz-box-sizing -moz-box - -moz-column-count - -moz-column-fill - -moz-column-gap - -moz-column-rule - -moz-column-rule-color - -moz-column-rule-style - -moz-column-rule-width - -moz-columns - -moz-column-width - -moz-hyphens - -moz-opacity - -moz-outline-style - -moz-perspective - -moz-resize - -moz-text-align-last - -moz-text-decoration-color - -moz-text-decoration-line - -moz-text-decoration-style - -moz-transform - -moz-transform-origin - -moz-transform-style - -moz-transition - -moz-transition-delay - -moz-transition-duration - -moz-transition-property - -moz-transition-timing-function - -moz-user-select - -o-background-size -o-linear-gradient - -o-text-overflow - -o-transition - -o-transform-origin konq_bgpos_x konq_bgpos_y - -khtml-background-size - -khtml-border-top-left-radius - -khtml-border-top-right-radius - -khtml-border-bottom-left-radius - -khtml-border-bottom-right-radius - -khtml-border-radius - -khtml-box-shadow - -khtml-opacity - -webkit-appearance - -webkit-animation - -webkit-animation-name - -webkit-animation-duration - -webkit-animation-iteration - -webkit-animation-direction - -webkit-animation-delay - -webkit-animation-play-state - -webkit-animation-fill-mode - -webkit-background-size - -webkit-backface-visibility - -webkit-border-image - -webkit-border-bottom-colors - -webkit-border-left-colors - -webkit-border-radius - -webkit-border-right-colors - -webkit-border-top-colors - -webkit-border-top-left-radius - -webkit-border-top-right-radius - -webkit-border-bottom-left-radius - -webkit-border-bottom-right-radius - -webkit-border-radius-bottomleft - -webkit-border-radius-bottomright -webkit-box-align -webkit-box-direction -webkit-box-flex @@ -665,46 +522,17 @@ Changelog: -webkit-box-orient -webkit-box-pack -webkit-box-reflect - -webkit-box-shadow - -webkit-box-sizing - -webkit-column-count - -webkit-column-gap - -webkit-hyphens -webkit-linear-gradient -webkit-gradient -webkit-overflow-scrolling - -webkit-perspective - -webkit-text-decoration -webkit-text-decoration-skip - -webkit-text-fill-color - -webkit-text-stroke-color - -webkit-text-stroke-width -webkit-text-size-adjust -webkit-tap-highlight-color - -webkit-transform - -webkit-transform-origin - -webkit-transform-style - -webkit-transition - -webkit-transition-property - -webkit-transition-delay - -webkit-transition-duration - -webkit-user-select - zoom - -ms-animation-name - -ms-animation-duration - -ms-animation-iteration - -ms-animation-direction - -ms-animation-delay - -ms-animation-play-state - -ms-animation-fill-mode - -ms-box-sizing -ms-filter -ms-flex -ms-flex-align - -ms-flex-direction - -ms-flex-flow -ms-flex-item-align -ms-flex-line-pack -ms-flex-negative @@ -713,278 +541,537 @@ Changelog: -ms-flex-positive -ms-flex-position -ms-flex-preferred-size - -ms-flex-wrap -ms-interpolation-mode -ms-linear-gradient - -ms-overflow-style -ms-text-size-adjust - -ms-transform - -ms-transition - -ms-user-select auto inherit + initial + revert + revert-layer unset - none - hidden - initial - revert - revert-layer - dotted - dashed - solid - double - groove - ridge - inset - outset - xx-small - x-small - small - medium - large - x-large - xx-large - smaller - larger - italic - oblique - small-caps - normal + -moz-arabic-indic + -moz-bengali + -moz-cjk-earthly-branch + -moz-cjk-heavenly-stem + -moz-devanagari + -moz-gujarati + -moz-gurmukhi + -moz-kannada + -moz-lao + -moz-malayalam + -moz-myanmar + -moz-oriya + -moz-persian + -moz-tamil + -moz-telugu + -moz-thai + absolute + accumulate + add + additive + alias + all + all-petite-caps + all-scroll + all-small-caps + allow-end + alpha + alphabetic + alternate + alternate-reverse + always + anywhere + arabic-indic + armenian + auto-add + auto-fill + auto-fit + avoid + avoid-column + avoid-page + avoid-region + backwards + balance + balance-all + baseline + bengali + bidi-override + bigger + block + block-end + block-start bold bolder - lighter - light - transparent - repeat - repeat-x - repeat-y - no-repeat - baseline - sub - super - top - text-top - middle + border + border-box + both + both-edges bottom - text-bottom - left - right + break-all + break-spaces + break-word + bullets + cambodian + cap-height + capitalize + cell center - justify - konq-center - disc + ch-width circle - square - box + cjk-decimal + cjk-earthly-branch + cjk-heavenly-stem + cjk-ideographic + clip + clone + close-quote + col-resize + collapse + color + color-burn + color-dodge + column + column-reverse + common-ligatures + compact + condensed + contain + content + content-box + contents + context-menu + contextual + copy + cover + crisp-edges + crosshair + currentcolor + cursive + cyclic + dark + darken + dashed decimal decimal-leading-zero - lower-roman - upper-roman - lower-greek - lower-alpha - lower-latin - upper-alpha - upper-latin - hebrew - armenian - georgian - cjk-ideographic - hiragana - katakana - hiragana-iroha - katakana-iroha - list-item - compact - marker - crosshair default - pointer - move + dense + devanagari + diagonal-fractions + difference + disc + disclosure-closed + disclosure-open + discretionary-ligatures + dot + dotted + double + double-circle e-resize - ne-resize - nw-resize - n-resize - se-resize - sw-resize - s-resize - w-resize - text - wait - help - above - absolute - always - avoid - avoid-page - avoid-column - avoid-region - below - bidi-override - blink - both - break-word - capitalize - caption - clip - close-quote - collapse - column - condensed - crop - cross + each-line + ease + ease-in + ease-in-out + ease-out + economy ellipsis - ellipsis-word embed + emoji + end + ethiopic-numeric + ew-resize + ex-height + exact + exclude + exclusion expanded + extends extra-condensed extra-expanded + fade + fallback + false + fangsong + fantasy + fill + fill-box + filled + first + fit-content fixed - hand + flat + flex + flex-end + flex-start + flow + flow-root + force-end + forwards + from-font + from-image + full-size-kana + full-width + georgian + grab + grabbing + grid + groove + gujarati + gurmukhi + hanging + hard-light + hebrew + help + hidden hide - higher - icon + high-quality + hiragana + hiragana-iroha + historical-forms + historical-ligatures + horizontal + horizontal-tb + hue + ic-height + ic-width + infinite + inline + inline-block + inline-end + inline-flex + inline-grid + inline-size + inline-start + inline-table + inset inside + inter-character + inter-word + intersect invert + isolate + isolate-override + italic + japanese-formal + japanese-informal + jump-both + jump-end + jump-none + jump-start + justify + justify-all + kannada + katakana + katakana-iroha + keep-all + keyword + khmer + korean-hangul-formal + korean-hanja-formal + korean-hanja-informal landscape - level + lao + large + larger + last + layout + left + legacy + light + lighten + lighter line-through - loud - lower + linear + lining-nums + local + loose + lower-alpha + lower-armenian + lower-greek + lower-latin + lower-roman lowercase ltr - menu - message-box - mix - narrower + luminance + luminosity + malayalam + mandatory + manipulation + manual + margin-box + match-parent + match-source + math + max-content + medium + min-content + mixed + mongolian + monospace + move + multiply + myanmar + n-resize + ne-resize + nesw-resize + no-clip no-close-quote + no-common-ligatures + no-contextual + no-discretionary-ligatures + no-drop + no-historical-ligatures no-open-quote + no-repeat + none + normal + not-allowed nowrap + ns-resize + numbers + numeric + nw-resize + nwse-resize + oblique + oldstyle-nums + only + open open-quote + optional + ordinal + oriya + outset outside + over + overlay overline + padding + padding-box + paint + painted + pan-down + pan-left + pan-right + pan-up + pan-x + pan-y + paused + persian + petite-caps + pinch-zoom + pixelated + plaintext + pointer portrait + position pre pre-line pre-wrap + preserve-3d + progress + proportional-nums + proportional-width + proximity + recto relative + repeat + repeat-x + repeat-y + replace + reverse + ridge + right + rotate-left + rotate-right + round + row + row-resize + row-reverse rtl + ruby + ruby-base + ruby-base-container + ruby-text + ruby-text-container + running + s-resize + safe + sans-serif + saturation + scale-down + screen scroll + scroll-position + se-resize + self-end + self-start semi-condensed semi-expanded separate + serif + sesame show - small-caption + sideways + sideways-lr + sideways-right + sideways-rl + simp-chinese-formal + simp-chinese-informal + size + slashed-zero + slice + small + small-caps + smaller + smooth + soft-light + solid + space + space-around + space-between + space-evenly + spell-out + square + stable + stacked-fractions + start static - static-position - status-bar + step-end + step-start sticky + stretch + strict + stroke + stroke-box + style + sub + subtract + super + sw-resize + swap + symbolic + system-ui + table + table-caption + table-cell + table-column + table-column-group + table-footer-group + table-header-group + table-row + table-row-group + tabular-nums + tamil + telugu + text + thai thick thin + tibetan + titling-caps + top + trad-chinese-formal + trad-chinese-informal + transparent + triangle + true + ui-monospace + ui-rounded + ui-sans-serif + ui-serif ultra-condensed ultra-expanded + under underline + unicase + unicode + unsafe + upper-alpha + upper-armenian + upper-latin + upper-roman uppercase + upright + use-glyph-orientation + verso + vertical + vertical-lr + vertical-rl + vertical-text + view-box visible - wider - break - serif - sans-serif - cursive - fantasy - monospace - border-box - content-box - -epub-hyphens - contain - cover + visibleFill + visiblePainted + visibleStroke + w-resize + wait + weight + words + wrap + wrap-reverse + x-large + x-small + xx-large + xx-small + xxx-large + zoom-in + zoom-out - - - block - inline - run-in + - flow - flow-root - table - flex - grid - ruby + after-edge + arcs + before-edge + bevel + bounding-box + butt + central + crispEdges + evenodd + fixed-position + freeze + geometricPrecision + ideographic + linearRGB + mathematical + middle + miter + miter-clip + non-rotation + non-scaling-size + non-scaling-stroke + nonzero + optimizeLegibility + optimizeQuality + optimizeSpeed + remove + sRGB + text-after-edge + text-before-edge + text-bottom + text-top - list-item - - table-row-group - table-header-group - table-footer-group - table-row - table-cell - table-column-group - table-column - table-caption - ruby-base - ruby-text - ruby-base-container - ruby-text-container - - contents - - inline-block - inline-table - inline-flex - inline-grid - - - all - ease - ease-in - ease-out - ease-in-out - step-start - step-end - linear - - - infinite - reverse - alternate - alternate-reverse - forwards - backwards - running - paused + + konq-center - black - silver - gray - white - maroon - red - purple - fuchsia - green - lime - olive - yellow - navy - blue - teal - aqua - orange aliceblue antiquewhite + aqua aquamarine azure beige bisque + black blanchedalmond + blue blueviolet brown burlywood @@ -996,7 +1083,6 @@ Changelog: cornsilk crimson cyan - aqua darkblue darkcyan darkgoldenrod @@ -1024,10 +1110,13 @@ Changelog: firebrick floralwhite forestgreen + fuchsia gainsboro ghostwhite gold goldenrod + gray + green greenyellow grey honeydew @@ -1055,10 +1144,11 @@ Changelog: lightslategrey lightsteelblue lightyellow + lime limegreen linen magenta - fuchsia + maroon mediumaquamarine mediumblue mediumorchid @@ -1073,8 +1163,11 @@ Changelog: mistyrose moccasin navajowhite + navy oldlace + olive olivedrab + orange orangered orchid palegoldenrod @@ -1087,7 +1180,9 @@ Changelog: pink plum powderblue + purple rebeccapurple + red rosybrown royalblue saddlebrown @@ -1096,6 +1191,7 @@ Changelog: seagreen seashell sienna + silver skyblue slateblue slategray @@ -1104,225 +1200,186 @@ Changelog: springgreen steelblue tan + teal thistle tomato turquoise violet wheat + white whitesmoke + yellow yellowgreen - rebeccapurple - - ActiveBorder - ActiveCaption - AppWorkspace - Background + + + AccentColor + AccentColorText + ActiveText + ButtonBorder ButtonFace - ButtonHighlight - ButtonShadow ButtonText - CaptionText + Canvas + CanvasText + Field + FieldText GrayText Highlight HighlightText - InactiveBorder - InactiveCaption - InactiveCaptionText - InfoBackground - InfoText - Menu - MenuText - Scrollbar - ThreeDDarkShadow - ThreeDFace - ThreeDHighlight - ThreeDLightShadow - ThreeDShadow - Window - WindowFrame - WindowText + LinkText + Mark + MarkText + VisitedText + - attr - cross-fade - env - fit-content - minmax - path - repeat - url - var - - - abs acos + annotation asin - atan2 atan - calc - clamp - cos - exp - hypot - log - max - min - mod - pow - rem - round - sign - sin - sqrt - tan - - - linear-gradient - radial-gradient - repeating-linear-gradient - repeating-radial-gradient - - - rgb - rgba - hsl - hsla - hwb - lab - lch - oklab - oklch - color - - - toggle - hwb - device-cmyk - color - element - image - image-set - conic-gradient - - - symbols - counter - counters - - - rect - - - inset - circle - ellipse - polygon - - + atan2 + attr blur brightness + calc + character-variant + circle + clamp + color + color-mix + conic-gradient contrast + cos + counter + counters + cross-fade + device-cmyk drop-shadow + ellipse + env + exp + fit-content + format grayscale + hsl hue-rotate + hwb + hypot + image + image-set + inset invert - opacity - saturate - sepia - - - max-content - min-content - repeat - - - cubic-bezier - frames - steps - - + lab + lch + linear-gradient + local + log matrix matrix3d + max + min + minmax + mod + oklab + oklch + opacity + ornaments + paint + path perspective + polygon + pow + radial-gradient + rem + repeat + repeating-conic-gradient + repeating-linear-gradient + repeating-radial-gradient + rgb rotate rotate3d rotateX rotateY rotateZ + round + saturate scale scale3d scaleX scaleY scaleZ + sepia + sign + sin skew skewX skewY + sqrt + styleset + stylistic + swash + symbols + tan + tech translate translate3d translateX translateY translateZ - - - local - format + url + var - - + all print screen speech + - - any-pointer + + -webkit-device-pixel-ratio + -webkit-transform-3d any-hover + any-pointer aspect-ratio color color-gamut color-index display-mode + dynamic-range + forced-colors grid height hover - max-aspect-ratio - max-color - max-color-index - max-device-aspect-ratio - max-device-height - max-device-width + inverted-colors max-height - max-monochrome - max-resolution max-width - min-aspect-ratio - min-color - min-color-index - min-device-aspect-ratio - min-device-height - min-device-width min-height - min-monochrome - min-resolution min-width monochrome orientation + overflow-block + overflow-inline pointer + prefers-color-scheme + prefers-contrast + prefers-reduced-motion resolution - scan + scripting update + video-dynamic-range width - + after backdrop before cue + cue-region file-selector-button first-letter first-line @@ -1332,16 +1389,7 @@ Changelog: selection slotted - - - - - - - value - choices - repeat-item - repeat-index + -moz-progress-bar -moz-range-progress @@ -1360,37 +1408,42 @@ Changelog: - - future - local-link - modal - picture-in-picture - + active any-link autofill + buffering checked + current default defined - + dir disabled empty enabled + first first-child first-of-type focus focus-visible focus-within fullscreen + has host + host-context hover in-range indeterminate invalid + is lang last-child last-of-type + left link + local-link + modal + muted not nth-child nth-last-child @@ -1400,36 +1453,28 @@ Changelog: only-of-type optional out-of-range + paused + picture-in-picture placeholder-shown + playing read-only read-write required + right root scope + seeking + stalled target + user-invalid + user-valid valid visited - - - after - before - cue - first-letter - first-line - selection - - - - has - host - host-context - is - matches - not + volume-locked where - + blank first left @@ -1439,412 +1484,548 @@ Changelog: - @character - @layer - @container @charset - @import - @namespace - - - + @container @font-feature-values - @document + @import + @keyframes + @layer @media + @namespace + @page @supports - + + @color-profile @counter-style - @viewport - @page @font-face - @keyframes - - - - min-width - max-width - width - min-height - max-height - height - zoom - min-zoom - max-zoom - user-zoom - orientation - viewport-fit - - - - size - marks - bleed - - - - font-display - font-family - font-stretch - font-style - font-weight - font-variant - font-feature-settings - font-variation-settings - src - unicode-range - - - - from - to + @font-palette-values + @property + or and only not - - - - - - + + + + + - - - - - - - - + + + + + + + + + + - - + + + + + - - - - - - - - + + + + + + + + - - + + - + + + + + + + + + + + + + - - + + - - - + + + - - - + + + - + - - - - + + + + - - - - - - - + + + + + + + - - - - + + + + + + + + + + - - - - - - - + + + + + + + + + - - - - - + + + + + + + + + + + + + + + + + + + + + + + + - - - - + + + + + + - - - - + + + + + + + + + + + + + + + + + - - - - - - + + + + + + + + + + + + + + + + + + + + + + + - - - - - + + + + + + + + + + + + + - - - + + + + + + - - - - + + + + + + + + - - - + + + + + + + - - - - + + + + + + + + + + + + + - - - - + + - - - - + + + + + + + + + + + + + + - - - - - - + + + + + + + + + - - - - - - - - + + + + + + + + + + + + + + + + + + + + + - - - - - - - - - - + + + + + + + - - - + + + + + + + + + + - - - - - + + + + + + + + + + + + + + - - - + + + + + + + + + + - - + + + + + - - - - - - + + + + + + + - - + + + + + + + - - - + + + + + + + + + + + + - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - + + - - - + + + + + + + - - - - - - - + + + + + + + + + + + + + + + + + + + + + - - - + + + + + + + + + + + + + + + + + - - - - + + + + - - - - + + + + + + + + + + + + + + + + + + + + + + + + + - - - - - - - - + + + + + + + - - - - - - - - - - - - - - - - - - + + + + + + + + + - - - + + + - - - + + + - - - + + + @@ -1852,36 +2033,49 @@ Changelog: + + + + + + + + + + - + + + + - + - + diff --git a/src/libs/3rdparty/syntax-highlighting/data/syntax/doxygen.xml b/src/libs/3rdparty/syntax-highlighting/data/syntax/doxygen.xml index 5516c1454b7..da87e4d9170 100644 --- a/src/libs/3rdparty/syntax-highlighting/data/syntax/doxygen.xml +++ b/src/libs/3rdparty/syntax-highlighting/data/syntax/doxygen.xml @@ -1,12 +1,12 @@ - ]> - + @@ -598,6 +598,7 @@ + diff --git a/src/libs/3rdparty/syntax-highlighting/data/syntax/dtd.xml b/src/libs/3rdparty/syntax-highlighting/data/syntax/dtd.xml index 8093b1c4e81..0526efc6250 100644 --- a/src/libs/3rdparty/syntax-highlighting/data/syntax/dtd.xml +++ b/src/libs/3rdparty/syntax-highlighting/data/syntax/dtd.xml @@ -1,5 +1,5 @@ - ]> diff --git a/src/libs/3rdparty/syntax-highlighting/data/syntax/gnuassembler.xml b/src/libs/3rdparty/syntax-highlighting/data/syntax/gnuassembler.xml index 35b9763277e..26a306c28af 100644 --- a/src/libs/3rdparty/syntax-highlighting/data/syntax/gnuassembler.xml +++ b/src/libs/3rdparty/syntax-highlighting/data/syntax/gnuassembler.xml @@ -1,5 +1,5 @@ - + + + + + + + + + + + + + + + + + - - + + - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + @@ -79,8 +96,8 @@ - - + + @@ -136,49 +153,40 @@ - - - + + + - - + - - - - - - - - - - - - - + + + - - + + + + - + - + - - - + + + @@ -186,25 +194,35 @@ - + + + + + + + + - + - + - + + + - + + @@ -220,11 +238,11 @@ - + - + @@ -250,8 +268,8 @@ - - + + @@ -259,8 +277,8 @@ - - + + @@ -268,25 +286,25 @@ - - + + - + - + - - + + - + - + @@ -299,7 +317,9 @@ + + diff --git a/src/libs/3rdparty/syntax-highlighting/data/syntax/ini.xml b/src/libs/3rdparty/syntax-highlighting/data/syntax/ini.xml index 849b90e7eee..56a35e80c7c 100644 --- a/src/libs/3rdparty/syntax-highlighting/data/syntax/ini.xml +++ b/src/libs/3rdparty/syntax-highlighting/data/syntax/ini.xml @@ -1,6 +1,6 @@ - - + + diff --git a/src/libs/3rdparty/syntax-highlighting/data/syntax/java.xml b/src/libs/3rdparty/syntax-highlighting/data/syntax/java.xml index 478fb6ff3e7..aaeef26c3fb 100644 --- a/src/libs/3rdparty/syntax-highlighting/data/syntax/java.xml +++ b/src/libs/3rdparty/syntax-highlighting/data/syntax/java.xml @@ -1,5 +1,5 @@ - @@ -7,7 +7,7 @@ ]> - + ACTIVE @@ -3705,6 +3705,8 @@ + + abstract class @@ -3714,7 +3716,6 @@ false implements instanceof - @interface interface native new @@ -3730,6 +3731,11 @@ transient true volatile + + non-sealed + permits + record + sealed assert @@ -3748,6 +3754,7 @@ throw try while + yield boolean @@ -3764,6 +3771,25 @@ var void + + + + @Override + @Deprecated + @SuppressWarnings + @SafeVarargs + @FunctionalInterface + @interface + + @Retention + @Documented + @Target + @Inherited + @Repeatable + + + + @@ -3783,6 +3809,7 @@ + @@ -3795,6 +3822,7 @@ + @@ -3831,6 +3859,11 @@ + + + + + @@ -3898,6 +3931,7 @@ + diff --git a/src/libs/3rdparty/syntax-highlighting/data/syntax/javadoc.xml b/src/libs/3rdparty/syntax-highlighting/data/syntax/javadoc.xml index 336fedd53c1..84c7841cadf 100644 --- a/src/libs/3rdparty/syntax-highlighting/data/syntax/javadoc.xml +++ b/src/libs/3rdparty/syntax-highlighting/data/syntax/javadoc.xml @@ -1,6 +1,6 @@ - - + + diff --git a/src/libs/3rdparty/syntax-highlighting/data/syntax/json.xml b/src/libs/3rdparty/syntax-highlighting/data/syntax/json.xml index 791a8081331..f302ff13692 100644 --- a/src/libs/3rdparty/syntax-highlighting/data/syntax/json.xml +++ b/src/libs/3rdparty/syntax-highlighting/data/syntax/json.xml @@ -1,5 +1,5 @@ - + - + null @@ -40,7 +40,12 @@ - + + + + + + @@ -57,13 +62,18 @@ - - + + - + + + + + + diff --git a/src/libs/3rdparty/syntax-highlighting/data/syntax/markdown.xml b/src/libs/3rdparty/syntax-highlighting/data/syntax/markdown.xml index 30b226ada01..c3811c772fb 100644 --- a/src/libs/3rdparty/syntax-highlighting/data/syntax/markdown.xml +++ b/src/libs/3rdparty/syntax-highlighting/data/syntax/markdown.xml @@ -22,7 +22,7 @@ Example: **bold text and _italic and bold text_** __bold and ~~strikeout and bold~~__ --> - @@ -72,6 +72,10 @@ + + + + @@ -90,7 +94,7 @@ ]> - + @@ -137,9 +141,12 @@ + + + @@ -148,6 +155,16 @@ + + + + + + + + + + @@ -207,6 +224,7 @@ + @@ -226,6 +244,7 @@ + @@ -254,6 +273,8 @@ + + @@ -284,13 +305,14 @@ to check the indentation of the text and determine if the content of the list ends. --> - + + @@ -303,6 +325,12 @@ + + + + + + @@ -312,42 +340,42 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + @@ -450,13 +478,13 @@ - + - + @@ -494,7 +522,7 @@ - + @@ -505,6 +533,8 @@ + + @@ -523,6 +553,7 @@ + @@ -531,8 +562,7 @@ - - + @@ -606,6 +636,7 @@ + @@ -621,6 +652,7 @@ + @@ -629,11 +661,14 @@ + + + diff --git a/src/libs/3rdparty/syntax-highlighting/data/syntax/modelines.xml b/src/libs/3rdparty/syntax-highlighting/data/syntax/modelines.xml index 43b49f3388c..855bca48029 100644 --- a/src/libs/3rdparty/syntax-highlighting/data/syntax/modelines.xml +++ b/src/libs/3rdparty/syntax-highlighting/data/syntax/modelines.xml @@ -1,5 +1,5 @@ - diff --git a/src/libs/3rdparty/syntax-highlighting/data/syntax/perl.xml b/src/libs/3rdparty/syntax-highlighting/data/syntax/perl.xml index b3822fe7b72..ed843a7d461 100644 --- a/src/libs/3rdparty/syntax-highlighting/data/syntax/perl.xml +++ b/src/libs/3rdparty/syntax-highlighting/data/syntax/perl.xml @@ -1,5 +1,5 @@ - + Add-Content Add-ADComputerServiceAccount @@ -847,11 +790,23 @@ \% \? + + + $Global: + $Local: + $Private: + $Script: + $Using: + $Workflow: + $Alias: + $Env: + $Function: + $Variable: + $_ $True $False - $Env $Null $^ $$ @@ -873,75 +828,176 @@ $Host $OFS + + + + .SYNOPSIS + .DESCRIPTION + .PARAMETER + .EXAMPLE + .INPUTS + .OUTPUTS + .NOTES + .LINK + .COMPONENT + .ROLE + .FUNCTIONALITY + .FORWARDHELPTARGETNAME + .FORWARDHELPCATEGORY + .REMOTEHELPRUNSPACE + .EXTERNALHELP + + + + + + - - - - - + + + + + + + + + + + + + + + + + + + + + + - + - - - - - + - - + + + + + - - - - - + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + - - - + + - - - + + + + - - + + - - + + + + + + + - - + + + + + + + + + + + + + + + - - + + diff --git a/src/libs/3rdparty/syntax-highlighting/data/syntax/qdocconf.xml b/src/libs/3rdparty/syntax-highlighting/data/syntax/qdocconf.xml index b735ca9f4a9..dfd8008d988 100644 --- a/src/libs/3rdparty/syntax-highlighting/data/syntax/qdocconf.xml +++ b/src/libs/3rdparty/syntax-highlighting/data/syntax/qdocconf.xml @@ -1,5 +1,5 @@ - + - + + @@ -374,6 +375,7 @@ + @@ -387,6 +389,7 @@ + @@ -401,6 +404,7 @@ + @@ -459,6 +463,7 @@ + @@ -595,6 +600,7 @@ + @@ -789,6 +795,7 @@ + @@ -855,6 +862,7 @@ + diff --git a/src/libs/3rdparty/syntax-highlighting/data/syntax/spdx-comments.xml b/src/libs/3rdparty/syntax-highlighting/data/syntax/spdx-comments.xml index 7d893119279..2b89fc5ac79 100644 --- a/src/libs/3rdparty/syntax-highlighting/data/syntax/spdx-comments.xml +++ b/src/libs/3rdparty/syntax-highlighting/data/syntax/spdx-comments.xml @@ -1,5 +1,5 @@ - + + + + + + true + false + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/src/libs/3rdparty/syntax-highlighting/data/syntax/valgrind-suppression.xml b/src/libs/3rdparty/syntax-highlighting/data/syntax/valgrind-suppression.xml index 46d8c646f7d..e795aca79f1 100644 --- a/src/libs/3rdparty/syntax-highlighting/data/syntax/valgrind-suppression.xml +++ b/src/libs/3rdparty/syntax-highlighting/data/syntax/valgrind-suppression.xml @@ -1,5 +1,5 @@ - + diff --git a/src/libs/3rdparty/syntax-highlighting/data/syntax/xml.xml b/src/libs/3rdparty/syntax-highlighting/data/syntax/xml.xml index 94a0f473244..da1910e26c3 100644 --- a/src/libs/3rdparty/syntax-highlighting/data/syntax/xml.xml +++ b/src/libs/3rdparty/syntax-highlighting/data/syntax/xml.xml @@ -1,12 +1,12 @@ - ]> - + diff --git a/src/libs/3rdparty/syntax-highlighting/data/syntax/yacc.xml b/src/libs/3rdparty/syntax-highlighting/data/syntax/yacc.xml index 8b939115947..4129a09bd7e 100644 --- a/src/libs/3rdparty/syntax-highlighting/data/syntax/yacc.xml +++ b/src/libs/3rdparty/syntax-highlighting/data/syntax/yacc.xml @@ -1,5 +1,5 @@ - + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +]> + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/src/libs/3rdparty/syntax-highlighting/data/themes/default.theme b/src/libs/3rdparty/syntax-highlighting/data/themes/default.theme deleted file mode 100644 index e9c5c838d39..00000000000 --- a/src/libs/3rdparty/syntax-highlighting/data/themes/default.theme +++ /dev/null @@ -1,174 +0,0 @@ -{ - "metadata" : { - "revision" : 3, - "name" : "Default" - }, - "text-styles": { - "Normal" : { - "text-color" : "#1f1c1b", - "selected-text-color" : "#ffffff", - "bold" : false, - "italic" : false, - "underline" : false, - "strike-through" : false - }, - "Keyword" : { - "text-color" : "#1f1c1b", - "selected-text-color" : "#ffffff", - "bold" : true - }, - "Function" : { - "text-color" : "#644a9b", - "selected-text-color" : "#452886" - }, - "Variable" : { - "text-color" : "#0057ae", - "selected-text-color" : "#00316e" - }, - "ControlFlow" : { - "text-color" : "#1f1c1b", - "selected-text-color" : "#ffffff", - "bold" : true - }, - "Operator" : { - "text-color" : "#1f1c1b", - "selected-text-color" : "#ffffff" - }, - "BuiltIn" : { - "text-color" : "#644a9b", - "selected-text-color" : "#452886", - "bold" : true - }, - "Extension" : { - "text-color" : "#0095ff", - "selected-text-color" : "#ffffff", - "bold" : true - }, - "Preprocessor" : { - "text-color" : "#006e28", - "selected-text-color" : "#006e28" - }, - "Attribute" : { - "text-color" : "#0057ae", - "selected-text-color" : "#00316e" - }, - "Char" : { - "text-color" : "#924c9d", - "selected-text-color" : "#6c2477" - }, - "SpecialChar" : { - "text-color" : "#3daee9", - "selected-text-color" : "#fcfcfc" - }, - "String" : { - "text-color" : "#bf0303", - "selected-text-color" : "#9c0e0e" - }, - "VerbatimString" : { - "text-color" : "#bf0303", - "selected-text-color" : "#9c0e0e" - }, - "SpecialString" : { - "text-color" : "#ff5500", - "selected-text-color" : "#ff5500" - }, - "Import" : { - "text-color" : "#ff5500", - "selected-text-color" : "#ff5500" - }, - "DataType" : { - "text-color" : "#0057ae", - "selected-text-color" : "#00316e" - }, - "DecVal" : { - "text-color" : "#b08000", - "selected-text-color" : "#805c00" - }, - "BaseN" : { - "text-color" : "#b08000", - "selected-text-color" : "#805c00" - }, - "Float" : { - "text-color" : "#b08000", - "selected-text-color" : "#805c00" - }, - "Constant" : { - "text-color" : "#aa5500", - "selected-text-color" : "#5e2f00" - }, - "Comment" : { - "text-color" : "#898887", - "selected-text-color" : "#5e5d5d" - }, - "Documentation" : { - "text-color" : "#607880", - "selected-text-color" : "#46585e" - }, - "Annotation" : { - "text-color" : "#ca60ca", - "selected-text-color" : "#a44ea4" - }, - "CommentVar" : { - "text-color" : "#0095ff", - "selected-text-color" : "#ffffff" - }, - "RegionMarker" : { - "text-color" : "#0057ae", - "selected-text-color" : "#00316e", - "background-color" : "#e0e9f8" - }, - "Information" : { - "text-color" : "#b08000", - "selected-text-color" : "#805c00" - }, - "Warning" : { - "text-color" : "#bf0303", - "selected-text-color" : "#9c0e0e" - }, - "Alert" : { - "text-color" : "#bf0303", - "selected-text-color" : "#9c0e0e", - "background-color" : "#f7e6e6", - "bold" : true - }, - "Error" : { - "text-color" : "#bf0303", - "selected-text-color" : "#9c0e0e", - "underline" : true - }, - "Others" : { - "text-color" : "#006e28", - "selected-text-color" : "#006e28" - } - }, - "editor-colors": { - "background-color" : "#ffffff", - "code-folding" : "#94caef", - "bracket-matching" : "#ffff00", - "current-line" : "#f8f7f6", - "icon-border" : "#f0f0f0", - "indentation-line" : "#d2d2d2", - "line-numbers" : "#a0a0a0", - "current-line-number" : "#1e1e1e", - "mark-bookmark" : "#0000ff", - "mark-breakpoint-active" : "#ff0000", - "mark-breakpoint-reached" : "#ffff00", - "mark-breakpoint-disabled" : "#ff00ff", - "mark-execution" : "#a0a0a4", - "mark-warning" : "#00ff00", - "mark-error" : "#ff0000", - "modified-lines" : "#fdbc4b", - "replace-highlight" : "#00ff00", - "saved-lines" : "#2ecc71", - "search-highlight" : "#ffff00", - "selection" : "#94caef", - "separator" : "#898887", - "spell-checking" : "#bf0303", - "tab-marker" : "#d2d2d2", - "template-background" : "#d6d2d0", - "template-placeholder" : "#baf8ce", - "template-focused-placeholder" : "#76da98", - "template-read-only-placeholder" : "#f6e6e6", - "word-wrap-marker" : "#ededed" - } -} diff --git a/src/libs/3rdparty/syntax-highlighting/data/themes/theme-data.qrc b/src/libs/3rdparty/syntax-highlighting/data/themes/theme-data.qrc index cf9d658c824..8f4aa6c7e43 100644 --- a/src/libs/3rdparty/syntax-highlighting/data/themes/theme-data.qrc +++ b/src/libs/3rdparty/syntax-highlighting/data/themes/theme-data.qrc @@ -1,26 +1,26 @@ - - - - atom-one-dark.theme - atom-one-light.theme - breeze-dark.theme - breeze-light.theme - ayu-dark.theme - ayu-light.theme - ayu-mirage.theme - dracula.theme - falcon.theme - github-dark.theme - github-light.theme - gruvbox-dark.theme - gruvbox-light.theme - monokai.theme - nord.theme - oblivion.theme - printing.theme - radical.theme - solarized-dark.theme - solarized-light.theme - vim-dark.theme - + + + atom-one-dark.theme + atom-one-light.theme + ayu-dark.theme + ayu-light.theme + ayu-mirage.theme + breeze-dark.theme + breeze-light.theme + dracula.theme + falcon.theme + github-dark.theme + github-light.theme + gruvbox-dark.theme + gruvbox-light.theme + homunculus.theme + monokai.theme + nord.theme + oblivion.theme + printing.theme + radical.theme + solarized-dark.theme + solarized-light.theme + vim-dark.theme + diff --git a/src/libs/3rdparty/syntax-highlighting/src/CMakeLists.txt b/src/libs/3rdparty/syntax-highlighting/src/CMakeLists.txt index 419b8ed5b7c..9d53a5bc3d5 100644 --- a/src/libs/3rdparty/syntax-highlighting/src/CMakeLists.txt +++ b/src/libs/3rdparty/syntax-highlighting/src/CMakeLists.txt @@ -1,9 +1,9 @@ add_subdirectory(indexer) -if(TARGET Qt${QT_MAJOR_VERSION}::Gui) +if(TARGET Qt6::Gui) add_subdirectory(lib) add_subdirectory(cli) endif() -if(TARGET Qt${QT_MAJOR_VERSION}::Quick) +if(TARGET Qt6::Quick) add_subdirectory(quick) endif() diff --git a/src/libs/3rdparty/syntax-highlighting/src/Messages.sh b/src/libs/3rdparty/syntax-highlighting/src/Messages.sh index 6fb605ddf08..4024d9b74d4 100644 --- a/src/libs/3rdparty/syntax-highlighting/src/Messages.sh +++ b/src/libs/3rdparty/syntax-highlighting/src/Messages.sh @@ -8,4 +8,4 @@ sed -i -e 's/^i18nc/QT_TRANSLATE_NOOP/' rc.cpp grep --no-filename '"name"' ../data/themes/*.theme | \ sed -r -e 's/"name"/QT_TRANSLATE_NOOP("Theme", /; s/://; s/,?$/);/' >> rc.cpp -$EXTRACT_TR_STRINGS `find . -name \*.cpp -o -name \*.h -o -name \*.ui -o -name \*.qml` -o $podir/syntaxhighlighting5_qt.pot +$EXTRACT_TR_STRINGS `find . -name \*.cpp -o -name \*.h -o -name \*.ui -o -name \*.qml` -o $podir/syntaxhighlighting6_qt.pot diff --git a/src/libs/3rdparty/syntax-highlighting/src/cli/CMakeLists.txt b/src/libs/3rdparty/syntax-highlighting/src/cli/CMakeLists.txt index 1a4d24d8284..3aa3a8afc3f 100644 --- a/src/libs/3rdparty/syntax-highlighting/src/cli/CMakeLists.txt +++ b/src/libs/3rdparty/syntax-highlighting/src/cli/CMakeLists.txt @@ -1,5 +1,5 @@ -add_executable(kate-syntax-highlighter kate-syntax-highlighter.cpp) -ecm_mark_nongui_executable(kate-syntax-highlighter) -target_link_libraries(kate-syntax-highlighter KF5SyntaxHighlighting) +add_executable(ksyntaxhighlighter6 ksyntaxhighlighter.cpp) +ecm_mark_nongui_executable(ksyntaxhighlighter6) +target_link_libraries(ksyntaxhighlighter6 KF6SyntaxHighlighting) -install(TARGETS kate-syntax-highlighter ${KDE_INSTALL_TARGETS_DEFAULT_ARGS}) +install(TARGETS ksyntaxhighlighter6 ${KDE_INSTALL_TARGETS_DEFAULT_ARGS}) diff --git a/src/libs/3rdparty/syntax-highlighting/src/cli/kate-syntax-highlighter.cpp b/src/libs/3rdparty/syntax-highlighting/src/cli/ksyntaxhighlighter.cpp similarity index 77% rename from src/libs/3rdparty/syntax-highlighting/src/cli/kate-syntax-highlighter.cpp rename to src/libs/3rdparty/syntax-highlighting/src/cli/ksyntaxhighlighter.cpp index 5ce90e00530..681410cb706 100644 --- a/src/libs/3rdparty/syntax-highlighting/src/cli/kate-syntax-highlighter.cpp +++ b/src/libs/3rdparty/syntax-highlighting/src/cli/ksyntaxhighlighter.cpp @@ -26,7 +26,6 @@ static void applyHighlighter(Highlighter &highlighter, QCommandLineParser &parser, bool fromFileName, const QString &inFileName, - const QCommandLineOption &stdinOption, const QCommandLineOption &outputName, const Ts &...highlightParams) { @@ -38,30 +37,36 @@ static void applyHighlighter(Highlighter &highlighter, if (fromFileName) { highlighter.highlightFile(inFileName, highlightParams...); - } else if (parser.isSet(stdinOption)) { + } else { QFile inFile; inFile.open(stdin, QIODevice::ReadOnly); highlighter.highlightData(&inFile, highlightParams...); - } else { - parser.showHelp(1); } } +static Theme theme(const Repository &repo, const QString &themeName, Repository::DefaultTheme t) +{ + if (themeName.isEmpty()) { + return repo.defaultTheme(t); + } + return repo.theme(themeName); +} + int main(int argc, char **argv) { QCoreApplication app(argc, argv); - QCoreApplication::setApplicationName(QStringLiteral("kate-syntax-highlighter")); + QCoreApplication::setApplicationName(QStringLiteral("ksyntaxhighlighter")); QCoreApplication::setOrganizationDomain(QStringLiteral("kde.org")); QCoreApplication::setOrganizationName(QStringLiteral("KDE")); - QCoreApplication::setApplicationVersion(QStringLiteral(SyntaxHighlighting_VERSION_STRING)); - - Repository repo; + QCoreApplication::setApplicationVersion(QStringLiteral(KSYNTAXHIGHLIGHTING_VERSION_STRING)); QCommandLineParser parser; - parser.setApplicationDescription(app.translate("SyntaxHighlightingCLI", "Command line syntax highlighter using Kate syntax definitions.")); + parser.setApplicationDescription(app.translate("SyntaxHighlightingCLI", "Command line syntax highlighter using KSyntaxHighlighting syntax definitions.")); parser.addHelpOption(); parser.addVersionOption(); - parser.addPositionalArgument(app.translate("SyntaxHighlightingCLI", "source"), app.translate("SyntaxHighlightingCLI", "The source file to highlight.")); + parser.addPositionalArgument( + app.translate("SyntaxHighlightingCLI", "source"), + app.translate("SyntaxHighlightingCLI", "The source file to highlight. If absent, read the file from stdin and the --syntax option must be used.")); QCommandLineOption listDefs(QStringList() << QStringLiteral("l") << QStringLiteral("list"), app.translate("SyntaxHighlightingCLI", "List all available syntax definitions.")); @@ -85,8 +90,7 @@ int main(int argc, char **argv) QCommandLineOption themeName(QStringList() << QStringLiteral("t") << QStringLiteral("theme"), app.translate("SyntaxHighlightingCLI", "Color theme to use for highlighting."), - app.translate("SyntaxHighlightingCLI", "theme"), - repo.defaultTheme(Repository::LightTheme).name()); + app.translate("SyntaxHighlightingCLI", "theme")); parser.addOption(themeName); QCommandLineOption outputFormatOption( @@ -99,7 +103,7 @@ int main(int argc, char **argv) QCommandLineOption traceOption(QStringList() << QStringLiteral("syntax-trace"), app.translate("SyntaxHighlightingCLI", "Add information to debug a syntax file. Only works with --output-format=ansi or ansi256Colors. Possible " - "values are format, region, context and stackSize."), + "values are format, region, context, stackSize and all."), app.translate("SyntaxHighlightingCLI", "type")); parser.addOption(traceOption); @@ -107,18 +111,20 @@ int main(int argc, char **argv) app.translate("SyntaxHighlightingCLI", "Disable ANSI background for the default color.")); parser.addOption(noAnsiEditorBg); + QCommandLineOption unbufferedAnsi(QStringList() << QStringLiteral("U") << QStringLiteral("unbuffered"), + app.translate("SyntaxHighlightingCLI", "For ansi and ansi256Colors formats, flush the output buffer on each line.")); + parser.addOption(unbufferedAnsi); + QCommandLineOption titleOption( QStringList() << QStringLiteral("T") << QStringLiteral("title"), - app.translate("SyntaxHighlightingCLI", "Set HTML page's title\n(default: the filename or \"Kate Syntax Highlighter\" if reading from stdin)."), + app.translate("SyntaxHighlightingCLI", "Set HTML page's title\n(default: the filename or \"KSyntaxHighlighter\" if reading from stdin)."), app.translate("SyntaxHighlightingCLI", "title")); parser.addOption(titleOption); - QCommandLineOption stdinOption(QStringList() << QStringLiteral("stdin"), - app.translate("SyntaxHighlightingCLI", "Read file from stdin. The -s option must also be used.")); - parser.addOption(stdinOption); - parser.process(app); + Repository repo; + if (parser.isSet(listDefs)) { for (const auto &def : repo.definitions()) { std::cout << qPrintable(def.name()) << std::endl; @@ -177,7 +183,7 @@ int main(int argc, char **argv) return 1; } - QString outputFormat = parser.value(outputFormatOption); + const QString outputFormat = parser.value(outputFormatOption); if (0 == outputFormat.compare(QLatin1String("html"), Qt::CaseInsensitive)) { QString title; if (parser.isSet(titleOption)) { @@ -186,8 +192,8 @@ int main(int argc, char **argv) HtmlHighlighter highlighter; highlighter.setDefinition(def); - highlighter.setTheme(repo.theme(parser.value(themeName))); - applyHighlighter(highlighter, parser, fromFileName, inFileName, stdinOption, outputName, title); + highlighter.setTheme(theme(repo, parser.value(themeName), Repository::LightTheme)); + applyHighlighter(highlighter, parser, fromFileName, inFileName, outputName, title); } else { auto AnsiFormat = AnsiHighlighter::AnsiFormat::TrueColor; if (0 == outputFormat.compare(QLatin1String("ansi256Colors"), Qt::CaseInsensitive)) { @@ -197,18 +203,22 @@ int main(int argc, char **argv) return 2; } - auto debugOptions = AnsiHighlighter::TraceOptions(); + AnsiHighlighter::Options options{}; + options |= parser.isSet(noAnsiEditorBg) ? AnsiHighlighter::Option::NoOptions : AnsiHighlighter::Option::UseEditorBackground; + options |= parser.isSet(unbufferedAnsi) ? AnsiHighlighter::Option::Unbuffered : AnsiHighlighter::Option::NoOptions; if (parser.isSet(traceOption)) { - const auto options = parser.values(traceOption); - for (auto const &option : options) { + const auto traceOptions = parser.values(traceOption); + for (auto const &option : traceOptions) { if (option == QStringLiteral("format")) { - debugOptions |= AnsiHighlighter::TraceOption::Format; + options |= AnsiHighlighter::Option::TraceFormat; } else if (option == QStringLiteral("region")) { - debugOptions |= AnsiHighlighter::TraceOption::Region; + options |= AnsiHighlighter::Option::TraceRegion; } else if (option == QStringLiteral("context")) { - debugOptions |= AnsiHighlighter::TraceOption::Context; + options |= AnsiHighlighter::Option::TraceContext; } else if (option == QStringLiteral("stackSize")) { - debugOptions |= AnsiHighlighter::TraceOption::StackSize; + options |= AnsiHighlighter::Option::TraceStackSize; + } else if (option == QStringLiteral("all")) { + options |= AnsiHighlighter::Option::TraceAll; } else { std::cerr << "Unknown trace name." << std::endl; return 2; @@ -218,8 +228,8 @@ int main(int argc, char **argv) AnsiHighlighter highlighter; highlighter.setDefinition(def); - highlighter.setTheme(repo.theme(parser.value(themeName))); - applyHighlighter(highlighter, parser, fromFileName, inFileName, stdinOption, outputName, AnsiFormat, !parser.isSet(noAnsiEditorBg), debugOptions); + highlighter.setTheme(theme(repo, parser.value(themeName), Repository::DarkTheme)); + applyHighlighter(highlighter, parser, fromFileName, inFileName, outputName, AnsiFormat, options); } return 0; diff --git a/src/libs/3rdparty/syntax-highlighting/src/indexer/CMakeLists.txt b/src/libs/3rdparty/syntax-highlighting/src/indexer/CMakeLists.txt index 77a16faf22e..cf6940b7bd5 100644 --- a/src/libs/3rdparty/syntax-highlighting/src/indexer/CMakeLists.txt +++ b/src/libs/3rdparty/syntax-highlighting/src/indexer/CMakeLists.txt @@ -4,13 +4,8 @@ if(CMAKE_CROSSCOMPILING AND KATEHIGHLIGHTINGINDEXER_EXECUTABLE) add_executable(katehighlightingindexer IMPORTED GLOBAL) set_target_properties(katehighlightingindexer PROPERTIES IMPORTED_LOCATION ${KATEHIGHLIGHTINGINDEXER_EXECUTABLE}) elseif(CMAKE_CROSSCOMPILING) - if (NOT KF5_HOST_TOOLING) - message(FATAL_ERROR "Please provide a prefix with a native Qt build and pass -DKF5_HOST_TOOLING=path") - endif() - - # search native tooling prefix - string(FIND ${KF5_HOST_TOOLING} /lib idx) - string(SUBSTRING ${KF5_HOST_TOOLING} 0 ${idx} NATIVE_PREFIX) + include(ECMQueryQt) + ecm_query_qt(NATIVE_PREFIX QT_HOST_PREFIX) message(STATUS "Building katehighlightingindexer against ${NATIVE_PREFIX}") include(ExternalProject) @@ -19,7 +14,7 @@ elseif(CMAKE_CROSSCOMPILING) CMAKE_ARGS -DKSYNTAXHIGHLIGHTING_USE_GUI=OFF -DECM_DIR=${ECM_DIR} -DCMAKE_PREFIX_PATH=${NATIVE_PREFIX} -DCMAKE_INSTALL_PREFIX=${CMAKE_CURRENT_BINARY_DIR} - -DQT_MAJOR_VERSION=${QT_MAJOR_VERSION} + -DQT_MAJOR_VERSION=6 INSTALL_COMMAND "" BUILD_BYPRODUCTS ${CMAKE_CURRENT_BINARY_DIR}/native_katehighlightingindexer-prefix/src/native_katehighlightingindexer-build/bin/katehighlightingindexer ) @@ -31,9 +26,11 @@ else() # host build add_executable(katehighlightingindexer katehighlightingindexer.cpp ../lib/worddelimiters.cpp) ecm_mark_nongui_executable(katehighlightingindexer) - if(Qt5XmlPatterns_FOUND AND NOT ECM_ENABLE_SANITIZERS) - target_link_libraries(katehighlightingindexer Qt5::XmlPatterns) + if(XercesC_FOUND) + add_definitions(-DHAS_XERCESC) + kde_target_enable_exceptions(katehighlightingindexer PRIVATE) + target_link_libraries(katehighlightingindexer Qt6::Core XercesC::XercesC) else() - target_link_libraries(katehighlightingindexer Qt${QT_MAJOR_VERSION}::Core) + target_link_libraries(katehighlightingindexer Qt6::Core) endif() endif() diff --git a/src/libs/3rdparty/syntax-highlighting/src/indexer/katehighlightingindexer.cpp b/src/libs/3rdparty/syntax-highlighting/src/indexer/katehighlightingindexer.cpp index 9c541ef1b42..787747e21c0 100644 --- a/src/libs/3rdparty/syntax-highlighting/src/indexer/katehighlightingindexer.cpp +++ b/src/libs/3rdparty/syntax-highlighting/src/indexer/katehighlightingindexer.cpp @@ -12,12 +12,167 @@ #include #include #include +#include #include #include -#ifdef QT_XMLPATTERNS_LIB -#include -#include +#ifdef HAS_XERCESC + +#include + +#include + +#include +#include + +#include +#include +#include + +#include +#include + +using namespace xercesc; + +/* + * Ideas taken from: + * + * author : Boris Kolpackov + * copyright : not copyrighted - public domain + * + * This program uses Xerces-C++ SAX2 parser to load a set of schema files + * and then to validate a set of XML documents against these schemas. To + * build this program you will need Xerces-C++ 3.0.0 or later. For more + * information, see: + * + * http://www.codesynthesis.com/~boris/blog/2010/03/15/validating-external-schemas-xerces-cxx/ + */ + +/** + * Error handler object used during xml schema validation. + */ +class CustomErrorHandler : public ErrorHandler +{ +public: + /** + * Constructor + * @param messages Pointer to the error message string to fill. + */ + CustomErrorHandler(QString *messages) + : m_messages(messages) + { + } + + /** + * Check global success/fail state. + * @return True if there was a failure, false otherwise. + */ + bool failed() const + { + return m_failed; + } + +private: + /** + * Severity classes for error messages. + */ + enum severity { s_warning, s_error, s_fatal }; + + /** + * Wrapper for warning exceptions. + * @param e Exception to handle. + */ + void warning(const SAXParseException &e) override + { + m_failed = true; // be strict, warnings are evil, too! + handle(e, s_warning); + } + + /** + * Wrapper for error exceptions. + * @param e Exception to handle. + */ + void error(const SAXParseException &e) override + { + m_failed = true; + handle(e, s_error); + } + + /** + * Wrapper for fatal error exceptions. + * @param e Exception to handle. + */ + void fatalError(const SAXParseException &e) override + { + m_failed = true; + handle(e, s_fatal); + } + + /** + * Reset the error status to "no error". + */ + void resetErrors() override + { + m_failed = false; + } + + /** + * Generic handler for error/warning/fatal error message exceptions. + * @param e Exception to handle. + * @param s Enum value encoding the message severtity. + */ + void handle(const SAXParseException &e, severity s) + { + // get id to print + const XMLCh *xid(e.getPublicId()); + if (!xid) + xid = e.getSystemId(); + + m_messages << QString::fromUtf16(xid) << ":" << e.getLineNumber() << ":" << e.getColumnNumber() << " " << (s == s_warning ? "warning: " : "error: ") + << QString::fromUtf16(e.getMessage()) << Qt::endl; + } + +private: + /** + * Storage for created error messages in this handler. + */ + QTextStream m_messages; + + /** + * Global error state. True if there was an error, false otherwise. + */ + bool m_failed = false; +}; + +void init_parser(SAX2XMLReaderImpl &parser) +{ + // Commonly useful configuration. + // + parser.setFeature(XMLUni::fgSAX2CoreNameSpaces, true); + parser.setFeature(XMLUni::fgSAX2CoreNameSpacePrefixes, true); + parser.setFeature(XMLUni::fgSAX2CoreValidation, true); + + // Enable validation. + // + parser.setFeature(XMLUni::fgXercesSchema, true); + parser.setFeature(XMLUni::fgXercesSchemaFullChecking, true); + parser.setFeature(XMLUni::fgXercesValidationErrorAsFatal, true); + + // Use the loaded grammar during parsing. + // + parser.setFeature(XMLUni::fgXercesUseCachedGrammarInParse, true); + + // Don't load schemas from any other source (e.g., from XML document's + // xsi:schemaLocation attributes). + // + parser.setFeature(XMLUni::fgXercesLoadSchema, false); + + // Xerces-C++ 3.1.0 is the first version with working multi import + // support. + // + parser.setFeature(XMLUni::fgXercesHandleMultipleImports, true); +} + #endif #include "../lib/worddelimiters_p.h" @@ -152,12 +307,10 @@ public: success = false; } - QSet referencedKeywords; QSet usedAttributeNames; QSet ignoredAttributeNames; - success = checkKeywordsList(definition, referencedKeywords) && success; - success = - checkContexts(definition, referencedKeywords, usedAttributeNames, ignoredAttributeNames, usedContexts, unreachableIncludedRules) && success; + success = checkKeywordsList(definition) && success; + success = checkContexts(definition, usedAttributeNames, ignoredAttributeNames, usedContexts, unreachableIncludedRules) && success; // search for non-existing itemDatas. const auto invalidNames = usedAttributeNames - definition.itemDatas.styleNames; @@ -362,7 +515,7 @@ private: QString content; int line; - friend uint qHash(const Item &item, uint seed = 0) + friend size_t qHash(const Item &item, size_t seed = 0) { return qHash(item.content, seed); } @@ -373,7 +526,7 @@ private: } }; - QVector keywords; + QList keywords; QSet includes; bool parseElement(const QString &filename, QXmlStreamReader &xml) @@ -486,7 +639,7 @@ private: QString weakDeliminator; // rules included by IncludeRules (without IncludeRule) - QVector includedRules; + QList includedRules; // IncludeRules included by IncludeRules QSet includedIncludeRules; @@ -683,9 +836,10 @@ private: ContextName lineEndContext; ContextName lineEmptyContext; ContextName fallthroughContext; - QVector rules; + QList rules; XmlBool dynamic{}; XmlBool fallthrough{}; + XmlBool stopEmptyLineContextSwitchLoop{}; bool parseElement(const QString &filename, QXmlStreamReader &xml) { @@ -697,12 +851,17 @@ private: Parser parser{filename, xml, attr, success}; XmlBool noIndentationBasedFolding{}; - const bool isExtracted = parser.extractString(name, QStringLiteral("name")) || parser.extractString(attribute, QStringLiteral("attribute")) + // clang-format off + const bool isExtracted = parser.extractString(name, QStringLiteral("name")) + || parser.extractString(attribute, QStringLiteral("attribute")) || parser.extractString(lineEndContext.name, QStringLiteral("lineEndContext")) || parser.extractString(lineEmptyContext.name, QStringLiteral("lineEmptyContext")) || parser.extractString(fallthroughContext.name, QStringLiteral("fallthroughContext")) - || parser.extractXmlBool(dynamic, QStringLiteral("dynamic")) || parser.extractXmlBool(fallthrough, QStringLiteral("fallthrough")) + || parser.extractXmlBool(dynamic, QStringLiteral("dynamic")) + || parser.extractXmlBool(fallthrough, QStringLiteral("fallthrough")) + || parser.extractXmlBool(stopEmptyLineContextSwitchLoop, QStringLiteral("stopEmptyLineContextSwitchLoop")) || parser.extractXmlBool(noIndentationBasedFolding, QStringLiteral("noIndentationBasedFolding")); + // clang-format on success = parser.checkIfExtracted(isExtracted); } @@ -717,11 +876,6 @@ private: success = false; } - if (lineEndContext.name.isEmpty()) { - qWarning() << filename << "line" << xml.lineNumber() << "missing attribute: lineEndContext"; - success = false; - } - return success; } }; @@ -747,7 +901,7 @@ private: QString name; int line; - friend uint qHash(const Style &style, uint seed = 0) + friend size_t qHash(const Style &style, size_t seed = 0) { return qHash(style.name, seed); } @@ -802,7 +956,6 @@ private: const Context *firstContext = nullptr; QString filename; WordDelimiters wordDelimiters; - XmlBool casesensitive{}; Version kateVersion{}; QString kateVersionStr; QString languageName; @@ -865,7 +1018,7 @@ private: void resolveIncludeRules() { QSet usedContexts; - QVector contexts; + QList contexts; QMutableMapIterator def(m_definitions); while (def.hasNext()) { @@ -936,7 +1089,7 @@ private: QSet extractUsedContexts() const { QSet usedContexts; - QVector contexts; + QList contexts; QMapIterator def(m_definitions); while (def.hasNext()) { @@ -982,13 +1135,12 @@ private: }; struct IncludedRuleUnreachableBy { - QVector unreachableBy; + QList unreachableBy; bool alwaysUnreachable = true; }; //! Check contexts and rules bool checkContexts(const Definition &definition, - QSet &referencedKeywords, QSet &usedAttributeNames, QSet &ignoredAttributeNames, const QSet &usedContexts, @@ -1018,7 +1170,7 @@ private: usedAttributeNames.insert({context.attribute, context.line}); } - success = checkfallthrough(definition, context) && success; + success = checkContextAttribute(definition, context) && success; success = checkUreachableRules(definition.filename, context, unreachableIncludedRules) && success; success = suggestRuleMerger(definition.filename, context) && success; @@ -1032,7 +1184,7 @@ private: } success = checkLookAhead(rule) && success; success = checkStringDetect(rule) && success; - success = checkKeyword(definition, rule, referencedKeywords) && success; + success = checkKeyword(definition, rule) && success; success = checkRegExpr(filename, rule, context) && success; success = checkDelimiters(definition, rule) && success; } @@ -1047,12 +1199,13 @@ private: //! - dynamic=true but no place holder used? //! - is not . with lookAhead="1" //! - is not ^... without column ou firstNonSpace attribute - //! - is not equivalent to DetectSpaces, DetectChar, Detect2Chars, StringDetect, DetectIdentifier, RangeDetect + //! - is not equivalent to DetectSpaces, DetectChar, Detect2Chars, StringDetect, DetectIdentifier, RangeDetect, LineContinue or AnyChar //! - has no unused captures //! - has no unnecessary quantifier with lookAhead bool checkRegExpr(const QString &filename, const Context::Rule &rule, const Context &context) const { - if (rule.type == Context::Rule::Type::RegExpr) { + // ignore empty regex because the error is raised during xml parsing + if (rule.type == Context::Rule::Type::RegExpr && !rule.string.isEmpty()) { const QRegularExpression regexp(rule.string); if (!checkRegularExpression(rule.filename, regexp, rule.line)) { return false; @@ -1092,13 +1245,21 @@ private: // is RangeDetect static const QRegularExpression isRange(QStringLiteral("^\\^?" REG_CHAR "(?:" - "\\.\\*[?*]?" REG_CHAR "|" - "\\[\\^(" REG_ESCAPE_CHAR "|.)\\]\\*[?*]?\\1" + "\\.\\*[?+]?" REG_CHAR "|" + "\\[\\^(" REG_ESCAPE_CHAR "|.)\\]\\*[?+]?\\1" ")$")); if ((rule.lookAhead == XmlBool::True || rule.minimal == XmlBool::True || rule.string.contains(QStringLiteral(".*?")) || rule.string.contains(QStringLiteral("[^"))) && reg.contains(isRange)) { - qWarning() << filename << "line" << rule.line << "RegExpr should be replaced by RangeDetect:" << rule.string; + qWarning() << rule.filename << "line" << rule.line << "RegExpr should be replaced by RangeDetect:" << rule.string; + return false; + } + + // is AnyChar + static const QRegularExpression isAnyChar(QStringLiteral(R"(^(\^|\((\?:)?)*\[(?!\^)[-\]]?(\\[^0BDPSWbdpswoux]|[^-\]\\])*\]\)*$)")); + if (rule.string.contains(isAnyChar)) { + auto extra = (reg[0] == QLatin1Char('^') || reg[1] == QLatin1Char('^')) ? "with column=\"0\"" : ""; + qWarning() << rule.filename << "line" << rule.line << "RegExpr should be replaced by AnyChar:" << rule.string << extra; return false; } @@ -1106,7 +1267,7 @@ private: static const QRegularExpression isLineContinue(QStringLiteral("^\\^?" REG_CHAR "\\$$")); if (reg.contains(isLineContinue)) { auto extra = (reg[0] == QLatin1Char('^')) ? "with column=\"0\"" : ""; - qWarning() << filename << "line" << rule.line << "RegExpr should be replaced by LineContinue:" << rule.string << extra; + qWarning() << rule.filename << "line" << rule.line << "RegExpr should be replaced by LineContinue:" << rule.string << extra; return false; } @@ -1124,7 +1285,7 @@ private: if (rule.lookAhead == XmlBool::True && rule.minimal != XmlBool::True && reg.contains(isMinimal) && !reg.contains(hasNotGreedy) && (!rule.context.context || !rule.context.context->hasDynamicRule || regexp.captureCount() == 0) && (reg.back() != QLatin1Char('$') || reg.contains(QLatin1Char('|')))) { - qWarning() << filename << "line" << rule.line + qWarning() << rule.filename << "line" << rule.line << "RegExpr should be have minimal=\"1\" or use lazy operator (i.g, '.*' -> '.*?'):" << rule.string; return false; } @@ -1160,8 +1321,8 @@ private: return false; } - // column="0" or firstNonSpace="1" - if (rule.column == -1 && rule.firstNonSpace != XmlBool::True) { + // column="0" + if (rule.column == -1) { // ^ without | // (^sas*) -> ok // (^sa|s*) -> ko @@ -1204,7 +1365,7 @@ private: } if (replace) { - qWarning() << rule.filename << "line" << rule.line << "column=\"0\" or firstNonSpace=\"1\" missing with RegExpr:" << rule.string; + qWarning() << rule.filename << "line" << rule.line << "column=\"0\" missing with RegExpr:" << rule.string; return false; } } @@ -1306,11 +1467,8 @@ private: if (!useCapture) { // is DetectIdentifier - static const QRegularExpression isInsensitiveDetectIdentifier( - QStringLiteral(R"(^(\((\?:)?)?\[((a-z|_){2}|(A-Z|_){2})\]([+][*?]?)?\[((0-9|a-z|_){3}|(0-9|A-Z|_){3})\][*][*?]?(\))?$)")); - static const QRegularExpression isSensitiveDetectIdentifier( - QStringLiteral(R"(^(\((\?:)?)?\[(a-z|A-Z|_){3}\]([+][*?]?)?\[(0-9|a-z|A-Z|_){4}\][*][*?]?(\))?$)")); - auto &isDetectIdentifier = (rule.insensitive == XmlBool::True) ? isInsensitiveDetectIdentifier : isSensitiveDetectIdentifier; + static const QRegularExpression isDetectIdentifier( + QStringLiteral(R"(^(\((\?:)?|\^)*\[(\\p\{L\}|_){2}\]([+][?+]?)?\[(\\p\{N\}|\\p\{L\}|_){3}\][*][?+]?\)*$)")); if (rule.string.contains(isDetectIdentifier)) { qWarning() << rule.filename << "line" << rule.line << "RegExpr should be replaced by DetectIdentifier:" << rule.string; return false; @@ -1357,7 +1515,7 @@ private: static const QRegularExpression unnecessaryQuantifier2(QStringLiteral(R"([*+?]([.][*+?]{0,2})?[)]*$)")); auto &unnecessaryQuantifier = useCapture ? unnecessaryQuantifier1 : unnecessaryQuantifier2; if (rule.lookAhead == XmlBool::True && rule.minimal != XmlBool::True && reg.contains(unnecessaryQuantifier)) { - qWarning() << filename << "line" << rule.line + qWarning() << rule.filename << "line" << rule.line << "Last quantifier is not necessary (i.g., 'xyz*' -> 'xy', 'xyz+.' -> 'xyz.'):" << rule.string; return false; } @@ -1418,19 +1576,13 @@ private: return true; } - //! Search for rules with lookAhead="true" and context="#stay". - //! This would cause an infinite loop. - bool checkfallthrough(const Definition &definition, const Context &context) const + //! Check fallthrough and fallthroughContext. + //! Check kateversion for stopEmptyLineContextSwitchLoop. + bool checkContextAttribute(const Definition &definition, const Context &context) const { bool success = true; if (!context.fallthroughContext.name.isEmpty()) { - if (context.fallthroughContext.stay) { - qWarning() << definition.filename << "line" << context.line << "possible infinite loop due to fallthroughContext=\"#stay\" in context " - << context.name; - success = false; - } - const bool mandatoryFallthroughAttribute = definition.kateVersion < Version{5, 62}; if (context.fallthrough == XmlBool::True && !mandatoryFallthroughAttribute) { qWarning() << definition.filename << "line" << context.line << "fallthrough attribute is unnecessary with kateversion >= 5.62 in context" @@ -1444,6 +1596,12 @@ private: } } + if (context.stopEmptyLineContextSwitchLoop != XmlBool::Unspecified && definition.kateVersion < Version{5, 103}) { + qWarning() << definition.filename << "line" << context.line + << "stopEmptyLineContextSwitchLoop attribute is only valid with kateversion >= 5.103 in context" << context.name; + success = false; + } + return success; } @@ -1478,15 +1636,12 @@ private: return false; } - //! Search for rules with lookAhead="true" and context="#stay". - //! This would cause an infinite loop. - bool checkKeyword(const Definition &definition, const Context::Rule &rule, QSet &referencedKeywords) const + //! Check that keyword rule reference an existing keyword list. + bool checkKeyword(const Definition &definition, const Context::Rule &rule) const { if (rule.type == Context::Rule::Type::keyword) { auto it = definition.keywordsList.find(rule.string); - if (it != definition.keywordsList.end()) { - referencedKeywords.insert(&*it); - } else { + if (it == definition.keywordsList.end()) { qWarning() << rule.filename << "line" << rule.line << "reference of non-existing keyword list:" << rule.string; return false; } @@ -1504,13 +1659,7 @@ private: return true; } - //! Check that StringDetect contains more that 2 characters - //! Fix with following command: - //! \code - //! sed -E - //! '/StringDetect/{/dynamic="(1|true)|insensitive="(1|true)/!{s/StringDetect(.*)String="(.|<|>|"|&)(.|<|>|"|&)"/Detect2Chars\1char="\2" - //! char1="\3"/;t;s/StringDetect(.*)String="(.|<|>|"|&)"/DetectChar\1char="\2"/}}' -i file.xml... - //! \endcode + //! Check that StringDetect contains a placeHolder when dynamic="1" bool checkStringDetect(const Context::Rule &rule) const { if (rule.type == Context::Rule::Type::StringDetect) { @@ -1527,7 +1676,7 @@ private: } //! Check \ and delimiter in a keyword list - bool checkKeywordsList(const Definition &definition, QSet &referencedKeywords) const + bool checkKeywordsList(const Definition &definition) const { bool success = true; @@ -1542,7 +1691,7 @@ private: << " is only available since version \"5.53\". Please, increase kateversion."; success = false; } - success = checkKeywordInclude(definition, include, referencedKeywords) && success; + success = checkKeywordInclude(definition, include) && success; } // Check that keyword list items do not have deliminator character @@ -1562,16 +1711,13 @@ private: } //! Search for non-existing keyword include. - bool checkKeywordInclude(const Definition &definition, const Keywords::Items::Item &include, QSet &referencedKeywords) const + bool checkKeywordInclude(const Definition &definition, const Keywords::Items::Item &include) const { bool containsKeywordName = true; int const idx = include.content.indexOf(QStringLiteral("##")); if (idx == -1) { auto it = definition.keywordsList.find(include.content); containsKeywordName = (it != definition.keywordsList.end()); - if (containsKeywordName) { - referencedKeywords.insert(&*it); - } } else { auto defName = include.content.mid(idx + 2); auto listName = include.content.left(idx); @@ -1644,10 +1790,10 @@ private: } /// Search RuleAndInclude associated with the characters of @p s. - /// \return an empty QVector when at least one character is not found. - QVector find(QStringView s) const + /// \return an empty QList when at least one character is not found. + QList find(QStringView s) const { - QVector result; + QList result; for (QChar c : s) { if (!find(c)) { @@ -1731,8 +1877,8 @@ private: } /// Search RuleAndInclude associated with the characters of @p s. - /// \return an empty QVector when at least one character is not found. - QVector find(QStringView s) const + /// \return an empty QList when at least one character is not found. + QList find(QStringView s) const { for (int i = 0; i < m_size; ++i) { auto result = m_charTables[i]->find(s); @@ -1743,7 +1889,7 @@ private: return result; } } - return QVector(); + return QList(); } /// Associates @p c with a rule. @@ -1785,7 +1931,7 @@ private: // Iterates over all the rules, including those in includedRules struct RuleIterator { - RuleIterator(const QVector &rules, const ObservableRule &endRule) + RuleIterator(const QList &rules, const ObservableRule &endRule) : m_end(&endRule - rules.data()) , m_rules(rules) { @@ -1830,10 +1976,10 @@ private: private: int m_i = 0; - int m_i2; - int m_end; - const QVector &m_rules; - const QVector *m_includedRules = nullptr; + int m_i2 = 0; + const int m_end; + const QList &m_rules; + const QList *m_includedRules = nullptr; }; // Dot regex container that satisfies firstNonSpace and column. @@ -1915,7 +2061,7 @@ private: DotRegex dotRegex; - QVector observedRules; + QList observedRules; observedRules.reserve(context.rules.size()); for (const Context::Rule &rule : context.rules) { const Context::Rule *includeRule = nullptr; @@ -1937,7 +2083,7 @@ private: for (auto &observedRule : observedRules) { const Context::Rule &rule = *observedRule.rule; bool isUnreachable = false; - QVector unreachableBy; + QList unreachableBy; // declare rule as unreachable if ruleAndInclude is not empty auto updateUnreachable1 = [&](RuleAndInclude ruleAndInclude) { @@ -1948,7 +2094,7 @@ private: }; // declare rule as unreachable if ruleAndIncludes is not empty - auto updateUnreachable2 = [&](const QVector &ruleAndIncludes) { + auto updateUnreachable2 = [&](const QList &ruleAndIncludes) { if (!ruleAndIncludes.isEmpty()) { isUnreachable = true; unreachableBy.append(ruleAndIncludes); @@ -2030,6 +2176,8 @@ private: case Context::Rule::Type::Float: updateUnreachable2(CharTableArray(detectChars, rule).find(QStringLiteral("0123456789."))); updateUnreachable1(floatRule.setRule(rule)); + // check that Float is before Int + updateUnreachable1(Rule4(intRule).setRule(rule)); break; // check if hidden by another DetectIdentifier rule @@ -2629,12 +2777,32 @@ int main(int argc, char *argv[]) return 1; } -#ifdef QT_XMLPATTERNS_LIB - // open schema - QXmlSchema schema; - if (!schema.load(QUrl::fromLocalFile(app.arguments().at(2)))) { +#ifdef HAS_XERCESC + // care for proper init and cleanup + XMLPlatformUtils::Initialize(); + auto cleanup = qScopeGuard(XMLPlatformUtils::Terminate); + + /* + * parse XSD first time and cache it + */ + XMLGrammarPoolImpl xsd(XMLPlatformUtils::fgMemoryManager); + + // create parser for the XSD + SAX2XMLReaderImpl parser(XMLPlatformUtils::fgMemoryManager, &xsd); + init_parser(parser); + QString messages; + CustomErrorHandler eh(&messages); + parser.setErrorHandler(&eh); + + // load grammar into the pool, on error just abort + const auto xsdFile = app.arguments().at(2); + if (!parser.loadGrammar((const char16_t *)xsdFile.utf16(), Grammar::SchemaGrammarType, true) || eh.failed()) { + qWarning("Failed to parse XSD %s: %s", qPrintable(xsdFile), qPrintable(messages)); return 2; } + + // lock the pool, no later modifications wanted! + xsd.lockPool(); #endif const QString hlFilenamesListing = app.arguments().value(3); @@ -2665,10 +2833,20 @@ int main(int argc, char *argv[]) continue; } -#ifdef QT_XMLPATTERNS_LIB - // validate against schema - QXmlSchemaValidator validator(schema); - if (!validator.validate(&hlFile, QUrl::fromLocalFile(hlFile.fileName()))) { +#ifdef HAS_XERCESC + // create parser + SAX2XMLReaderImpl parser(XMLPlatformUtils::fgMemoryManager, &xsd); + init_parser(parser); + QString messages; + CustomErrorHandler eh(&messages); + parser.setErrorHandler(&eh); + + // parse the XML file + parser.parse((const char16_t *)hlFile.fileName().utf16()); + + // report issues + if (eh.failed()) { + qWarning("Failed to validate XML %s: %s", qPrintable(hlFile.fileName()), qPrintable(messages)); anyError = 4; continue; } @@ -2708,6 +2886,10 @@ int main(int argc, char *argv[]) // add boolean one hl[QStringLiteral("hidden")] = attrToBool(xml.attributes().value(QLatin1String("hidden"))); + // keep some strings as UTF-8 for faster translations + hl[QStringLiteral("nameUtf8")] = hl[QStringLiteral("name")].toString().toUtf8(); + hl[QStringLiteral("sectionUtf8")] = hl[QStringLiteral("section")].toString().toUtf8(); + // remember hl hls[QFileInfo(hlFile).fileName()] = hl; diff --git a/src/libs/3rdparty/syntax-highlighting/src/lib/CMakeLists.txt b/src/libs/3rdparty/syntax-highlighting/src/lib/CMakeLists.txt index fe89fdd715e..2b2845eba4d 100644 --- a/src/libs/3rdparty/syntax-highlighting/src/lib/CMakeLists.txt +++ b/src/libs/3rdparty/syntax-highlighting/src/lib/CMakeLists.txt @@ -1,8 +1,14 @@ -add_library(KF5SyntaxHighlighting) +add_library(KF6SyntaxHighlighting) -ecm_create_qm_loader(syntax_highlighting_QM_LOADER syntaxhighlighting5_qt) +set_target_properties(KF6SyntaxHighlighting PROPERTIES + VERSION ${KSYNTAXHIGHLIGHTING_VERSION} + SOVERSION ${KSYNTAXHIGHLIGHTING_SOVERSION} + EXPORT_NAME SyntaxHighlighting +) -target_sources(KF5SyntaxHighlighting PRIVATE +ecm_create_qm_loader(syntax_highlighting_QM_LOADER syntaxhighlighting6_qt) + +target_sources(KF6SyntaxHighlighting PRIVATE abstracthighlighter.cpp context.cpp contextswitch.cpp @@ -25,7 +31,7 @@ target_sources(KF5SyntaxHighlighting PRIVATE ${syntax_highlighting_QM_LOADER} $ ) -ecm_qt_declare_logging_category(KF5SyntaxHighlighting +ecm_qt_declare_logging_category(KF6SyntaxHighlighting HEADER ksyntaxhighlighting_logging.h IDENTIFIER KSyntaxHighlighting::Log CATEGORY_NAME kf.syntaxhighlighting @@ -34,25 +40,21 @@ ecm_qt_declare_logging_category(KF5SyntaxHighlighting EXPORT KSYNTAXHIGHLIGHTING ) -ecm_generate_export_header(KF5SyntaxHighlighting +ecm_generate_export_header(KF6SyntaxHighlighting BASE_NAME KSyntaxHighlighting GROUP_BASE_NAME KF VERSION ${KF_VERSION} + USE_VERSION_HEADER DEPRECATED_BASE_VERSION 0 - DEPRECATION_VERSIONS 5.87 + DEPRECATION_VERSIONS EXCLUDE_DEPRECATED_BEFORE_AND_AT ${EXCLUDE_DEPRECATED_BEFORE_AND_AT} ) -set_target_properties(KF5SyntaxHighlighting PROPERTIES - VERSION ${SyntaxHighlighting_VERSION} - SOVERSION ${SyntaxHighlighting_SOVERSION} - EXPORT_NAME SyntaxHighlighting -) -target_link_libraries(KF5SyntaxHighlighting +target_link_libraries(KF6SyntaxHighlighting PUBLIC - Qt${QT_MAJOR_VERSION}::Gui + Qt6::Gui PRIVATE - Qt${QT_MAJOR_VERSION}::Network + Qt6::Network ) set(Forwarding_Header_Names @@ -74,12 +76,12 @@ ecm_generate_headers(CamelCase_HEADERS OUTPUT_DIR ${CMAKE_BINARY_DIR}/KSyntaxHighlighting/KSyntaxHighlighting ) -target_include_directories(KF5SyntaxHighlighting +target_include_directories(KF6SyntaxHighlighting INTERFACE "$" PUBLIC "$" ) -install(TARGETS KF5SyntaxHighlighting EXPORT KF5SyntaxHighlightingTargets ${KDE_INSTALL_TARGETS_DEFAULT_ARGS}) +install(TARGETS KF6SyntaxHighlighting EXPORT KF6SyntaxHighlightingTargets ${KDE_INSTALL_TARGETS_DEFAULT_ARGS}) install(FILES ${CamelCase_HEADERS} @@ -90,17 +92,17 @@ install(FILES if(BUILD_QCH) ecm_add_qch( - KF5SyntaxHighlighting_QCH + KF6SyntaxHighlighting_QCH NAME KSyntaxHighlighting - BASE_NAME KF5SyntaxHighlighting + BASE_NAME KF6SyntaxHighlighting VERSION ${KF_VERSION} ORG_DOMAIN org.kde SOURCES # using only public headers, to cover only public API ${SyntaxHighlighting_HEADERS} MD_MAINPAGE "${CMAKE_SOURCE_DIR}/README.md" LINK_QCHS - Qt5Core_QCH - Qt5Gui_QCH + Qt6Core_QCH + Qt6Gui_QCH INCLUDE_DIRS ${CMAKE_CURRENT_BINARY_DIR} BLANK_MACROS @@ -111,11 +113,3 @@ if(BUILD_QCH) COMPONENT Devel ) endif() -ecm_generate_pri_file( - BASE_NAME KSyntaxHighlighting LIB_NAME - KF5SyntaxHighlighting - DEPS "gui" - FILENAME_VAR PRI_FILENAME - INCLUDE_INSTALL_DIR ${KDE_INSTALL_INCLUDEDIR_KF}/KSyntaxHighlighting -) -install(FILES ${PRI_FILENAME} DESTINATION ${ECM_MKSPECS_INSTALL_DIR}) diff --git a/src/libs/3rdparty/syntax-highlighting/src/lib/abstracthighlighter.cpp b/src/libs/3rdparty/syntax-highlighting/src/lib/abstracthighlighter.cpp index ac5d98abfb3..87dabadc7b1 100644 --- a/src/libs/3rdparty/syntax-highlighting/src/lib/abstracthighlighter.cpp +++ b/src/libs/3rdparty/syntax-highlighting/src/lib/abstracthighlighter.cpp @@ -12,6 +12,7 @@ #include "format.h" #include "ksyntaxhighlighting_logging.h" #include "repository.h" +#include "repository_p.h" #include "rule_p.h" #include "state.h" #include "state_p.h" @@ -97,13 +98,6 @@ static inline int firstNonSpaceChar(QStringView text) return text.size(); } -#if KSYNTAXHIGHLIGHTING_BUILD_DEPRECATED_SINCE(5, 87) -State AbstractHighlighter::highlightLine(const QString &text, const State &state) -{ - return highlightLine(QStringView(text), state); -} -#endif - State AbstractHighlighter::highlightLine(QStringView text, const State &state) { Q_D(AbstractHighlighter); @@ -116,43 +110,47 @@ State AbstractHighlighter::highlightLine(QStringView text, const State &state) return State(); } + // limit the cache for unification to some reasonable size + // we use here at the moment 64k elements to not hog too much memory + // and to make the clearing no big stall + if (defData->unify.size() > 64 * 1024) + defData->unify.clear(); + // verify/initialize state auto newState = state; auto stateData = StateData::get(newState); - const auto definitionId = DefinitionData::get(d->m_definition)->id; - if (!stateData->isEmpty() && stateData->m_defId != definitionId) { + bool isSharedData = true; + if (Q_UNLIKELY(stateData && stateData->m_defId != defData->id)) { qCDebug(Log) << "Got invalid state, resetting."; - stateData->clear(); + stateData = nullptr; } - if (stateData->isEmpty()) { + if (Q_UNLIKELY(!stateData)) { + stateData = StateData::reset(newState); stateData->push(defData->initialContext(), QStringList()); - stateData->m_defId = definitionId; + stateData->m_defId = defData->id; + isSharedData = false; } // process empty lines - if (text.isEmpty()) { + if (Q_UNLIKELY(text.isEmpty())) { /** * handle line empty context switches * guard against endless loops * see https://phabricator.kde.org/D18509 */ int endlessLoopingCounter = 0; - while (!stateData->topContext()->lineEmptyContext().isStay() || !stateData->topContext()->lineEndContext().isStay()) { + while (!stateData->topContext()->lineEmptyContext().isStay()) { /** * line empty context switches */ - if (!stateData->topContext()->lineEmptyContext().isStay()) { - if (!d->switchContext(stateData, stateData->topContext()->lineEmptyContext(), QStringList())) { - /** - * end when trying to #pop the main context - */ - break; - } + if (!d->switchContext(stateData, stateData->topContext()->lineEmptyContext(), QStringList(), newState, isSharedData)) { /** - * line end context switches only when lineEmptyContext is #stay. This avoids - * skipping empty lines after a line continuation character (see bug 405903) + * end when trying to #pop the main context */ - } else if (!d->switchContext(stateData, stateData->topContext()->lineEndContext(), QStringList())) { + break; + } + + if (stateData->topContext()->stopEmptyLineContextSwitchLoop()) { break; } @@ -165,9 +163,11 @@ State AbstractHighlighter::highlightLine(QStringView text, const State &state) } auto context = stateData->topContext(); applyFormat(0, 0, context->attributeFormat()); - return newState; + return *defData->unify.insert(newState); } + auto &dynamicRegexpCache = RepositoryPrivate::get(defData->repo)->m_dynamicRegexpCache; + int offset = 0; int beginOffset = 0; bool lineContinuation = false; @@ -178,10 +178,10 @@ State AbstractHighlighter::highlightLine(QStringView text, const State &state) * - store the result of the first position that matches (or -1 for no match in the full line) in the skipOffsets hash for re-use * - have capturesForLastDynamicSkipOffset as guard for dynamic regexes to invalidate the cache if they might have changed */ - QVarLengthArray, 8> skipOffsets; + QVarLengthArray, 8> skipOffsets; QStringList capturesForLastDynamicSkipOffset; - auto getSkipOffsetValue = [&skipOffsets](Rule *r) -> int { + auto getSkipOffsetValue = [&skipOffsets](const Rule *r) -> int { auto i = std::find_if(skipOffsets.begin(), skipOffsets.end(), [r](const auto &v) { return v.first == r; }); @@ -190,7 +190,7 @@ State AbstractHighlighter::highlightLine(QStringView text, const State &state) return i->second; }; - auto insertSkipOffset = [&skipOffsets](Rule *r, int i) { + auto insertSkipOffset = [&skipOffsets](const Rule *r, int i) { auto it = std::find_if(skipOffsets.begin(), skipOffsets.end(), [r](const auto &v) { return v.first == r; }); @@ -237,7 +237,8 @@ State AbstractHighlighter::highlightLine(QStringView text, const State &state) bool isLookAhead = false; int newOffset = 0; const Format *newFormat = nullptr; - for (const auto &rule : stateData->topContext()->rules()) { + for (const auto &ruleShared : stateData->topContext()->rules()) { + auto rule = ruleShared.get(); /** * filter out rules that require a specific column */ @@ -265,29 +266,33 @@ State AbstractHighlighter::highlightLine(QStringView text, const State &state) } } - /** - * shall we skip application of this rule? two cases: - * - rule can't match at all => currentSkipOffset < 0 - * - rule will only match for some higher offset => currentSkipOffset > offset - * - * we need to invalidate this if we are dynamic and have different captures then last time - */ - if (rule->isDynamic() && (capturesForLastDynamicSkipOffset != stateData->topCaptures())) { - skipOffsets.clear(); - } - const auto currentSkipOffset = getSkipOffsetValue(rule.get()); - if (currentSkipOffset < 0 || currentSkipOffset > offset) { - continue; + int currentSkipOffset = 0; + if (Q_UNLIKELY(rule->hasSkipOffset())) { + /** + * shall we skip application of this rule? two cases: + * - rule can't match at all => currentSkipOffset < 0 + * - rule will only match for some higher offset => currentSkipOffset > offset + * + * we need to invalidate this if we are dynamic and have different captures then last time + */ + if (rule->isDynamic() && (capturesForLastDynamicSkipOffset != stateData->topCaptures())) { + skipOffsets.clear(); + } else { + currentSkipOffset = getSkipOffsetValue(rule); + if (currentSkipOffset < 0 || currentSkipOffset > offset) { + continue; + } + } } - const auto newResult = rule->doMatch(text, offset, stateData->topCaptures()); + auto newResult = rule->doMatch(text, offset, stateData->topCaptures(), dynamicRegexpCache); newOffset = newResult.offset(); /** * update skip offset if new one rules out any later match or is larger than current one */ if (newResult.skipOffset() < 0 || newResult.skipOffset() > currentSkipOffset) { - insertSkipOffset(rule.get(), newResult.skipOffset()); + insertSkipOffset(rule, newResult.skipOffset()); // remember new captures, if dynamic to enforce proper reset above on change! if (rule->isDynamic()) { @@ -316,12 +321,12 @@ State AbstractHighlighter::highlightLine(QStringView text, const State &state) if (rule->isLookAhead()) { Q_ASSERT(!rule->context().isStay()); - d->switchContext(stateData, rule->context(), newResult.captures()); + d->switchContext(stateData, rule->context(), std::move(newResult.captures()), newState, isSharedData); isLookAhead = true; break; } - d->switchContext(stateData, rule->context(), newResult.captures()); + d->switchContext(stateData, rule->context(), std::move(newResult.captures()), newState, isSharedData); newFormat = rule->attributeFormat().isValid() ? &rule->attributeFormat() : &stateData->topContext()->attributeFormat(); if (newOffset == text.size() && rule->isLineContinue()) { lineContinuation = true; @@ -334,7 +339,7 @@ State AbstractHighlighter::highlightLine(QStringView text, const State &state) if (newOffset <= offset) { // no matching rule if (stateData->topContext()->fallthrough()) { - d->switchContext(stateData, stateData->topContext()->fallthroughContext(), QStringList()); + d->switchContext(stateData, stateData->topContext()->fallthroughContext(), QStringList(), newState, isSharedData); continue; } @@ -381,7 +386,7 @@ State AbstractHighlighter::highlightLine(QStringView text, const State &state) { int endlessLoopingCounter = 0; while (!stateData->topContext()->lineEndContext().isStay() && !lineContinuation) { - if (!d->switchContext(stateData, stateData->topContext()->lineEndContext(), QStringList())) { + if (!d->switchContext(stateData, stateData->topContext()->lineEndContext(), QStringList(), newState, isSharedData)) { break; } @@ -394,18 +399,30 @@ State AbstractHighlighter::highlightLine(QStringView text, const State &state) } } - return newState; + return *defData->unify.insert(newState); } -bool AbstractHighlighterPrivate::switchContext(StateData *data, const ContextSwitch &contextSwitch, const QStringList &captures) +bool AbstractHighlighterPrivate::switchContext(StateData *&data, const ContextSwitch &contextSwitch, QStringList &&captures, State &state, bool &isSharedData) { + const auto popCount = contextSwitch.popCount(); + const auto context = contextSwitch.context(); + if (popCount <= 0 && !context) { + return true; + } + + // a modified state must be detached before modification + if (isSharedData) { + data = StateData::detach(state); + isSharedData = false; + } + // kill as many items as requested from the stack, will always keep the initial context alive! - const bool initialContextSurvived = data->pop(contextSwitch.popCount()); + const bool initialContextSurvived = data->pop(popCount); // if we have a new context to add, push it // then we always "succeed" - if (contextSwitch.context()) { - data->push(contextSwitch.context(), captures); + if (context) { + data->push(context, std::move(captures)); return true; } diff --git a/src/libs/3rdparty/syntax-highlighting/src/lib/abstracthighlighter.h b/src/libs/3rdparty/syntax-highlighting/src/lib/abstracthighlighter.h index 49cfbf25303..676a0f522ab 100644 --- a/src/libs/3rdparty/syntax-highlighting/src/lib/abstracthighlighter.h +++ b/src/libs/3rdparty/syntax-highlighting/src/lib/abstracthighlighter.h @@ -7,20 +7,15 @@ #ifndef KSYNTAXHIGHLIGHTING_ABSTRACTHIGHLIGHTERM_H #define KSYNTAXHIGHLIGHTING_ABSTRACTHIGHLIGHTERM_H +#include "definition.h" #include "ksyntaxhighlighting_export.h" #include - -#include - -QT_BEGIN_NAMESPACE -class QString; -QT_END_NAMESPACE +#include namespace KSyntaxHighlighting { class AbstractHighlighterPrivate; -class Definition; class FoldingRegion; class Format; class State; @@ -106,21 +101,8 @@ public: protected: AbstractHighlighter(); - AbstractHighlighter(AbstractHighlighterPrivate *dd); + KSYNTAXHIGHLIGHTING_NO_EXPORT explicit AbstractHighlighter(AbstractHighlighterPrivate *dd); -#if KSYNTAXHIGHLIGHTING_ENABLE_DEPRECATED_SINCE(5, 87) - /** - * @copydoc highlightLine(QStringView,const State&) - * @deprecated since 5.87, use highlightLine(QStringView, const State&) instead. - */ - // no deprecation warning, as removal of this will automatically "port" the using code - State highlightLine(const QString &text, const State &state); -#endif - - // TODO KF6: add an optional void* context argument that is passed through - // to the applyX() calls, so highlighters dealing with some form of line object - // (such as QSyntaxHighlighter or KTextEditor) can avoid some ugly hacks to have - // this context available in their applyX methods /** * Highlight the given line. Call this from your derived class * where appropriate. This will result in any number of applyFormat() diff --git a/src/libs/3rdparty/syntax-highlighting/src/lib/abstracthighlighter_p.h b/src/libs/3rdparty/syntax-highlighting/src/lib/abstracthighlighter_p.h index 6128beccfa0..04ac9898f8c 100644 --- a/src/libs/3rdparty/syntax-highlighting/src/lib/abstracthighlighter_p.h +++ b/src/libs/3rdparty/syntax-highlighting/src/lib/abstracthighlighter_p.h @@ -14,6 +14,7 @@ namespace KSyntaxHighlighting { class ContextSwitch; class StateData; +class State; class AbstractHighlighterPrivate { @@ -22,7 +23,7 @@ public: virtual ~AbstractHighlighterPrivate(); void ensureDefinitionLoaded(); - bool switchContext(StateData *data, const ContextSwitch &contextSwitch, const QStringList &captures); + bool switchContext(StateData *&data, const ContextSwitch &contextSwitch, QStringList &&captures, State &state, bool &isSharedData); Definition m_definition; Theme m_theme; diff --git a/src/libs/3rdparty/syntax-highlighting/src/lib/ansihighlighter.cpp b/src/libs/3rdparty/syntax-highlighting/src/lib/ansihighlighter.cpp index 31678018f9f..e9bea02d1c7 100644 --- a/src/libs/3rdparty/syntax-highlighting/src/lib/ansihighlighter.cpp +++ b/src/libs/3rdparty/syntax-highlighting/src/lib/ansihighlighter.cpp @@ -5,6 +5,7 @@ */ #include "ansihighlighter.h" +#include "abstracthighlighter_p.h" #include "context_p.h" #include "definition.h" #include "definition_p.h" @@ -18,6 +19,7 @@ #include #include #include +#include #include #include @@ -783,7 +785,7 @@ GraphLine &lineAtOffset(std::vector &graphLines, int offset) } // disable bold, italic and underline on | -const QLatin1String graphSymbol("\x1b[21;23;24m|"); +const QLatin1String graphSymbol("\x1b[22;23;24m|"); // reverse video const QLatin1String nameStyle("\x1b[7m"); @@ -793,8 +795,8 @@ const QLatin1String nameStyle("\x1b[7m"); class DebugSyntaxHighlighter : public KSyntaxHighlighting::AbstractHighlighter { public: - using TraceOption = KSyntaxHighlighting::AnsiHighlighter::TraceOption; - using TraceOptions = KSyntaxHighlighting::AnsiHighlighter::TraceOptions; + using Option = KSyntaxHighlighting::AnsiHighlighter::Option; + using Options = KSyntaxHighlighting::AnsiHighlighter::Options; void setDefinition(const KSyntaxHighlighting::Definition &def) override { @@ -815,14 +817,14 @@ public: QLatin1String infoStyle, QLatin1String editorBackground, const std::vector> &ansiStyles, - TraceOptions traceOptions) + Options options) { initRegionStyles(ansiStyles); - m_hasFormatTrace = traceOptions.testFlag(TraceOption::Format); - m_hasRegionTrace = traceOptions.testFlag(TraceOption::Region); - m_hasStackSizeTrace = traceOptions.testFlag(TraceOption::StackSize); - m_hasContextTrace = traceOptions.testFlag(TraceOption::Context); + m_hasFormatTrace = options.testFlag(Option::TraceFormat); + m_hasRegionTrace = options.testFlag(Option::TraceRegion); + m_hasStackSizeTrace = options.testFlag(Option::TraceStackSize); + m_hasContextTrace = options.testFlag(Option::TraceContext); const bool hasFormatOrContextTrace = m_hasFormatTrace || m_hasContextTrace || m_hasStackSizeTrace; const bool hasSeparator = hasFormatOrContextTrace && m_hasRegionTrace; @@ -831,6 +833,7 @@ public: bool firstLine = true; State state; QString currentLine; + const bool isUnbuffered = options.testFlag(Option::Unbuffered); while (in.readLineInto(¤tLine)) { auto oldState = state; state = highlightLine(currentLine, state); @@ -864,6 +867,10 @@ public: } m_highlightedFragments.clear(); + + if (isUnbuffered) { + out.flush(); + } } } @@ -970,12 +977,14 @@ private: QString label; if (m_hasStackSizeTrace) { - label += QLatin1Char('(') % QString::number(stateData->size()) % QLatin1Char(')'); + // first state is empty + int stateSize = stateData ? stateData->size() : 0; + label = QLatin1Char('(') % QString::number(stateSize) % QLatin1Char(')'); } if (m_hasContextTrace) { // first state is empty - if (stateData->isEmpty()) { + if (!stateData) { return label + QStringLiteral("[???]"); } @@ -1138,7 +1147,7 @@ private: QString name; int offset; int length; - quint16 formatId; + int formatId; }; struct ContextCaptureHighlighter : KSyntaxHighlighting::AbstractHighlighter { @@ -1168,7 +1177,7 @@ private: int depth; int offset; int bindIndex; - quint16 regionId; + int regionId; State state; }; @@ -1190,7 +1199,7 @@ private: }; } // anonymous namespace -class KSyntaxHighlighting::AnsiHighlighterPrivate +class KSyntaxHighlighting::AnsiHighlighterPrivate : public AbstractHighlighterPrivate { public: QTextStream out; @@ -1201,7 +1210,7 @@ public: }; AnsiHighlighter::AnsiHighlighter() - : d(new AnsiHighlighterPrivate()) + : AbstractHighlighter(new AnsiHighlighterPrivate()) { } @@ -1209,6 +1218,7 @@ AnsiHighlighter::~AnsiHighlighter() = default; void AnsiHighlighter::setOutputFile(const QString &fileName) { + Q_D(AnsiHighlighter); if (d->file.isOpen()) { d->file.close(); } @@ -1218,21 +1228,16 @@ void AnsiHighlighter::setOutputFile(const QString &fileName) return; } d->out.setDevice(&d->file); -#if QT_VERSION < QT_VERSION_CHECK(6, 0, 0) - d->out.setCodec("UTF-8"); -#endif } void AnsiHighlighter::setOutputFile(FILE *fileHandle) { + Q_D(AnsiHighlighter); d->file.open(fileHandle, QIODevice::WriteOnly); d->out.setDevice(&d->file); -#if QT_VERSION < QT_VERSION_CHECK(6, 0, 0) - d->out.setCodec("UTF-8"); -#endif } -void AnsiHighlighter::highlightFile(const QString &fileName, AnsiFormat format, bool useEditorBackground, TraceOptions traceOptions) +void AnsiHighlighter::highlightFile(const QString &fileName, AnsiFormat format, Options options) { QFileInfo fi(fileName); QFile f(fileName); @@ -1241,19 +1246,21 @@ void AnsiHighlighter::highlightFile(const QString &fileName, AnsiFormat format, return; } - highlightData(&f, format, useEditorBackground, traceOptions); + highlightData(&f, format, options); } -void AnsiHighlighter::highlightData(QIODevice *dev, AnsiFormat format, bool useEditorBackground, TraceOptions traceOptions) +void AnsiHighlighter::highlightData(QIODevice *dev, AnsiFormat format, Options options) { + Q_D(AnsiHighlighter); + if (!d->out.device()) { qCWarning(Log) << "No output stream defined!"; return; } const auto is256Colors = (format == AnsiFormat::XTerm256Color); - const auto theme = this->theme(); - const auto definition = this->definition(); + const auto &theme = d->m_theme; + const auto &definition = d->m_definition; auto definitions = definition.includedDefinitions(); definitions.append(definition); @@ -1265,6 +1272,8 @@ void AnsiHighlighter::highlightData(QIODevice *dev, AnsiFormat format, bool useE QLatin1String foregroundDefaultColor; QLatin1String backgroundDefaultColor; + const bool useEditorBackground = options.testFlag(Option::UseEditorBackground); + // https://en.wikipedia.org/wiki/ANSI_escape_code#SGR_parameters if (useEditorBackground) { @@ -1277,23 +1286,19 @@ void AnsiHighlighter::highlightData(QIODevice *dev, AnsiFormat format, bool useE backgroundDefaultColor = backgroundColorBuffer.latin1().mid(2); } - // ansiStyles must not be empty for applyFormat to work even with a definition without any context - if (d->ansiStyles.empty()) { - d->ansiStyles.resize(32); - } else { - d->ansiStyles[0].first.clear(); - d->ansiStyles[0].second.clear(); + int maxId = 0; + for (const auto &definition : std::as_const(definitions)) { + for (const auto &format : std::as_const(DefinitionData::get(definition)->formats)) { + maxId = qMax(maxId, format.id()); + } } + d->ansiStyles.clear(); + // ansiStyles must not be empty for applyFormat to work even with a definition without any context + d->ansiStyles.resize(maxId + 1); // initialize ansiStyles - for (auto &&definition : std::as_const(definitions)) { - for (auto &&format : std::as_const(DefinitionData::get(definition)->formats)) { - const auto id = format.id(); - if (id >= d->ansiStyles.size()) { - // better than id + 1 to avoid successive allocations - d->ansiStyles.resize(id * 2); - } - + for (const auto &definition : std::as_const(definitions)) { + for (const auto &format : std::as_const(DefinitionData::get(definition)->formats)) { AnsiBuffer buffer; buffer.append(QLatin1String("\x1b[")); @@ -1329,7 +1334,8 @@ void AnsiHighlighter::highlightData(QIODevice *dev, AnsiFormat format, bool useE // if there is ANSI style if (buffer.latin1().size() > 2) { buffer.setFinalStyle(); - d->ansiStyles[id].first = buffer.latin1(); + auto &style = d->ansiStyles[format.id()]; + style.first = buffer.latin1(); if (useEditorBackground) { buffer.clear(); @@ -1338,11 +1344,11 @@ void AnsiHighlighter::highlightData(QIODevice *dev, AnsiFormat format, bool useE buffer.append(hasEffect ? QLatin1String("\x1b[0;") : QLatin1String("\x1b[")); buffer.append(backgroundDefaultColor); buffer.setFinalStyle(); - d->ansiStyles[id].second = buffer.latin1(); + style.second = buffer.latin1(); } else if (hasEffect) { buffer.append(QLatin1String("\x1b[")); if (hasBold) { - buffer.append(QLatin1String("21;")); + buffer.append(QLatin1String("22;")); } if (hasItalic) { buffer.append(QLatin1String("23;")); @@ -1354,10 +1360,10 @@ void AnsiHighlighter::highlightData(QIODevice *dev, AnsiFormat format, bool useE buffer.append(QLatin1String("29;")); } buffer.setFinalStyle(); - d->ansiStyles[id].second = buffer.latin1(); + style.second = buffer.latin1(); } } else { - d->ansiStyles[id].second = QStringLiteral("\x1b[0m"); + style.second = QStringLiteral("\x1b[0m"); } } } @@ -1370,13 +1376,11 @@ void AnsiHighlighter::highlightData(QIODevice *dev, AnsiFormat format, bool useE } QTextStream in(dev); -#if QT_VERSION < QT_VERSION_CHECK(6, 0, 0) - in.setCodec("UTF-8"); -#endif - if (!traceOptions) { + if (!options.testAnyFlag(Option::TraceAll)) { State state; QString currentLine; + const bool isUnbuffered = options.testFlag(Option::Unbuffered); while (in.readLineInto(¤tLine)) { d->currentLine = currentLine; state = highlightLine(d->currentLine, state); @@ -1386,6 +1390,10 @@ void AnsiHighlighter::highlightData(QIODevice *dev, AnsiFormat format, bool useE } else { d->out << QLatin1Char('\n'); } + + if (isUnbuffered) { + d->out.flush(); + } } } else { AnsiBuffer buffer; @@ -1394,7 +1402,7 @@ void AnsiHighlighter::highlightData(QIODevice *dev, AnsiFormat format, bool useE buffer.setFinalStyle(); DebugSyntaxHighlighter debugHighlighter; debugHighlighter.setDefinition(definition); - debugHighlighter.highlightData(in, d->out, buffer.latin1(), backgroundDefaultColor, d->ansiStyles, traceOptions); + debugHighlighter.highlightData(in, d->out, buffer.latin1(), backgroundDefaultColor, d->ansiStyles, options); } if (useEditorBackground) { @@ -1408,6 +1416,7 @@ void AnsiHighlighter::highlightData(QIODevice *dev, AnsiFormat format, bool useE void AnsiHighlighter::applyFormat(int offset, int length, const Format &format) { + Q_D(AnsiHighlighter); auto const &ansiStyle = d->ansiStyles[format.id()]; d->out << ansiStyle.first << d->currentLine.mid(offset, length) << ansiStyle.second; } diff --git a/src/libs/3rdparty/syntax-highlighting/src/lib/ansihighlighter.h b/src/libs/3rdparty/syntax-highlighting/src/lib/ansihighlighter.h index ffb13f38f37..0942aa0242b 100644 --- a/src/libs/3rdparty/syntax-highlighting/src/lib/ansihighlighter.h +++ b/src/libs/3rdparty/syntax-highlighting/src/lib/ansihighlighter.h @@ -11,10 +11,11 @@ #include "ksyntaxhighlighting_export.h" #include -#include #include -#include +QT_BEGIN_NAMESPACE +class QIODevice; +QT_END_NAMESPACE namespace KSyntaxHighlighting { @@ -29,24 +30,25 @@ public: XTerm256Color, }; - enum class TraceOption { + enum class Option { NoOptions, - Format = 1 << 0, - Region = 1 << 1, - Context = 1 << 2, - StackSize = 1 << 3, + UseEditorBackground = 1 << 0, + Unbuffered = 1 << 1, + + // Options that displays a useful visual aid for syntax creation + TraceFormat = 1 << 2, + TraceRegion = 1 << 3, + TraceContext = 1 << 4, + TraceStackSize = 1 << 5, + TraceAll = TraceFormat | TraceRegion | TraceContext | TraceStackSize, }; - Q_DECLARE_FLAGS(TraceOptions, TraceOption) + Q_DECLARE_FLAGS(Options, Option) AnsiHighlighter(); ~AnsiHighlighter() override; - void highlightFile(const QString &fileName, - AnsiFormat format = AnsiFormat::TrueColor, - bool useEditorBackground = true, - TraceOptions traceOptions = TraceOptions()); - void - highlightData(QIODevice *device, AnsiFormat format = AnsiFormat::TrueColor, bool useEditorBackground = true, TraceOptions traceOptions = TraceOptions()); + void highlightFile(const QString &fileName, AnsiFormat format = AnsiFormat::TrueColor, Options options = Option::UseEditorBackground); + void highlightData(QIODevice *device, AnsiFormat format = AnsiFormat::TrueColor, Options options = Option::UseEditorBackground); void setOutputFile(const QString &fileName); void setOutputFile(FILE *fileHandle); @@ -55,10 +57,10 @@ protected: void applyFormat(int offset, int length, const Format &format) override; private: - std::unique_ptr d; + Q_DECLARE_PRIVATE(AnsiHighlighter) }; } -Q_DECLARE_OPERATORS_FOR_FLAGS(KSyntaxHighlighting::AnsiHighlighter::TraceOptions) +Q_DECLARE_OPERATORS_FOR_FLAGS(KSyntaxHighlighting::AnsiHighlighter::Options) #endif // KSYNTAXHIGHLIGHTING_ANSIHIGHLIGHTER_H diff --git a/src/libs/3rdparty/syntax-highlighting/src/lib/context.cpp b/src/libs/3rdparty/syntax-highlighting/src/lib/context.cpp index ff5254cb6e5..af269d14d03 100644 --- a/src/libs/3rdparty/syntax-highlighting/src/lib/context.cpp +++ b/src/libs/3rdparty/syntax-highlighting/src/lib/context.cpp @@ -38,7 +38,15 @@ void Context::resolveContexts(DefinitionData &def, const HighlightingContextData m_lineEndContext.resolve(def, data.lineEndContext); m_lineEmptyContext.resolve(def, data.lineEmptyContext); m_fallthroughContext.resolve(def, data.fallthroughContext); - m_fallthrough = !m_fallthroughContext.isStay(); + m_stopEmptyLineContextSwitchLoop = data.stopEmptyLineContextSwitchLoop; + + /** + * line end context switches only when lineEmptyContext is #stay. This avoids + * skipping empty lines after a line continuation character (see bug 405903) + */ + if (m_lineEmptyContext.isStay()) { + m_lineEmptyContext = m_lineEndContext; + } m_rules.reserve(data.rules.size()); for (const auto &ruleData : data.rules) { @@ -65,6 +73,7 @@ void Context::resolveIncludes(DefinitionData &def) for (auto it = m_rules.begin(); it != m_rules.end();) { const IncludeRules *includeRules = it->get()->castToIncludeRules(); if (!includeRules) { + m_hasDynamicRule = m_hasDynamicRule || it->get()->isDynamic(); ++it; continue; } @@ -111,6 +120,8 @@ void Context::resolveIncludes(DefinitionData &def) context->resolveIncludes(*defData); } + m_hasDynamicRule = m_hasDynamicRule || context->m_hasDynamicRule; + /** * handle included attribute * transitive closure: we might include attributes included from somewhere else diff --git a/src/libs/3rdparty/syntax-highlighting/src/lib/context_p.h b/src/libs/3rdparty/syntax-highlighting/src/lib/context_p.h index 7e077b5a244..8cf0f1bfaba 100644 --- a/src/libs/3rdparty/syntax-highlighting/src/lib/context_p.h +++ b/src/libs/3rdparty/syntax-highlighting/src/lib/context_p.h @@ -16,10 +16,6 @@ #include -QT_BEGIN_NAMESPACE -class QXmlStreamReader; -QT_END_NAMESPACE - namespace KSyntaxHighlighting { class DefinitionData; @@ -52,7 +48,17 @@ public: bool fallthrough() const { - return m_fallthrough; + return !m_fallthroughContext.isStay(); + } + + bool hasDynamicRule() const + { + return m_hasDynamicRule; + } + + bool stopEmptyLineContextSwitchLoop() const + { + return m_stopEmptyLineContextSwitchLoop; } const ContextSwitch &fallthroughContext() const @@ -96,7 +102,8 @@ private: Format m_attributeFormat; ResolveState m_resolveState = Unresolved; - bool m_fallthrough = false; + bool m_hasDynamicRule = false; + bool m_stopEmptyLineContextSwitchLoop = true; bool m_indentationBasedFolding; }; } diff --git a/src/libs/3rdparty/syntax-highlighting/src/lib/definition.cpp b/src/libs/3rdparty/syntax-highlighting/src/lib/definition.cpp index 670dfddedb6..e2cca6da712 100644 --- a/src/libs/3rdparty/syntax-highlighting/src/lib/definition.cpp +++ b/src/libs/3rdparty/syntax-highlighting/src/lib/definition.cpp @@ -26,8 +26,6 @@ #include #include #include -#include -#include #include #include @@ -43,13 +41,8 @@ DefinitionData::DefinitionData() DefinitionData::~DefinitionData() = default; -DefinitionData *DefinitionData::get(const Definition &def) -{ - return def.d.get(); -} - Definition::Definition() - : d(new DefinitionData) + : d(std::make_shared()) { d->q = *this; } @@ -63,6 +56,9 @@ Definition &Definition::operator=(const Definition &) = default; Definition::Definition(std::shared_ptr &&dd) : d(std::move(dd)) { + if (!d) { + Definition().d.swap(d); + } } bool Definition::operator==(const Definition &other) const @@ -92,7 +88,10 @@ QString Definition::name() const QString Definition::translatedName() const { - return QCoreApplication::instance()->translate("Language", d->name.toUtf8().constData()); + if (d->translatedName.isEmpty()) { + d->translatedName = QCoreApplication::instance()->translate("Language", d->nameUtf8.isEmpty() ? d->name.toUtf8().constData() : d->nameUtf8.constData()); + } + return d->translatedName; } QString Definition::section() const @@ -102,15 +101,19 @@ QString Definition::section() const QString Definition::translatedSection() const { - return QCoreApplication::instance()->translate("Language Section", d->section.toUtf8().constData()); + if (d->translatedSection.isEmpty()) { + d->translatedSection = QCoreApplication::instance()->translate("Language Section", + d->sectionUtf8.isEmpty() ? d->section.toUtf8().constData() : d->sectionUtf8.constData()); + } + return d->translatedSection; } -QVector Definition::mimeTypes() const +QList Definition::mimeTypes() const { return d->mimetypes; } -QVector Definition::extensions() const +QList Definition::extensions() const { return d->extensions; } @@ -218,12 +221,12 @@ bool Definition::setKeywordList(const QString &name, const QStringList &content) } } -QVector Definition::formats() const +QList Definition::formats() const { d->load(); // sort formats so that the order matches the order of the itemDatas in the xml files. - auto formatList = QVector::fromList(d->formats.values()); + auto formatList = d->formats.values(); std::sort(formatList.begin(), formatList.end(), [](const KSyntaxHighlighting::Format &lhs, const KSyntaxHighlighting::Format &rhs) { return lhs.id() < rhs.id(); }); @@ -231,13 +234,13 @@ QVector Definition::formats() const return formatList; } -QVector Definition::includedDefinitions() const +QList Definition::includedDefinitions() const { d->load(); // init worklist and result used as guard with this definition - QVector queue{d.get()}; - QVector definitions{*this}; + QList queue{d.get()}; + QList definitions{*this}; while (!queue.empty()) { const auto *def = queue.back(); queue.pop_back(); @@ -275,7 +278,7 @@ QPair Definition::multiLineCommentMarker() const return {d->multiLineCommentStartMarker, d->multiLineCommentEndMarker}; } -QVector> Definition::characterEncodings() const +QList> Definition::characterEncodings() const { d->load(); return d->characterEncodings; @@ -394,7 +397,11 @@ void DefinitionData::clear() characterEncodings.clear(); fileName.clear(); + nameUtf8.clear(); + translatedName.clear(); section.clear(); + sectionUtf8.clear(); + translatedSection.clear(); style.clear(); indenter.clear(); author.clear(); @@ -405,6 +412,9 @@ void DefinitionData::clear() version = 0.0f; priority = 0; hidden = false; + + // purge our cache that is used to unify states + unify.clear(); } bool DefinitionData::loadMetaData(const QString &definitionFileName) @@ -433,7 +443,9 @@ bool DefinitionData::loadMetaData(const QString &definitionFileName) bool DefinitionData::loadMetaData(const QString &file, const QCborMap &obj) { name = obj.value(QLatin1String("name")).toString(); + nameUtf8 = obj.value(QLatin1String("name")).toByteArray(); section = obj.value(QLatin1String("section")).toString(); + sectionUtf8 = obj.value(QLatin1String("section")).toByteArray(); version = obj.value(QLatin1String("version")).toInteger(); priority = obj.value(QLatin1String("priority")).toInteger(); style = obj.value(QLatin1String("style")).toString(); @@ -444,13 +456,10 @@ bool DefinitionData::loadMetaData(const QString &file, const QCborMap &obj) fileName = file; const auto exts = obj.value(QLatin1String("extensions")).toString(); - for (const auto &ext : exts.split(QLatin1Char(';'), Qt::SkipEmptyParts)) { - extensions.push_back(ext); - } + extensions = exts.split(QLatin1Char(';'), Qt::SkipEmptyParts); + const auto mts = obj.value(QLatin1String("mimetype")).toString(); - for (const auto &mt : mts.split(QLatin1Char(';'), Qt::SkipEmptyParts)) { - mimetypes.push_back(mt); - } + mimetypes = mts.split(QLatin1Char(';'), Qt::SkipEmptyParts); return true; } @@ -805,10 +814,10 @@ bool DefinitionData::checkKateVersion(QStringView verStr) qCWarning(Log) << "Skipping" << fileName << "due to having no valid kateversion attribute:" << verStr; return false; } - const auto major = verStr.left(idx).toString().toInt(); - const auto minor = verStr.mid(idx + 1).toString().toInt(); + const auto major = verStr.left(idx).toInt(); + const auto minor = verStr.mid(idx + 1).toInt(); - if (major > SyntaxHighlighting_VERSION_MAJOR || (major == SyntaxHighlighting_VERSION_MAJOR && minor > SyntaxHighlighting_VERSION_MINOR)) { + if (major > KSYNTAXHIGHLIGHTING_VERSION_MAJOR || (major == KSYNTAXHIGHLIGHTING_VERSION_MAJOR && minor > KSYNTAXHIGHLIGHTING_VERSION_MINOR)) { qCWarning(Log) << "Skipping" << fileName << "due to being too new, version:" << verStr; return false; } @@ -834,34 +843,20 @@ void DefinitionData::addImmediateIncludedDefinition(const Definition &def) DefinitionRef::DefinitionRef() = default; -DefinitionRef::DefinitionRef(const Definition &def) +DefinitionRef::DefinitionRef(const Definition &def) noexcept : d(def.d) { } -DefinitionRef::DefinitionRef(Definition &&def) - : d(std::move(def.d)) -{ -} - -DefinitionRef &DefinitionRef::operator=(const Definition &def) +DefinitionRef &DefinitionRef::operator=(const Definition &def) noexcept { d = def.d; return *this; } -DefinitionRef &DefinitionRef::operator=(Definition &&def) -{ - d = std::move(def.d); - return *this; -} - Definition DefinitionRef::definition() const { - if (!d.expired()) { - return Definition(d.lock()); - } - return Definition(); + return Definition(d.lock()); } bool DefinitionRef::operator==(const DefinitionRef &other) const @@ -873,3 +868,5 @@ bool DefinitionRef::operator==(const Definition &other) const { return !d.owner_before(other.d) && !other.d.owner_before(d); } + +#include "moc_definition.cpp" diff --git a/src/libs/3rdparty/syntax-highlighting/src/lib/definition.h b/src/libs/3rdparty/syntax-highlighting/src/lib/definition.h index 05757ea52a3..e69492bee42 100644 --- a/src/libs/3rdparty/syntax-highlighting/src/lib/definition.h +++ b/src/libs/3rdparty/syntax-highlighting/src/lib/definition.h @@ -10,16 +10,12 @@ #include "ksyntaxhighlighting_export.h" +#include #include -#include +#include #include #include -QT_BEGIN_NAMESPACE -class QChar; -class QString; -QT_END_NAMESPACE - namespace KSyntaxHighlighting { class Context; @@ -185,13 +181,13 @@ public: /** * Mime types associated with this syntax definition. */ - QVector mimeTypes() const; + QList mimeTypes() const; /** * File extensions associated with this syntax definition. * The returned list contains wildcards. */ - QVector extensions() const; + QList extensions() const; /** * Returns the definition version. @@ -360,7 +356,7 @@ public: * The order of the Format items equals the order of the itemDatas in the xml file. * @since 5.49 */ - QVector formats() const; + QList formats() const; /** * Returns a list of Definitions that are referenced with the IncludeRules rule. @@ -369,7 +365,7 @@ public: * * @since 5.49 */ - QVector includedDefinitions() const; + QList includedDefinitions() const; /** * Returns the marker that starts a single line comment. @@ -400,7 +396,7 @@ public: * the string \"{A} represents the character Ä. * @since 5.50 */ - QVector> characterEncodings() const; + QList> characterEncodings() const; /** * @} @@ -409,14 +405,14 @@ public: private: friend class DefinitionData; friend class DefinitionRef; - explicit Definition(std::shared_ptr &&dd); + KSYNTAXHIGHLIGHTING_NO_EXPORT explicit Definition(std::shared_ptr &&dd); std::shared_ptr d; }; } QT_BEGIN_NAMESPACE -Q_DECLARE_TYPEINFO(KSyntaxHighlighting::Definition, Q_MOVABLE_TYPE); +Q_DECLARE_TYPEINFO(KSyntaxHighlighting::Definition, Q_RELOCATABLE_TYPE); QT_END_NAMESPACE #endif diff --git a/src/libs/3rdparty/syntax-highlighting/src/lib/definition_p.h b/src/libs/3rdparty/syntax-highlighting/src/lib/definition_p.h index 542f255b321..ec00b318970 100644 --- a/src/libs/3rdparty/syntax-highlighting/src/lib/definition_p.h +++ b/src/libs/3rdparty/syntax-highlighting/src/lib/definition_p.h @@ -10,11 +10,13 @@ #include "definitionref_p.h" #include "highlightingdata_p.hpp" +#include "state.h" #include "worddelimiters_p.h" #include +#include +#include #include -#include #include @@ -36,7 +38,10 @@ public: DefinitionData(const DefinitionData &) = delete; DefinitionData &operator=(const DefinitionData &) = delete; - static DefinitionData *get(const Definition &def); + static DefinitionData *get(const Definition &def) + { + return def.d.get(); + } bool isLoaded() const; bool loadMetaData(const QString &definitionFileName); @@ -80,9 +85,9 @@ public: std::vector contexts; QHash formats; // data loaded from xml file and emptied after loading contexts - QVector contextDatas; + QList contextDatas; // Definition referenced by IncludeRules and ContextSwitch - QVector immediateIncludedDefinitions; + QList immediateIncludedDefinitions; WordDelimiters wordDelimiters; WordDelimiters wordWrapDelimiters; bool keywordIsLoaded = false; @@ -93,21 +98,28 @@ public: CommentPosition singleLineCommentPosition = CommentPosition::StartOfLine; QString multiLineCommentStartMarker; QString multiLineCommentEndMarker; - QVector> characterEncodings; + QList> characterEncodings; QString fileName; QString name = QStringLiteral(QT_TRANSLATE_NOOP("Language", "None")); + QByteArray nameUtf8; + mutable QString translatedName; QString section; + QByteArray sectionUtf8; + mutable QString translatedSection; QString style; QString indenter; QString author; QString license; - QVector mimetypes; - QVector extensions; + QList mimetypes; + QList extensions; Qt::CaseSensitivity caseSensitive = Qt::CaseSensitive; int version = 0; int priority = 0; bool hidden = false; + + // cache that is used to unify states in AbstractHighlighter::highlightLine + mutable QSet unify; }; } diff --git a/src/libs/3rdparty/syntax-highlighting/src/lib/definitiondownloader.cpp b/src/libs/3rdparty/syntax-highlighting/src/lib/definitiondownloader.cpp index c1335789dc9..88ba5d77591 100644 --- a/src/libs/3rdparty/syntax-highlighting/src/lib/definitiondownloader.cpp +++ b/src/libs/3rdparty/syntax-highlighting/src/lib/definitiondownloader.cpp @@ -169,8 +169,8 @@ DefinitionDownloader::~DefinitionDownloader() void DefinitionDownloader::start() { - const QString url = QLatin1String("https://www.kate-editor.org/syntax/update-") + QString::number(SyntaxHighlighting_VERSION_MAJOR) + QLatin1Char('.') - + QString::number(SyntaxHighlighting_VERSION_MINOR) + QLatin1String(".xml"); + const QString url = QLatin1String("https://www.kate-editor.org/syntax/update-") + QString::number(KSYNTAXHIGHLIGHTING_VERSION_MAJOR) + QLatin1Char('.') + + QString::number(KSYNTAXHIGHLIGHTING_VERSION_MINOR) + QLatin1String(".xml"); auto req = QNetworkRequest(QUrl(url)); req.setAttribute(QNetworkRequest::RedirectPolicyAttribute, QNetworkRequest::NoLessSafeRedirectPolicy); auto reply = d->nam->get(req); @@ -178,3 +178,5 @@ void DefinitionDownloader::start() d->definitionListDownloadFinished(reply); }); } + +#include "moc_definitiondownloader.cpp" diff --git a/src/libs/3rdparty/syntax-highlighting/src/lib/definitionref_p.h b/src/libs/3rdparty/syntax-highlighting/src/lib/definitionref_p.h index 0bd805624dd..a7ef08f614f 100644 --- a/src/libs/3rdparty/syntax-highlighting/src/lib/definitionref_p.h +++ b/src/libs/3rdparty/syntax-highlighting/src/lib/definitionref_p.h @@ -30,10 +30,8 @@ class DefinitionRef { public: DefinitionRef(); - explicit DefinitionRef(const Definition &def); - explicit DefinitionRef(Definition &&def); - DefinitionRef &operator=(const Definition &def); - DefinitionRef &operator=(Definition &&def); + explicit DefinitionRef(const Definition &def) noexcept; + DefinitionRef &operator=(const Definition &def) noexcept; Definition definition() const; diff --git a/src/libs/3rdparty/syntax-highlighting/src/lib/dynamicregexpcache_p.h b/src/libs/3rdparty/syntax-highlighting/src/lib/dynamicregexpcache_p.h new file mode 100644 index 00000000000..dcef97a8416 --- /dev/null +++ b/src/libs/3rdparty/syntax-highlighting/src/lib/dynamicregexpcache_p.h @@ -0,0 +1,39 @@ +/* + SPDX-FileCopyrightText: 2023 Jonathan Poelen + + SPDX-License-Identifier: MIT +*/ + +#ifndef KSYNTAXHIGHLIGHTING_DYNAMICREGEXPCACHE_P_H +#define KSYNTAXHIGHLIGHTING_DYNAMICREGEXPCACHE_P_H + +#include +#include +#include + +#include + +namespace KSyntaxHighlighting +{ + +class DynamicRegexpCache +{ +public: + const QRegularExpression &compileRegexp(QString &&pattern, QRegularExpression::PatternOptions patternOptions) + { + const auto key = std::pair{std::move(pattern), patternOptions}; + if (const auto regexp = m_cache.object(key)) { + return *regexp; + } + auto regexp = new QRegularExpression(key.first, patternOptions); + m_cache.insert(key, regexp); + return *regexp; + } + +private: + QCache, QRegularExpression> m_cache; +}; + +} + +#endif diff --git a/src/libs/3rdparty/syntax-highlighting/src/lib/foldingregion.cpp b/src/libs/3rdparty/syntax-highlighting/src/lib/foldingregion.cpp index 3bca63eecda..9ed625b12ed 100644 --- a/src/libs/3rdparty/syntax-highlighting/src/lib/foldingregion.cpp +++ b/src/libs/3rdparty/syntax-highlighting/src/lib/foldingregion.cpp @@ -8,36 +8,39 @@ using namespace KSyntaxHighlighting; -static_assert(sizeof(FoldingRegion) == 2, "FoldingRegion is size-sensitive to frequent use in KTextEditor!"); +static_assert(sizeof(FoldingRegion) == sizeof(int), "FoldingRegion is size-sensitive to frequent use in KTextEditor!"); -FoldingRegion::FoldingRegion() - : m_type(None) - , m_id(0) -{ -} +FoldingRegion::FoldingRegion() = default; -FoldingRegion::FoldingRegion(Type type, quint16 id) - : m_type(type) - , m_id(id) +FoldingRegion::FoldingRegion(Type type, int id) + : m_idWithType((type == End) ? -id : id) { } bool FoldingRegion::operator==(const FoldingRegion &other) const { - return m_id == other.m_id && m_type == other.m_type; + return m_idWithType == other.m_idWithType; } bool FoldingRegion::isValid() const { - return type() != None; + return m_idWithType != 0; } -quint16 FoldingRegion::id() const +int FoldingRegion::id() const { - return m_id; + return (m_idWithType < 0) ? -m_idWithType : m_idWithType; } FoldingRegion::Type FoldingRegion::type() const { - return static_cast(m_type); + if (isValid()) { + return (m_idWithType < 0) ? End : Begin; + } + return None; +} + +FoldingRegion FoldingRegion::sibling() const +{ + return isValid() ? FoldingRegion(type() ? End : Begin, id()) : FoldingRegion(); } diff --git a/src/libs/3rdparty/syntax-highlighting/src/lib/foldingregion.h b/src/libs/3rdparty/syntax-highlighting/src/lib/foldingregion.h index ca4cacafb25..e2a9e1fc680 100644 --- a/src/libs/3rdparty/syntax-highlighting/src/lib/foldingregion.h +++ b/src/libs/3rdparty/syntax-highlighting/src/lib/foldingregion.h @@ -22,7 +22,7 @@ public: * Defines whether a FoldingRegion starts or ends a folding region. */ enum Type { - //! Used internally as indicator for invalid FoldingRegion%s. + //! Used internally as indicator for an invalid FoldingRegion. None, //! Indicates the start of a FoldingRegion. Begin, @@ -64,7 +64,7 @@ public: * brace, you need to do kind of a reference counting to find the correct * closing brace. */ - quint16 id() const; + int id() const; /** * Returns whether this is the begin or end of a region. @@ -74,12 +74,21 @@ public: */ Type type() const; + /** + * Returns the matching start or end region. + * + * @note Will return invalid region for an invalid region. + * + * @since 6.0 + */ + FoldingRegion sibling() const; + private: friend class Rule; - FoldingRegion(Type type, quint16 id); + KSYNTAXHIGHLIGHTING_NO_EXPORT FoldingRegion(Type type, int id); - quint16 m_type : 2; - quint16 m_id : 14; + // 0 is invalid, positive begin, negative end + int m_idWithType = 0; }; } diff --git a/src/libs/3rdparty/syntax-highlighting/src/lib/format.cpp b/src/libs/3rdparty/syntax-highlighting/src/lib/format.cpp index 518a1e9ee9e..2259cd34115 100644 --- a/src/libs/3rdparty/syntax-highlighting/src/lib/format.cpp +++ b/src/libs/3rdparty/syntax-highlighting/src/lib/format.cpp @@ -98,7 +98,7 @@ QString Format::name() const return d->name; } -quint16 Format::id() const +int Format::id() const { return d->id; } diff --git a/src/libs/3rdparty/syntax-highlighting/src/lib/format.h b/src/libs/3rdparty/syntax-highlighting/src/lib/format.h index 496a54e42cb..397a1bab01c 100644 --- a/src/libs/3rdparty/syntax-highlighting/src/lib/format.h +++ b/src/libs/3rdparty/syntax-highlighting/src/lib/format.h @@ -13,12 +13,6 @@ #include -QT_BEGIN_NAMESPACE -class QColor; -class QString; -class QXmlStreamReader; -QT_END_NAMESPACE - namespace KSyntaxHighlighting { class FormatPrivate; @@ -54,7 +48,7 @@ public: * the repository is reloaded (which also invalidatess the corresponding * Definition anyway). */ - quint16 id() const; + int id() const; /** Returns the underlying TextStyle of this Format. * Every Theme::TextStyle is visually defined by a Theme. A Format uses one @@ -192,7 +186,7 @@ private: } QT_BEGIN_NAMESPACE -Q_DECLARE_TYPEINFO(KSyntaxHighlighting::Format, Q_MOVABLE_TYPE); +Q_DECLARE_TYPEINFO(KSyntaxHighlighting::Format, Q_RELOCATABLE_TYPE); QT_END_NAMESPACE #endif // KSYNTAXHIGHLIGHTING_FORMAT_H diff --git a/src/libs/3rdparty/syntax-highlighting/src/lib/format_p.h b/src/libs/3rdparty/syntax-highlighting/src/lib/format_p.h index d8770f1ef7c..ea74531445e 100644 --- a/src/libs/3rdparty/syntax-highlighting/src/lib/format_p.h +++ b/src/libs/3rdparty/syntax-highlighting/src/lib/format_p.h @@ -13,6 +13,10 @@ #include #include +QT_BEGIN_NAMESPACE +class QXmlStreamReader; +QT_END_NAMESPACE + namespace KSyntaxHighlighting { class FormatPrivate : public QSharedData @@ -21,6 +25,11 @@ public: FormatPrivate() = default; static FormatPrivate *detachAndGet(Format &format); + static std::intptr_t ptrId(const Format &format) + { + return std::intptr_t(format.d.data()); + } + TextStyleData styleOverride(const Theme &theme) const; void load(QXmlStreamReader &reader); @@ -33,7 +42,7 @@ public: QString name; TextStyleData style; Theme::TextStyle defaultStyle = Theme::Normal; - quint16 id = 0; + int id = 0; bool spellCheck = true; }; diff --git a/src/libs/3rdparty/syntax-highlighting/src/lib/highlightingdata.cpp b/src/libs/3rdparty/syntax-highlighting/src/lib/highlightingdata.cpp index adb1c346c13..d95ad43b7fe 100644 --- a/src/libs/3rdparty/syntax-highlighting/src/lib/highlightingdata.cpp +++ b/src/libs/3rdparty/syntax-highlighting/src/lib/highlightingdata.cpp @@ -379,6 +379,7 @@ void HighlightingContextData::load(const QString &defName, QXmlStreamReader &rea lineEmptyContext = reader.attributes().value(QLatin1String("lineEmptyContext")).toString(); fallthroughContext = reader.attributes().value(QLatin1String("fallthroughContext")).toString(); noIndentationBasedFolding = Xml::attrToBool(reader.attributes().value(QLatin1String("noIndentationBasedFolding"))); + stopEmptyLineContextSwitchLoop = Xml::attrToBool(reader.attributes().value(QLatin1String("stopEmptyLineContextSwitchLoop"))); rules.reserve(8); diff --git a/src/libs/3rdparty/syntax-highlighting/src/lib/highlightingdata_p.hpp b/src/libs/3rdparty/syntax-highlighting/src/lib/highlightingdata_p.hpp index 80aeaf49340..f49227dbf96 100644 --- a/src/libs/3rdparty/syntax-highlighting/src/lib/highlightingdata_p.hpp +++ b/src/libs/3rdparty/syntax-highlighting/src/lib/highlightingdata_p.hpp @@ -208,6 +208,7 @@ public: std::vector rules; + bool stopEmptyLineContextSwitchLoop = false; bool noIndentationBasedFolding = false; }; } diff --git a/src/libs/3rdparty/syntax-highlighting/src/lib/htmlhighlighter.cpp b/src/libs/3rdparty/syntax-highlighting/src/lib/htmlhighlighter.cpp index 1f68e33d3e4..928ae149d1b 100644 --- a/src/libs/3rdparty/syntax-highlighting/src/lib/htmlhighlighter.cpp +++ b/src/libs/3rdparty/syntax-highlighting/src/lib/htmlhighlighter.cpp @@ -6,7 +6,9 @@ */ #include "htmlhighlighter.h" +#include "abstracthighlighter_p.h" #include "definition.h" +#include "definition_p.h" #include "format.h" #include "ksyntaxhighlighting_logging.h" #include "state.h" @@ -14,21 +16,22 @@ #include #include +#include #include -#include using namespace KSyntaxHighlighting; -class KSyntaxHighlighting::HtmlHighlighterPrivate +class KSyntaxHighlighting::HtmlHighlighterPrivate : public AbstractHighlighterPrivate { public: std::unique_ptr out; std::unique_ptr file; QString currentLine; + std::vector htmlStyles; }; HtmlHighlighter::HtmlHighlighter() - : d(new HtmlHighlighterPrivate()) + : AbstractHighlighter(new HtmlHighlighterPrivate()) { } @@ -38,27 +41,21 @@ HtmlHighlighter::~HtmlHighlighter() void HtmlHighlighter::setOutputFile(const QString &fileName) { + Q_D(HtmlHighlighter); d->file.reset(new QFile(fileName)); if (!d->file->open(QFile::WriteOnly | QFile::Truncate)) { qCWarning(Log) << "Failed to open output file" << fileName << ":" << d->file->errorString(); return; } d->out.reset(new QTextStream(d->file.get())); -#if QT_VERSION >= QT_VERSION_CHECK(6, 0, 0) d->out->setEncoding(QStringConverter::Utf8); -#else - d->out->setCodec("UTF-8"); -#endif } void HtmlHighlighter::setOutputFile(FILE *fileHandle) { + Q_D(HtmlHighlighter); d->out.reset(new QTextStream(fileHandle, QIODevice::WriteOnly)); -#if QT_VERSION >= QT_VERSION_CHECK(6, 0, 0) d->out->setEncoding(QStringConverter::Utf8); -#else - d->out->setCodec("UTF-8"); -#endif } void HtmlHighlighter::highlightFile(const QString &fileName, const QString &title) @@ -79,7 +76,7 @@ void HtmlHighlighter::highlightFile(const QString &fileName, const QString &titl /** * @brief toHtmlRgba - * Converts QColor -> rgba(r, g, b, a) if there is an alpha channel + * Converts QColor -> #RRGGBBAA if there is an alpha channel * otherwise it will just return the hexcode. This is because QColor * outputs #AARRGGBB, whereas browser support #RRGGBBAA. * @@ -91,22 +88,24 @@ static QString toHtmlRgbaString(const QColor &color) if (color.alpha() == 0xFF) { return color.name(); } - - QString rgba = QStringLiteral("rgba("); - rgba.append(QString::number(color.red())); - rgba.append(QLatin1Char(',')); - rgba.append(QString::number(color.green())); - rgba.append(QLatin1Char(',')); - rgba.append(QString::number(color.blue())); - rgba.append(QLatin1Char(',')); - // this must be alphaF - rgba.append(QString::number(color.alphaF())); - rgba.append(QLatin1Char(')')); - return rgba; + static const char16_t digits[]{'0', '1', '2', '3', '4', '5', '6', '7', '8', '9', 'a', 'b', 'c', 'd', 'e', 'f'}; + QChar hexcode[9]; + hexcode[0] = QLatin1Char('#'); + hexcode[1] = digits[color.red() >> 4]; + hexcode[2] = digits[color.red() & 0xf]; + hexcode[3] = digits[color.green() >> 4]; + hexcode[4] = digits[color.green() & 0xf]; + hexcode[5] = digits[color.blue() >> 4]; + hexcode[6] = digits[color.blue() & 0xf]; + hexcode[7] = digits[color.alpha() >> 4]; + hexcode[8] = digits[color.alpha() & 0xf]; + return QString(hexcode, 9); } void HtmlHighlighter::highlightData(QIODevice *dev, const QString &title) { + Q_D(HtmlHighlighter); + if (!d->out) { qCWarning(Log) << "No output stream defined!"; return; @@ -114,29 +113,73 @@ void HtmlHighlighter::highlightData(QIODevice *dev, const QString &title) QString htmlTitle; if (title.isEmpty()) { - htmlTitle = QStringLiteral("Kate Syntax Highlighter"); + htmlTitle = QStringLiteral("KSyntaxHighlighter"); } else { htmlTitle = title.toHtmlEscaped(); } + const auto &theme = d->m_theme; + const auto &definition = d->m_definition; + + auto definitions = definition.includedDefinitions(); + definitions.append(definition); + + int maxId = 0; + for (const auto &definition : std::as_const(definitions)) { + for (const auto &format : std::as_const(DefinitionData::get(definition)->formats)) { + maxId = qMax(maxId, format.id()); + } + } + d->htmlStyles.clear(); + // htmlStyles must not be empty for applyFormat to work even with a definition without any context + d->htmlStyles.resize(maxId + 1); + + // initialize htmlStyles + for (const auto &definition : std::as_const(definitions)) { + for (const auto &format : std::as_const(DefinitionData::get(definition)->formats)) { + auto &buffer = d->htmlStyles[format.id()]; + if (format.hasTextColor(theme)) { + buffer += QStringLiteral("color:") + toHtmlRgbaString(format.textColor(theme)) + QStringLiteral(";"); + } + if (format.hasBackgroundColor(theme)) { + buffer += QStringLiteral("background-color:") + toHtmlRgbaString(format.backgroundColor(theme)) + QStringLiteral(";"); + } + if (format.isBold(theme)) { + buffer += QStringLiteral("font-weight:bold;"); + } + if (format.isItalic(theme)) { + buffer += QStringLiteral("font-style:italic;"); + } + if (format.isUnderline(theme)) { + buffer += QStringLiteral("text-decoration:underline;"); + } + if (format.isStrikeThrough(theme)) { + buffer += QStringLiteral("text-decoration:line-through;"); + } + + if (!buffer.isEmpty()) { + buffer.insert(0, QStringLiteral("'; + } + } + } + State state; *d->out << "\n"; *d->out << "\n"; *d->out << "\n"; *d->out << "" << htmlTitle << "\n"; - *d->out << "\n"; + *d->out << "\n"; *d->out << "out << " style=\"background-color:" << toHtmlRgbaString(QColor::fromRgba(theme().editorColor(Theme::BackgroundColor))); - if (theme().textColor(Theme::Normal)) { - *d->out << ";color:" << toHtmlRgbaString(QColor::fromRgba(theme().textColor(Theme::Normal))); + *d->out << " style=\"background-color:" << toHtmlRgbaString(QColor::fromRgba(theme.editorColor(Theme::BackgroundColor))); + if (theme.textColor(Theme::Normal)) { + *d->out << ";color:" << toHtmlRgbaString(QColor::fromRgba(theme.textColor(Theme::Normal))); } *d->out << "\">
\n";
 
     QTextStream in(dev);
-#if QT_VERSION < QT_VERSION_CHECK(6, 0, 0)
-    in.setCodec("UTF-8");
-#endif
     while (in.readLineInto(&d->currentLine)) {
         state = highlightLine(d->currentLine, state);
         *d->out << "\n";
@@ -155,38 +198,24 @@ void HtmlHighlighter::applyFormat(int offset, int length, const Format &format)
         return;
     }
 
-    // collect potential output, cheaper than thinking about "is there any?"
-    QVarLengthArray formatOutput;
-    if (format.hasTextColor(theme())) {
-        formatOutput << QStringLiteral("color:") << toHtmlRgbaString(format.textColor(theme())) << QStringLiteral(";");
-    }
-    if (format.hasBackgroundColor(theme())) {
-        formatOutput << QStringLiteral("background-color:") << toHtmlRgbaString(format.backgroundColor(theme())) << QStringLiteral(";");
-    }
-    if (format.isBold(theme())) {
-        formatOutput << QStringLiteral("font-weight:bold;");
-    }
-    if (format.isItalic(theme())) {
-        formatOutput << QStringLiteral("font-style:italic;");
-    }
-    if (format.isUnderline(theme())) {
-        formatOutput << QStringLiteral("text-decoration:underline;");
-    }
-    if (format.isStrikeThrough(theme())) {
-        formatOutput << QStringLiteral("text-decoration:line-through;");
+    Q_D(HtmlHighlighter);
+
+    auto const &htmlStyle = d->htmlStyles[format.id()];
+
+    if (!htmlStyle.isEmpty()) {
+        *d->out << htmlStyle;
     }
 
-    if (!formatOutput.isEmpty()) {
-        *d->out << "out << out;
-        }
-        *d->out << "\">";
+    for (QChar ch : QStringView(d->currentLine).mid(offset, length)) {
+        if (ch == u'<')
+            *d->out << QStringLiteral("<");
+        else if (ch == u'&')
+            *d->out << QStringLiteral("&");
+        else
+            *d->out << ch;
     }
 
-    *d->out << d->currentLine.mid(offset, length).toHtmlEscaped();
-
-    if (!formatOutput.isEmpty()) {
-        *d->out << "";
+    if (!htmlStyle.isEmpty()) {
+        *d->out << QStringLiteral("");
     }
 }
diff --git a/src/libs/3rdparty/syntax-highlighting/src/lib/htmlhighlighter.h b/src/libs/3rdparty/syntax-highlighting/src/lib/htmlhighlighter.h
index 8754057345d..741cb851031 100644
--- a/src/libs/3rdparty/syntax-highlighting/src/lib/htmlhighlighter.h
+++ b/src/libs/3rdparty/syntax-highlighting/src/lib/htmlhighlighter.h
@@ -10,10 +10,11 @@
 #include "abstracthighlighter.h"
 #include "ksyntaxhighlighting_export.h"
 
-#include 
 #include 
 
-#include 
+QT_BEGIN_NAMESPACE
+class QIODevice;
+QT_END_NAMESPACE
 
 namespace KSyntaxHighlighting
 {
@@ -35,7 +36,7 @@ protected:
     void applyFormat(int offset, int length, const Format &format) override;
 
 private:
-    std::unique_ptr d;
+    Q_DECLARE_PRIVATE(HtmlHighlighter)
 };
 }
 
diff --git a/src/libs/3rdparty/syntax-highlighting/src/lib/keywordlist.cpp b/src/libs/3rdparty/syntax-highlighting/src/lib/keywordlist.cpp
index 133b6d28ac5..847f6af6d46 100644
--- a/src/libs/3rdparty/syntax-highlighting/src/lib/keywordlist.cpp
+++ b/src/libs/3rdparty/syntax-highlighting/src/lib/keywordlist.cpp
@@ -47,7 +47,7 @@ bool KeywordList::contains(QStringView str, Qt::CaseSensitivity caseSensitive) c
     /**
      * search with right predicate
      */
-    return std::binary_search(vectorToSearch.begin(), vectorToSearch.end(), QStringView(str), KeywordComparator{caseSensitive});
+    return std::binary_search(vectorToSearch.begin(), vectorToSearch.end(), str, KeywordComparator{caseSensitive});
 }
 
 void KeywordList::load(QXmlStreamReader &reader)
@@ -103,10 +103,7 @@ void KeywordList::initLookupForCaseSensitivity(Qt::CaseSensitivity caseSensitive
     /**
      * fill vector with refs to keywords
      */
-    vectorToSort.reserve(m_keywords.size());
-    for (const auto &keyword : std::as_const(m_keywords)) {
-        vectorToSort.push_back(keyword);
-    }
+    vectorToSort.assign(m_keywords.constBegin(), m_keywords.constEnd());
 
     /**
      * sort with right predicate
diff --git a/src/libs/3rdparty/syntax-highlighting/src/lib/matchresult_p.h b/src/libs/3rdparty/syntax-highlighting/src/lib/matchresult_p.h
index 1e0f7c61027..7112d4e291b 100644
--- a/src/libs/3rdparty/syntax-highlighting/src/lib/matchresult_p.h
+++ b/src/libs/3rdparty/syntax-highlighting/src/lib/matchresult_p.h
@@ -41,9 +41,9 @@ public:
      * @param offset offset of match
      * @param captures captures of the match
      */
-    explicit MatchResult(const int offset, const QStringList &captures)
+    explicit MatchResult(const int offset, QStringList &&captures)
         : m_offset(offset)
-        , m_captures(captures)
+        , m_captures(std::move(captures))
     {
     }
 
@@ -69,7 +69,7 @@ public:
      * Captures of the match.
      * @return captured text of this match
      */
-    const QStringList &captures() const
+    QStringList &captures()
     {
         return m_captures;
     }
diff --git a/src/libs/3rdparty/syntax-highlighting/src/lib/repository.cpp b/src/libs/3rdparty/syntax-highlighting/src/lib/repository.cpp
index a12d4ba1a3a..07c28454c5b 100644
--- a/src/libs/3rdparty/syntax-highlighting/src/lib/repository.cpp
+++ b/src/libs/3rdparty/syntax-highlighting/src/lib/repository.cpp
@@ -77,9 +77,9 @@ Definition findHighestPriorityDefinitionIf(const QMap &defs
 }
 
 template
-QVector findDefinitionsIf(const QMap &defs, UnaryPredicate predicate)
+QList findDefinitionsIf(const QMap &defs, UnaryPredicate predicate)
 {
-    QVector matches;
+    QList matches;
     std::copy_if(defs.cbegin(), defs.cend(), std::back_inserter(matches), predicate);
     std::stable_sort(matches.begin(), matches.end(), [](const Definition &lhs, const Definition &rhs) {
         return lhs.priority() > rhs.priority();
@@ -127,7 +127,7 @@ Definition Repository::definitionForFileName(const QString &fileName) const
     return findHighestPriorityDefinitionIf(d->m_defs, anyWildcardMatches(fileNameFromFilePath(fileName)));
 }
 
-QVector Repository::definitionsForFileName(const QString &fileName) const
+QList Repository::definitionsForFileName(const QString &fileName) const
 {
     return findDefinitionsIf(d->m_defs, anyWildcardMatches(fileNameFromFilePath(fileName)));
 }
@@ -137,22 +137,22 @@ Definition Repository::definitionForMimeType(const QString &mimeType) const
     return findHighestPriorityDefinitionIf(d->m_defs, anyMimeTypeEquals(mimeType));
 }
 
-QVector Repository::definitionsForMimeType(const QString &mimeType) const
+QList Repository::definitionsForMimeType(const QString &mimeType) const
 {
     return findDefinitionsIf(d->m_defs, anyMimeTypeEquals(mimeType));
 }
 
-QVector Repository::definitions() const
+QList Repository::definitions() const
 {
     return d->m_sortedDefs;
 }
 
-QVector Repository::themes() const
+QList Repository::themes() const
 {
     return d->m_themes;
 }
 
-static auto lowerBoundTheme(const QVector &themes, QStringView themeName)
+static auto lowerBoundTheme(const QList &themes, QStringView themeName)
 {
     return std::lower_bound(themes.begin(), themes.end(), themeName, [](const Theme &lhs, QStringView rhs) {
         return lhs.name() < rhs;
@@ -177,42 +177,32 @@ Theme Repository::defaultTheme(Repository::DefaultTheme t) const
     return theme(QStringLiteral("Breeze Light"));
 }
 
-Theme Repository::defaultTheme(Repository::DefaultTheme t)
-{
-    return std::as_const(*this).defaultTheme(t);
-}
-
 Theme Repository::themeForPalette(const QPalette &palette) const
 {
     const auto base = palette.color(QPalette::Base);
+    const auto highlight = palette.color(QPalette::Highlight).rgb();
 
-    // find themes with matching background colors
-    QVector matchingThemes;
+    // find themes with matching background and highlight colors
+    const Theme *firstMatchingTheme = nullptr;
     for (const auto &theme : std::as_const(d->m_themes)) {
-        const auto background = theme.editorColor(KSyntaxHighlighting::Theme::EditorColorRole::BackgroundColor);
+        const auto background = theme.editorColor(Theme::EditorColorRole::BackgroundColor);
         if (background == base.rgb()) {
-            matchingThemes.append(&theme);
-        }
-    }
-    if (!matchingThemes.empty()) {
-        // if there's multiple, search for one with a matching highlight color
-        const auto highlight = palette.color(QPalette::Highlight);
-        for (const auto *theme : std::as_const(matchingThemes)) {
-            auto selection = theme->editorColor(KSyntaxHighlighting::Theme::EditorColorRole::TextSelection);
-            if (selection == highlight.rgb()) {
-                return *theme;
+            // find theme with a matching highlight color
+            auto selection = theme.editorColor(Theme::EditorColorRole::TextSelection);
+            if (selection == highlight) {
+                return theme;
+            }
+            if (!firstMatchingTheme) {
+                firstMatchingTheme = &theme;
             }
         }
-        return *matchingThemes.first();
+    }
+    if (firstMatchingTheme) {
+        return *firstMatchingTheme;
     }
 
     // fallback to just use the default light or dark theme
-    return defaultTheme((base.lightness() < 128) ? KSyntaxHighlighting::Repository::DarkTheme : KSyntaxHighlighting::Repository::LightTheme);
-}
-
-Theme Repository::themeForPalette(const QPalette &palette)
-{
-    return std::as_const(*this).themeForPalette(palette);
+    return defaultTheme((base.lightness() < 128) ? Repository::DarkTheme : Repository::LightTheme);
 }
 
 void RepositoryPrivate::load(Repository *repo)
@@ -238,12 +228,6 @@ void RepositoryPrivate::load(Repository *repo)
                                                      QStandardPaths::LocateDirectory)) {
         loadSyntaxFolder(repo, dir);
     }
-
-    // backward compatibility with Kate
-    for (const auto &dir :
-         QStandardPaths::locateAll(QStandardPaths::GenericDataLocation, QStringLiteral("katepart5/syntax"), QStandardPaths::LocateDirectory)) {
-        loadSyntaxFolder(repo, dir);
-    }
 #endif
 
     // default resources are always used, this is the one location that has a index cbor file
@@ -377,25 +361,27 @@ void RepositoryPrivate::addTheme(const Theme &theme)
     }
 }
 
-quint16 RepositoryPrivate::foldingRegionId(const QString &defName, const QString &foldName)
+int RepositoryPrivate::foldingRegionId(const QString &defName, const QString &foldName)
 {
     const auto it = m_foldingRegionIds.constFind(qMakePair(defName, foldName));
     if (it != m_foldingRegionIds.constEnd()) {
         return it.value();
     }
+    Q_ASSERT(m_foldingRegionId < std::numeric_limits::max());
     m_foldingRegionIds.insert(qMakePair(defName, foldName), ++m_foldingRegionId);
     return m_foldingRegionId;
 }
 
-quint16 RepositoryPrivate::nextFormatId()
+int RepositoryPrivate::nextFormatId()
 {
-    Q_ASSERT(m_formatId < std::numeric_limits::max());
+    Q_ASSERT(m_formatId < std::numeric_limits::max());
     return ++m_formatId;
 }
 
 void Repository::reload()
 {
-    qCDebug(Log) << "Reloading syntax definitions!";
+    Q_EMIT aboutToReload();
+
     for (const auto &def : std::as_const(d->m_sortedDefs)) {
         DefinitionData::get(def)->clear();
     }
@@ -410,6 +396,8 @@ void Repository::reload()
     d->m_formatId = 0;
 
     d->load(this);
+
+    Q_EMIT reloaded();
 }
 
 void Repository::addCustomSearchPath(const QString &path)
@@ -418,7 +406,9 @@ void Repository::addCustomSearchPath(const QString &path)
     reload();
 }
 
-QVector Repository::customSearchPaths() const
+QList Repository::customSearchPaths() const
 {
     return d->m_customSearchPaths;
 }
+
+#include "moc_repository.cpp"
diff --git a/src/libs/3rdparty/syntax-highlighting/src/lib/repository.h b/src/libs/3rdparty/syntax-highlighting/src/lib/repository.h
index 7c74753bfe3..612ba54d6a4 100644
--- a/src/libs/3rdparty/syntax-highlighting/src/lib/repository.h
+++ b/src/libs/3rdparty/syntax-highlighting/src/lib/repository.h
@@ -9,7 +9,8 @@
 
 #include "ksyntaxhighlighting_export.h"
 
-#include 
+#include 
+#include 
 #include 
 
 #include 
@@ -76,13 +77,6 @@ class Theme;
  *    map to $HOME/.local5/share/org.kde.syntax-highlighting/syntax and
  *    /usr/share/org.kde.syntax-highlighting/syntax.
  *
- * -# Next, for backwards compatibility with Kate, all syntax highlighting
- *    files are loaded that are located in
- *    QStandardPaths::locateAll(QStandardPaths::GenericDataLocation, QStringLiteral("katepart5/syntax"), QStandardPaths::LocateDirectory);
- *    Again, under Unix, this uses $XDG_DATA_HOME and $XDG_DATA_DIRS, which
- *    could map to $HOME/.local5/share/katepart5/syntax and
- *    /usr/share/katepart5/syntax.
- *
  * -# Then, all files compiled into the library through resources are loaded.
  *    The internal resource path is ":/org.kde.syntax-highlighting/syntax".
  *    This path should never be touched by other applications.
@@ -124,8 +118,12 @@ class Theme;
  * @see Definition, Theme, AbstractHighlighter
  * @since 5.28
  */
-class KSYNTAXHIGHLIGHTING_EXPORT Repository
+class KSYNTAXHIGHLIGHTING_EXPORT Repository : public QObject
 {
+    Q_OBJECT
+    Q_PROPERTY(QList definitions READ definitions NOTIFY reloaded)
+    Q_PROPERTY(QList themes READ themes NOTIFY reloaded)
+
 public:
     /**
      * Create a new syntax definition repository.
@@ -148,7 +146,7 @@ public:
      *       Therefore, only the string "JavaScript" will return a valid
      *       Definition file.
      */
-    Definition definitionForName(const QString &defName) const;
+    Q_INVOKABLE KSyntaxHighlighting::Definition definitionForName(const QString &defName) const;
 
     /**
      * Returns the best matching Definition for the file named @p fileName.
@@ -159,7 +157,7 @@ public:
      * If no match is found, Definition::isValid() of the returned instance
      * returns false.
      */
-    Definition definitionForFileName(const QString &fileName) const;
+    Q_INVOKABLE KSyntaxHighlighting::Definition definitionForFileName(const QString &fileName) const;
 
     /**
      * Returns all Definition%s for the file named @p fileName sorted by priority.
@@ -168,7 +166,7 @@ public:
      *
      * @since 5.56
      */
-    QVector definitionsForFileName(const QString &fileName) const;
+    Q_INVOKABLE QList definitionsForFileName(const QString &fileName) const;
 
     /**
      * Returns the best matching Definition to the type named @p mimeType
@@ -178,34 +176,34 @@ public:
      *
      * @since 5.50
      */
-    Definition definitionForMimeType(const QString &mimeType) const;
+    Q_INVOKABLE KSyntaxHighlighting::Definition definitionForMimeType(const QString &mimeType) const;
 
     /**
      * Returns all Definition%s to the type named @p mimeType sorted by priority
      *
      * @since 5.56
      */
-    QVector definitionsForMimeType(const QString &mimeType) const;
+    Q_INVOKABLE QList definitionsForMimeType(const QString &mimeType) const;
 
     /**
      * Returns all available Definition%s.
      * Definition%ss are ordered by translated section and translated names,
      * for consistent displaying.
      */
-    QVector definitions() const;
+    Q_INVOKABLE QList definitions() const;
 
     /**
      * Returns all available color themes.
      * The returned list should never be empty.
      */
-    QVector themes() const;
+    Q_INVOKABLE QList themes() const;
 
     /**
      * Returns the theme called @p themeName.
      * If the requested theme cannot be found, the retunred Theme is invalid,
      * see Theme::isValid().
      */
-    Theme theme(const QString &themeName) const;
+    Q_INVOKABLE KSyntaxHighlighting::Theme theme(const QString &themeName) const;
 
     /**
      * Built-in default theme types.
@@ -217,21 +215,14 @@ public:
         //! Theme with a dark background color.
         DarkTheme
     };
+    Q_ENUM(DefaultTheme)
 
     /**
      * Returns a default theme instance of the given type.
      * The returned Theme is guaranteed to be a valid theme.
      * @since 5.79
      */
-    Theme defaultTheme(DefaultTheme t = LightTheme) const;
-
-    /**
-     * Returns a default theme instance of the given type.
-     * The returned Theme is guaranteed to be a valid theme.
-     *
-     * KF6: remove in favor of const variant
-     */
-    Theme defaultTheme(DefaultTheme t = LightTheme);
+    Q_INVOKABLE KSyntaxHighlighting::Theme defaultTheme(DefaultTheme t = LightTheme) const;
 
     /**
      * Returns the best matching theme for the given palette
@@ -239,14 +230,6 @@ public:
      **/
     Theme themeForPalette(const QPalette &palette) const;
 
-    /**
-     * Returns the best matching theme for the given palette
-     * @since 5.77
-     *
-     * KF6: remove in favor of const variant
-     **/
-    Theme themeForPalette(const QPalette &palette);
-
     /**
      * Reloads the repository.
      * This is a moderately expensive operations and should thus only be
@@ -278,7 +261,20 @@ public:
      * @see addCustomSearchPath()
      * @since 5.39
      */
-    QVector customSearchPaths() const;
+    QList customSearchPaths() const;
+
+Q_SIGNALS:
+    /**
+     * This signal is emitted before the reload is started.
+     * @since 6.0
+     */
+    void aboutToReload();
+
+    /**
+     * This signal is emitted when the reload is finished.
+     * @since 6.0
+     */
+    void reloaded();
 
 private:
     Q_DISABLE_COPY(Repository)
diff --git a/src/libs/3rdparty/syntax-highlighting/src/lib/repository_p.h b/src/libs/3rdparty/syntax-highlighting/src/lib/repository_p.h
index 447cfae6990..bb9f8ba0820 100644
--- a/src/libs/3rdparty/syntax-highlighting/src/lib/repository_p.h
+++ b/src/libs/3rdparty/syntax-highlighting/src/lib/repository_p.h
@@ -8,11 +8,11 @@
 #define KSYNTAXHIGHLIGHTING_REPOSITORY_P_H
 
 #include 
-#include 
+#include 
+#include 
+#include 
 
-QT_BEGIN_NAMESPACE
-class QString;
-QT_END_NAMESPACE
+#include "dynamicregexpcache_p.h"
 
 namespace KSyntaxHighlighting
 {
@@ -36,22 +36,24 @@ public:
     void loadThemeFolder(const QString &path);
     void addTheme(const Theme &theme);
 
-    quint16 foldingRegionId(const QString &defName, const QString &foldName);
-    quint16 nextFormatId();
+    int foldingRegionId(const QString &defName, const QString &foldName);
+    int nextFormatId();
 
-    QVector m_customSearchPaths;
+    QList m_customSearchPaths;
 
     // sorted map to have deterministic iteration order for e.g. definitionsForFileName
     QMap m_defs;
 
     // this vector is sorted by translated sections/names
-    QVector m_sortedDefs;
+    QList m_sortedDefs;
 
-    QVector m_themes;
+    QList m_themes;
 
-    QHash, quint16> m_foldingRegionIds;
-    quint16 m_foldingRegionId = 0;
-    quint16 m_formatId = 0;
+    QHash, int> m_foldingRegionIds;
+    int m_foldingRegionId = 0;
+    int m_formatId = 0;
+
+    DynamicRegexpCache m_dynamicRegexpCache;
 };
 }
 
diff --git a/src/libs/3rdparty/syntax-highlighting/src/lib/rule.cpp b/src/libs/3rdparty/syntax-highlighting/src/lib/rule.cpp
index 1d02bd6ac34..186ed16120d 100644
--- a/src/libs/3rdparty/syntax-highlighting/src/lib/rule.cpp
+++ b/src/libs/3rdparty/syntax-highlighting/src/lib/rule.cpp
@@ -1,20 +1,19 @@
 /*
     SPDX-FileCopyrightText: 2016 Volker Krause 
     SPDX-FileCopyrightText: 2018 Christoph Cullmann 
-    SPDX-FileCopyrightText: 2020 Jonathan Poelen 
+    SPDX-FileCopyrightText: 2020 Jonathan Poelen 
 
     SPDX-License-Identifier: MIT
 */
 
 #include "context_p.h"
 #include "definition_p.h"
+#include "dynamicregexpcache_p.h"
 #include "ksyntaxhighlighting_logging.h"
 #include "rule_p.h"
 #include "worddelimiters_p.h"
 #include "xml_p.h"
 
-#include 
-
 using namespace KSyntaxHighlighting;
 
 // QChar::isDigit() match any digit in unicode (romain numeral, etc)
@@ -90,8 +89,8 @@ static int matchEscapedChar(QStringView text, int offset)
 static QString replaceCaptures(const QString &pattern, const QStringList &captures, bool quote)
 {
     auto result = pattern;
-    for (int i = captures.size() - 1; i >= 1; --i) {
-        result.replace(QLatin1Char('%') + QString::number(i), quote ? QRegularExpression::escape(captures.at(i)) : captures.at(i));
+    for (int i = captures.size(); i >= 1; --i) {
+        result.replace(QLatin1Char('%') + QString::number(i), quote ? QRegularExpression::escape(captures.at(i - 1)) : captures.at(i - 1));
     }
     return result;
 }
@@ -233,7 +232,7 @@ AnyChar::AnyChar(const HighlightingContextData::Rule::AnyChar &data)
 {
 }
 
-MatchResult AnyChar::doMatch(QStringView text, int offset, const QStringList &) const
+MatchResult AnyChar::doMatch(QStringView text, int offset, const QStringList &, DynamicRegexpCache &) const
 {
     if (m_chars.contains(text.at(offset))) {
         return offset + 1;
@@ -243,15 +242,15 @@ MatchResult AnyChar::doMatch(QStringView text, int offset, const QStringList &)
 
 DetectChar::DetectChar(const HighlightingContextData::Rule::DetectChar &data)
     : m_char(data.char1)
-    , m_captureIndex(data.dynamic ? data.char1.digitValue() : 0)
+    , m_captureIndex((data.dynamic ? data.char1.digitValue() : 0) - 1)
 {
     m_dynamic = data.dynamic;
 }
 
-MatchResult DetectChar::doMatch(QStringView text, int offset, const QStringList &captures) const
+MatchResult DetectChar::doMatch(QStringView text, int offset, const QStringList &captures, DynamicRegexpCache &) const
 {
     if (m_dynamic) {
-        if (m_captureIndex == 0 || captures.size() <= m_captureIndex || captures.at(m_captureIndex).isEmpty()) {
+        if (m_captureIndex == -1 || captures.size() <= m_captureIndex || captures.at(m_captureIndex).isEmpty()) {
             return offset;
         }
         if (text.at(offset) == captures.at(m_captureIndex).at(0)) {
@@ -272,7 +271,7 @@ Detect2Chars::Detect2Chars(const HighlightingContextData::Rule::Detect2Chars &da
 {
 }
 
-MatchResult Detect2Chars::doMatch(QStringView text, int offset, const QStringList &) const
+MatchResult Detect2Chars::doMatch(QStringView text, int offset, const QStringList &, DynamicRegexpCache &) const
 {
     if (text.size() - offset < 2) {
         return offset;
@@ -283,7 +282,7 @@ MatchResult Detect2Chars::doMatch(QStringView text, int offset, const QStringLis
     return offset;
 }
 
-MatchResult DetectIdentifier::doMatch(QStringView text, int offset, const QStringList &) const
+MatchResult DetectIdentifier::doMatch(QStringView text, int offset, const QStringList &, DynamicRegexpCache &) const
 {
     if (!text.at(offset).isLetter() && text.at(offset) != QLatin1Char('_')) {
         return offset;
@@ -299,7 +298,7 @@ MatchResult DetectIdentifier::doMatch(QStringView text, int offset, const QStrin
     return text.size();
 }
 
-MatchResult DetectSpaces::doMatch(QStringView text, int offset, const QStringList &) const
+MatchResult DetectSpaces::doMatch(QStringView text, int offset, const QStringList &, DynamicRegexpCache &) const
 {
     while (offset < text.size() && text.at(offset).isSpace()) {
         ++offset;
@@ -313,7 +312,7 @@ Float::Float(DefinitionData &def, const HighlightingContextData::Rule::Float &da
     resolveAdditionalWordDelimiters(m_wordDelimiters, data.wordDelimiters);
 }
 
-MatchResult Float::doMatch(QStringView text, int offset, const QStringList &) const
+MatchResult Float::doMatch(QStringView text, int offset, const QStringList &, DynamicRegexpCache &) const
 {
     if (offset > 0 && !m_wordDelimiters.contains(text.at(offset - 1))) {
         return offset;
@@ -358,7 +357,7 @@ MatchResult Float::doMatch(QStringView text, int offset, const QStringList &) co
     return expOffset;
 }
 
-MatchResult HlCChar::doMatch(QStringView text, int offset, const QStringList &) const
+MatchResult HlCChar::doMatch(QStringView text, int offset, const QStringList &, DynamicRegexpCache &) const
 {
     if (text.size() < offset + 3) {
         return offset;
@@ -393,7 +392,7 @@ HlCHex::HlCHex(DefinitionData &def, const HighlightingContextData::Rule::HlCHex
     resolveAdditionalWordDelimiters(m_wordDelimiters, data.wordDelimiters);
 }
 
-MatchResult HlCHex::doMatch(QStringView text, int offset, const QStringList &) const
+MatchResult HlCHex::doMatch(QStringView text, int offset, const QStringList &, DynamicRegexpCache &) const
 {
     if (offset > 0 && !m_wordDelimiters.contains(text.at(offset - 1))) {
         return offset;
@@ -427,7 +426,7 @@ HlCOct::HlCOct(DefinitionData &def, const HighlightingContextData::Rule::HlCOct
     resolveAdditionalWordDelimiters(m_wordDelimiters, data.wordDelimiters);
 }
 
-MatchResult HlCOct::doMatch(QStringView text, int offset, const QStringList &) const
+MatchResult HlCOct::doMatch(QStringView text, int offset, const QStringList &, DynamicRegexpCache &) const
 {
     if (offset > 0 && !m_wordDelimiters.contains(text.at(offset - 1))) {
         return offset;
@@ -453,7 +452,7 @@ MatchResult HlCOct::doMatch(QStringView text, int offset, const QStringList &) c
     return offset;
 }
 
-MatchResult HlCStringChar::doMatch(QStringView text, int offset, const QStringList &) const
+MatchResult HlCStringChar::doMatch(QStringView text, int offset, const QStringList &, DynamicRegexpCache &) const
 {
     return matchEscapedChar(text, offset);
 }
@@ -464,7 +463,7 @@ IncludeRules::IncludeRules(const HighlightingContextData::Rule::IncludeRules &da
 {
 }
 
-MatchResult IncludeRules::doMatch(QStringView text, int offset, const QStringList &) const
+MatchResult IncludeRules::doMatch(QStringView text, int offset, const QStringList &, DynamicRegexpCache &) const
 {
     Q_UNUSED(text);
     qCWarning(Log) << "Unresolved include rule";
@@ -477,7 +476,7 @@ Int::Int(DefinitionData &def, const HighlightingContextData::Rule::Int &data)
     resolveAdditionalWordDelimiters(m_wordDelimiters, data.wordDelimiters);
 }
 
-MatchResult Int::doMatch(QStringView text, int offset, const QStringList &) const
+MatchResult Int::doMatch(QStringView text, int offset, const QStringList &, DynamicRegexpCache &) const
 {
     if (offset > 0 && !m_wordDelimiters.contains(text.at(offset - 1))) {
         return offset;
@@ -521,9 +520,10 @@ KeywordListRule::KeywordListRule(const KeywordList &keywordList, DefinitionData
     , m_caseSensitivity(data.hasCaseSensitivityOverride ? data.caseSensitivityOverride : keywordList.caseSensitivity())
 {
     resolveAdditionalWordDelimiters(m_wordDelimiters, data.wordDelimiters);
+    m_hasSkipOffset = true;
 }
 
-MatchResult KeywordListRule::doMatch(QStringView text, int offset, const QStringList &) const
+MatchResult KeywordListRule::doMatch(QStringView text, int offset, const QStringList &, DynamicRegexpCache &) const
 {
     auto newOffset = offset;
     while (text.size() > newOffset && !m_wordDelimiters.contains(text.at(newOffset))) {
@@ -546,7 +546,7 @@ LineContinue::LineContinue(const HighlightingContextData::Rule::LineContinue &da
 {
 }
 
-MatchResult LineContinue::doMatch(QStringView text, int offset, const QStringList &) const
+MatchResult LineContinue::doMatch(QStringView text, int offset, const QStringList &, DynamicRegexpCache &) const
 {
     if (offset == text.size() - 1 && text.at(offset) == m_char) {
         return offset + 1;
@@ -560,7 +560,7 @@ RangeDetect::RangeDetect(const HighlightingContextData::Rule::RangeDetect &data)
 {
 }
 
-MatchResult RangeDetect::doMatch(QStringView text, int offset, const QStringList &) const
+MatchResult RangeDetect::doMatch(QStringView text, int offset, const QStringList &, DynamicRegexpCache &) const
 {
     if (text.size() - offset < 2) {
         return offset;
@@ -591,25 +591,16 @@ static QRegularExpression::PatternOptions makePattenOptions(const HighlightingCo
 
 static void resolveRegex(QRegularExpression ®exp, Context *context)
 {
-    if (!regexp.isValid()) {
-        // DontCaptureOption with back reference capture is an error, remove this option then try again
+    bool enableCapture = context && context->hasDynamicRule();
+
+    // disable DontCaptureOption when reference a context with dynamic rule or
+    // with invalid regex because DontCaptureOption with back reference capture is an error
+    if (enableCapture || !regexp.isValid()) {
         regexp.setPatternOptions(regexp.patternOptions() & ~QRegularExpression::DontCaptureOption);
-
-        if (!regexp.isValid()) {
-            qCDebug(Log) << "Invalid regexp:" << regexp.pattern();
-        }
-
-        return;
     }
 
-    // disable DontCaptureOption when reference a context with dynamic rule
-    if (context) {
-        for (const Rule::Ptr &rule : context->rules()) {
-            if (rule->isDynamic()) {
-                regexp.setPatternOptions(regexp.patternOptions() & ~QRegularExpression::DontCaptureOption);
-                break;
-            }
-        }
+    if (!regexp.isValid()) {
+        qCDebug(Log) << "Invalid regexp:" << regexp.pattern();
     }
 }
 
@@ -618,15 +609,25 @@ static MatchResult regexMatch(const QRegularExpression ®exp, QStringView text
     /**
      * match the pattern
      */
+#if QT_VERSION >= QT_VERSION_CHECK(6, 5, 0)
+    const auto result = regexp.matchView(text, offset, QRegularExpression::NormalMatch, QRegularExpression::DontCheckSubjectStringMatchOption);
+#else
     const auto result = regexp.match(text, offset, QRegularExpression::NormalMatch, QRegularExpression::DontCheckSubjectStringMatchOption);
+#endif
     if (result.capturedStart() == offset) {
         /**
          * we only need to compute the captured texts if we have real capture groups
          * highlightings should only address %1..%.., see e.g. replaceCaptures
          * DetectChar ignores %0, too
          */
-        if (result.lastCapturedIndex() > 0) {
-            return MatchResult(offset + result.capturedLength(), result.capturedTexts());
+        int lastCapturedIndex = result.lastCapturedIndex();
+        if (lastCapturedIndex > 0) {
+            QStringList captures;
+            captures.reserve(lastCapturedIndex);
+            // ignore the capturing group number 0
+            for (int i = 1; i <= lastCapturedIndex; ++i)
+                captures.push_back(result.captured(i));
+            return MatchResult(offset + result.capturedLength(), std::move(captures));
         }
 
         /**
@@ -645,20 +646,17 @@ static MatchResult regexMatch(const QRegularExpression ®exp, QStringView text
 RegExpr::RegExpr(const HighlightingContextData::Rule::RegExpr &data)
     : m_regexp(data.pattern, makePattenOptions(data))
 {
+    m_hasSkipOffset = true;
 }
 
 void RegExpr::resolve()
 {
-    if (m_isResolved) {
-        return;
-    }
-
     m_isResolved = true;
 
     resolveRegex(m_regexp, context().context());
 }
 
-MatchResult RegExpr::doMatch(QStringView text, int offset, const QStringList &) const
+MatchResult RegExpr::doMatch(QStringView text, int offset, const QStringList &, DynamicRegexpCache &) const
 {
     if (Q_UNLIKELY(!m_isResolved)) {
         const_cast(this)->resolve();
@@ -672,14 +670,11 @@ DynamicRegExpr::DynamicRegExpr(const HighlightingContextData::Rule::RegExpr &dat
     , m_patternOptions(makePattenOptions(data))
 {
     m_dynamic = true;
+    m_hasSkipOffset = true;
 }
 
 void DynamicRegExpr::resolve()
 {
-    if (m_isResolved) {
-        return;
-    }
-
     m_isResolved = true;
 
     QRegularExpression regexp(m_pattern, m_patternOptions);
@@ -687,7 +682,7 @@ void DynamicRegExpr::resolve()
     m_patternOptions = regexp.patternOptions();
 }
 
-MatchResult DynamicRegExpr::doMatch(QStringView text, int offset, const QStringList &captures) const
+MatchResult DynamicRegExpr::doMatch(QStringView text, int offset, const QStringList &captures, DynamicRegexpCache &dynamicRegexpCache) const
 {
     if (Q_UNLIKELY(!m_isResolved)) {
         const_cast(this)->resolve();
@@ -696,8 +691,8 @@ MatchResult DynamicRegExpr::doMatch(QStringView text, int offset, const QStringL
     /**
      * create new pattern with right instantiation
      */
-    const QRegularExpression regexp(replaceCaptures(m_pattern, captures, true), m_patternOptions);
-
+    auto pattern = replaceCaptures(m_pattern, captures, true);
+    auto ®exp = dynamicRegexpCache.compileRegexp(std::move(pattern), m_patternOptions);
     return regexMatch(regexp, text, offset);
 }
 
@@ -707,7 +702,7 @@ StringDetect::StringDetect(const HighlightingContextData::Rule::StringDetect &da
 {
 }
 
-MatchResult StringDetect::doMatch(QStringView text, int offset, const QStringList &) const
+MatchResult StringDetect::doMatch(QStringView text, int offset, const QStringList &, DynamicRegexpCache &) const
 {
     return matchString(m_string, text, offset, m_caseSensitivity);
 }
@@ -719,7 +714,7 @@ DynamicStringDetect::DynamicStringDetect(const HighlightingContextData::Rule::St
     m_dynamic = true;
 }
 
-MatchResult DynamicStringDetect::doMatch(QStringView text, int offset, const QStringList &captures) const
+MatchResult DynamicStringDetect::doMatch(QStringView text, int offset, const QStringList &captures, DynamicRegexpCache &) const
 {
     /**
      * for dynamic case: create new pattern with right instantiation
@@ -736,7 +731,7 @@ WordDetect::WordDetect(DefinitionData &def, const HighlightingContextData::Rule:
     resolveAdditionalWordDelimiters(m_wordDelimiters, data.wordDelimiters);
 }
 
-MatchResult WordDetect::doMatch(QStringView text, int offset, const QStringList &) const
+MatchResult WordDetect::doMatch(QStringView text, int offset, const QStringList &, DynamicRegexpCache &) const
 {
     if (text.size() - offset < m_word.size()) {
         return offset;
diff --git a/src/libs/3rdparty/syntax-highlighting/src/lib/rule_p.h b/src/libs/3rdparty/syntax-highlighting/src/lib/rule_p.h
index 7536d92e803..bc5f367ad67 100644
--- a/src/libs/3rdparty/syntax-highlighting/src/lib/rule_p.h
+++ b/src/libs/3rdparty/syntax-highlighting/src/lib/rule_p.h
@@ -27,6 +27,7 @@ namespace KSyntaxHighlighting
 class WordDelimiters;
 class DefinitionData;
 class IncludeRules;
+class DynamicRegexpCache;
 
 class Rule
 {
@@ -83,7 +84,15 @@ public:
         return m_type == Type::LineContinue;
     }
 
-    virtual MatchResult doMatch(QStringView text, int offset, const QStringList &captures) const = 0;
+    // If true, then the rule uses the skipOffset parameter of MatchResult.
+    // This is used by AbstractHighlighter::highlightLine() to look for a rule
+    // in the skipOffsets cache only if it can be found there.
+    bool hasSkipOffset() const
+    {
+        return m_hasSkipOffset;
+    }
+
+    virtual MatchResult doMatch(QStringView text, int offset, const QStringList &captures, DynamicRegexpCache &dynamicRegexpCache) const = 0;
 
     static Rule::Ptr create(DefinitionData &def, const HighlightingContextData::Rule &ruleData, QStringView lookupContextName);
 
@@ -98,6 +107,7 @@ private:
         IncludeRules,
     };
 
+private:
     Format m_attributeFormat;
     ContextSwitch m_context;
     int m_column = -1;
@@ -108,6 +118,7 @@ private:
     bool m_lookAhead = false;
 
 protected:
+    bool m_hasSkipOffset = false;
     bool m_dynamic = false;
 };
 
@@ -117,10 +128,10 @@ public:
     AnyChar(const HighlightingContextData::Rule::AnyChar &data);
 
 protected:
-    MatchResult doMatch(QStringView text, int offset, const QStringList &) const override;
+    MatchResult doMatch(QStringView text, int offset, const QStringList &, DynamicRegexpCache &) const override;
 
 private:
-    QString m_chars;
+    WordDelimiters m_chars;
 };
 
 class DetectChar final : public Rule
@@ -129,7 +140,7 @@ public:
     DetectChar(const HighlightingContextData::Rule::DetectChar &data);
 
 protected:
-    MatchResult doMatch(QStringView text, int offset, const QStringList &) const override;
+    MatchResult doMatch(QStringView text, int offset, const QStringList &, DynamicRegexpCache &) const override;
 
 private:
     QChar m_char;
@@ -142,7 +153,7 @@ public:
     Detect2Chars(const HighlightingContextData::Rule::Detect2Chars &data);
 
 protected:
-    MatchResult doMatch(QStringView text, int offset, const QStringList &) const override;
+    MatchResult doMatch(QStringView text, int offset, const QStringList &, DynamicRegexpCache &) const override;
 
 private:
     QChar m_char1;
@@ -152,13 +163,13 @@ private:
 class DetectIdentifier final : public Rule
 {
 protected:
-    MatchResult doMatch(QStringView text, int offset, const QStringList &) const override;
+    MatchResult doMatch(QStringView text, int offset, const QStringList &, DynamicRegexpCache &) const override;
 };
 
 class DetectSpaces final : public Rule
 {
 protected:
-    MatchResult doMatch(QStringView text, int offset, const QStringList &) const override;
+    MatchResult doMatch(QStringView text, int offset, const QStringList &, DynamicRegexpCache &) const override;
 };
 
 class Float final : public Rule
@@ -167,7 +178,7 @@ public:
     Float(DefinitionData &def, const HighlightingContextData::Rule::Float &data);
 
 protected:
-    MatchResult doMatch(QStringView text, int offset, const QStringList &) const override;
+    MatchResult doMatch(QStringView text, int offset, const QStringList &, DynamicRegexpCache &) const override;
 
 private:
     WordDelimiters m_wordDelimiters;
@@ -189,7 +200,7 @@ public:
     }
 
 protected:
-    MatchResult doMatch(QStringView text, int offset, const QStringList &) const override;
+    MatchResult doMatch(QStringView text, int offset, const QStringList &, DynamicRegexpCache &) const override;
 
 private:
     QString m_contextName;
@@ -202,7 +213,7 @@ public:
     Int(DefinitionData &def, const HighlightingContextData::Rule::Int &data);
 
 protected:
-    MatchResult doMatch(QStringView text, int offset, const QStringList &) const override;
+    MatchResult doMatch(QStringView text, int offset, const QStringList &, DynamicRegexpCache &) const override;
 
 private:
     WordDelimiters m_wordDelimiters;
@@ -211,7 +222,7 @@ private:
 class HlCChar final : public Rule
 {
 protected:
-    MatchResult doMatch(QStringView text, int offset, const QStringList &) const override;
+    MatchResult doMatch(QStringView text, int offset, const QStringList &, DynamicRegexpCache &) const override;
 };
 
 class HlCHex final : public Rule
@@ -220,7 +231,7 @@ public:
     HlCHex(DefinitionData &def, const HighlightingContextData::Rule::HlCHex &data);
 
 protected:
-    MatchResult doMatch(QStringView text, int offset, const QStringList &) const override;
+    MatchResult doMatch(QStringView text, int offset, const QStringList &, DynamicRegexpCache &) const override;
 
 private:
     WordDelimiters m_wordDelimiters;
@@ -232,7 +243,7 @@ public:
     HlCOct(DefinitionData &def, const HighlightingContextData::Rule::HlCOct &data);
 
 protected:
-    MatchResult doMatch(QStringView text, int offset, const QStringList &) const override;
+    MatchResult doMatch(QStringView text, int offset, const QStringList &, DynamicRegexpCache &) const override;
 
 private:
     WordDelimiters m_wordDelimiters;
@@ -241,7 +252,7 @@ private:
 class HlCStringChar final : public Rule
 {
 protected:
-    MatchResult doMatch(QStringView text, int offset, const QStringList &) const override;
+    MatchResult doMatch(QStringView text, int offset, const QStringList &, DynamicRegexpCache &) const override;
 };
 
 class KeywordListRule final : public Rule
@@ -252,7 +263,7 @@ public:
     static Rule::Ptr create(DefinitionData &def, const HighlightingContextData::Rule::Keyword &data, QStringView lookupContextName);
 
 protected:
-    MatchResult doMatch(QStringView text, int offset, const QStringList &) const override;
+    MatchResult doMatch(QStringView text, int offset, const QStringList &, DynamicRegexpCache &) const override;
 
 private:
     WordDelimiters m_wordDelimiters;
@@ -266,7 +277,7 @@ public:
     LineContinue(const HighlightingContextData::Rule::LineContinue &data);
 
 protected:
-    MatchResult doMatch(QStringView text, int offset, const QStringList &) const override;
+    MatchResult doMatch(QStringView text, int offset, const QStringList &, DynamicRegexpCache &) const override;
 
 private:
     QChar m_char;
@@ -278,7 +289,7 @@ public:
     RangeDetect(const HighlightingContextData::Rule::RangeDetect &data);
 
 protected:
-    MatchResult doMatch(QStringView text, int offset, const QStringList &) const override;
+    MatchResult doMatch(QStringView text, int offset, const QStringList &, DynamicRegexpCache &) const override;
 
 private:
     QChar m_begin;
@@ -291,7 +302,7 @@ public:
     RegExpr(const HighlightingContextData::Rule::RegExpr &data);
 
 protected:
-    MatchResult doMatch(QStringView text, int offset, const QStringList &) const override;
+    MatchResult doMatch(QStringView text, int offset, const QStringList &, DynamicRegexpCache &) const override;
 
 private:
     void resolve();
@@ -305,7 +316,7 @@ public:
     DynamicRegExpr(const HighlightingContextData::Rule::RegExpr &data);
 
 protected:
-    MatchResult doMatch(QStringView text, int offset, const QStringList &) const override;
+    MatchResult doMatch(QStringView text, int offset, const QStringList &, DynamicRegexpCache &) const override;
 
 private:
     void resolve();
@@ -320,7 +331,7 @@ public:
     StringDetect(const HighlightingContextData::Rule::StringDetect &data);
 
 protected:
-    MatchResult doMatch(QStringView text, int offset, const QStringList &) const override;
+    MatchResult doMatch(QStringView text, int offset, const QStringList &, DynamicRegexpCache &) const override;
 
 private:
     QString m_string;
@@ -333,7 +344,7 @@ public:
     DynamicStringDetect(const HighlightingContextData::Rule::StringDetect &data);
 
 protected:
-    MatchResult doMatch(QStringView text, int offset, const QStringList &) const override;
+    MatchResult doMatch(QStringView text, int offset, const QStringList &, DynamicRegexpCache &) const override;
 
 private:
     QString m_string;
@@ -346,7 +357,7 @@ public:
     WordDetect(DefinitionData &def, const HighlightingContextData::Rule::WordDetect &data);
 
 protected:
-    MatchResult doMatch(QStringView text, int offset, const QStringList &) const override;
+    MatchResult doMatch(QStringView text, int offset, const QStringList &, DynamicRegexpCache &) const override;
 
 private:
     WordDelimiters m_wordDelimiters;
diff --git a/src/libs/3rdparty/syntax-highlighting/src/lib/state.cpp b/src/libs/3rdparty/syntax-highlighting/src/lib/state.cpp
index fc44a6dbd4c..dca58b35b7c 100644
--- a/src/libs/3rdparty/syntax-highlighting/src/lib/state.cpp
+++ b/src/libs/3rdparty/syntax-highlighting/src/lib/state.cpp
@@ -1,4 +1,4 @@
-/*
+/*
     SPDX-FileCopyrightText: 2016 Volker Krause 
     SPDX-FileCopyrightText: 2018 Christoph Cullmann 
 
@@ -14,36 +14,23 @@
 
 using namespace KSyntaxHighlighting;
 
-StateData *StateData::get(State &state)
+StateData *StateData::reset(State &state)
 {
-    // create state data on demand, to make default state construction cheap
-    if (!state.d) {
-        state.d = new StateData();
-    } else {
-        state.d.detach();
-    }
+    auto *p = new StateData();
+    state.d.reset(p);
+    return p;
+}
+
+StateData *StateData::detach(State &state)
+{
+    state.d.detach();
     return state.d.data();
 }
 
-bool StateData::isEmpty() const
-{
-    return m_contextStack.isEmpty();
-}
-
-void StateData::clear()
-{
-    m_contextStack.clear();
-}
-
-int StateData::size() const
-{
-    return m_contextStack.size();
-}
-
-void StateData::push(Context *context, const QStringList &captures)
+void StateData::push(Context *context, QStringList &&captures)
 {
     Q_ASSERT(context);
-    m_contextStack.push_back(qMakePair(context, captures));
+    m_contextStack.push_back(StackValue{context, std::move(captures)});
 }
 
 bool StateData::pop(int popCount)
@@ -54,42 +41,23 @@ bool StateData::pop(int popCount)
     }
 
     // keep the initial context alive in any case
-    Q_ASSERT(!isEmpty());
-    const bool initialContextSurvived = m_contextStack.size() > popCount;
+    Q_ASSERT(!m_contextStack.empty());
+    const bool initialContextSurvived = int(m_contextStack.size()) > popCount;
     m_contextStack.resize(std::max(1, int(m_contextStack.size()) - popCount));
     return initialContextSurvived;
 }
 
-Context *StateData::topContext() const
-{
-    Q_ASSERT(!isEmpty());
-    return m_contextStack.last().first;
-}
+State::State() = default;
 
-const QStringList &StateData::topCaptures() const
-{
-    Q_ASSERT(!isEmpty());
-    return m_contextStack.last().second;
-}
+State::State(State &&other) noexcept = default;
 
-State::State()
-{
-}
+State::State(const State &other) noexcept = default;
 
-State::State(const State &other)
-    : d(other.d)
-{
-}
+State::~State() = default;
 
-State::~State()
-{
-}
+State &State::operator=(State &&other) noexcept = default;
 
-State &State::operator=(const State &other)
-{
-    d = other.d;
-    return *this;
-}
+State &State::operator=(const State &other) noexcept = default;
 
 bool State::operator==(const State &other) const
 {
@@ -104,8 +72,13 @@ bool State::operator!=(const State &other) const
 
 bool State::indentationBasedFoldingEnabled() const
 {
-    if (!d || d->m_contextStack.isEmpty()) {
+    if (!d || d->m_contextStack.empty()) {
         return false;
     }
-    return d->m_contextStack.last().first->indentationBasedFoldingEnabled();
+    return d->m_contextStack.back().context->indentationBasedFoldingEnabled();
+}
+
+std::size_t KSyntaxHighlighting::qHash(const State &state, std::size_t seed)
+{
+    return state.d ? qHashMulti(seed, *state.d) : 0;
 }
diff --git a/src/libs/3rdparty/syntax-highlighting/src/lib/state.h b/src/libs/3rdparty/syntax-highlighting/src/lib/state.h
index 726ff32a884..3003a9b7cbf 100644
--- a/src/libs/3rdparty/syntax-highlighting/src/lib/state.h
+++ b/src/libs/3rdparty/syntax-highlighting/src/lib/state.h
@@ -10,11 +10,15 @@
 #include "ksyntaxhighlighting_export.h"
 
 #include 
+#include 
 
 namespace KSyntaxHighlighting
 {
+class State;
 class StateData;
 
+KSYNTAXHIGHLIGHTING_EXPORT std::size_t qHash(const State &state, std::size_t seed = 0);
+
 /** Opaque handle to the state of the highlighting engine.
  *  This needs to be fed into AbstractHighlighter for every line of text
  *  and allows concrete highlighter implementations to store state per
@@ -29,9 +33,11 @@ public:
      *  in a document.
      */
     State();
-    State(const State &other);
+    State(State &&other) noexcept;
+    State(const State &other) noexcept;
     ~State();
-    State &operator=(const State &rhs);
+    State &operator=(State &&rhs) noexcept;
+    State &operator=(const State &rhs) noexcept;
 
     /** Compares two states for equality.
      *  For two equal states and identical text input, AbstractHighlighter
@@ -56,13 +62,13 @@ public:
 
 private:
     friend class StateData;
+    KSYNTAXHIGHLIGHTING_EXPORT friend std::size_t qHash(const State &, std::size_t);
     QExplicitlySharedDataPointer d;
 };
-
 }
 
 QT_BEGIN_NAMESPACE
-Q_DECLARE_TYPEINFO(KSyntaxHighlighting::State, Q_MOVABLE_TYPE);
+Q_DECLARE_TYPEINFO(KSyntaxHighlighting::State, Q_RELOCATABLE_TYPE);
 QT_END_NAMESPACE
 
 #endif // KSYNTAXHIGHLIGHTING_STATE_H
diff --git a/src/libs/3rdparty/syntax-highlighting/src/lib/state_p.h b/src/libs/3rdparty/syntax-highlighting/src/lib/state_p.h
index 0248330304f..4aee1416818 100644
--- a/src/libs/3rdparty/syntax-highlighting/src/lib/state_p.h
+++ b/src/libs/3rdparty/syntax-highlighting/src/lib/state_p.h
@@ -8,8 +8,10 @@
 #ifndef KSYNTAXHIGHLIGHTING_STATE_P_H
 #define KSYNTAXHIGHLIGHTING_STATE_P_H
 
+#include 
+
 #include 
-#include 
+#include 
 
 #include "definitionref_p.h"
 
@@ -21,15 +23,25 @@ class StateData : public QSharedData
 {
     friend class State;
     friend class AbstractHighlighter;
+    friend std::size_t qHash(const StateData &, std::size_t);
 
 public:
     StateData() = default;
-    static StateData *get(State &state);
 
-    bool isEmpty() const;
-    void clear();
-    int size() const;
-    void push(Context *context, const QStringList &captures);
+    static StateData *reset(State &state);
+    static StateData *detach(State &state);
+
+    static StateData *get(const State &state)
+    {
+        return state.d.data();
+    }
+
+    int size() const
+    {
+        return m_contextStack.size();
+    }
+
+    void push(Context *context, QStringList &&captures);
 
     /**
      * Pop the number of elements given from the top of the current stack.
@@ -39,8 +51,25 @@ public:
      */
     bool pop(int popCount);
 
-    Context *topContext() const;
-    const QStringList &topCaptures() const;
+    Context *topContext() const
+    {
+        return m_contextStack.back().context;
+    }
+
+    const QStringList &topCaptures() const
+    {
+        return m_contextStack.back().captures;
+    }
+
+    struct StackValue {
+        Context *context;
+        QStringList captures;
+
+        bool operator==(const StackValue &other) const
+        {
+            return context == other.context && captures == other.captures;
+        }
+    };
 
 private:
     /**
@@ -51,9 +80,18 @@ private:
     /**
      * the context stack combines the active context + valid captures
      */
-    QVector> m_contextStack;
+    std::vector m_contextStack;
 };
 
+inline std::size_t qHash(const StateData::StackValue &stackValue, std::size_t seed = 0)
+{
+    return qHashMulti(seed, stackValue.context, stackValue.captures);
+}
+
+inline std::size_t qHash(const StateData &k, std::size_t seed = 0)
+{
+    return qHashMulti(seed, k.m_defId, qHashRange(k.m_contextStack.begin(), k.m_contextStack.end(), seed));
+}
 }
 
 #endif
diff --git a/src/libs/3rdparty/syntax-highlighting/src/lib/syntaxhighlighter.cpp b/src/libs/3rdparty/syntax-highlighting/src/lib/syntaxhighlighter.cpp
index 4754da22c61..70b26a79bf8 100644
--- a/src/libs/3rdparty/syntax-highlighting/src/lib/syntaxhighlighter.cpp
+++ b/src/libs/3rdparty/syntax-highlighting/src/lib/syntaxhighlighter.cpp
@@ -7,10 +7,13 @@
 #include "syntaxhighlighter.h"
 #include "abstracthighlighter_p.h"
 #include "definition.h"
+#include "definition_p.h"
 #include "foldingregion.h"
 #include "format.h"
+#include "format_p.h"
 #include "state.h"
 #include "theme.h"
+#include "themedata_p.h"
 
 Q_DECLARE_METATYPE(QTextBlock)
 
@@ -22,14 +25,26 @@ class TextBlockUserData : public QTextBlockUserData
 {
 public:
     State state;
-    QVector foldingRegions;
+    QList foldingRegions;
 };
 
 class SyntaxHighlighterPrivate : public AbstractHighlighterPrivate
 {
 public:
     static FoldingRegion foldingRegion(const QTextBlock &startBlock);
-    QVector foldingRegions;
+    void initTextFormat(QTextCharFormat &tf, const Format &format);
+    void computeTextFormats();
+
+    struct TextFormat {
+        QTextCharFormat tf;
+        /**
+         * id to check that the format belongs to the definition
+         */
+        std::intptr_t ptrId;
+    };
+
+    QList foldingRegions;
+    std::vector tfs;
 };
 
 }
@@ -48,6 +63,52 @@ FoldingRegion SyntaxHighlighterPrivate::foldingRegion(const QTextBlock &startBlo
     return FoldingRegion();
 }
 
+void SyntaxHighlighterPrivate::initTextFormat(QTextCharFormat &tf, const Format &format)
+{
+    // always set the foreground color to avoid palette issues
+    tf.setForeground(format.textColor(m_theme));
+
+    if (format.hasBackgroundColor(m_theme)) {
+        tf.setBackground(format.backgroundColor(m_theme));
+    }
+    if (format.isBold(m_theme)) {
+        tf.setFontWeight(QFont::Bold);
+    }
+    if (format.isItalic(m_theme)) {
+        tf.setFontItalic(true);
+    }
+    if (format.isUnderline(m_theme)) {
+        tf.setFontUnderline(true);
+    }
+    if (format.isStrikeThrough(m_theme)) {
+        tf.setFontStrikeOut(true);
+    }
+}
+
+void SyntaxHighlighterPrivate::computeTextFormats()
+{
+    auto definitions = m_definition.includedDefinitions();
+    definitions.append(m_definition);
+
+    int maxId = 0;
+    for (const auto &definition : std::as_const(definitions)) {
+        for (const auto &format : std::as_const(DefinitionData::get(definition)->formats)) {
+            maxId = qMax(maxId, format.id());
+        }
+    }
+    tfs.clear();
+    tfs.resize(maxId + 1);
+
+    // initialize tfs
+    for (const auto &definition : std::as_const(definitions)) {
+        for (const auto &format : std::as_const(DefinitionData::get(definition)->formats)) {
+            auto &tf = tfs[format.id()];
+            tf.ptrId = FormatPrivate::ptrId(format);
+            initTextFormat(tf.tf, format);
+        }
+    }
+}
+
 SyntaxHighlighter::SyntaxHighlighter(QObject *parent)
     : QSyntaxHighlighter(parent)
     , AbstractHighlighter(new SyntaxHighlighterPrivate)
@@ -68,13 +129,27 @@ SyntaxHighlighter::~SyntaxHighlighter()
 
 void SyntaxHighlighter::setDefinition(const Definition &def)
 {
-    const auto needsRehighlight = definition() != def;
-    AbstractHighlighter::setDefinition(def);
+    Q_D(SyntaxHighlighter);
+
+    const auto needsRehighlight = d->m_definition != def;
+    if (DefinitionData::get(d->m_definition) != DefinitionData::get(def)) {
+        d->m_definition = def;
+        d->tfs.clear();
+    }
     if (needsRehighlight) {
         rehighlight();
     }
 }
 
+void SyntaxHighlighter::setTheme(const Theme &theme)
+{
+    Q_D(SyntaxHighlighter);
+    if (ThemeData::get(d->m_theme) != ThemeData::get(theme)) {
+        d->m_theme = theme;
+        d->tfs.clear();
+    }
+}
+
 bool SyntaxHighlighter::startsFoldingRegion(const QTextBlock &startBlock) const
 {
     return SyntaxHighlighterPrivate::foldingRegion(startBlock).type() == FoldingRegion::Begin;
@@ -92,13 +167,13 @@ QTextBlock SyntaxHighlighter::findFoldingRegionEnd(const QTextBlock &startBlock)
         if (!data) {
             continue;
         }
-        for (auto it = data->foldingRegions.constBegin(); it != data->foldingRegions.constEnd(); ++it) {
-            if ((*it).id() != region.id()) {
+        for (const auto &foldingRegion : std::as_const(data->foldingRegions)) {
+            if (foldingRegion.id() != region.id()) {
                 continue;
             }
-            if ((*it).type() == FoldingRegion::End) {
+            if (foldingRegion.type() == FoldingRegion::End) {
                 --depth;
-            } else if ((*it).type() == FoldingRegion::Begin) {
+            } else if (foldingRegion.type() == FoldingRegion::Begin) {
                 ++depth;
             }
             if (depth == 0) {
@@ -114,30 +189,31 @@ void SyntaxHighlighter::highlightBlock(const QString &text)
 {
     Q_D(SyntaxHighlighter);
 
-    State state;
+    static const State emptyState;
+    const State *previousState = &emptyState;
     if (currentBlock().position() > 0) {
         const auto prevBlock = currentBlock().previous();
         const auto prevData = dynamic_cast(prevBlock.userData());
         if (prevData) {
-            state = prevData->state;
+            previousState = &prevData->state;
         }
     }
     d->foldingRegions.clear();
-    state = highlightLine(text, state);
+    auto newState = highlightLine(text, *previousState);
 
     auto data = dynamic_cast(currentBlockUserData());
     if (!data) { // first time we highlight this
         data = new TextBlockUserData;
-        data->state = state;
+        data->state = std::move(newState);
         data->foldingRegions = d->foldingRegions;
         setCurrentBlockUserData(data);
         return;
     }
 
-    if (data->state == state && data->foldingRegions == d->foldingRegions) { // we ended up in the same state, so we are done here
+    if (data->state == newState && data->foldingRegions == d->foldingRegions) { // we ended up in the same state, so we are done here
         return;
     }
-    data->state = state;
+    data->state = std::move(newState);
     data->foldingRegions = d->foldingRegions;
 
     const auto nextBlock = currentBlock().next();
@@ -146,40 +222,35 @@ void SyntaxHighlighter::highlightBlock(const QString &text)
     }
 }
 
-void SyntaxHighlighter::applyFormat(int offset, int length, const KSyntaxHighlighting::Format &format)
+void SyntaxHighlighter::applyFormat(int offset, int length, const Format &format)
 {
     if (length == 0) {
         return;
     }
 
-    QTextCharFormat tf;
-    // always set the foreground color to avoid palette issues
-    tf.setForeground(format.textColor(theme()));
+    Q_D(SyntaxHighlighter);
 
-    if (format.hasBackgroundColor(theme())) {
-        tf.setBackground(format.backgroundColor(theme()));
-    }
-    if (format.isBold(theme())) {
-        tf.setFontWeight(QFont::Bold);
-    }
-    if (format.isItalic(theme())) {
-        tf.setFontItalic(true);
-    }
-    if (format.isUnderline(theme())) {
-        tf.setFontUnderline(true);
-    }
-    if (format.isStrikeThrough(theme())) {
-        tf.setFontStrikeOut(true);
+    if (Q_UNLIKELY(d->tfs.empty())) {
+        d->computeTextFormats();
     }
 
-    QSyntaxHighlighter::setFormat(offset, length, tf);
+    const auto id = static_cast(format.id());
+    // This doesn't happen when format comes from the definition.
+    // But as the user can override the function to pass any format, this is a possible scenario.
+    if (id < d->tfs.size() && d->tfs[id].ptrId == FormatPrivate::ptrId(format)) {
+        QSyntaxHighlighter::setFormat(offset, length, d->tfs[id].tf);
+    } else {
+        QTextCharFormat tf;
+        d->initTextFormat(tf, format);
+        QSyntaxHighlighter::setFormat(offset, length, tf);
+    }
 }
 
 void SyntaxHighlighter::applyFolding(int offset, int length, FoldingRegion region)
 {
     Q_UNUSED(offset);
     Q_UNUSED(length);
-    [[maybe_unused]] Q_D(SyntaxHighlighter);
+    Q_D(SyntaxHighlighter);
 
     if (region.type() == FoldingRegion::Begin) {
         d->foldingRegions.push_back(region);
@@ -196,3 +267,5 @@ void SyntaxHighlighter::applyFolding(int offset, int length, FoldingRegion regio
         d->foldingRegions.push_back(region);
     }
 }
+
+#include "moc_syntaxhighlighter.cpp"
diff --git a/src/libs/3rdparty/syntax-highlighting/src/lib/syntaxhighlighter.h b/src/libs/3rdparty/syntax-highlighting/src/lib/syntaxhighlighter.h
index a57455d9baa..c19cb798dd1 100644
--- a/src/libs/3rdparty/syntax-highlighting/src/lib/syntaxhighlighter.h
+++ b/src/libs/3rdparty/syntax-highlighting/src/lib/syntaxhighlighter.h
@@ -32,6 +32,7 @@ public:
     ~SyntaxHighlighter() override;
 
     void setDefinition(const Definition &def) override;
+    void setTheme(const Theme &theme) override;
 
     /** Returns whether there is a folding region beginning at @p startBlock.
      *  This only considers syntax-based folding regions,
diff --git a/src/libs/3rdparty/syntax-highlighting/src/lib/theme.cpp b/src/libs/3rdparty/syntax-highlighting/src/lib/theme.cpp
index b23852f337a..c54bb38b180 100644
--- a/src/libs/3rdparty/syntax-highlighting/src/lib/theme.cpp
+++ b/src/libs/3rdparty/syntax-highlighting/src/lib/theme.cpp
@@ -103,3 +103,5 @@ QRgb Theme::editorColor(EditorColorRole role) const
 {
     return m_data->editorColor(role);
 }
+
+#include "moc_theme.cpp"
diff --git a/src/libs/3rdparty/syntax-highlighting/src/lib/theme.h b/src/libs/3rdparty/syntax-highlighting/src/lib/theme.h
index 37f9de1694b..c3fb0e6b6e6 100644
--- a/src/libs/3rdparty/syntax-highlighting/src/lib/theme.h
+++ b/src/libs/3rdparty/syntax-highlighting/src/lib/theme.h
@@ -67,11 +67,6 @@ class KSYNTAXHIGHLIGHTING_EXPORT Theme
     Q_PROPERTY(QString name READ name)
     Q_PROPERTY(QString translatedName READ translatedName)
 public:
-    // TODO KF6:
-    // - make TextStyle an enum class
-    // - move out of Theme into KSyntaxHighlighting
-    // - do the same for EditorColorRole
-
     /**
      * Default styles that can be referenced from syntax definition XML files.
      * Make sure to choose readable colors with good contrast especially in
@@ -342,7 +337,7 @@ private:
     /**
      * Constructor taking a shared ThemeData instance.
      */
-    explicit Theme(ThemeData *data);
+    KSYNTAXHIGHLIGHTING_NO_EXPORT explicit Theme(ThemeData *data);
     friend class RepositoryPrivate;
     friend class ThemeData;
 
@@ -356,7 +351,7 @@ private:
 }
 
 QT_BEGIN_NAMESPACE
-Q_DECLARE_TYPEINFO(KSyntaxHighlighting::Theme, Q_MOVABLE_TYPE);
+Q_DECLARE_TYPEINFO(KSyntaxHighlighting::Theme, Q_RELOCATABLE_TYPE);
 QT_END_NAMESPACE
 
 #endif // KSYNTAXHIGHLIGHTING_THEME_H
diff --git a/src/libs/3rdparty/syntax-highlighting/src/lib/themedata.cpp b/src/libs/3rdparty/syntax-highlighting/src/lib/themedata.cpp
index 4f77dcc494f..9d42d03db03 100644
--- a/src/libs/3rdparty/syntax-highlighting/src/lib/themedata.cpp
+++ b/src/libs/3rdparty/syntax-highlighting/src/lib/themedata.cpp
@@ -18,11 +18,6 @@
 
 using namespace KSyntaxHighlighting;
 
-ThemeData *ThemeData::get(const Theme &theme)
-{
-    return theme.m_data.data();
-}
-
 ThemeData::ThemeData()
 {
     memset(m_editorColors, 0, sizeof(m_editorColors));
@@ -87,9 +82,18 @@ bool ThemeData::load(const QString &filePath)
         return false;
     }
     const QByteArray jsonData = loadFile.readAll();
+    // look for metadata object
+    int metaDataStart = jsonData.indexOf("\"metadata\"");
+    int start = jsonData.indexOf('{', metaDataStart);
+    int end = jsonData.indexOf("}", metaDataStart);
+    if (start < 0 || end < 0) {
+        qCWarning(Log) << "Failed to parse theme file" << filePath << ":"
+                       << "no metadata object found";
+        return false;
+    }
 
     QJsonParseError parseError;
-    QJsonDocument jsonDoc = QJsonDocument::fromJson(jsonData, &parseError);
+    QJsonDocument jsonDoc = QJsonDocument::fromJson(jsonData.mid(start, (end + 1) - start), &parseError);
     if (parseError.error != QJsonParseError::NoError) {
         qCWarning(Log) << "Failed to parse theme file" << filePath << ":" << parseError.errorString();
         return false;
@@ -97,13 +101,34 @@ bool ThemeData::load(const QString &filePath)
 
     m_filePath = filePath;
 
-    QJsonObject obj = jsonDoc.object();
-
     // read metadata
-    const QJsonObject metadata = obj.value(QLatin1String("metadata")).toObject();
+    QJsonObject metadata = jsonDoc.object();
     m_name = metadata.value(QLatin1String("name")).toString();
     m_revision = metadata.value(QLatin1String("revision")).toInt();
+    return true;
+}
 
+void ThemeData::loadComplete()
+{
+    if (m_completelyLoaded) {
+        return;
+    }
+    m_completelyLoaded = true;
+
+    QFile loadFile(m_filePath);
+    if (!loadFile.open(QIODevice::ReadOnly)) {
+        return;
+    }
+    const QByteArray jsonData = loadFile.readAll();
+
+    QJsonParseError parseError;
+    QJsonDocument jsonDoc = QJsonDocument::fromJson(jsonData, &parseError);
+    if (parseError.error != QJsonParseError::NoError) {
+        qCWarning(Log) << "Failed to parse theme file" << m_filePath << ":" << parseError.errorString();
+        return;
+    }
+
+    QJsonObject obj = jsonDoc.object();
     // read text styles
     const auto metaEnumStyle = QMetaEnum::fromType();
     const QJsonObject textStyles = obj.value(QLatin1String("text-styles")).toObject();
@@ -162,7 +187,7 @@ bool ThemeData::load(const QString &filePath)
         }
     }
 
-    return true;
+    return;
 }
 
 QString ThemeData::name() const
@@ -187,6 +212,9 @@ QString ThemeData::filePath() const
 
 TextStyleData ThemeData::textStyle(Theme::TextStyle style) const
 {
+    if (!m_completelyLoaded) {
+        const_cast(this)->loadComplete();
+    }
     return m_textStyles[style];
 }
 
@@ -232,12 +260,18 @@ bool ThemeData::isStrikeThrough(Theme::TextStyle style) const
 
 QRgb ThemeData::editorColor(Theme::EditorColorRole role) const
 {
+    if (!m_completelyLoaded) {
+        const_cast(this)->loadComplete();
+    }
     Q_ASSERT(static_cast(role) >= 0 && static_cast(role) <= static_cast(Theme::TemplateReadOnlyPlaceholder));
     return m_editorColors[role];
 }
 
 TextStyleData ThemeData::textStyleOverride(const QString &definitionName, const QString &attributeName) const
 {
+    if (!m_completelyLoaded) {
+        const_cast(this)->loadComplete();
+    }
     auto it = m_textStyleOverrides.find(definitionName);
     if (it != m_textStyleOverrides.end()) {
         return it->value(attributeName);
diff --git a/src/libs/3rdparty/syntax-highlighting/src/lib/themedata_p.h b/src/libs/3rdparty/syntax-highlighting/src/lib/themedata_p.h
index 4ce87f0aaf9..6ee772f172c 100644
--- a/src/libs/3rdparty/syntax-highlighting/src/lib/themedata_p.h
+++ b/src/libs/3rdparty/syntax-highlighting/src/lib/themedata_p.h
@@ -24,7 +24,10 @@ namespace KSyntaxHighlighting
 class ThemeData : public QSharedData
 {
 public:
-    static ThemeData *get(const Theme &theme);
+    static ThemeData *get(const Theme &theme)
+    {
+        return theme.m_data.data();
+    }
 
     /**
      * Default constructor, creating an uninitialized ThemeData instance.
@@ -37,6 +40,8 @@ public:
      */
     bool load(const QString &filePath);
 
+    void loadComplete();
+
     /**
      * Returns the unique name of this Theme.
      */
@@ -140,6 +145,8 @@ private:
     //! on disk (in a read-only or a writeable location).
     QString m_filePath;
 
+    bool m_completelyLoaded = false;
+
     //! TextStyles
     std::vector m_textStyles;
 
@@ -154,7 +161,7 @@ private:
 }
 
 QT_BEGIN_NAMESPACE
-Q_DECLARE_TYPEINFO(KSyntaxHighlighting::TextStyleData, Q_MOVABLE_TYPE);
+Q_DECLARE_TYPEINFO(KSyntaxHighlighting::TextStyleData, Q_RELOCATABLE_TYPE);
 QT_END_NAMESPACE
 
 #endif // KSYNTAXHIGHLIGHTING_THEMEDATA_P_H
diff --git a/src/libs/3rdparty/syntax-highlighting/src/lib/worddelimiters.cpp b/src/libs/3rdparty/syntax-highlighting/src/lib/worddelimiters.cpp
index c5401a57cc9..ce55cd4b293 100644
--- a/src/libs/3rdparty/syntax-highlighting/src/lib/worddelimiters.cpp
+++ b/src/libs/3rdparty/syntax-highlighting/src/lib/worddelimiters.cpp
@@ -16,6 +16,12 @@ WordDelimiters::WordDelimiters()
     }
 }
 
+WordDelimiters::WordDelimiters(QStringView str)
+    : asciiDelimiters{}
+{
+    append(str);
+}
+
 bool WordDelimiters::contains(QChar c) const
 {
     if (c.unicode() < 128) {
diff --git a/src/libs/3rdparty/syntax-highlighting/src/lib/worddelimiters_p.h b/src/libs/3rdparty/syntax-highlighting/src/lib/worddelimiters_p.h
index ccad679a4ef..c23670d6344 100644
--- a/src/libs/3rdparty/syntax-highlighting/src/lib/worddelimiters_p.h
+++ b/src/libs/3rdparty/syntax-highlighting/src/lib/worddelimiters_p.h
@@ -26,6 +26,11 @@ class WordDelimiters
 public:
     WordDelimiters();
 
+    /**
+     * Initialize with a default delimiters.
+     */
+    explicit WordDelimiters(QStringView str);
+
     /**
      * Returns @c true if @p c is a word delimiter; otherwise returns @c false.
      */
diff --git a/src/libs/3rdparty/syntax-highlighting/src/quick/CMakeLists.txt b/src/libs/3rdparty/syntax-highlighting/src/quick/CMakeLists.txt
index 9277c2aee7d..1fb92ad2201 100644
--- a/src/libs/3rdparty/syntax-highlighting/src/quick/CMakeLists.txt
+++ b/src/libs/3rdparty/syntax-highlighting/src/quick/CMakeLists.txt
@@ -7,11 +7,10 @@ ecm_add_qml_module(kquicksyntaxhighlightingplugin URI "org.kde.syntaxhighlightin
 target_sources(kquicksyntaxhighlightingplugin PRIVATE
     kquicksyntaxhighlightingplugin.cpp
     kquicksyntaxhighlighter.cpp
-    repositorywrapper.cpp
 )
 target_link_libraries(kquicksyntaxhighlightingplugin PRIVATE
-    KF5SyntaxHighlighting
-    Qt${QT_MAJOR_VERSION}::Quick
+    KF6SyntaxHighlighting
+    Qt6::Quick
 )
 
 ecm_finalize_qml_module(kquicksyntaxhighlightingplugin DESTINATION ${KDE_INSTALL_QMLDIR})
diff --git a/src/libs/3rdparty/syntax-highlighting/src/quick/kquicksyntaxhighlighter.cpp b/src/libs/3rdparty/syntax-highlighting/src/quick/kquicksyntaxhighlighter.cpp
index eb795b1468e..19cfbacf58c 100644
--- a/src/libs/3rdparty/syntax-highlighting/src/quick/kquicksyntaxhighlighter.cpp
+++ b/src/libs/3rdparty/syntax-highlighting/src/quick/kquicksyntaxhighlighter.cpp
@@ -49,7 +49,7 @@ QVariant KQuickSyntaxHighlighter::definition() const
 void KQuickSyntaxHighlighter::setDefinition(const QVariant &definition)
 {
     Definition def;
-    if (definition.type() == QVariant::String) {
+    if (definition.userType() == QMetaType::QString) {
         def = unwrappedRepository()->definitionForName(definition.toString());
     } else {
         def = definition.value();
@@ -73,9 +73,9 @@ QVariant KQuickSyntaxHighlighter::theme() const
 void KQuickSyntaxHighlighter::setTheme(const QVariant &theme)
 {
     Theme t;
-    if (theme.type() == QVariant::String) {
+    if (theme.userType() == QMetaType::QString) {
         t = unwrappedRepository()->theme(theme.toString());
-    } else if (theme.type() == QVariant::Int) {
+    } else if (theme.userType() == QMetaType::Int) {
         t = unwrappedRepository()->defaultTheme(static_cast(theme.toInt()));
     } else {
         t = theme.value();
@@ -89,12 +89,12 @@ void KQuickSyntaxHighlighter::setTheme(const QVariant &theme)
     }
 }
 
-RepositoryWrapper *KQuickSyntaxHighlighter::repository() const
+Repository *KQuickSyntaxHighlighter::repository() const
 {
     return m_repository;
 }
 
-void KQuickSyntaxHighlighter::setRepository(RepositoryWrapper *repository)
+void KQuickSyntaxHighlighter::setRepository(Repository *repository)
 {
     if (m_repository == repository) {
         return;
@@ -106,7 +106,9 @@ void KQuickSyntaxHighlighter::setRepository(RepositoryWrapper *repository)
 Repository *KQuickSyntaxHighlighter::unwrappedRepository() const
 {
     if (m_repository) {
-        return m_repository->m_repository;
+        return m_repository;
     }
     return defaultRepository();
 }
+
+#include "moc_kquicksyntaxhighlighter.cpp"
diff --git a/src/libs/3rdparty/syntax-highlighting/src/quick/kquicksyntaxhighlighter.h b/src/libs/3rdparty/syntax-highlighting/src/quick/kquicksyntaxhighlighter.h
index 211f80d37f5..b45c26339f2 100644
--- a/src/libs/3rdparty/syntax-highlighting/src/quick/kquicksyntaxhighlighter.h
+++ b/src/libs/3rdparty/syntax-highlighting/src/quick/kquicksyntaxhighlighter.h
@@ -8,8 +8,6 @@
 #ifndef KQUICKSYNTAXHIGHLIGHTER_H
 #define KQUICKSYNTAXHIGHLIGHTER_H
 
-#include "repositorywrapper.h"
-
 #include 
 #include 
 
@@ -29,7 +27,7 @@ class KQuickSyntaxHighlighter : public QObject
     Q_PROPERTY(QObject *textEdit READ textEdit WRITE setTextEdit NOTIFY textEditChanged)
     Q_PROPERTY(QVariant definition READ definition WRITE setDefinition NOTIFY definitionChanged)
     Q_PROPERTY(QVariant theme READ theme WRITE setTheme NOTIFY themeChanged)
-    Q_PROPERTY(RepositoryWrapper *repository READ repository WRITE setRepository NOTIFY repositoryChanged)
+    Q_PROPERTY(KSyntaxHighlighting::Repository *repository READ repository WRITE setRepository NOTIFY repositoryChanged)
 
 public:
     explicit KQuickSyntaxHighlighter(QObject *parent = nullptr);
@@ -44,8 +42,8 @@ public:
     QVariant theme() const;
     void setTheme(const QVariant &theme);
 
-    RepositoryWrapper *repository() const;
-    void setRepository(RepositoryWrapper *repository);
+    KSyntaxHighlighting::Repository *repository() const;
+    void setRepository(KSyntaxHighlighting::Repository *repository);
 
 Q_SIGNALS:
     void textEditChanged() const;
@@ -59,7 +57,7 @@ private:
     QObject *m_textEdit;
     KSyntaxHighlighting::Definition m_definition;
     KSyntaxHighlighting::Theme m_theme;
-    RepositoryWrapper *m_repository = nullptr;
+    KSyntaxHighlighting::Repository *m_repository = nullptr;
     KSyntaxHighlighting::SyntaxHighlighter *m_highlighter = nullptr;
 };
 
diff --git a/src/libs/3rdparty/syntax-highlighting/src/quick/kquicksyntaxhighlightingplugin.cpp b/src/libs/3rdparty/syntax-highlighting/src/quick/kquicksyntaxhighlightingplugin.cpp
index 9aeb503ec5d..5eb06862df8 100644
--- a/src/libs/3rdparty/syntax-highlighting/src/quick/kquicksyntaxhighlightingplugin.cpp
+++ b/src/libs/3rdparty/syntax-highlighting/src/quick/kquicksyntaxhighlightingplugin.cpp
@@ -7,7 +7,6 @@
 
 #include "kquicksyntaxhighlightingplugin.h"
 #include "kquicksyntaxhighlighter.h"
-#include "repositorywrapper.h"
 
 #include 
 #include 
@@ -30,17 +29,18 @@ void KQuickSyntaxHighlightingPlugin::registerTypes(const char *uri)
 {
     Q_ASSERT(QLatin1String(uri) == QLatin1String("org.kde.syntaxhighlighting"));
     qRegisterMetaType();
-    qRegisterMetaType>();
+    qRegisterMetaType>();
     qRegisterMetaType();
-    qRegisterMetaType>();
+    qRegisterMetaType>();
     qmlRegisterType(uri, 1, 0, "SyntaxHighlighter");
-    qmlRegisterUncreatableType(uri, 1, 0, "Definition", {});
-    qmlRegisterUncreatableType(uri, 1, 0, "Theme", {});
-    qmlRegisterSingletonType(uri, 1, 0, "Repository", [](auto engine, auto scriptEngine) {
+    qmlRegisterUncreatableMetaObject(Definition::staticMetaObject, uri, 1, 0, "Definition", {});
+    qmlRegisterUncreatableMetaObject(Theme::staticMetaObject, uri, 1, 0, "Theme", {});
+    qmlRegisterSingletonType(uri, 1, 0, "Repository", [](auto engine, auto scriptEngine) {
         (void)engine;
-        (void)scriptEngine;
-        auto repo = new RepositoryWrapper;
-        repo->m_repository = defaultRepository();
-        return repo;
+        auto repo = defaultRepository();
+        scriptEngine->setObjectOwnership(repo, QJSEngine::CppOwnership);
+        return defaultRepository();
     });
 }
+
+#include "moc_kquicksyntaxhighlightingplugin.cpp"
diff --git a/src/libs/3rdparty/syntax-highlighting/src/quick/repositorywrapper.cpp b/src/libs/3rdparty/syntax-highlighting/src/quick/repositorywrapper.cpp
deleted file mode 100644
index 733c799ed13..00000000000
--- a/src/libs/3rdparty/syntax-highlighting/src/quick/repositorywrapper.cpp
+++ /dev/null
@@ -1,65 +0,0 @@
-/*
-    SPDX-FileCopyrightText: 2021 Volker Krause 
-
-    SPDX-License-Identifier: MIT
-*/
-
-#include "repositorywrapper.h"
-
-#include 
-#include 
-#include 
-
-using namespace KSyntaxHighlighting;
-
-RepositoryWrapper::RepositoryWrapper(QObject *parent)
-    : QObject(parent)
-{
-}
-
-Definition RepositoryWrapper::definitionForName(const QString &defName) const
-{
-    return m_repository->definitionForName(defName);
-}
-
-Definition RepositoryWrapper::definitionForFileName(const QString &fileName) const
-{
-    return m_repository->definitionForFileName(fileName);
-}
-
-QVector RepositoryWrapper::definitionsForFileName(const QString &fileName) const
-{
-    return m_repository->definitionsForFileName(fileName);
-}
-
-Definition RepositoryWrapper::definitionForMimeType(const QString &mimeType) const
-{
-    return m_repository->definitionForMimeType(mimeType);
-}
-
-QVector RepositoryWrapper::definitionsForMimeType(const QString &mimeType) const
-{
-    return m_repository->definitionsForMimeType(mimeType);
-}
-
-QVector RepositoryWrapper::definitions() const
-{
-    return m_repository->definitions();
-}
-
-QVector RepositoryWrapper::themes() const
-{
-    return m_repository->themes();
-}
-
-Theme RepositoryWrapper::theme(const QString &themeName) const
-{
-    return m_repository->theme(themeName);
-}
-
-Theme RepositoryWrapper::defaultTheme(DefaultTheme t) const
-{
-    return m_repository->defaultTheme(static_cast(t));
-}
-
-#include "moc_repositorywrapper.cpp"
diff --git a/src/libs/3rdparty/syntax-highlighting/src/quick/repositorywrapper.h b/src/libs/3rdparty/syntax-highlighting/src/quick/repositorywrapper.h
deleted file mode 100644
index d4fb8d251cc..00000000000
--- a/src/libs/3rdparty/syntax-highlighting/src/quick/repositorywrapper.h
+++ /dev/null
@@ -1,45 +0,0 @@
-/*
-    SPDX-FileCopyrightText: 2021 Volker Krause 
-
-    SPDX-License-Identifier: MIT
-*/
-
-#ifndef REPOSITORYWRAPPER_H
-#define REPOSITORYWRAPPER_H
-
-#include 
-
-namespace KSyntaxHighlighting
-{
-class Definition;
-class Repository;
-class Theme;
-}
-
-// TODO KF6: merge this into KSyntaxHighlighting::Repository
-class RepositoryWrapper : public QObject
-{
-    Q_OBJECT
-    // TODO KF6: NOTIFY on reload
-    Q_PROPERTY(QVector definitions READ definitions CONSTANT)
-    Q_PROPERTY(QVector themes READ themes CONSTANT)
-public:
-    explicit RepositoryWrapper(QObject *parent = nullptr);
-
-    Q_INVOKABLE KSyntaxHighlighting::Definition definitionForName(const QString &defName) const;
-    Q_INVOKABLE KSyntaxHighlighting::Definition definitionForFileName(const QString &fileName) const;
-    Q_INVOKABLE QVector definitionsForFileName(const QString &fileName) const;
-    Q_INVOKABLE KSyntaxHighlighting::Definition definitionForMimeType(const QString &mimeType) const;
-    Q_INVOKABLE QVector definitionsForMimeType(const QString &mimeType) const;
-    QVector definitions() const;
-
-    QVector themes() const;
-    Q_INVOKABLE KSyntaxHighlighting::Theme theme(const QString &themeName) const;
-    enum DefaultTheme { LightTheme, DarkTheme };
-    Q_ENUM(DefaultTheme)
-    Q_INVOKABLE KSyntaxHighlighting::Theme defaultTheme(DefaultTheme t = LightTheme) const;
-
-    KSyntaxHighlighting::Repository *m_repository = nullptr;
-};
-
-#endif // REPOSITORYWRAPPER_H
diff --git a/src/libs/3rdparty/syntax-highlighting/syntax-highlighting.qbs b/src/libs/3rdparty/syntax-highlighting/syntax-highlighting.qbs
index 2df844c71cd..b0495897677 100644
--- a/src/libs/3rdparty/syntax-highlighting/syntax-highlighting.qbs
+++ b/src/libs/3rdparty/syntax-highlighting/syntax-highlighting.qbs
@@ -25,7 +25,7 @@ Project {
         name: "KSyntaxHighlighting_bundled"
         condition: !qtc.preferSystemSyntaxHighlighting || !Qt.KSyntaxHighlighting.present
 
-        cpp.defines: base.concat("KF5SyntaxHighlighting_EXPORTS")
+        cpp.defines: base.concat("KF6SyntaxHighlighting_EXPORTS")
         cpp.includePaths: [
             product.sourceDirectory + "/src/lib/",
             product.sourceDirectory + "/autogenerated/include/",
@@ -58,6 +58,7 @@ Project {
                 "definitiondownloader.cpp",
                 "definitiondownloader.h",
                 "definitionref_p.h",
+                "dynamicregexpcache_p.h",
                 "foldingregion.cpp",
                 "foldingregion.h",
                 "format.cpp",

From d0ae84539eaf5d3f41c94350b64104219900acbb Mon Sep 17 00:00:00 2001
From: Jarek Kobus 
Date: Thu, 15 Feb 2024 14:56:56 +0100
Subject: [PATCH 044/243] Axivion: Don't leak model on shutdown

Detected by memory analyzer.

Change-Id: I715c604f5769b958ad53da6444fd3763f3bdcc30
Reviewed-by: Christian Stenger 
---
 src/plugins/axivion/axivionoutputpane.cpp | 4 ++--
 1 file changed, 2 insertions(+), 2 deletions(-)

diff --git a/src/plugins/axivion/axivionoutputpane.cpp b/src/plugins/axivion/axivionoutputpane.cpp
index 6cdf6121089..9bd50784f3a 100644
--- a/src/plugins/axivion/axivionoutputpane.cpp
+++ b/src/plugins/axivion/axivionoutputpane.cpp
@@ -314,7 +314,7 @@ IssuesWidget::IssuesWidget(QWidget *parent)
     m_issuesView = new BaseTreeView(this);
     m_issuesView->setHorizontalScrollBarPolicy(Qt::ScrollBarAsNeeded);
     m_issuesView->enableColumnHiding();
-    m_issuesModel = new TreeModel;
+    m_issuesModel = new TreeModel(this);
     m_issuesView->setModel(m_issuesModel);
     auto sb = m_issuesView->verticalScrollBar();
     if (QTC_GUARD(sb)) {
@@ -363,7 +363,7 @@ void IssuesWidget::setTableDto(const Dto::TableInfoDto &dto)
     m_currentTableInfo.emplace(dto);
 
     // update issues table layout - for now just simple approach
-    TreeModel<> *issuesModel = new TreeModel;
+    TreeModel<> *issuesModel = new TreeModel(this);
     QStringList columnHeaders;
     QStringList hiddenColumns;
     for (const Dto::ColumnInfoDto &column : dto.columns) {

From 8ab6b94c480336cc6e2c951b2986f617ca8a5083 Mon Sep 17 00:00:00 2001
From: hjk 
Date: Wed, 14 Feb 2024 08:13:02 +0100
Subject: [PATCH 045/243] Debugger: Move string length annotation to type
 column

... and make it clear what it is.

Fixes: QTCREATORBUG-30065
Change-Id: Iccbe0f069569ef2682363eb889f34081e2c2b4d7
Reviewed-by: 
Reviewed-by: David Schulz 
---
 src/plugins/debugger/watchhandler.cpp | 4 ++--
 1 file changed, 2 insertions(+), 2 deletions(-)

diff --git a/src/plugins/debugger/watchhandler.cpp b/src/plugins/debugger/watchhandler.cpp
index 841dc4d0156..1c73cf33b58 100644
--- a/src/plugins/debugger/watchhandler.cpp
+++ b/src/plugins/debugger/watchhandler.cpp
@@ -826,8 +826,6 @@ static QString formattedValue(const WatchItem *item)
             v.chop(1);
             v.append("...\"");
         }
-        if (item->valuelen > 0)
-            v += QString(" (%1)").arg(item->valuelen);
         return v;
     }
 
@@ -961,6 +959,8 @@ static QString displayType(const WatchItem *item)
         result += QString(":%1").arg(item->bitsize);
     result.remove('\'');
     result = watchModel(item)->removeNamespaces(result);
+    if (item->valuelen > 0)
+        result = Tr::tr("%1 of length %2").arg(result).arg(item->valuelen);
     return result;
 }
 

From 7b198ea3ce738a65f8385de0fb055cbe56ae2074 Mon Sep 17 00:00:00 2001
From: hjk 
Date: Thu, 15 Feb 2024 18:07:38 +0100
Subject: [PATCH 046/243] Debugger: Select C++ debugger if there is nothing
 else selected

We want one-or-more debuggers enabled. This was accidentally not
done if the python debugger was the last one to unselect.

Change-Id: I1bcdb43a66dc110dc213eba0db079e6d02c00170
Reviewed-by: Jarek Kobus 
---
 src/plugins/debugger/debuggerrunconfigurationaspect.cpp | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/src/plugins/debugger/debuggerrunconfigurationaspect.cpp b/src/plugins/debugger/debuggerrunconfigurationaspect.cpp
index 1b44afd821b..53eaab1df9c 100644
--- a/src/plugins/debugger/debuggerrunconfigurationaspect.cpp
+++ b/src/plugins/debugger/debuggerrunconfigurationaspect.cpp
@@ -128,7 +128,7 @@ DebuggerRunConfigurationAspect::DebuggerRunConfigurationAspect(Target *target)
         if (Utils::allOf({&m_cppAspect, &m_qmlAspect, &m_pythonAspect}, &isDisabled))
             m_cppAspect.setValue(TriState::Default);
     });
-    connect(&m_qmlAspect, &TriStateAspect::changed, this, [this] {
+    connect(&m_pythonAspect, &TriStateAspect::changed, this, [this] {
         if (Utils::allOf({&m_cppAspect, &m_qmlAspect, &m_pythonAspect}, &isDisabled))
             m_cppAspect.setValue(TriState::Default);
     });

From 7201fa0e4d202c94794b4d68629aa113ce8aa769 Mon Sep 17 00:00:00 2001
From: hjk 
Date: Thu, 15 Feb 2024 18:22:53 +0100
Subject: [PATCH 047/243] Debugger: Create more uniform summary for debugger
 selection

Change-Id: I82ddcae84e4ff8d4776aa5fa988bb49b943b8d6f
Reviewed-by: Jarek Kobus 
---
 .../debuggerrunconfigurationaspect.cpp        | 33 ++++++++++---------
 1 file changed, 17 insertions(+), 16 deletions(-)

diff --git a/src/plugins/debugger/debuggerrunconfigurationaspect.cpp b/src/plugins/debugger/debuggerrunconfigurationaspect.cpp
index 53eaab1df9c..cff934e398d 100644
--- a/src/plugins/debugger/debuggerrunconfigurationaspect.cpp
+++ b/src/plugins/debugger/debuggerrunconfigurationaspect.cpp
@@ -53,12 +53,12 @@ DebuggerRunConfigurationAspect::DebuggerRunConfigurationAspect(Target *target)
     setConfigWidgetCreator([this] {
         Layouting::Grid builder;
         builder.addRow({m_cppAspect});
-        builder.addRow({m_pythonAspect});
         auto info = new QLabel(
             Tr::tr("What are the prerequisites?"));
         builder.addRow({m_qmlAspect, info});
+        builder.addRow({m_pythonAspect});
         connect(info, &QLabel::linkActivated, [](const QString &link) {
             Core::HelpManager::showHelpUrl(link);
         });
@@ -76,26 +76,28 @@ DebuggerRunConfigurationAspect::DebuggerRunConfigurationAspect(Target *target)
         builder.attachTo(innerPane);
 
         const auto setSummaryText = [this, details] {
-            QStringList items;
-            if (m_cppAspect() == TriState::Enabled)
-                items.append(Tr::tr("Enable C++ debugger."));
-            else if (m_cppAspect() == TriState::Default)
-                items.append(Tr::tr("Try to determine need for C++ debugger."));
+            const auto describe = [](const TriStateAspect &aspect, const QString &name) {
+                if (aspect() == TriState::Enabled)
+                    return Tr::tr("Enable %1 debugger.").arg(name);
+                if (aspect() == TriState::Disabled)
+                    return Tr::tr("Disable %1 debugger.").arg(name);
+                return Tr::tr("Try to determine need for %1 debugger.").arg(name);
+            };
 
-            if (m_qmlAspect() == TriState::Enabled)
-                items.append(Tr::tr("Enable QML debugger."));
-            else if (m_qmlAspect() == TriState::Default)
-                items.append(Tr::tr("Try to determine need for QML debugger."));
-
-            items.append(m_overrideStartupAspect().isEmpty()
-                             ? Tr::tr("Without additional startup commands.")
-                             : Tr::tr("With additional startup commands."));
-            details->setSummaryText(items.join(" "));
+            details->setSummaryText(QStringList{
+                describe(m_cppAspect, "C++"),
+                describe(m_qmlAspect, "QML"),
+                describe(m_pythonAspect, "Python"),
+                m_overrideStartupAspect().isEmpty()
+                                 ? Tr::tr("No additional startup commands.")
+                                 : Tr::tr("Use additional startup commands.")
+            }.join(" "));
         };
         setSummaryText();
 
         connect(&m_cppAspect, &BaseAspect::changed, this, setSummaryText);
         connect(&m_qmlAspect, &BaseAspect::changed, this, setSummaryText);
+        connect(&m_pythonAspect, &BaseAspect::changed, this, setSummaryText);
         connect(&m_overrideStartupAspect, &BaseAspect::changed, this, setSummaryText);
 
         return details;
@@ -179,7 +181,6 @@ bool DebuggerRunConfigurationAspect::useQmlDebugger() const
         if (!languages.contains(ProjectExplorer::Constants::QMLJS_LANGUAGE_ID))
             return projectHasQmlDefines(m_target->project());
 
-        //
         // Try to find a build configuration to check whether qml debugging is enabled there
         if (BuildConfiguration *bc = m_target->activeBuildConfiguration()) {
             if (const auto aspect = bc->aspect())

From 198251db9b031dd0d4f604dfe4ccb1035455a660 Mon Sep 17 00:00:00 2001
From: Eike Ziller 
Date: Thu, 15 Feb 2024 14:59:19 +0100
Subject: [PATCH 048/243] Bump version to 13.0.0-beta2

Change-Id: Ia03b43a4e3906350d79a2ba4dbfd800c5f80f77d
Reviewed-by: David Schulz 
Reviewed-by: 
---
 cmake/QtCreatorIDEBranding.cmake | 6 +++---
 qbs/modules/qtc/qtc.qbs          | 6 +++---
 2 files changed, 6 insertions(+), 6 deletions(-)

diff --git a/cmake/QtCreatorIDEBranding.cmake b/cmake/QtCreatorIDEBranding.cmake
index 275454a6684..6890a1ef957 100644
--- a/cmake/QtCreatorIDEBranding.cmake
+++ b/cmake/QtCreatorIDEBranding.cmake
@@ -1,6 +1,6 @@
-set(IDE_VERSION "12.0.82")                            # The IDE version.
-set(IDE_VERSION_COMPAT "12.0.82")                     # The IDE Compatibility version.
-set(IDE_VERSION_DISPLAY "13.0.0-beta1")               # The IDE display version.
+set(IDE_VERSION "12.0.83")                            # The IDE version.
+set(IDE_VERSION_COMPAT "12.0.83")                     # The IDE Compatibility version.
+set(IDE_VERSION_DISPLAY "13.0.0-beta2")               # The IDE display version.
 set(IDE_COPYRIGHT_YEAR "2024")                        # The IDE current copyright year.
 
 set(IDE_SETTINGSVARIANT "QtProject")                  # The IDE settings variation.
diff --git a/qbs/modules/qtc/qtc.qbs b/qbs/modules/qtc/qtc.qbs
index 1fe9fe91354..cb40782268e 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: '13.0.0-beta1'
+    property string qtcreator_display_version: '13.0.0-beta2'
     property string ide_version_major: '12'
     property string ide_version_minor: '0'
-    property string ide_version_release: '82'
+    property string ide_version_release: '83'
     property string qtcreator_version: ide_version_major + '.' + ide_version_minor + '.'
                                        + ide_version_release
 
     property string ide_compat_version_major: '12'
     property string ide_compat_version_minor: '0'
-    property string ide_compat_version_release: '82'
+    property string ide_compat_version_release: '83'
     property string qtcreator_compat_version: ide_compat_version_major + '.'
             + ide_compat_version_minor + '.' + ide_compat_version_release
 

From 8f23a64ac3df859557b2882b85eb6993fce94649 Mon Sep 17 00:00:00 2001
From: Jarek Kobus 
Date: Fri, 16 Feb 2024 08:50:09 +0100
Subject: [PATCH 049/243] DocumentClangToolRunner: Fix isEmpty() condition

Since we were adding the parallel item unconditionally to the
tasks list, the if(tasks.isEmpty()) condition was always false.
The intention was to check whether any call to addClangTool()
added at least one task.

The fix is to add parallel item after the condition is checked.

Change-Id: Iafdf21f1ac0f8fdd547a462990313e09a2dc46fd
Reviewed-by: David Schulz 
---
 src/plugins/clangtools/documentclangtoolrunner.cpp | 6 +++---
 1 file changed, 3 insertions(+), 3 deletions(-)

diff --git a/src/plugins/clangtools/documentclangtoolrunner.cpp b/src/plugins/clangtools/documentclangtoolrunner.cpp
index 06cdb8cdd5a..d503f80d63b 100644
--- a/src/plugins/clangtools/documentclangtoolrunner.cpp
+++ b/src/plugins/clangtools/documentclangtoolrunner.cpp
@@ -191,7 +191,7 @@ void DocumentClangToolRunner::run()
     vfso().update();
     const ClangDiagnosticConfig config = diagnosticConfig(runSettings.diagnosticConfigId());
     const Environment env = projectBuildEnvironment(project);
-    QList tasks{parallel};
+    QList tasks;
     const auto addClangTool = [this, &runSettings, &config, &env, &tasks](ClangToolType tool) {
         if (!toolEnabled(tool, config, runSettings))
             return;
@@ -204,7 +204,7 @@ void DocumentClangToolRunner::run()
         if (includeDir.isEmpty() || clangVersion.isEmpty())
             return;
         const AnalyzeUnits units{{m_fileInfo, includeDir, clangVersion}};
-        auto diagnosticFilter = [mappedPath = vfso().autoSavedFilePath(m_document)](
+        const auto diagnosticFilter = [mappedPath = vfso().autoSavedFilePath(m_document)](
                                     const FilePath &path) { return path == mappedPath; };
         const AnalyzeInputData input{tool,
                                      runSettings,
@@ -225,7 +225,7 @@ void DocumentClangToolRunner::run()
         return;
 
     cleanup.dismiss();
-    m_taskTreeRunner.start(tasks);
+    m_taskTreeRunner.start({parallel, tasks});
 }
 
 static void updateLocation(Debugger::DiagnosticLocation &location)

From 2abe04ff34173a1c25b2adc7dc11760a8b4b2ed7 Mon Sep 17 00:00:00 2001
From: Christian Kandeler 
Date: Thu, 15 Feb 2024 13:52:12 +0100
Subject: [PATCH 050/243] CppEditor: Do not duplicate minimum clangd version

Amends 55161882900b459da6bc76e2d5c48e3c32ea4b34.

Change-Id: I1de7249c06c0e262d0c36f980cc687f0e792f755
Reviewed-by: 
Reviewed-by: David Schulz 
Reviewed-by: Qt CI Bot 
---
 src/plugins/cppeditor/cppcodemodelsettings.cpp | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/src/plugins/cppeditor/cppcodemodelsettings.cpp b/src/plugins/cppeditor/cppcodemodelsettings.cpp
index bac28694f52..29516c62189 100644
--- a/src/plugins/cppeditor/cppcodemodelsettings.cpp
+++ b/src/plugins/cppeditor/cppcodemodelsettings.cpp
@@ -273,7 +273,7 @@ ClangdSettings::ClangdSettings()
 
 bool ClangdSettings::useClangd() const
 {
-    return m_data.useClangd && Utils::clangdVersion(clangdFilePath()) >= QVersionNumber(14);
+    return m_data.useClangd && clangdVersion(clangdFilePath()) >= minimumClangdVersion();
 }
 
 void ClangdSettings::setUseClangd(bool use) { instance().m_data.useClangd = use; }

From 64393a714d032455948002cb7649dc7f8a92b38f Mon Sep 17 00:00:00 2001
From: Christian Kandeler 
Date: Thu, 15 Feb 2024 15:28:51 +0100
Subject: [PATCH 051/243] QbsProjectManager: Fix potential freeze when
 importing projects

We forgot to quit the event loop in the case of an incompatible build
graph, causing each such operation to take ten seconds instead of
fractions of a second. In directories with lots of qbs builds, this
could result in Qt Creator freezing for several minutes.

Change-Id: I9f3de2e23fd67a87e9f487eb2a1b6e45fbde6f31
Reviewed-by: Christian Stenger 
Reviewed-by: 
Reviewed-by: Qt CI Bot 
---
 src/plugins/qbsprojectmanager/qbssession.cpp | 1 +
 1 file changed, 1 insertion(+)

diff --git a/src/plugins/qbsprojectmanager/qbssession.cpp b/src/plugins/qbsprojectmanager/qbssession.cpp
index 69dd6a7b2e1..4bbdbb6ebc7 100644
--- a/src/plugins/qbsprojectmanager/qbssession.cpp
+++ b/src/plugins/qbsprojectmanager/qbssession.cpp
@@ -413,6 +413,7 @@ QbsSession::BuildGraphInfo QbsSession::getBuildGraphInfo(const FilePath &bgFileP
     QTimer::singleShot(10000, &session, [&session] { session.d->eventLoop.exit(1); });
     connect(&session, &QbsSession::errorOccurred, [&] {
         bgInfo.error = ErrorInfo(Tr::tr("Failed to load qbs build graph."));
+        session.d->eventLoop.quit();
     });
     connect(&session, &QbsSession::projectResolved, [&](const ErrorInfo &error) {
         bgInfo.error = error;

From 718b4b60b08518efb45587f145176163b76c961b Mon Sep 17 00:00:00 2001
From: Eike Ziller 
Date: Fri, 16 Feb 2024 10:02:14 +0100
Subject: [PATCH 052/243] Add missing license file
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit

Amends 2ceb1e2ad7be8b4d6ec2856da97530723cde7eb8

Change-Id: I3e6c1d1e1878a4502b6871cc5ea45b54f52327f8
Reviewed-by: David Schulz 
Reviewed-by: 
Reviewed-by: Robert Löhning 
---
 .../src/overview/license-LGPLv2.0.txt         | 408 ++++++++++++++++++
 1 file changed, 408 insertions(+)
 create mode 100644 doc/qtcreator/src/overview/license-LGPLv2.0.txt

diff --git a/doc/qtcreator/src/overview/license-LGPLv2.0.txt b/doc/qtcreator/src/overview/license-LGPLv2.0.txt
new file mode 100644
index 00000000000..6c972cf1596
--- /dev/null
+++ b/doc/qtcreator/src/overview/license-LGPLv2.0.txt
@@ -0,0 +1,408 @@
+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

From 1bd3c7d9e5b93b23fc642700a34933780db52a48 Mon Sep 17 00:00:00 2001
From: Christian Kandeler 
Date: Fri, 16 Feb 2024 13:15:17 +0100
Subject: [PATCH 053/243] Wizards: Stop chasing The Current Thing in string
 construction

Guard against random deprecations by using a robust solution that works
across all Qt versions.

Fixes: QTCREATORBUG-30325
Change-Id: I00428d2454fcd6abffd3a25631946ea5d27cc4ae
Reviewed-by: Qt CI Bot 
Reviewed-by: 
Reviewed-by: Alessandro Portale 
---
 .../wizards/projects/qtquick2-extension/example/example.cpp     | 2 +-
 .../templates/wizards/projects/qtquickapplication/main.cpp      | 2 +-
 .../wizards/projects/qtquickapplication_compat/main.cpp         | 2 +-
 3 files changed, 3 insertions(+), 3 deletions(-)

diff --git a/share/qtcreator/templates/wizards/projects/qtquick2-extension/example/example.cpp b/share/qtcreator/templates/wizards/projects/qtquick2-extension/example/example.cpp
index b7b83acf554..5787dfa4953 100644
--- a/share/qtcreator/templates/wizards/projects/qtquick2-extension/example/example.cpp
+++ b/share/qtcreator/templates/wizards/projects/qtquick2-extension/example/example.cpp
@@ -11,7 +11,7 @@ int main(int argc, char *argv[])
     QQmlApplicationEngine engine;
     // The first subfolder is the libraryName followed by the regular
     // folder structure: LibraryName/Subfolder
-    const QUrl url(u"qrc:/ExampleProjectApp/example/example.qml"_qs);
+    const QUrl url(QStringLiteral("qrc:/ExampleProjectApp/example/example.qml"));
     QObject::connect(&engine, &QQmlApplicationEngine::objectCreated,
         &app, [url](QObject *obj, const QUrl &objUrl) {
             if (!obj && url == objUrl)
diff --git a/share/qtcreator/templates/wizards/projects/qtquickapplication/main.cpp b/share/qtcreator/templates/wizards/projects/qtquickapplication/main.cpp
index 155667fb122..07725874746 100644
--- a/share/qtcreator/templates/wizards/projects/qtquickapplication/main.cpp
+++ b/share/qtcreator/templates/wizards/projects/qtquickapplication/main.cpp
@@ -11,7 +11,7 @@ int main(int argc, char *argv[])
 
     QQmlApplicationEngine engine;
 @if !%{HasLoadFromModule}
-    const QUrl url(u"qrc:/%{JS: value('ProjectName')}/Main.qml"_qs);
+    const QUrl url(QStringLiteral("qrc:/%{JS: value('ProjectName')}/Main.qml"));
 @endif
 @if %{HasFailureSignal}
     QObject::connect(&engine, &QQmlApplicationEngine::objectCreationFailed,
diff --git a/share/qtcreator/templates/wizards/projects/qtquickapplication_compat/main.cpp b/share/qtcreator/templates/wizards/projects/qtquickapplication_compat/main.cpp
index 08698bb6bea..9c5b49e9f00 100644
--- a/share/qtcreator/templates/wizards/projects/qtquickapplication_compat/main.cpp
+++ b/share/qtcreator/templates/wizards/projects/qtquickapplication_compat/main.cpp
@@ -43,7 +43,7 @@ int main(int argc, char *argv[])
 
     QQmlApplicationEngine engine;
 @if %{IsQt6}
-    const QUrl url(u"qrc:/%{JS: value('ProjectName')}/main.qml"_qs);
+    const QUrl url(QStringLiteral("qrc:/%{JS: value('ProjectName')}/main.qml"));
 @else
     const QUrl url(QStringLiteral("qrc:/main.qml"));
 @endif

From d13a7dc9b51fcdfb1d7686c753aa1a2d4070cbf0 Mon Sep 17 00:00:00 2001
From: Cristian Adam 
Date: Fri, 9 Feb 2024 14:32:33 +0100
Subject: [PATCH 054/243] CMakePM: Update cmake conan for auto-setup

Update to https://github.com/conan-io/cmake-conan/commit/
f6464d1e13ef7a47c569f5061f9607ea63339d39

Task-number: QTCREATORBUG-30169
Change-Id: Ibb8f3d353117c5c8ce21b8686cb6e2e5ee146698
Reviewed-by: Alessandro Portale 
Reviewed-by: Marcus Tillmanns 
---
 .../package-manager/conan_provider.cmake      | 253 +++++++++++++-----
 .../cmakeprojectmanager/conan/CMakeLists.txt  |   1 +
 2 files changed, 183 insertions(+), 71 deletions(-)

diff --git a/src/share/3rdparty/package-manager/conan_provider.cmake b/src/share/3rdparty/package-manager/conan_provider.cmake
index d94a9d811f8..e5fa9cec190 100644
--- a/src/share/3rdparty/package-manager/conan_provider.cmake
+++ b/src/share/3rdparty/package-manager/conan_provider.cmake
@@ -1,5 +1,5 @@
 # https://github.com/conan-io/cmake-conan/blob/develop2/conan_provider.cmake
-# commit: 451fa97d2c59c07b13fb4812a64b2a6391f9e781
+# commit: f6464d1e13ef7a47c569f5061f9607ea63339d39
 #
 # The MIT License (MIT)
 #
@@ -30,22 +30,26 @@ function(detect_os OS OS_API_LEVEL OS_SDK OS_SUBSYSTEM OS_VERSION)
     # it could be cross compilation
     message(STATUS "CMake-Conan: cmake_system_name=${CMAKE_SYSTEM_NAME}")
     if(CMAKE_SYSTEM_NAME AND NOT CMAKE_SYSTEM_NAME STREQUAL "Generic")
-        if(${CMAKE_SYSTEM_NAME} STREQUAL "Darwin")
+        if(CMAKE_SYSTEM_NAME STREQUAL "Darwin")
             set(${OS} Macos PARENT_SCOPE)
-        elseif(${CMAKE_SYSTEM_NAME} STREQUAL "QNX")
+        elseif(CMAKE_SYSTEM_NAME STREQUAL "QNX")
             set(${OS} Neutrino PARENT_SCOPE)
-        elseif(${CMAKE_SYSTEM_NAME} STREQUAL "CYGWIN")
+        elseif(CMAKE_SYSTEM_NAME STREQUAL "CYGWIN")
             set(${OS} Windows PARENT_SCOPE)
             set(${OS_SUBSYSTEM} cygwin PARENT_SCOPE)
-        elseif(${CMAKE_SYSTEM_NAME} MATCHES "^MSYS")
+        elseif(CMAKE_SYSTEM_NAME MATCHES "^MSYS")
             set(${OS} Windows PARENT_SCOPE)
             set(${OS_SUBSYSTEM} msys2 PARENT_SCOPE)
         else()
             set(${OS} ${CMAKE_SYSTEM_NAME} PARENT_SCOPE)
         endif()
-        if(${CMAKE_SYSTEM_NAME} STREQUAL "Android")
-            string(REGEX MATCH "[0-9]+" _OS_API_LEVEL ${ANDROID_PLATFORM})
-            message(STATUS "CMake-Conan: android_platform=${ANDROID_PLATFORM}")
+        if(CMAKE_SYSTEM_NAME STREQUAL "Android")
+            if(DEFINED ANDROID_PLATFORM)
+                string(REGEX MATCH "[0-9]+" _OS_API_LEVEL ${ANDROID_PLATFORM})
+            elseif(DEFINED CMAKE_SYSTEM_VERSION)
+                set(_OS_API_LEVEL ${CMAKE_SYSTEM_VERSION})
+            endif()
+            message(STATUS "CMake-Conan: android api level=${_OS_API_LEVEL}")
             set(${OS_API_LEVEL} ${_OS_API_LEVEL} PARENT_SCOPE)
         endif()
         if(CMAKE_SYSTEM_NAME MATCHES "Darwin|iOS|tvOS|watchOS")
@@ -91,15 +95,22 @@ function(detect_arch ARCH)
             message(WARNING "CMake-Conan: Multiple architectures detected, this will only work if Conan recipe(s) produce fat binaries.")
         endif()
     endif()
-    if(CMAKE_SYSTEM_PROCESSOR MATCHES "aarch64|ARM64|arm64" OR CMAKE_OSX_ARCHITECTURES MATCHES arm64)
+    if(CMAKE_SYSTEM_NAME MATCHES "Darwin|iOS|tvOS|watchOS" AND NOT CMAKE_OSX_ARCHITECTURES STREQUAL "")
+        set(host_arch ${CMAKE_OSX_ARCHITECTURES})
+    elseif(MSVC)
+        set(host_arch ${CMAKE_CXX_COMPILER_ARCHITECTURE_ID})
+    else()
+        set(host_arch ${CMAKE_SYSTEM_PROCESSOR})
+    endif()
+    if(host_arch MATCHES "aarch64|arm64|ARM64")
         set(_ARCH armv8)
-    elseif(CMAKE_SYSTEM_PROCESSOR MATCHES "armv7-a|armv7l" OR CMAKE_OSX_ARCHITECTURES MATCHES armv7)
+    elseif(host_arch MATCHES "armv7|armv7-a|armv7l|ARMV7")
         set(_ARCH armv7)
-    elseif(CMAKE_OSX_ARCHITECTURES MATCHES armv7s)
+    elseif(host_arch MATCHES armv7s)
         set(_ARCH armv7s)
-    elseif(CMAKE_SYSTEM_PROCESSOR MATCHES "i686" OR CMAKE_OSX_ARCHITECTURES MATCHES i386)
+    elseif(host_arch MATCHES "i686|i386|X86")
         set(_ARCH x86)
-    elseif(CMAKE_SYSTEM_PROCESSOR MATCHES "AMD64|amd64|x86_64" OR CMAKE_OSX_ARCHITECTURES MATCHES x86_64)
+    elseif(host_arch MATCHES "AMD64|amd64|x86_64|x64")
         set(_ARCH x86_64)
     endif()
     message(STATUS "CMake-Conan: cmake_system_processor=${_ARCH}")
@@ -114,6 +125,7 @@ function(detect_cxx_standard CXX_STANDARD)
     endif()
 endfunction()
 
+
 macro(detect_gnu_libstdcxx)
     # _CONAN_IS_GNU_LIBSTDCXX true if GNU libstdc++
     check_cxx_source_compiles("
@@ -136,6 +148,7 @@ macro(detect_gnu_libstdcxx)
     unset (_CONAN_GNU_LIBSTDCXX_IS_CXX11_ABI)
 endmacro()
 
+
 macro(detect_libcxx)
     # _CONAN_IS_LIBCXX true if LLVM libc++
     check_cxx_source_compiles("
@@ -147,10 +160,10 @@ macro(detect_libcxx)
 endmacro()
 
 
-function(detect_lib_cxx OS LIB_CXX)
-    if(${OS} STREQUAL "Android")
-        message(STATUS "CMake-Conan: android_stl=${ANDROID_STL}")
-        set(${LIB_CXX} ${ANDROID_STL} PARENT_SCOPE)
+function(detect_lib_cxx LIB_CXX)
+    if(CMAKE_SYSTEM_NAME STREQUAL "Android")
+        message(STATUS "CMake-Conan: android_stl=${CMAKE_ANDROID_STL_TYPE}")
+        set(${LIB_CXX} ${CMAKE_ANDROID_STL_TYPE} PARENT_SCOPE)
         return()
     endif()
 
@@ -207,37 +220,42 @@ function(detect_compiler COMPILER COMPILER_VERSION COMPILER_RUNTIME COMPILER_RUN
         string(SUBSTRING ${MSVC_VERSION} 0 3 _COMPILER_VERSION)
         # Configure compiler.runtime and compiler.runtime_type settings for MSVC
         if(CMAKE_MSVC_RUNTIME_LIBRARY)
-            set(_KNOWN_MSVC_RUNTIME_VALUES "")
-            list(APPEND _KNOWN_MSVC_RUNTIME_VALUES MultiThreaded MultiThreadedDLL)
-            list(APPEND _KNOWN_MSVC_RUNTIME_VALUES MultiThreadedDebug MultiThreadedDebugDLL)
-            list(APPEND _KNOWN_MSVC_RUNTIME_VALUES MultiThreaded$<$:Debug> MultiThreaded$<$:Debug>DLL)
-
-            # only accept the 6 possible values, otherwise we don't don't know to map this
-            if(NOT CMAKE_MSVC_RUNTIME_LIBRARY IN_LIST _KNOWN_MSVC_RUNTIME_VALUES)
-                message(FATAL_ERROR "CMake-Conan: unable to map MSVC runtime: ${CMAKE_MSVC_RUNTIME_LIBRARY} to Conan settings")
-            endif()
-
-            # Runtime is "dynamic" in all cases if it ends in DLL
-            if(CMAKE_MSVC_RUNTIME_LIBRARY MATCHES ".*DLL$")
-                set(_COMPILER_RUNTIME "dynamic")
-            else()
-                set(_COMPILER_RUNTIME "static")
-            endif()
-
-            # Only define compiler.runtime_type when explicitly requested
-            # If a generator expression is used, let Conan handle it conditional on build_type
-            get_property(_IS_MULTI_CONFIG_GENERATOR GLOBAL PROPERTY GENERATOR_IS_MULTI_CONFIG)
-            if(NOT CMAKE_MSVC_RUNTIME_LIBRARY MATCHES ":Debug>")
-                if(CMAKE_MSVC_RUNTIME_LIBRARY MATCHES "Debug")
-                    set(_COMPILER_RUNTIME_TYPE "Debug")
-                else()
-                    set(_COMPILER_RUNTIME_TYPE "Release")
-                endif()
-            endif()
-
-            unset(_KNOWN_MSVC_RUNTIME_VALUES)
-            unset(_IS_MULTI_CONFIG_GENERATOR)
+            set(_msvc_runtime_library ${CMAKE_MSVC_RUNTIME_LIBRARY})
+        else()
+            set(_msvc_runtime_library MultiThreaded$<$:Debug>DLL) # default value documented by CMake
         endif()
+
+        set(_KNOWN_MSVC_RUNTIME_VALUES "")
+        list(APPEND _KNOWN_MSVC_RUNTIME_VALUES MultiThreaded MultiThreadedDLL)
+        list(APPEND _KNOWN_MSVC_RUNTIME_VALUES MultiThreadedDebug MultiThreadedDebugDLL)
+        list(APPEND _KNOWN_MSVC_RUNTIME_VALUES MultiThreaded$<$:Debug> MultiThreaded$<$:Debug>DLL)
+
+        # only accept the 6 possible values, otherwise we don't don't know to map this
+        if(NOT _msvc_runtime_library IN_LIST _KNOWN_MSVC_RUNTIME_VALUES)
+            message(FATAL_ERROR "CMake-Conan: unable to map MSVC runtime: ${_msvc_runtime_library} to Conan settings")
+        endif()
+
+        # Runtime is "dynamic" in all cases if it ends in DLL
+        if(_msvc_runtime_library MATCHES ".*DLL$")
+            set(_COMPILER_RUNTIME "dynamic")
+        else()
+            set(_COMPILER_RUNTIME "static")
+        endif()
+        message(STATUS "CMake-Conan: CMake compiler.runtime=${_COMPILER_RUNTIME}")
+
+        # Only define compiler.runtime_type when explicitly requested
+        # If a generator expression is used, let Conan handle it conditional on build_type
+        if(NOT _msvc_runtime_library MATCHES ":Debug>")
+            if(_msvc_runtime_library MATCHES "Debug")
+                set(_COMPILER_RUNTIME_TYPE "Debug")
+            else()
+                set(_COMPILER_RUNTIME_TYPE "Release")
+            endif()
+            message(STATUS "CMake-Conan: CMake compiler.runtime_type=${_COMPILER_RUNTIME_TYPE}")
+        endif()
+
+        unset(_KNOWN_MSVC_RUNTIME_VALUES)
+
     elseif(_COMPILER MATCHES AppleClang)
         set(_COMPILER "apple-clang")
         string(REPLACE "." ";" VERSION_LIST ${CMAKE_CXX_COMPILER_VERSION})
@@ -267,6 +285,7 @@ function(detect_compiler COMPILER COMPILER_VERSION COMPILER_RUNTIME COMPILER_RUN
     set(${COMPILER_RUNTIME_TYPE} ${_COMPILER_RUNTIME_TYPE} PARENT_SCOPE)
 endfunction()
 
+
 function(detect_build_type BUILD_TYPE)
     get_property(_MULTICONFIG_GENERATOR GLOBAL PROPERTY GENERATOR_IS_MULTI_CONFIG)
     if(NOT _MULTICONFIG_GENERATOR)
@@ -276,23 +295,43 @@ function(detect_build_type BUILD_TYPE)
     endif()
 endfunction()
 
+macro(set_conan_compiler_if_appleclang lang command output_variable)
+    if(CMAKE_${lang}_COMPILER_ID STREQUAL "AppleClang")
+        execute_process(COMMAND xcrun --find ${command}
+            OUTPUT_VARIABLE _xcrun_out OUTPUT_STRIP_TRAILING_WHITESPACE)
+        cmake_path(GET _xcrun_out PARENT_PATH _xcrun_toolchain_path)
+        cmake_path(GET CMAKE_${lang}_COMPILER PARENT_PATH _compiler_parent_path)
+        if ("${_xcrun_toolchain_path}" STREQUAL "${_compiler_parent_path}")
+            set(${output_variable} "")
+        endif()
+        unset(_xcrun_out)
+        unset(_xcrun_toolchain_path)
+        unset(_compiler_parent_path)
+    endif()
+endmacro()
+
+
 macro(append_compiler_executables_configuration)
     set(_conan_c_compiler "")
     set(_conan_cpp_compiler "")
     if(CMAKE_C_COMPILER)
         set(_conan_c_compiler "\"c\":\"${CMAKE_C_COMPILER}\",")
+        set_conan_compiler_if_appleclang(C cc _conan_c_compiler)
     else()
         message(WARNING "CMake-Conan: The C compiler is not defined. "
                         "Please define CMAKE_C_COMPILER or enable the C language.")
     endif()
     if(CMAKE_CXX_COMPILER)
         set(_conan_cpp_compiler "\"cpp\":\"${CMAKE_CXX_COMPILER}\"")
+        set_conan_compiler_if_appleclang(CXX c++ _conan_cpp_compiler)
     else()
         message(WARNING "CMake-Conan: The C++ compiler is not defined. "
                         "Please define CMAKE_CXX_COMPILER or enable the C++ language.")
     endif()
 
-    string(APPEND PROFILE "tools.build:compiler_executables={${_conan_c_compiler}${_conan_cpp_compiler}}\n")
+    if(NOT "x${_conan_c_compiler}${_conan_cpp_compiler}" STREQUAL "x")
+        string(APPEND PROFILE "tools.build:compiler_executables={${_conan_c_compiler}${_conan_cpp_compiler}}\n")
+    endif()
     unset(_conan_c_compiler)
     unset(_conan_cpp_compiler)
 endmacro()
@@ -303,7 +342,7 @@ function(detect_host_profile output_file)
     detect_arch(MYARCH)
     detect_compiler(MYCOMPILER MYCOMPILER_VERSION MYCOMPILER_RUNTIME MYCOMPILER_RUNTIME_TYPE)
     detect_cxx_standard(MYCXX_STANDARD)
-    detect_lib_cxx(MYOS MYLIB_CXX)
+    detect_lib_cxx(MYLIB_CXX)
     detect_build_type(MYBUILD_TYPE)
 
     set(PROFILE "")
@@ -360,7 +399,7 @@ function(detect_host_profile output_file)
     # propagate compilers via profile
     append_compiler_executables_configuration()
 
-    if(${MYOS} STREQUAL "Android")
+    if(MYOS STREQUAL "Android")
         string(APPEND PROFILE "tools.android:ndk_path=${CMAKE_ANDROID_NDK}\n")
     endif()
 
@@ -398,12 +437,26 @@ function(conan_install)
     # Invoke "conan install" with the provided arguments
     set(CONAN_ARGS ${CONAN_ARGS} -of=${CONAN_OUTPUT_FOLDER})
     message(STATUS "CMake-Conan: conan install ${CMAKE_SOURCE_DIR} ${CONAN_ARGS} ${ARGN}")
+
+
+    # In case there was not a valid cmake executable in the PATH, we inject the
+    # same we used to invoke the provider to the PATH
+    if(DEFINED PATH_TO_CMAKE_BIN)
+        set(_OLD_PATH $ENV{PATH})
+        set(ENV{PATH} "$ENV{PATH}:${PATH_TO_CMAKE_BIN}")
+    endif()
+
     execute_process(COMMAND ${CONAN_COMMAND} install ${CMAKE_SOURCE_DIR} ${CONAN_ARGS} ${ARGN} --format=json
                     RESULT_VARIABLE return_code
                     OUTPUT_VARIABLE conan_stdout
                     ERROR_VARIABLE conan_stderr
                     ECHO_ERROR_VARIABLE    # show the text output regardless
                     WORKING_DIRECTORY ${CMAKE_CURRENT_BINARY_DIR})
+
+    if(DEFINED PATH_TO_CMAKE_BIN)
+        set(ENV{PATH} "${_OLD_PATH}")
+    endif()
+
     if(NOT "${return_code}" STREQUAL "0")
         message(FATAL_ERROR "Conan install failed='${return_code}'")
     else()
@@ -411,6 +464,7 @@ function(conan_install)
         # one is specified, but we don't know a priori where this is.
         # TODO: this can be made more robust if Conan can provide this in the json output
         string(JSON CONAN_GENERATORS_FOLDER GET ${conan_stdout} graph nodes 0 generators_folder)
+        cmake_path(CONVERT ${CONAN_GENERATORS_FOLDER} TO_CMAKE_PATH_LIST CONAN_GENERATORS_FOLDER)
         # message("conan stdout: ${conan_stdout}")
         message(STATUS "CMake-Conan: CONAN_GENERATORS_FOLDER=${CONAN_GENERATORS_FOLDER}")
         set_property(GLOBAL PROPERTY CONAN_GENERATORS_FOLDER "${CONAN_GENERATORS_FOLDER}")
@@ -459,6 +513,7 @@ function(conan_version_check)
     endif()
 endfunction()
 
+
 macro(construct_profile_argument argument_variable profile_list)
     set(${argument_variable} "")
     if("${profile_list}" STREQUAL "CONAN_HOST_PROFILE")
@@ -479,8 +534,8 @@ endmacro()
 
 macro(conan_provide_dependency method package_name)
     set_property(GLOBAL PROPERTY CONAN_PROVIDE_DEPENDENCY_INVOKED TRUE)
-    get_property(CONAN_INSTALL_SUCCESS GLOBAL PROPERTY CONAN_INSTALL_SUCCESS)
-    if(NOT CONAN_INSTALL_SUCCESS)
+    get_property(_conan_install_success GLOBAL PROPERTY CONAN_INSTALL_SUCCESS)
+    if(NOT _conan_install_success)
         find_program(CONAN_COMMAND "conan" REQUIRED)
         conan_get_version(${CONAN_COMMAND} CONAN_CURRENT_VERSION)
         conan_version_check(MINIMUM ${CONAN_MINIMUM_VERSION} CURRENT ${CONAN_CURRENT_VERSION})
@@ -493,21 +548,39 @@ macro(conan_provide_dependency method package_name)
         endif()
         construct_profile_argument(_host_profile_flags CONAN_HOST_PROFILE)
         construct_profile_argument(_build_profile_flags CONAN_BUILD_PROFILE)
-        get_property(_MULTICONFIG_GENERATOR GLOBAL PROPERTY GENERATOR_IS_MULTI_CONFIG)
-        if(NOT _MULTICONFIG_GENERATOR)
+        if(EXISTS "${CMAKE_SOURCE_DIR}/conanfile.py")
+            file(READ "${CMAKE_SOURCE_DIR}/conanfile.py" outfile)
+            if(NOT "${outfile}" MATCHES ".*CMakeDeps.*")
+                message(WARNING "Cmake-conan: CMakeDeps generator was not defined in the conanfile")
+            endif()
+            set(generator "")
+        elseif (EXISTS "${CMAKE_SOURCE_DIR}/conanfile.txt")
+            file(READ "${CMAKE_SOURCE_DIR}/conanfile.txt" outfile)
+            if(NOT "${outfile}" MATCHES ".*CMakeDeps.*")
+                message(WARNING "Cmake-conan: CMakeDeps generator was not defined in the conanfile. "
+                        "Please define the generator as it will be mandatory in the future")
+            endif()
+            set(generator "-g;CMakeDeps")
+        endif()
+        get_property(_multiconfig_generator GLOBAL PROPERTY GENERATOR_IS_MULTI_CONFIG)
+        if(NOT _multiconfig_generator)
             message(STATUS "CMake-Conan: Installing single configuration ${CMAKE_BUILD_TYPE}")
-            conan_install(${_host_profile_flags} ${_build_profile_flags} --build=missing -g CMakeDeps)
+            conan_install(${_host_profile_flags} ${_build_profile_flags} ${CONAN_INSTALL_ARGS} ${generator})
         else()
             message(STATUS "CMake-Conan: Installing both Debug and Release")
-            conan_install(${_host_profile_flags} ${_build_profile_flags} -s build_type=Release --build=missing -g CMakeDeps)
-            conan_install(${_host_profile_flags} ${_build_profile_flags} -s build_type=Debug --build=missing -g CMakeDeps)
+            conan_install(${_host_profile_flags} ${_build_profile_flags} -s build_type=Release ${CONAN_INSTALL_ARGS} ${generator})
+            conan_install(${_host_profile_flags} ${_build_profile_flags} -s build_type=Debug ${CONAN_INSTALL_ARGS} ${generator})
         endif()
-        unset(_MULTICONFIG_GENERATOR)
+        unset(_host_profile_flags)
+        unset(_build_profile_flags)
+        unset(_multiconfig_generator)
+        unset(_conan_install_success)
     else()
         message(STATUS "CMake-Conan: find_package(${ARGV1}) found, 'conan install' already ran")
+        unset(_conan_install_success)
     endif()
 
-    get_property(CONAN_GENERATORS_FOLDER GLOBAL PROPERTY CONAN_GENERATORS_FOLDER)
+    get_property(_conan_generators_folder GLOBAL PROPERTY CONAN_GENERATORS_FOLDER)
 
     # Ensure that we consider Conan-provided packages ahead of any other,
     # irrespective of other settings that modify the search order or search paths
@@ -517,28 +590,66 @@ macro(conan_provide_dependency method package_name)
     #       find_package ()
 
     # Filter out `REQUIRED` from the argument list, as the first call may fail
-    set(_find_args "${ARGN}")
-    list(REMOVE_ITEM _find_args "REQUIRED")
-    if(NOT "MODULE" IN_LIST _find_args)
-        find_package(${package_name} ${_find_args} BYPASS_PROVIDER PATHS "${CONAN_GENERATORS_FOLDER}" NO_DEFAULT_PATH NO_CMAKE_FIND_ROOT_PATH)
+    set(_find_args_${package_name} "${ARGN}")
+    list(REMOVE_ITEM _find_args_${package_name} "REQUIRED")
+    if(NOT "MODULE" IN_LIST _find_args_${package_name})
+        find_package(${package_name} ${_find_args_${package_name}} BYPASS_PROVIDER PATHS "${_conan_generators_folder}" NO_DEFAULT_PATH NO_CMAKE_FIND_ROOT_PATH)
+        unset(_find_args_${package_name})
     endif()
 
     # Invoke find_package a second time - if the first call succeeded,
     # this will simply reuse the result. If not, fall back to CMake default search
     # behaviour, also allowing modules to be searched.
-    set(_cmake_module_path_orig "${CMAKE_MODULE_PATH}")
-    list(PREPEND CMAKE_MODULE_PATH "${CONAN_GENERATORS_FOLDER}")
     if(NOT ${package_name}_FOUND)
+        list(FIND CMAKE_MODULE_PATH "${_conan_generators_folder}" _index)
+        if(_index EQUAL -1)
+            list(PREPEND CMAKE_MODULE_PATH "${_conan_generators_folder}")
+        endif()
+        unset(_index)
         find_package(${package_name} ${ARGN} BYPASS_PROVIDER)
+        list(REMOVE_ITEM CMAKE_MODULE_PATH "${_conan_generators_folder}")
     endif()
-
-    set(CMAKE_MODULE_PATH "${_cmake_module_path_orig}")
-    unset(_find_args)
-    unset(_cmake_module_path_orig)
-    unset(_host_profile_flags)
-    unset(_build_profile_flags)
 endmacro()
 
+#[=[ not needed by Qt Creator, and if not commented it would break the auto-setup feature
+
+cmake_language(
+    SET_DEPENDENCY_PROVIDER conan_provide_dependency
+    SUPPORTED_METHODS FIND_PACKAGE
+)
+
+
+macro(conan_provide_dependency_check)
+    set(_CONAN_PROVIDE_DEPENDENCY_INVOKED FALSE)
+    get_property(_CONAN_PROVIDE_DEPENDENCY_INVOKED GLOBAL PROPERTY CONAN_PROVIDE_DEPENDENCY_INVOKED)
+    if(NOT _CONAN_PROVIDE_DEPENDENCY_INVOKED)
+        message(WARNING "Conan is correctly configured as dependency provider, "
+                        "but Conan has not been invoked. Please add at least one "
+                        "call to `find_package()`.")
+        if(DEFINED CONAN_COMMAND)
+            # supress warning in case `CONAN_COMMAND` was specified but unused.
+            set(_CONAN_COMMAND ${CONAN_COMMAND})
+            unset(_CONAN_COMMAND)
+        endif()
+    endif()
+    unset(_CONAN_PROVIDE_DEPENDENCY_INVOKED)
+endmacro()
+
+
+# Add a deferred call at the end of processing the top-level directory
+# to check if the dependency provider was invoked at all.
+cmake_language(DEFER DIRECTORY "${CMAKE_SOURCE_DIR}" CALL conan_provide_dependency_check)
+
+]=]
+
 # Configurable variables for Conan profiles
 set(CONAN_HOST_PROFILE "default;auto-cmake" CACHE STRING "Conan host profile")
 set(CONAN_BUILD_PROFILE "default" CACHE STRING "Conan build profile")
+set(CONAN_INSTALL_ARGS "--build=missing" CACHE STRING "Command line arguments for conan install")
+
+find_program(_cmake_program NAMES cmake NO_PACKAGE_ROOT_PATH NO_CMAKE_PATH NO_CMAKE_ENVIRONMENT_PATH NO_CMAKE_SYSTEM_PATH NO_CMAKE_FIND_ROOT_PATH)
+if(NOT _cmake_program)
+    get_filename_component(PATH_TO_CMAKE_BIN "${CMAKE_COMMAND}" DIRECTORY)
+    set(PATH_TO_CMAKE_BIN "${PATH_TO_CMAKE_BIN}" CACHE INTERNAL "Path where the CMake executable is")
+endif()
+
diff --git a/tests/manual/cmakeprojectmanager/conan/CMakeLists.txt b/tests/manual/cmakeprojectmanager/conan/CMakeLists.txt
index 0892c9be4d2..1179a388ab9 100644
--- a/tests/manual/cmakeprojectmanager/conan/CMakeLists.txt
+++ b/tests/manual/cmakeprojectmanager/conan/CMakeLists.txt
@@ -1,5 +1,6 @@
 cmake_minimum_required(VERSION 3.15)
 
+set(CMAKE_CXX_STANDARD 14)
 project(conan-libfmt)
 
 find_package(fmt REQUIRED)

From 0a2b6a910acd8d75bb14c1860c60c248aa5e073e Mon Sep 17 00:00:00 2001
From: David Schulz 
Date: Fri, 16 Feb 2024 08:40:37 +0100
Subject: [PATCH 055/243] Debugger: make last locals command debuggable in the
 cdbengine

Change-Id: I4d06cecbd23bdb2f16697b3713be5bca0a695fdb
Reviewed-by: Christian Stenger 
---
 src/plugins/debugger/cdb/cdbengine.cpp | 7 +++++++
 src/plugins/debugger/cdb/cdbengine.h   | 3 +++
 2 files changed, 10 insertions(+)

diff --git a/src/plugins/debugger/cdb/cdbengine.cpp b/src/plugins/debugger/cdb/cdbengine.cpp
index 31c57af0c1c..d292028050a 100644
--- a/src/plugins/debugger/cdb/cdbengine.cpp
+++ b/src/plugins/debugger/cdb/cdbengine.cpp
@@ -1078,6 +1078,8 @@ void CdbEngine::doUpdateLocals(const UpdateParameters &updateParameters)
         };
 
         runCommand(cmd);
+        cmd.arg("passexceptions", true);
+        m_lastDebuggableCommand = cmd;
     } else {
 
         const bool partialUpdate = !updateParameters.partialVariable.isEmpty();
@@ -2968,6 +2970,11 @@ BreakpointParameters CdbEngine::parseBreakPoint(const GdbMi &gdbmi)
     return result;
 }
 
+void CdbEngine::debugLastCommand()
+{
+    runCommand(m_lastDebuggableCommand);
+}
+
 void CdbEngine::handleBreakPoints(const DebuggerResponse &response)
 {
     if (debugBreakpoints) {
diff --git a/src/plugins/debugger/cdb/cdbengine.h b/src/plugins/debugger/cdb/cdbengine.h
index 2721429a308..b8afe1e2d91 100644
--- a/src/plugins/debugger/cdb/cdbengine.h
+++ b/src/plugins/debugger/cdb/cdbengine.h
@@ -171,6 +171,9 @@ private:
     void checkQtSdkPdbFiles(const QString &module);
     BreakpointParameters parseBreakPoint(const GdbMi &gdbmi);
 
+    void debugLastCommand() final;
+    DebuggerCommand m_lastDebuggableCommand;
+
     const QString m_tokenPrefix;
     void handleSetupFailure(const QString &errorMessage);
 

From 95bad0c91d22b6c1ded3c957f94b02be549ae5ed Mon Sep 17 00:00:00 2001
From: David Schulz 
Date: Fri, 16 Feb 2024 08:41:47 +0100
Subject: [PATCH 056/243] Debugger: add more debug output to the python cdbext
 module

Change-Id: I48b4fb6a65eb486b190238ff161ea358bf4d3bf5
Reviewed-by: 
Reviewed-by: Christian Stenger 
---
 src/libs/qtcreatorcdbext/pycdbextmodule.cpp | 17 +++++++++++++++++
 1 file changed, 17 insertions(+)

diff --git a/src/libs/qtcreatorcdbext/pycdbextmodule.cpp b/src/libs/qtcreatorcdbext/pycdbextmodule.cpp
index bf3c379272d..68b9eb334c9 100644
--- a/src/libs/qtcreatorcdbext/pycdbextmodule.cpp
+++ b/src/libs/qtcreatorcdbext/pycdbextmodule.cpp
@@ -101,6 +101,9 @@ static PyObject *cdbext_resolveSymbol(PyObject *, PyObject *args) // -> Value
     if (!PyArg_ParseTuple(args, "s", &pattern))
         Py_RETURN_NONE;
 
+    if (debugPyCdbextModule)
+        DebugPrint() << "resolve symbol: " << pattern;
+
     CIDebugSymbols *symbols = ExtensionCommandContext::instance()->symbols();
     auto rc = PyList_New(0);
 
@@ -132,6 +135,9 @@ static PyObject *cdbext_getNameByAddress(PyObject *, PyObject *args)
     if (!PyArg_ParseTuple(args, "K", &address))
         Py_RETURN_NONE;
 
+    if (debugPyCdbextModule)
+        DebugPrint() << "name by address: " << address;
+
     CIDebugSymbols *symbols = ExtensionCommandContext::instance()->symbols();
 
     PyObject* ret = NULL;
@@ -153,6 +159,9 @@ static PyObject *cdbext_getAddressByName(PyObject *, PyObject *args)
     if (!PyArg_ParseTuple(args, "s", &name))
         Py_RETURN_NONE;
 
+    if (debugPyCdbextModule)
+        DebugPrint() << "address by name: " << name;
+
     CIDebugSymbols *symbols = ExtensionCommandContext::instance()->symbols();
 
     ULONG64 address = 0;
@@ -177,6 +186,14 @@ static PyObject *cdbext_listOfLocals(PyObject *, PyObject *args) // -> [ Value ]
         Py_RETURN_NONE;
 
     const std::string partialVariable(partialVariablesC);
+
+    if (debugPyCdbextModule) {
+        if (partialVariable.empty())
+            DebugPrint() << "list of locals";
+        else
+            DebugPrint() << "list of locals with partial variable: " << partialVariable;
+    }
+
     IDebugSymbolGroup2 *symbolGroup = nullptr;
     auto locals = PyList_New(0);
     if (partialVariable.empty()) {

From c4abbef0a8de2346e08bad9c5f46db7c44f24efc Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?Robert=20L=C3=B6hning?= 
Date: Fri, 16 Feb 2024 22:16:19 +0100
Subject: [PATCH 057/243] SquishTests: Stabilize adding documentation

I noticed that Creator built on Qt 6.6.0 never needed longer than
two seconds to update the documentation after adding qtcreator.qch.
The same sources of Creator built on Qt 6.6.2 needed up to four
seconds. This subtle difference can lead to the situation that the
documentation was not yet updated when clicking "Getting Started"
in tst_WELP01, which then just displays an empty page.

Change-Id: I11ab2a902825190ed8ae27dad55a847f01ba44dc
Reviewed-by: Christian Stenger 
---
 tests/system/shared/utils.py | 4 ++++
 1 file changed, 4 insertions(+)

diff --git a/tests/system/shared/utils.py b/tests/system/shared/utils.py
index d424bd72021..853c5f6fde0 100644
--- a/tests/system/shared/utils.py
+++ b/tests/system/shared/utils.py
@@ -269,6 +269,8 @@ def addHelpDocumentation(which):
         clickButton(waitForObject("{type='QPushButton' name='addButton' visible='1' text='Add...'}"))
         selectFromFileDialog(qch)
     clickButton(waitForObject(":Options.OK_QPushButton"))
+    progressBarWait(10000)  # Wait for "Update Documentation"
+
 
 def addCurrentCreatorDocumentation():
     currentCreatorPath = currentApplicationContext().cwd
@@ -297,6 +299,8 @@ def addCurrentCreatorDocumentation():
     except:
         test.fail("Added Qt Creator's documentation explicitly.")
     clickButton(waitForObject(":Options.OK_QPushButton"))
+    progressBarWait(10000)  # Wait for "Update Documentation"
+
 
 def verifyOutput(string, substring, outputFrom, outputIn):
     index = string.find(substring)

From cfb26a06a7fc63363ffc61e4f3e12c0efd440b48 Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?Robert=20L=C3=B6hning?= 
Date: Thu, 15 Feb 2024 17:16:32 +0100
Subject: [PATCH 058/243] SquishTests: Improve toggling filter names in
 "Issues" view

- Explicitly set a shorter timeout. After the menu appears, it
  should not take that long until the item is there, too.

- Warn when an item can't be found. This should not go unnoticed,
  because it either means that the GUI changed or that there's a
  bug in the test. Both require a fix.

Change-Id: Id7faa2b91926c392bd0d894214f498d8ba8edaa1
Reviewed-by: Jukka Nokso 
Reviewed-by: 
Reviewed-by: Christian Stenger 
---
 tests/system/shared/build_utils.py | 6 +++---
 1 file changed, 3 insertions(+), 3 deletions(-)

diff --git a/tests/system/shared/build_utils.py b/tests/system/shared/build_utils.py
index c26634f61db..fbc89c5920f 100644
--- a/tests/system/shared/build_utils.py
+++ b/tests/system/shared/build_utils.py
@@ -9,7 +9,7 @@ def toggleIssuesFilter(filterName, checked):
         filterMenu = waitForObject("{type='QMenu' unnamed='1' visible='1'}")
         waitFor("filterMenu.visible", 1000)
 
-        filterCategory = waitForObjectItem(filterMenu, filterName)
+        filterCategory = waitForObjectItem(filterMenu, filterName, 1000)
         waitFor("filterCategory.visible", 2000)
         if filterCategory.checked == checked:
             test.log("Filter '%s' has already check state %s - not toggling."
@@ -20,8 +20,8 @@ def toggleIssuesFilter(filterName, checked):
             test.log("Filter '%s' check state changed to %s." % (filterName, checked))
     except:
         t,v = sys.exc_info()[:2]
-        test.log("Exception while toggling filter '%s'" % filterName,
-                 "%s: %s" % (t.__name__, str(v)))
+        test.warning("Exception while toggling filter '%s'" % filterName,
+                     "%s: %s" % (t.__name__, str(v)))
 
 
 def getBuildIssues(ignoreCodeModel=True):

From 8a532af3af4a000d0044a69f232c748ad6c1a1ea Mon Sep 17 00:00:00 2001
From: Eike Ziller 
Date: Mon, 19 Feb 2024 12:05:17 +0100
Subject: [PATCH 059/243] Markdown: Fix the Show Editor/Preview buttons

Calling QToolButton::setCheckable on a button with a defaultAction
doesn't work as expected. It needs to be called on the action itself.

Amends acedf93ba32467a9848cebe25da35c096a5993ae

Fixes: QTCREATORBUG-30382
Change-Id: Icbddb1d331fe6547622bf0428d890012fef0d9c5
Reviewed-by: David Schulz 
---
 src/plugins/texteditor/markdowneditor.cpp | 4 ++--
 1 file changed, 2 insertions(+), 2 deletions(-)

diff --git a/src/plugins/texteditor/markdowneditor.cpp b/src/plugins/texteditor/markdowneditor.cpp
index 6d91225dbcd..dbfdcda2b42 100644
--- a/src/plugins/texteditor/markdowneditor.cpp
+++ b/src/plugins/texteditor/markdowneditor.cpp
@@ -138,12 +138,12 @@ public:
         agg->add(m_widget.get());
 
         m_togglePreviewVisible = Command::createToolButtonWithShortcutToolTip(TOGGLEPREVIEW_ACTION);
-        m_togglePreviewVisible->setCheckable(true);
+        m_togglePreviewVisible->defaultAction()->setCheckable(true);
         m_togglePreviewVisible->setChecked(showPreview);
         m_previewWidget->setVisible(showPreview);
 
         m_toggleEditorVisible = Command::createToolButtonWithShortcutToolTip(TOGGLEEDITOR_ACTION);
-        m_toggleEditorVisible->setCheckable(true);
+        m_toggleEditorVisible->defaultAction()->setCheckable(true);
         m_toggleEditorVisible->setChecked(showEditor);
         m_textEditorWidget->setVisible(showEditor);
 

From 4b042f1aeb7e18ba2af30acea2e1caec73b3ace8 Mon Sep 17 00:00:00 2001
From: Christian Kandeler 
Date: Fri, 16 Feb 2024 14:07:40 +0100
Subject: [PATCH 060/243] Update qbs submodule to HEAD of 2.3 branch

Change-Id: Id0bdf4a85008f11de34953832cd02d2e0b46b3bd
Reviewed-by: 
Reviewed-by: Christian Stenger 
---
 src/shared/qbs | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/src/shared/qbs b/src/shared/qbs
index a30e54c2e7f..bd0c59e572f 160000
--- a/src/shared/qbs
+++ b/src/shared/qbs
@@ -1 +1 @@
-Subproject commit a30e54c2e7fb7d9735a364497914a5df452dd1ad
+Subproject commit bd0c59e572f95953337177e68fa32cb0c4aa1e29

From eea7fae890e6e1fb0219faa5f2b3f132fc1ce944 Mon Sep 17 00:00:00 2001
From: Christian Kandeler 
Date: Tue, 13 Feb 2024 15:09:08 +0100
Subject: [PATCH 061/243] RemoteLinux: Announce initial connection attempt

So if the device turns out to be unresponsive, users will not be
confused about the temporary freeze.

Task-number: QTCREATORBUG-30319
Change-Id: If65d6ea2777232239c8fb324b06352d92ad451c6
Reviewed-by: 
Reviewed-by: Marcus Tillmanns 
---
 src/plugins/remotelinux/linuxdevice.cpp | 46 +++++++++++++++++++++----
 1 file changed, 40 insertions(+), 6 deletions(-)

diff --git a/src/plugins/remotelinux/linuxdevice.cpp b/src/plugins/remotelinux/linuxdevice.cpp
index b166b702d34..0872ff54d3d 100644
--- a/src/plugins/remotelinux/linuxdevice.cpp
+++ b/src/plugins/remotelinux/linuxdevice.cpp
@@ -38,6 +38,7 @@
 #include 
 #include 
 
+#include 
 #include 
 #include 
 #include 
@@ -312,8 +313,11 @@ public:
     explicit LinuxDevicePrivate(LinuxDevice *parent);
     ~LinuxDevicePrivate();
 
-    bool setupShell(const SshParameters &sshParameters);
+    bool 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_"); }
 
     void attachToSharedConnection(SshConnectionHandle *connectionHandle,
                                   const SshParameters &sshParameters);
@@ -1166,18 +1170,24 @@ void LinuxDevicePrivate::checkOsType()
 }
 
 // Call me with shell mutex locked
-bool LinuxDevicePrivate::setupShell(const SshParameters &sshParameters)
+bool LinuxDevicePrivate::setupShell(const SshParameters &sshParameters, bool announce)
 {
     if (m_handler->isRunning(sshParameters))
         return true;
 
     invalidateEnvironmentCache();
 
+    if (announce)
+        announceConnectionAttempt();
+
     bool ok = false;
     QMetaObject::invokeMethod(m_handler, [this, sshParameters] {
         return m_handler->start(sshParameters);
     }, Qt::BlockingQueuedConnection, &ok);
 
+    if (announce)
+        unannounceConnectionAttempt();
+
     if (ok) {
         setDisconnected(false);
         queryOsType([this](const CommandLine &cmd) { return m_handler->runInShell(cmd); });
@@ -1194,24 +1204,48 @@ RunResult LinuxDevicePrivate::runInShell(const CommandLine &cmd, const QByteArra
     DEBUG(cmd.toUserOutput());
     if (checkDisconnectedWithWarning())
         return {};
-    const bool isSetup = setupShell(q->sshParameters());
+    const bool isSetup = setupShell(q->sshParameters(), true);
     if (checkDisconnectedWithWarning())
         return {};
     QTC_ASSERT(isSetup, return {});
     return m_handler->runInShell(cmd, data);
 }
 
+void LinuxDevicePrivate::announceConnectionAttempt()
+{
+    const auto announce = [id = announceId(), name = q->displayName()] {
+        Core::ICore::infoBar()->addInfo(
+            InfoBarEntry(id,
+                         Tr::tr("Establishing initial connection to device \"%1\". "
+                                "This might take a moment.")
+                             .arg(name)));
+        QCoreApplication::processEvents(QEventLoop::ExcludeUserInputEvents);
+        QCoreApplication::processEvents(QEventLoop::ExcludeUserInputEvents); // Yes, twice.
+    };
+    if (QThread::currentThread() == qApp->thread())
+        announce();
+    else
+        QMetaObject::invokeMethod(Core::ICore::infoBar(), announce, Qt::BlockingQueuedConnection);
+}
+
+void LinuxDevicePrivate::unannounceConnectionAttempt()
+{
+    QMetaObject::invokeMethod(Core::ICore::infoBar(),
+                              [id = announceId()] { Core::ICore::infoBar()->removeInfo(id); });
+}
+
 bool LinuxDevicePrivate::checkDisconnectedWithWarning()
 {
     if (!disconnected())
         return false;
 
     QMetaObject::invokeMethod(Core::ICore::infoBar(), [id = q->id(), name = q->displayName()] {
-        if (!Core::ICore::infoBar()->canInfoBeAdded(id))
+        const Id errorId = id.withPrefix("error_");
+        if (!Core::ICore::infoBar()->canInfoBeAdded(errorId))
             return;
         const QString warnStr
             = Tr::tr("Device \"%1\" is currently marked as disconnected.").arg(name);
-        InfoBarEntry info(id, warnStr, InfoBarEntry::GlobalSuppression::Enabled);
+        InfoBarEntry info(errorId, warnStr, InfoBarEntry::GlobalSuppression::Enabled);
         info.setDetailsWidgetCreator([] {
             const auto label = new QLabel(Tr::tr(
                 "The device was not available when trying to connect previously.
" @@ -1638,7 +1672,7 @@ QFuture LinuxDevice::tryToConnect() { return Utils::asyncRun([this] { QMutexLocker locker(&d->m_shellMutex); - return d->setupShell(sshParameters()); + return d->setupShell(sshParameters(), false); }); } From c28a388b1f6259686c625cd285588c7ecad9e5af Mon Sep 17 00:00:00 2001 From: Leena Miettinen Date: Tue, 13 Feb 2024 11:14:41 +0100 Subject: [PATCH 062/243] Doc: Turn "Running on Multiple Platforms" into how-to topics - Update screenshots of kit selector and Devices preferences, which now show the device status - Turn running on QML and Linux into their own topics - Remove conditions because the projects folder is excluded from QDS Manual Task-number: QTCREATORBUG-30209 Task-number: QTCREATORBUG-29361 Change-Id: I869f6b577016c6712c6b37170dbee2249ded1f8e Reviewed-by: Christian Kandeler --- doc/qtcreator/images/icons/build.png | Bin 0 -> 159 bytes doc/qtcreator/images/icons/cancel-build.png | Bin 0 -> 167 bytes .../images/qtcreator-android-avd-manager.png | Bin 14237 -> 0 bytes .../images/qtcreator-android-avd-manager.webp | Bin 0 -> 9784 bytes .../images/qtcreator-kit-selector.png | Bin 10480 -> 0 bytes .../images/qtcreator-kit-selector.webp | Bin 0 -> 6202 bytes doc/qtcreator/src/android/androiddev.qdoc | 2 +- .../src/baremetal/creator-baremetal-dev.qdoc | 2 +- .../creator-only/creator-debugger.qdoc | 2 +- .../src/debugger/qtquick-debugging.qdoc | 2 +- .../creator-embedded-platforms.qdoc | 4 +- ...or-projects-how-to-run-generic-linux.qdoc} | 22 +++-- .../creator-mobile-platforms.qdoc | 4 +- .../creator-only/creator-reference.qdoc | 19 +++- .../creator-projects-building-running.qdoc | 2 +- .../creator-projects-building.qdoc | 19 ++-- .../projects/creator-projects-running.qdoc | 86 ++++++++++-------- ...c => creator-projects-how-to-run-qnx.qdoc} | 34 +++---- doc/qtcreator/src/qtcreator-toc.qdoc | 1 - doc/qtcreator/src/qtcreator.qdoc | 1 - .../creator-only/qtquick-states-scxml.qdocinc | 2 +- .../src/user-interface/creator-ui.qdoc | 2 +- .../src/webassembly/creator-webassembly.qdoc | 2 +- 23 files changed, 114 insertions(+), 92 deletions(-) create mode 100644 doc/qtcreator/images/icons/build.png create mode 100644 doc/qtcreator/images/icons/cancel-build.png delete mode 100644 doc/qtcreator/images/qtcreator-android-avd-manager.png create mode 100644 doc/qtcreator/images/qtcreator-android-avd-manager.webp delete mode 100644 doc/qtcreator/images/qtcreator-kit-selector.png create mode 100644 doc/qtcreator/images/qtcreator-kit-selector.webp rename doc/qtcreator/src/linux-mobile/{creator-projects-running-generic-linux.qdocinc => creator-projects-how-to-run-generic-linux.qdoc} (55%) rename doc/qtcreator/src/qnx/{creator-projects-running-qnx.qdocinc => creator-projects-how-to-run-qnx.qdoc} (65%) diff --git a/doc/qtcreator/images/icons/build.png b/doc/qtcreator/images/icons/build.png new file mode 100644 index 0000000000000000000000000000000000000000..590e9b052c39cba751609d910be46bff914291c0 GIT binary patch literal 159 zcmeAS@N?(olHy`uVBq!ia0y~yU=RRd4i*LmhONKMUokK+q?O;E$xAgpvpMk8 zJY|!7v_jkPt%CC#N89RB*WTUkkv{};c=GxjP0kc#8WikPxbcQ9JV$rQC9Rcz85kHC NJYD@<);T3K0RZbkIwk-B literal 0 HcmV?d00001 diff --git a/doc/qtcreator/images/icons/cancel-build.png b/doc/qtcreator/images/icons/cancel-build.png new file mode 100644 index 0000000000000000000000000000000000000000..a3773413a88d810aeccdb46258fad914a6ebeecc GIT binary patch literal 167 zcmeAS@N?(olHy`uVBq!ia0y~yU=RRd4i*LmhONKMUokK+rr;B4q#jUql&h9<^qU84ad>wn z?o8Gbjjdh%3E8O|j@`TQK0v#D?-%DA_4m%(8n528>eHv%K*zMyXO@+p)}PY%pX>AF z|K!`-^X;p?ytuhJz5T9Zly>g4Y4>-PzUE_axc{?LBi}^o?pvu#X_-IW}`fY+bI#yonRenMGZyINY;#RqvMDb8=(zU5}bw z?Vfsfj_OK@pU?J3nc6ia^>1#QRs5zmEQ@W~yG1J}=M`y(#Gb!W6tegK$K&6(_N_j( z?B0co5}`l-?XBG)>gD$&P~+*%@AvoLYgyTQR!jZplC!IxcC9@fVrBoUM9Xzo*qSLb z*1UMdHF5p-m*#&3SNxt)^WvL~kF8Gd>Q#Me!YOU*K5Ur~6&8Kl^l;Qd%V2e_6*?{7 zX5F&6?XvB+;q3|MJ+sZWCU34>@;G;I*yDB9Ca>edLtYv!i~Cx|K*u48J<~ zu03Nve`(Y?k=ee_Uf)o@w(ybf_m#$~Hk+q>{M&!aqVbclU0m1;H@+)d7O(hoF1#*1 zYj4!vip}2ww@!QGzpXU?dEwb*Wu4a~9tW7M%(cDM_}z5Zp3^g;GUu5(J@}o{%Qn^Z zp3dr?y?=h(+J5(#`>`)lbBhhWZt#)auUmDX(%hmvcTwEZHMVI<;{DG<_Wz4Ge5G|k zXsC8`|Izbble{EbL-v0;rT;sr;@8$kCA%vQf7{5$D-yihd`DccwZDK@`AxoyM!k`V zb8gx3XUw1eSme_$_vMfGOe~*L`fj>DM{kUl$9d6H_oRxqY^;79#J23+dyB2v2dp+$ zJo^+BY`yD3=YiR>e*<`zWgPv={B!2#@?GT@jIB!!AD#V9eO5DD?wjD~W#_^#Z;LZ( zxp2c`Yt_6^-luOwZda`rs$9IL^x&24chlbgHCQK+QT!s9|II!A)Rx1qnA|7LJNs;B z=HbQi@8q^9{c`ikEmwWx{cx^P>86=UAHJ8~wAgy@=DM2JwHphw-s)uXw_MrrWcwA1 z(y;oCvf-bd)@pR`S-fU*T6%=kKJW8+-e&B<{4eUVVi&&RXseofVb_L?E6K5eJ?W9B zXB%$)nR{mc$#dO)`!4e5o^g@Ei32S)&7b! zpExbtaO>aHl2XGn&KLJB%6RD}`S1+3x*EEjN8JQd@TH%38zH-!C8D z*T|}U?s#O?aY&Xe_4l>i6Oov8;L40yZHZanT>S0el^Syc(`9kS16SF)6!cCB(m3a@ z?CJI7rAk=&|<*ipX-MZB$ zd8~{{epUPx@t+>PyY_JG-KVi?QG~(&=k;OPCieP&ANO?~dn}NDPvmu~@#9WaGMf3TvHGi+@H1e!Q8p&p>&yY25A3is<~bsJZWAFR%WZbDg6}a^~BbpNWe% zm1R{`FDt8i>&+LJo7V5M_Kf}PrBUZX=0Xa`b&u+T?W@1N`8=mk|6f;sD`_-$U#EF)?$a7E|C_hJZapVVR^Y0VDS7pbsEpj- z3(r~H?R(sg*%oDM_pNOe_vAe_!S`0hZoyM4-8&ubwC!1S;YQ!q%%>)yB4@7`vmN@Z zDPp?QYv$(|O;Z={;+Q|t77X<3jVsan?LUVb-S97b+%sK_x;yy z50yO_uwE!iT&%ZhjdoY}m6=n0bGLYJboyi`zHXUk>cl)>*H!2G_NC3v+5LI->X}

uXjZ)u-o0~ViUvv4&x!Bd4W7AWn1S=-I;+=8p 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 S_!a{L1B0ilpUXO@geCxPMKMAE diff --git a/doc/qtcreator/images/qtcreator-android-avd-manager.webp b/doc/qtcreator/images/qtcreator-android-avd-manager.webp new file mode 100644 index 0000000000000000000000000000000000000000..88c4f1bd0b36d8139d7f03c4b19bf8f2a7f3512a GIT binary patch literal 9784 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 literal 0 HcmV?d00001 diff --git a/doc/qtcreator/images/qtcreator-kit-selector.png b/doc/qtcreator/images/qtcreator-kit-selector.png deleted file mode 100644 index e2635364c1c258135538d85b389f73dc8a0d48df..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 10480 zcmeAS@N?(olHy`uVBq!ia0y~yVDx2RVC3LnV_;yoow`h#fq{Xuz$3DlfkCz%gcUV!rPE{_*>n0`H_;JvUuH z0pr{aomb_y?(E6DuwZM6xns5*3rSri@ctFWl(=uDmS(#Lmy*2p)x7auF}bz!FpYipX$lc|?)WVN(^^f$d` zbc93x^uf>w-|S?|$DP)KlG3edXDU{lJg;tVKVPbUHkbF(>C<;js_}ZY$5481M~{Eh zB6b7OEn6yAM9lV%i?iH*?fHe5g^$asSDakGWa)-k*SO3X_AN8=dbLL+Yte?s^@kJ^owEAC$IIsTUI&Xw(A((mtXopkKi(>HqBi97!ER@8s^5$%5S zSny>3)YBgC|10i3d|yUt`^QMmx^*8OzZ7p?BGsBEBeJf*IbAxgh|zq@)5-Cjg;Mbo zor5FoO7A(XihjNF-HGL!Huc;&Ry9rf{jyz5S)V>H%;*5)*I&s62UlRSF@3Z704wypSl=+%bY1$#Emd(`E2ihtUM?57&<&+9JVSfOAL z&9yqSR9i#!>&q`TX?H?c)@O!2F$qkYmR^xzynoL8=F8h>$Hp~?-Ljc5+4@CS%0sR@ z3u~_izcJZ%GJ2=X^7PjmL{mDp_f7iqaMc-`FuignyR!G6+P1Bg*^>B>Yq8FoHy@bd z%HDos^qaPRPesf3a^9L>kCNv6$k1B7L^WsrxktY^eM~x4<~bRsv8~H|Hhb#*il4JI zjK5EvFLm9j)=oL0+q?OCQMA^{^&eaIz1LZ{JT&;tq$ZJBoh2KD=NDUQe`er{d}y|M z*TLH&$!YwRPp61CZC@;WC)+ab;IweRBS1i56@o&Qi5l_=y%Vv7qv+~L+%2=DfbjE|P`=$wQTbZ$R z>!FI1!NKghQ>Q#N3zDzVpC|Q6`}T*BkQQGS+4mPzr(E=?Ewo*G^jP-3Wsdm<{es(i zm#bCmdN2F#uljm>d$XJL#lSdgF>zUQ*I!sdF9dcTA_O}{)zVR{ zRrENf@6|-DO@~BxFvefbU3ejL<(h-c7Tw-I-F~i>INLTyMM-2?r3AHy1- z>6`f9e)0cdTgiq=Qt;vI(3Ta(}*{>?5;R2ULx~ldY+x7+b)+mxB6Odb{w{x zcuAeBQMk1E*p(p558X+J<}O>5;9)H0>B)6g;`6ns0nSGye!2J6_+F0QZd&p8)3pnx zrk{V^o1wL7Pm$E&GMPZx)_LhBRYxNtWXpW@^HonDcC!9sCi8yX-5(6kKTUnYdwsX@ zmxER>RE+lY2H)Js{_Ep0lU0e^w}10a_z|Dc%r|*9^N$xc7T^AQeG1Ar=IEWuJNM{U zlWFs9J}fF1-(8zL_d>=(qy0T<_Yat!B%n}i+cP;@pOzl4hN*#{l;_z#j zA^gJaa)NQd;dPzY#2+7VK3gCWRBWt+tHWfWcy%8aq&=rb=; z+TY5y_;J9d&)*h5NLG1Na%ILz?d2QyNj&G+&cj<77t|&BDMHY*a+OK2ANN!@O|cr5V;<&P zmUHCGZa4kebE;@lX%W9&GH1N-c1;6y-q2aXOZ428g1fbl>bS{q5tI9ul>d3!=Bd2r z`vRX9=Iq za}48US*9LkzxzQ|dCgpj@3Y*?47_-fXTF{>JJi!j)8z5N8lLyJiatfX`q1`nYfGcn zmI<$}ZGFJF{q{+Zt06BAX3ua;+Oytx(d0=VpT}xTuZ-Vk9dWkD>_`H)@%N}xpQG4r zoo@|Y%zWJVc%IZsC#e`!srfG-ET|TD-!pyVhAS28m#6(WAQN+O_V+5j>-Wy(1ea$Q zRHqw$U3;`5D{Fz$p11c3=AU==tz+K#@T$VYt4SOF&K0(iU*RwA}Jhuxo3Lw+#ho+&m50n^6cHHwrdS% zm-pG%S$;)U`P^n#3pSU1Xgzo+>s7aPFQ0v??~@Rdpn2DwoQ0WluXBYz_?9DkT=Sj- z_x3qI-7IFW?mP3&cH&vfCfTW3P1+OlWOs3`+;EFWa`Vi#*;ZH#i>; z2)Zu1vH!&UT3)$1BG=vZihEyN+7dSR;bYH*lI3pvo}1?<*KQOpDr)|JnSafByBja1 zH~q8HH)prWb^H4A?$NyYf(7?tcQ4#=<;9!Lhh(`V^J7n1NQcgFOzXS6Ca*1W`rS)u zTe7+TIZ6DnTsWCepZToGoYRq>vd31Pf4WA8XWf4@`|A;`)jgMPHg5d=K|xNx_>A1K z3tKWG<~`6qd`e77ZO*YBTEd5}y^_wp+U)IHxY?;V%+qoC^N&XM?CBq@ZgnO4r>lQ3 zKNNjD%wJoZi~Hc)g=>p!tR??U7j3hDtGA@;k1}s&=I4NiWt(f(UgXN#k@YEIIsYBM zJK9|AR`-^3eHL;o*p&XyKsbNWtdPuO&L2MV&s$qsVd=5_ykwczJon0<4-S|xoiSgb z+Xt%QwRo1mdb+gkO`Ns2&}sC>6G;GJ2@8T-~4-b(`#<|gOJ*UIm!mw z`xK`xid1A>efgklYm?}z%b9a#@rU1>d3UaoR8>ov{F;L1&|OdM<{XyFcwCoYu4Tp=d+p-}5VO?71@a%7n{Nj@hd}#@d)3oEg0Mu%DrX zsMlQaL;h9KTAHVGm)Pxy_xJthAbR6c+j6CLzwWgqcSP6DILtA>}@-{2=Up zobT(dZ5DU*Oui`QKc39=U2WF#8-}$RvzJJP&YJ8b_cZ%%#kRiJNoh$Dxe_w^&H3S6 zp%<0d;Ki6)lMASU-qjJY;KH099UGn8h-bbxg)7Z=olsfYxgbK~($kDdHs{@4LNbr_ z9gk3!i*dKRm_EPTqbOjhB)e{|oYpld?eIOVSGTNt%Tp%DwcC7hk<{zr7hiT1?&j3p z|5@lw#bJ-{Tzv0NJzltM&F3GtTi#ZCgucmMl#~6Vn%(O4k6EWQZf*?<-QttE%H;8a zg4XJu)4%Ur5POsJSSM|ZXwSs{&$2I;32XL$I<_JA%=3xi;%;V#&+?ZUOHJ9Xz4|bd z@s(>i4=R3g`OHibnPr%4m$ZHA*15@VJMz})n_YL1j?((vzTT)k^84K&ON}E=<`dax zznhi4?XLEZV-vpKihHGXc$bo8x2D;zCA?Dmf8IQ1c~NE3A(2^z#sN2d*ThCL{j71j ze>~tYkAA7DTfT4e?5>o0xd|RqG)UMb8Rpx0GmUc0uJiKyPh9CN>{$3)HIc|^SXUxAFnd8|M%l@M!)h>OPM|w zen*!_F2at8-W)iwh#=avE=QVFc+ZCB+}hk38g_4ECjaa;dlZj8nQAW8e^qwb`n1HY z7Zvvf-feJA^80I&oO|MN4P%YT)ZT0DmueQw-1v6g<6JGJ!pTdfK2u4t+jHhki`}c> z%V+prW_{A0)2=uiY~1{7q0rzjf-hV@02w?q{d&P>*f#yB;0AQsT6+v5Sh< zq(@(Bt}g3+Vp2C*)&6GwzC+7;8Mt>o+$OrEwwTlYW`4_q^=4}q?R_jgr6g?QlP=lB z-yHk$&%4^}OX0MRIJ(SsZiw#ACRt~G$@+5}+`S$of7jFR`Cgb^`SebfP5AUpldPVF zYg@QJQsvY-+d60BW!KxuzuSM#>%LPtcaPYgYyXbldU48Sy|jg2X|cwyxy_0`h?jvfnec=!LLs7~aj7FF+6FLZwPExq~U zMrX~kogGW2EwQk@|M9Mt-mTBt-=;{^*KJy*^<(beKToc?ZTp+WUv0)@<9T(G?3?9t zkLB)9>i?(|+k5}X^@X*yla06i?Xumu|LIBYeWzFtUf(UXf2PdxmuJ+Eb6)Ul7cXKg zm}D$(VX@7&!rF>a{oI_N3!;Km)*ZX*U;ORO&5aV?r;03Ol)qn=c{^?Kp{ywO_z7Q3 z13?{(-mfCo2ZJa3JLf5XJtlu*ea^yy8Lwx6`tBxI^@M`C&T3fXWptfbGKuB7iK|Oc zyHl{s5hiS-4I5&=+{rqo*y6bU0W$Q zILL>Em8o$Ci`s!RGmU><+rCe9vR0VOvUy8ZnEb7)*D%P=%34(ARr~p@xpDTjH7nlw zyDT%yUMR_N;r;i^_ph@zDC_dJ-{lkL*y*4k5XgG#t!Ln$t`45;GYemS|NYYPn_>Eo z%|B0hiZ|aqCVxNs>DL3ZZ{+r^;MJHFy3FsStIDloBD4P1*2?_-zi5xeY#yiZ)mO}zT^4#IF+xe{WTwyZ=Pzf@43XW@{Qu_*(_MD&9`!}^ zd%381_P)$YiHfqS=iGDZVrK1<^ps;&K8KjzRVL`(x3|6cSYYD8V?r+tkr{y$eZgF*ZI`=z$ubdqbby?)Oa3)9W`wvmyay~U^=j{=x`xabu{m+!peutZ)X*bR$ z{gc*xvhJtm{pxE+OOF=!?LMuYw`a=F{yXw_&hIw-&!H4N_2~s4?(A)^J<5GnWzYS7 zuR4ED|Bi-3pBFx`T5NTv@Tbm+d9rI9?mzYS-^<(Zy|>)*@s`J}&zQK*%ioA|Njmyl9`p6`Ep6E(ysop4L5USEQ?xZ8mAXs_BD4cz0dG|U-sJ)(`5%Me+9|yKX>%p z{J-=5r}4eLyIEs*665y!U$qR{-;1Ar_-)w-^D~K8#nV3CGG-2aQnNg;bltB*IxpBN zW`BDZ8M7&eZ~OjrS-~pPCMA8lleT$d>S?icJD<&3vAwYR``z-NPxb3Fe;PTJG+#bC zmp|tG++!Up*8j-du&HMD?fgH?>)7>{K5q2x^_~Bhc{{T~_oi8|HJM-3wT1e+N!

T-0$rzV2u0zrXkY*B%Mjax-Vi^5y+2pT_(!J!_hMt>)zRUdG^F?Z*bCoVmF*(n%>1NK7rAr?c^xR3xJJ`hP%p{y}agpns+HW^2_TEeU zF8%NQ#!W&qPChC=n%&!}VxV<-x5x~ojT1~3O8$FakT&_z`r5bI%KPfSzPcLt`p3Mk zM$QlSeWOq2O4V8m&YUr2hkx&NVvuxHO6PI>iE=3tjc>Mxy(w`g77 zQuXx}=lxYn4v0*=xa6(X_x(EiGrzsLX((|jpwXdW&z?Px!)7i!U-xbEoXTf2569gW z5$v3{WXG~fo8RBxKYz7)y2BotCsNjwl3^Yk)C_H zt0N+TyC?aSWt_0%%0mwe3~GOUap8A%Nm{dgd-&949UY<=!>e5#5fh>ozKn8z+sq%h z``pwQ6FW|bOx-a1w*H=*n+JbxU;pS%ecbUs>hB&uXf^-r@U!yZ`~4>u-;eiC z{@}knF6=Dxbjf)6sx6avzdN3MmZg`>zJ1Mp{%g6I?pbH+f&rkiT=J;;&ZSKbtvKH$`JA=G={~ z*ep2X{PozQvsS;Zu;Y_=bWvOXg!`=X-I8;spM^AuK5agz_3=thQCqFE+45d1{Vy`- zZ3OQo9-F+ng!}B-vnJ;GOAgd*Oi(@>?R9a=438SslP`C6Pm&HR)cWuz|J~z+>sEY) zayC&X+kW3VY!-d|Y2tfJUFik0&2K$4;b6^vKH)EW^VZrE=1J#6PffdZHKjf7#_4B^ zw95J_*;&^_^4>NVxp?8-q7rXoX?eXxT5Qgu6ECV-nAjgp-EQAfSZP#oca!V`JF_dP zpB;W4*y_#q_QACI67g;EmuvRDbGKnUQ~%9ZZ}%IUb(J3$b|~9?Tx_-PLqg?^LZL(j z4Q?~D&2`C))~k<6%wAV%@$qAbwSzV9bur2H;xg}jm4vi|SD&7kExUF5da0;`eisUN z%k1>J8T9%|;^tjCH#|O1wKKcJXnxh|zg*N?pS5LZL^8UEd<(;wZsIbp(TL8ZxepYWgk_WMS`*IG`wBT3iH%{R*}sJ50~cb9Wr zP=dbyOwq)3li$2s{?-?<=pOYQC-k1pkG+MJykXZs;buXAUMw$V-B ze;0hX!qn@J6|&5o)P2PD)7>JI(9$0-&c&S)k7Z!hiRRh2ZsV1%ww*{!rN;W-?)IFmj1&kdEHv3=>ZsLy})R9j0+C0T?`)Xd2` zJMVbMJV6yB(-)GUX0Ik>5(Bf@i?#g`kb$D`;Et%nsi~>1)iRoEw{JJU=qxbNB5)~W zKp577+15QTI(KLB?}|M|H-kS~_&9y}_H9-1?h_&l&b?Jq5(C@svFid43scO;yQy<5 z(xVo&Pg2nH+HSIWqXMY*eW-F*xrVusVZNpL>^qzN4t_qtIIr$X_kR0}i)S%}Yer{< zPnNAp)SunG>c-3+f}JN=R6>_Zac)bx*UZ|f)Cn^`Pmv#Ime>1T_S zy1Ke<>?t>V9qQJ#WX(nGvknb)`{)0=7x(M;?+?G3Z{(O=x^&6I+yD5x0+&*UX8FT) zmon9ZioEUE=Y9LQ{CC`w7r$)-ZR7U5t;y1Vy?#zRcLsaR(&!bjvTK~b=Pg^YO8FBn zt8`}E{u@7bfzmz}YcgV|JStio@c4s637$jRnx%II_nAsxKm2UbqJST3 zH8U1uJ@;GH)pRm^!^CG_vo$g*8Y<1#w!M|s$jUe#8s(+;Kx=R3Qh(|7fg2`1)AlZW zn`6+YuQaW9RvBY`!<;WUUgvcBDrzsD?EbO*@beFEng5^qBB|bRR&2B5tW9Yt1uxD2 zb)Ju(ar%ATN16K975dMP_w*fIlb@Gnn;5G2;Mb#|O`A8b%#E|%kg50M%zEx=8)qEV z;oB#^pn6{5VzHc@V>%9r`WO7B^M|e9*Llf4-rL!k`Rxvk*jc`1WxCCL3onRBE)R6R zoVNYq)$3PEdEou%`VkE6)!a1!ryZ3-dPdXIr_Ub_8PtEUl{ypgRa;1 z4fl55T@etwG-qWg(}vBb)_Ba$Johf`cbj!n`vuLN9$R{>1XH%(eEGn)Os0Cy-8~M` z4=m08oqxOV{rrhj4;!RkF-+fn+v0ta_|vWNX%|_~CHlXfeD0i(hEI^Pgxfz4GVQ_0$;QzmG0GF!d2%D(zi((eLoq**CLg z7#|BP<&jBxkS(||?@RYYGwHH+Ws`@Oi`UFAUCuYf>3r=D{@xRZV@)p)QUf3 z`7`}Pd;I=L^6K|-yLx+HE-HHvQvW_})vd-=yk~9;eXIIj zW@d8a`Q|Pkw`teregFE+=q)pQ^z>`S<;P;=e!k|b`?7uaNvXrTUT<7u%g@5}<;#~3 z&F%kF*En}wxc@x;{QLN)C-2KFSbyDqU2RYMwRzn>yijBQW=PrFZ=bf)_}QhxCC&0> zS0_!JDtX#4>XFCh$9h(iv)}ER!umYD{~w#6VD~YRS!oG*KmVu|r9a*Dym#-E|4*yW zSUeQI@%H0v2C3B!3J&q{oBa7YJ+!3$+MWGZ=VvkP3EcNF&L!o_g*WftFMjeQsVMy^ zQ^Cn}y=Pa??~(ZR@9%m$kGs~<8`D#c^Oj`FQxx%h$v|e3$Y+5fahmv8GpQR@v^kXEHCJm^01hukQVf z`q}QU<~@49e!qWJmDS6ao%`o$DFr)U`g+-BUcddDhyLI9A26=}p)L7RG9@Kt#V(PF zJG?qU38c@g5|S^uyahewJjFpy zTqeJL;>3xLRaLu~f?Xzc=^FI8O}TkL#$lrX}2G9TX0T-j6-jSv=|a%jrr= z%a&yGigU31IJ5KSlX<0F^W6D9d|4d#=kMbE{w^wVlU7~gVPX36U7B;|yoU<^Pi_A3 z?d^1f_h&3QJa%94ng`95Y-&;>V zD?BSZz383lXUDU5T~!<>>6!GaXS=aYuX{ZIN7z*_zmtDc7PTuY1qXPwE_*rUa(ZA@ zG-JHhUz?eiC*|pRyQpoP!sE-Z`|hzy@!cBh{~C4c74TI@=_?84YD&*qmZ_c+6tb^n zQgoQX^DX`=RTfG{CzsY_%<_w`FuMP*zx(9=EWyl|lb5tN+gm64gQ%EZ^pSte z`j>aDZQbG{oqId(P#bgm;fXI4yH2P~4qE=a{eDG%ZSMMy2dm|aS3Hh=BR|jMUXwB7 ziRc2g_j{xgt~3AM@K8ZlcWJ$RhsPwZl^1H3zBTCf-#y3v-yep%a@O-p=N^tNzk9M< zf8UAN^1DYrJw5&NRQSF_FPG0h$6xn>+0XLn6c_$T7qyvFw2m*EEArsx^Y5SP|6OM@ zGU_RPvF@kdzTbD>Z_2!^_Uzo;)0ZQD-=EvlEB-Fs zUwlk5U8el@ojWnhd}l8Uby5;4)hw)%<6yb*n_d6^?^V$cCOzCQe=cu(@%Ovs%mHCx zZD*Hl^H36!^^~90Ui<#ypU=xHYyT(Ct69R*e)yn%-A8UCV`KLke}8}e)YQ};f9p1F z+VsdGN^s_zNoFS1eP2HwIsE&BiTr^?e`RB1{({Bdzq_u|9HuJ*5>LPRb^Y@_QQ>5(+;O?E8g;FGmF zV)=Z|;iKa5b2=V&pHP`zGIiPAyyY*C=cc5jOqe%Mj_Zhnfn7i{EM7j~#bUGin=>`*brHV%fK z*WWIB9(H_b@O$m)wxXa>v1x%_KC-LeP1^}U+2<2qEY>}gnY*jwNR(G=T3DFa^!l%> z&&;vRKJmS;_K%@;naSsGxAWB#Qk0BBmt1-I^WtLn${!2cE1u6?cyPwdsYh3Zx}KS7 ztj?$`JaJ{xmkT^*|KI-nk!<(t1GC+q;Cue-zVSZADW&PcVfAJfuV9T8^hc8@=u=M{r)L2jK6Qo#q*!kt4;?h z2ym3feDCLLmOMFQs#B=yDl#Kc>UT{ z7OpCGZoIy;&$5|G>$&r38&BV4RI9oD$z6^E?Y8be>)+cq+P+zs_Oam8m%6+dsRxs1 z8tBUI+qR%x_I5k}xh-ExjEsyQTiFTD+;gnN@9q2d&oA8+|D?~ouCHQm;{El7OO^_r zk3RL>@Acz&@$bb+2JH6lnszJzfryF^u>=%mme0iynAet?>@`;xyrw9+ntvzU3#>paw&Mg*3H)T`|rPB zzJ0lH{Wh}%W7Vc)Gh?G=$7>3fJ!V}d+4U^fzi$8hd-v|`U|rVXqr12*tv+7<`q{r$ z(^J+z$(R2l+Yp>KM`qW_zu)t1+myA-woCV_8Z>rPTQD~|yvP=um?35RHs?eCJ^mRJ z4VyRnMT%7YJUnmlo#(kvOsmZ!zhxRq-icr~Ho5YE_d}zDL!+jWp zCUkkM>5-acwtH^R8Xcoen=GDv-+cSO&61lI4<{QZ3;Crbh-*1u^sVO`dt zq8^z|~(k1)6>$1KjD@+=v@OTT(teW&}*0K%{E%f5VDcI#m c(|`VNbM}Sz&y-eXU|?YIboFyt=akR{01Y$PS^xk5 diff --git a/doc/qtcreator/images/qtcreator-kit-selector.webp b/doc/qtcreator/images/qtcreator-kit-selector.webp new file mode 100644 index 0000000000000000000000000000000000000000..a9b44fd822cfed1cfae33f5af2d842fdfd137b21 GIT binary patch literal 6202 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 literal 0 HcmV?d00001 diff --git a/doc/qtcreator/src/android/androiddev.qdoc b/doc/qtcreator/src/android/androiddev.qdoc index 69947c4fc03..7e172f0650a 100644 --- a/doc/qtcreator/src/android/androiddev.qdoc +++ b/doc/qtcreator/src/android/androiddev.qdoc @@ -195,7 +195,7 @@ To view the available AVDs, select \preferences > \uicontrol Devices. You can add more AVDs. - \image qtcreator-android-avd-manager.png {Android device in Devices} + \image qtcreator-android-avd-manager.webp {Android device in Devices} You can see the status of the selected device in \uicontrol {Current state}. To update the status information, select \uicontrol Refresh. diff --git a/doc/qtcreator/src/baremetal/creator-baremetal-dev.qdoc b/doc/qtcreator/src/baremetal/creator-baremetal-dev.qdoc index 368e313851a..dfde42b473e 100644 --- a/doc/qtcreator/src/baremetal/creator-baremetal-dev.qdoc +++ b/doc/qtcreator/src/baremetal/creator-baremetal-dev.qdoc @@ -262,7 +262,7 @@ You can build applications for and run them on bare metal devices in the same way as for and on the desktop. For more information, see - \l{Building for Multiple Platforms} and \l{Running on Multiple Platforms}. + \l{Building for Multiple Platforms} and \l{Run on many platforms}. \sa {Enable and disable plugins} */ diff --git a/doc/qtcreator/src/debugger/creator-only/creator-debugger.qdoc b/doc/qtcreator/src/debugger/creator-only/creator-debugger.qdoc index 101bd3a1889..0676655ec52 100644 --- a/doc/qtcreator/src/debugger/creator-only/creator-debugger.qdoc +++ b/doc/qtcreator/src/debugger/creator-only/creator-debugger.qdoc @@ -1985,7 +1985,7 @@ \li Select the \inlineimage icons/run_small.png (\uicontrol Run) button to verify that the - \l {Running on Multiple Platforms}{build and run kit selector} + \l {Run on many platforms}{build and run kit selector} picked a runnable target and you can run the application. \li Make sure the debugger is \l{Setting Up Debugger}{set up properly}. diff --git a/doc/qtcreator/src/debugger/qtquick-debugging.qdoc b/doc/qtcreator/src/debugger/qtquick-debugging.qdoc index a9d297419cd..c888927e022 100644 --- a/doc/qtcreator/src/debugger/qtquick-debugging.qdoc +++ b/doc/qtcreator/src/debugger/qtquick-debugging.qdoc @@ -80,7 +80,7 @@ \li To debug applications on \l{glossary-device}{devices}, check that Qt 5.0, or later, libraries are installed on the device and - \l{Running on Multiple Platforms}{select the corresponding kit for the device} + \l{Run on many platforms}{select the corresponding kit for the device} before you start debugging. \endlist diff --git a/doc/qtcreator/src/linux-mobile/creator-embedded-platforms.qdoc b/doc/qtcreator/src/linux-mobile/creator-embedded-platforms.qdoc index 1d1c863befc..14f642e38ba 100644 --- a/doc/qtcreator/src/linux-mobile/creator-embedded-platforms.qdoc +++ b/doc/qtcreator/src/linux-mobile/creator-embedded-platforms.qdoc @@ -76,7 +76,7 @@ \li \l{Connecting Remote Linux Devices} \li \l{Deploying to Remote Linux} \li \l{Remote Linux Run Settings} - \li \l{Running on Remote Linux Devices} + \li \l{Run on remote Linux devices} \li \l{https://doc.qt.io/qtcreator/creator-overview-qtasam.html} {Qt Creator Plugin for Qt Application Manager} \endlist @@ -110,7 +110,7 @@ \li \l{Connecting QNX Devices} \li \l{Deploying to QNX Neutrino} \li \l{QNX Run Settings} - \li \l{Running on QNX Devices} + \li \l{Run on QNX devices} \li \l{Qt for QNX} \endlist diff --git a/doc/qtcreator/src/linux-mobile/creator-projects-running-generic-linux.qdocinc b/doc/qtcreator/src/linux-mobile/creator-projects-how-to-run-generic-linux.qdoc similarity index 55% rename from doc/qtcreator/src/linux-mobile/creator-projects-running-generic-linux.qdocinc rename to doc/qtcreator/src/linux-mobile/creator-projects-how-to-run-generic-linux.qdoc index 995ad8ce4b9..b78dcd5ca20 100644 --- a/doc/qtcreator/src/linux-mobile/creator-projects-running-generic-linux.qdocinc +++ b/doc/qtcreator/src/linux-mobile/creator-projects-how-to-run-generic-linux.qdoc @@ -1,24 +1,25 @@ -// Copyright (C) 2017 The Qt Company Ltd. +// Copyright (C) 2024 The Qt Company Ltd. // SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GFDL-1.3-no-invariants-only /*! -//! [running on embedded linux] + \page creator-how-to-run-on-remote-linux.html + \previouspage creator-how-tos.html - \section1 Running on Remote Linux Devices + \ingroup creator-how-to-run - To build the application and run it on a device: + \title Run on remote Linux devices + + To build an application and run it on a device: \list 1 - \li Specify a connection to the device. For more information, see - \l{Connecting Remote Linux Devices}. + \li Specify a connection to the device. - \li Click the \uicontrol Run button. + \li Select \inlineimage icons/run_small.png (\uicontrol Run). \endlist - \QC uses the compiler specified in the project build settings - (tool chain) to build the application. + \QC uses the compiler from the kit (tool chain) to build the application. \QC copies the application files to the connected device and runs the application. The application views are @@ -33,5 +34,6 @@ Debugging works transparently if GDB server is installed on the device and it is compatible with the GDB on the host. -//! [running on embedded linux] + \sa {Connecting Remote Linux Devices}, {Run on many platforms}, {Compilers}, + {Embedded Platforms}, {kit-preferences}{Kits} */ diff --git a/doc/qtcreator/src/overview/creator-only/creator-mobile-platforms.qdoc b/doc/qtcreator/src/overview/creator-only/creator-mobile-platforms.qdoc index 21e648dcfba..fef448c3f15 100644 --- a/doc/qtcreator/src/overview/creator-only/creator-mobile-platforms.qdoc +++ b/doc/qtcreator/src/overview/creator-only/creator-mobile-platforms.qdoc @@ -44,7 +44,7 @@ \list \li \l{Connecting Android Devices} \li \l{Deploying to Android} - \li \l{Running on Multiple Platforms} + \li \l{Run on many platforms} \li \l{Creating a Mobile Application} \li \l{Debugging on Android Devices} \li \l{Qt for Android} @@ -64,7 +64,7 @@ \list \li \l{Connecting iOS Devices} - \li \l{Running on Multiple Platforms} + \li \l{Run on many platforms} \li \l{Creating a Mobile Application} \li \l{Qt for iOS} \endlist diff --git a/doc/qtcreator/src/overview/creator-only/creator-reference.qdoc b/doc/qtcreator/src/overview/creator-only/creator-reference.qdoc index 8ad2729814e..c26df6eb3e5 100644 --- a/doc/qtcreator/src/overview/creator-only/creator-reference.qdoc +++ b/doc/qtcreator/src/overview/creator-only/creator-reference.qdoc @@ -21,12 +21,12 @@ \section1 Build Configurations + Build configurations have everything you need to compile the sources into + binaries. Build configurations use the tools and settings defined in their + corresponding kit. + \annotatedlist creator-reference-build-configurations - \section1 Run Configurations - - \annotatedlist creator-reference-run-configurations - \section1 Editors \annotatedlist creator-reference-editors @@ -59,6 +59,17 @@ \annotatedlist creator-reference-preferences-text-editor + \section1 Run Configurations + + Run configurations start the application in the location where the + \e {deploy configuration} copied it. By default, when you select + \uicontrol Run, \QC builds the project, deploys it to the device + defined in the kit, and runs it there. If you did not make changes + to the project since you last built and deployed it, \QC simply runs + it again. + + \annotatedlist creator-reference-run-configurations + \section1 UI Design Design UIs with either \l{User Interfaces}{Qt Quick or Qt Widgets}. diff --git a/doc/qtcreator/src/projects/creator-only/creator-projects-building-running.qdoc b/doc/qtcreator/src/projects/creator-only/creator-projects-building-running.qdoc index 25951a3e804..32f2fdc5880 100644 --- a/doc/qtcreator/src/projects/creator-only/creator-projects-building-running.qdoc +++ b/doc/qtcreator/src/projects/creator-only/creator-projects-building-running.qdoc @@ -37,7 +37,7 @@ the sources into binaries. Build configurations use the tools and settings defined in their corresponding kit. - \li \l{Running on Multiple Platforms} + \li \l{Run on many platforms} \e {Run configurations} start the application in the location where it was copied by the \e{deploy configuration}. By default, diff --git a/doc/qtcreator/src/projects/creator-only/creator-projects-building.qdoc b/doc/qtcreator/src/projects/creator-only/creator-projects-building.qdoc index 6071c329274..13b7d6eb9a9 100644 --- a/doc/qtcreator/src/projects/creator-only/creator-projects-building.qdoc +++ b/doc/qtcreator/src/projects/creator-only/creator-projects-building.qdoc @@ -1,4 +1,4 @@ -// Copyright (C) 2020 The Qt Company Ltd. +// Copyright (C) 2024 The Qt Company Ltd. // SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GFDL-1.3-no-invariants-only // ********************************************************************** @@ -30,25 +30,28 @@ \list 1 - \li Click the \uicontrol {Build and Run Kit Selector} icon (1) or select + \li Select the \uicontrol {Build and Run Kit Selector} icon or go to \uicontrol Build > \uicontrol {Open Build and Run Kit Selector} to select the build and run \l{glossary-buildandrun-kit}{kit} or an \l{Managing Android Virtual Devices (AVD)}{Android device}. - \image qtcreator-kit-selector.png "Kit selector" + \image qtcreator-kit-selector.webp {Kit selector} \li Choose \uicontrol Build > \uicontrol {Build Project} or press \key {Ctrl+B}. - You can also select the \uicontrol Run button (2) to also deploy and run - the application after building it. + Or, select \inlineimage icons/run_small.png (\uicontrol Run) to + deploy and run the application after building it. \endlist - While the application is being built, the \uicontrol Build button (3) - changes to a \uicontrol {Cancel Build} button. To cancel the build, select + While the application is being built, the \inlineimage icons/build.png + (\uicontrol Build) button changes to a \inlineimage icons/cancel-build.png + (\uicontrol {Cancel Build}) button. To cancel the build, select the button, press \key {Alt+Backspace}, or select \uicontrol Build > - \uicontrol {Cancel Build}. If you selected a build command and + \uicontrol {Cancel Build}. + + If you selected a build command and decide you would also like to run the application, you can select the \uicontrol Run button to schedule running the project after building is done. diff --git a/doc/qtcreator/src/projects/creator-projects-running.qdoc b/doc/qtcreator/src/projects/creator-projects-running.qdoc index 9c833bf8e7e..80eb0650e4e 100644 --- a/doc/qtcreator/src/projects/creator-projects-running.qdoc +++ b/doc/qtcreator/src/projects/creator-projects-running.qdoc @@ -1,4 +1,4 @@ -// Copyright (C) 2021 The Qt Company Ltd. +// Copyright (C) 2024 The Qt Company Ltd. // SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GFDL-1.3-no-invariants-only // ********************************************************************** @@ -9,68 +9,76 @@ /*! \page creator-running-targets.html - \if defined(qtdesignstudio) - \previouspage studio-live-preview.html - \else - \previouspage creator-building-targets.html - \endif - \nextpage creator-deployment.html + \previouspage creator-how-tos.html - \title Running on Multiple Platforms + \ingroup creator-how-to-run + + \title Run on many platforms By default, running an application also builds it and deploys it to a - location from where it can be run on the desktop, on a device emulator or + location from where it can run on the desktop, on a device emulator or simulator, or on a \l{glossary-device}{device} that is connected to - the development PC. + the computer. - To run executable files without deploying them first, select \uicontrol Build > - \uicontrol {Run Without Deployment}. To make this the default option, deselect the - \preferences > \uicontrol {Build & Run} > - \uicontrol General > \uicontrol {Always deploy project before running it} - check box. + \section1 Run applications To run applications: \list 1 - \li Click the \uicontrol {Build and Run Kit Selector} icon (1) or select + \li Select the \uicontrol {Build and Run Kit Selector} icon or go to \uicontrol Build > \uicontrol {Open Build and Run Kit Selector} to select the build and run \l{glossary-buildandrun-kit}{kit}. - \image qtcreator-kit-selector.png "Kit selector" + \image qtcreator-kit-selector.webp {Kit selector} - \li Click the \uicontrol Run button (2). + \li Select \inlineimage icons/run_small.png (\uicontrol Run). \endlist + \section1 Run on mobile and embedded devices + + If you have connected \l{Mobile Platforms}{mobile devices} or + \l{Embedded Platforms}{embedded devices} to the computer + or added virtual devices, such as \l{Managing Android Virtual Devices (AVD)} + {Android Virtual Devices (AVD)}, you can select them in the kit selector. + + Select \uicontrol Manage to manage device settings. For example, you can add + AVDs or manually start disconnected AVDs. + + \section1 Select run targets + If your project has several run targets defined, such as \l{Running Autotests}{tests}, you can select them in the kit selector. - \image qtcreator-kit-selector-run-targets.png "Run targets in the kit selector" + \image qtcreator-kit-selector-run-targets.png {Run targets in the kit selector} - If you have connected \l{Mobile Platforms}{mobile devices} or - \l{Embedded Platforms}{embedded devices} to the development PC - or added virtual devices, such as \l{Managing Android Virtual Devices (AVD)} - {Android Virtual Devices (AVD)}, you can select them in the kit selector. - Select \uicontrol Manage to manage device settings. For example, you can add - AVDs or manually start disconnected AVDs. + \section1 Run without deploying - \l {Application Output} displays the status of the - application while it is running. You can select the \uicontrol Run button - to re-run applications without building them first. This is - useful when developing Qt Quick applications because the QML files are - interpreted at runtime. Therefore, the application does not need to be + To run executable files without deploying them first, select \uicontrol Build > + \uicontrol {Run Without Deployment}. + + To make this the default option, go to \preferences > + \uicontrol {Build & Run} > \uicontrol General, and clear + \uicontrol {Always deploy project before running it}. + + \section1 Run without building + + \l {Application Output} displays the status of the application while it is + running. + + \image qtcreator-application-output.webp {Application Output view} + + Select \inlineimage icons/run_small.png (\uicontrol Run) + to re-run applications without building them first. + + This is useful when developing Qt Quick applications because the QML files + are interpreted at runtime. Therefore, the application does not need to be built again if you edited only QML files. This saves time especially if the application has large image files that would need to be bundled into the resource file before running the application. - \image qtcreator-application-output.webp {Application Output view} - - \include linux-mobile/creator-projects-running-generic-linux.qdocinc running on embedded linux - - \if defined(qtcreator) - - \include qnx/creator-projects-running-qnx.qdocinc running on qnx - \sa {Configure projects for running}, {Run Python applications} - \endif + \sa {Configure projects for running}, {Customizing the Build Process}, + {Run on QNX devices}, {Run on remote Linux devices}, + {Run Python applications}, {Supported Platforms} */ diff --git a/doc/qtcreator/src/qnx/creator-projects-running-qnx.qdocinc b/doc/qtcreator/src/qnx/creator-projects-how-to-run-qnx.qdoc similarity index 65% rename from doc/qtcreator/src/qnx/creator-projects-running-qnx.qdocinc rename to doc/qtcreator/src/qnx/creator-projects-how-to-run-qnx.qdoc index 0d9bc2c43d5..364ee316bcc 100644 --- a/doc/qtcreator/src/qnx/creator-projects-running-qnx.qdocinc +++ b/doc/qtcreator/src/qnx/creator-projects-how-to-run-qnx.qdoc @@ -1,22 +1,21 @@ -// Copyright (C) 2022 The Qt Company Ltd. +// Copyright (C) 2024 The Qt Company Ltd. // SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GFDL-1.3-no-invariants-only /*! -//! [running on qnx] + \page creator-how-to-run-on-qnx.html + \previouspage creator-how-tos.html - \section1 Running on QNX Devices + \ingroup creator-how-to-run + + \title Run on QNX devices + + To build an application and run it on a device: \list 1 - - \li Connect the device to the development PC or to the Wi-Fi network. - - \li Configure the device and specify a connection to it. For more - information, see \l{Connecting QNX Devices}. - + \li Connect the device to the computer or to the Wi-Fi network. + \li Configure the device and specify a connection to it. \li Make sure that your kit has your QNX device set. - - \li Click the \uicontrol Run button. - + \li Select \inlineimage icons/run_small.png (\uicontrol Run). \endlist \QC uses the compiler specified in the QNX tool chain to build the @@ -25,23 +24,23 @@ \note Debugging is currently only fully supported on Linux and \macos. It is not possible to insert breakpoints during runtime on Windows. - \section2 Troubleshooting Errors + \section1 Troubleshoot errors To support running, debugging, and stopping applications from \QC, the QNX Neutrino RTOS has additional command-line tools and services, as described in \l {Qt for QNX}. - \section3 Debug Output Cannot Be Shown + \section2 Debug output cannot be shown For the command-line output to show up in the \uicontrol{Application Output}, - \QC needs to be able to establish an SSH connection to the device. + \QC has to create an SSH connection to the device. This is only possible if QNX Momentics is not running, and the SSH key configured for the device is a 4096-bit key. If these conditions are not met, you will get an error message saying debug output cannot be shown. - \section3 Cannot Run, Debug, or Stop Applications + \section2 Cannot run, debug, or stop applications The board support package (BSP) for the QNX device might be missing some of the following applications that \QC needs to run, debug, and stop @@ -49,5 +48,6 @@ \c printf, \c ps, \c read, \c sed, \c sleep, \c uname, \c slog2info, and \c cat. -//! [running on qnx] + \sa {Connecting QNX Devices}, {Run on many platforms}, {Compilers}, + {Embedded Platforms}, {kit-preferences}{Kits} */ diff --git a/doc/qtcreator/src/qtcreator-toc.qdoc b/doc/qtcreator/src/qtcreator-toc.qdoc index 60f8248b38c..26fb9aa33fa 100644 --- a/doc/qtcreator/src/qtcreator-toc.qdoc +++ b/doc/qtcreator/src/qtcreator-toc.qdoc @@ -49,7 +49,6 @@ \li \l{Previewing in Browsers} \endlist \li \l{Building for Multiple Platforms} - \li \l{Running on Multiple Platforms} \li \l{Deploying to Devices} \list \li \l{Deploying to Android} diff --git a/doc/qtcreator/src/qtcreator.qdoc b/doc/qtcreator/src/qtcreator.qdoc index aefa86c3946..85c60896ac7 100644 --- a/doc/qtcreator/src/qtcreator.qdoc +++ b/doc/qtcreator/src/qtcreator.qdoc @@ -57,7 +57,6 @@ \list \li \l{Validating with Target Hardware} \li \l{Building for Multiple Platforms} - \li \l{Running on Multiple Platforms} \li \l{Deploying to Devices} \li \l{Connecting Devices} \endlist diff --git a/doc/qtcreator/src/qtquick/creator-only/qtquick-states-scxml.qdocinc b/doc/qtcreator/src/qtquick/creator-only/qtquick-states-scxml.qdocinc index 0195f0e1cf2..1f0fd5a8e01 100644 --- a/doc/qtcreator/src/qtquick/creator-only/qtquick-states-scxml.qdocinc +++ b/doc/qtcreator/src/qtquick/creator-only/qtquick-states-scxml.qdocinc @@ -19,7 +19,7 @@ If you add animation to the states, you can \l{Validating with Target Hardware}{preview} - or \l{Running on Multiple Platforms}{run} + or \l{Run on many platforms}{run} the application to test the animation. //! [scxml state machines] diff --git a/doc/qtcreator/src/user-interface/creator-ui.qdoc b/doc/qtcreator/src/user-interface/creator-ui.qdoc index bf4bb2c455d..d70c94d90ee 100644 --- a/doc/qtcreator/src/user-interface/creator-ui.qdoc +++ b/doc/qtcreator/src/user-interface/creator-ui.qdoc @@ -40,7 +40,7 @@ \li \inlineimage numbers/03.png \li Run button \li Run the application on the selected target platform. - \li \l{Running on Multiple Platforms} + \li \l{Run on many platforms} \row \li \inlineimage numbers/04.png \li Debug button diff --git a/doc/qtcreator/src/webassembly/creator-webassembly.qdoc b/doc/qtcreator/src/webassembly/creator-webassembly.qdoc index f53830d29f8..e0ab35464c3 100644 --- a/doc/qtcreator/src/webassembly/creator-webassembly.qdoc +++ b/doc/qtcreator/src/webassembly/creator-webassembly.qdoc @@ -110,7 +110,7 @@ You can now build Qt applications in WebAssembly format and run them in a web browser as described in \l {Building for Multiple Platforms} and - \l{Running on Multiple Platforms}. + \l{Run on many platforms}. \sa {Enable and disable plugins} */ From 5a05044c0c037905a85a11961be1cb5776195817 Mon Sep 17 00:00:00 2001 From: Leena Miettinen Date: Tue, 13 Feb 2024 14:12:14 +0100 Subject: [PATCH 063/243] Doc: Turn Customizing the Build Process into a how-to topic - Update the screenshot of Preferences > Build & Run > General (there is a new option that will be described in another change) Task-number: QTCREATORBUG-29361 Task-number: QTCREATORBUG-30209 Change-Id: I62eaeef96b2d40dfec42022a4430da15c1590050 Reviewed-by: Christian Kandeler --- ...creator-preferences-build-run-general.webp | Bin 0 -> 13754 bytes .../qtcreator-project-options-deploy.png | Bin 21686 -> 0 bytes .../creator-projects-building-running.qdoc | 22 +------- .../creator-projects-builds-customizing.qdoc | 51 +++++++++++------- .../projects/creator-projects-running.qdoc | 2 +- doc/qtcreator/src/qtcreator-toc.qdoc | 1 - 6 files changed, 34 insertions(+), 42 deletions(-) create mode 100644 doc/qtcreator/images/qtcreator-preferences-build-run-general.webp delete mode 100644 doc/qtcreator/images/qtcreator-project-options-deploy.png diff --git a/doc/qtcreator/images/qtcreator-preferences-build-run-general.webp b/doc/qtcreator/images/qtcreator-preferences-build-run-general.webp new file mode 100644 index 0000000000000000000000000000000000000000..c7636894960c309e228f59a43e02407c7a07034b GIT binary patch literal 13754 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 \uicontrol {Build & Run} > \uicontrol General. - \image qtcreator-project-options-deploy.png "Project General preferences" + \image qtcreator-preferences-build-run-general.webp {Build & Run General preferences} - By default, the \uicontrol {Always deploy project before running it} (1) and - \uicontrol {Build the Whole Project} (2) options are enabled. Therefore, - when you select the \uicontrol Run function, \QC checks for changes in the - project files and also builds and deploys the project if necessary. + By default, \uicontrol {Always deploy project before running it} (1) and + \uicontrol {Build the Whole Project} (2) are selected. Therefore, when + you select \inlineimage icons/run_small.png (\uicontrol Run), \QC checks + for changes in the project files and also builds and deploys the project if + necessary. To deploy applications without building them or to just build the application that you want to run, select the appropriate options - in the \uicontrol {Build before deploying} field. + in \uicontrol {Build before deploying}. + + \section1 Stop applications before building By default, the applications that the project contains are stopped - before rebuilding the project. To stop just the current application, - the applications in the same build directory, all applications, - or no applications, select the appropriate option in the - \uicontrol {Stop applications before building} field. + before rebuilding the project. + + To stop just the current application, the applications in the same build + directory, all applications, or no applications, select the appropriate + option in \uicontrol {Stop applications before building}. + + \section1 Use jom On Windows, you can use \c jom instead of \c nmake for building the project - to distribute the compilation process to multiple CPU cores. You can download - \c jom from \l{http://download.qt.io/official_releases/jom}{Qt Downloads}. - To use \c jom, select the \uicontrol {Use jom instead of nmake} check box. - Deselect the check box if you experience build problems. + to distribute the compilation process to multiple CPU cores. + To use \c jom: + + \list 1 + \li Download \c jom from \l{http://download.qt.io/official_releases/jom} + {Qt Downloads}. + \li Select \uicontrol {Use jom instead of nmake}. + \endlist + + Clear the check box if builds fail. */ diff --git a/doc/qtcreator/src/projects/creator-projects-running.qdoc b/doc/qtcreator/src/projects/creator-projects-running.qdoc index 80eb0650e4e..43d80f08c8d 100644 --- a/doc/qtcreator/src/projects/creator-projects-running.qdoc +++ b/doc/qtcreator/src/projects/creator-projects-running.qdoc @@ -78,7 +78,7 @@ the application has large image files that would need to be bundled into the resource file before running the application. - \sa {Configure projects for running}, {Customizing the Build Process}, + \sa {Configure projects for running}, {Customize the build process}, {Run on QNX devices}, {Run on remote Linux devices}, {Run Python applications}, {Supported Platforms} */ diff --git a/doc/qtcreator/src/qtcreator-toc.qdoc b/doc/qtcreator/src/qtcreator-toc.qdoc index 26fb9aa33fa..9038a168073 100644 --- a/doc/qtcreator/src/qtcreator-toc.qdoc +++ b/doc/qtcreator/src/qtcreator-toc.qdoc @@ -68,7 +68,6 @@ \li \l{Connecting Remote Linux Devices} \li \l{Building Applications for the Web} \endlist - \li \l{Customizing the Build Process} \endlist \li \l{Testing} \list From 04d7f63186a0f7958990630f0c51f9b6230cf564 Mon Sep 17 00:00:00 2001 From: hjk Date: Fri, 16 Feb 2024 10:47:40 +0100 Subject: [PATCH 064/243] Debugger: Fix Attach to QML Port This does not yet fix the reported problem but at least attaches and gives a working QML inspector in a QML-only debugging session. Task-number: QTCREATORBUG-30263 Change-Id: Ieac517c2b7c5dde24792f3bbcffe0058073ddbd1 Reviewed-by: Christian Stenger --- src/plugins/debugger/debuggerruncontrol.cpp | 5 +---- src/plugins/debugger/qml/qmlengine.cpp | 5 +++-- 2 files changed, 4 insertions(+), 6 deletions(-) diff --git a/src/plugins/debugger/debuggerruncontrol.cpp b/src/plugins/debugger/debuggerruncontrol.cpp index 4a0f20b8d64..8ef76e7a75b 100644 --- a/src/plugins/debugger/debuggerruncontrol.cpp +++ b/src/plugins/debugger/debuggerruncontrol.cpp @@ -176,8 +176,8 @@ void DebuggerRunTool::setBreakOnMainNextTime() void DebuggerRunTool::setStartMode(DebuggerStartMode startMode) { + m_runParameters.startMode = startMode; if (startMode == AttachToQmlServer) { - m_runParameters.startMode = AttachToRemoteProcess; m_runParameters.cppEngineType = NoEngineType; m_runParameters.isQmlDebugging = true; m_runParameters.closeMode = KillAtClose; @@ -194,9 +194,6 @@ void DebuggerRunTool::setStartMode(DebuggerStartMode startMode) m_runParameters.projectSourceFiles.append(project->files(Project::SourceFiles)); if (!projects.isEmpty()) m_runParameters.projectSourceDirectory = projects.first()->projectDirectory(); - - } else { - m_runParameters.startMode = startMode; } } diff --git a/src/plugins/debugger/qml/qmlengine.cpp b/src/plugins/debugger/qml/qmlengine.cpp index d271d15c5a5..2ffe5bf313a 100644 --- a/src/plugins/debugger/qml/qmlengine.cpp +++ b/src/plugins/debugger/qml/qmlengine.cpp @@ -547,9 +547,10 @@ void QmlEngine::setupEngine() if (isPrimaryEngine()) { // QML only. - if (runParameters().startMode == AttachToRemoteServer) + const DebuggerStartMode startMode = runParameters().startMode; + if (startMode == AttachToQmlServer || startMode == AttachToRemoteServer) tryToConnect(); - else if (runParameters().startMode == AttachToRemoteProcess) + else if (startMode == AttachToRemoteProcess) beginConnection(); else startProcess(); From 70f7e275e25cbecc53ebe509ffeb21a1aa8592f4 Mon Sep 17 00:00:00 2001 From: Eike Ziller Date: Fri, 16 Feb 2024 16:00:12 +0100 Subject: [PATCH 065/243] EditorManager: Avoid warnings about already registered actions When opening new editor windows, we want the _window_ to have the EditorManager context as well as the individual window context, but the window _actions_ (close, etc) may only be registered for the individual window context. Add the corresponding option to ICore::registerWindow et al. Change-Id: I67d0a6b386603e0047a77dfb357c207e7ffe99e6 Reviewed-by: David Schulz Reviewed-by: Qt CI Bot --- .../coreplugin/editormanager/editorwindow.cpp | 6 ++++-- src/plugins/coreplugin/icore.cpp | 7 ++++--- src/plugins/coreplugin/icore.h | 4 +++- src/plugins/coreplugin/windowsupport.cpp | 15 ++++++++------- src/plugins/coreplugin/windowsupport.h | 2 +- 5 files changed, 20 insertions(+), 14 deletions(-) diff --git a/src/plugins/coreplugin/editormanager/editorwindow.cpp b/src/plugins/coreplugin/editormanager/editorwindow.cpp index 3e23a7285ed..fbd60ebc15b 100644 --- a/src/plugins/coreplugin/editormanager/editorwindow.cpp +++ b/src/plugins/coreplugin/editormanager/editorwindow.cpp @@ -47,9 +47,11 @@ EditorWindow::EditorWindow(QWidget *parent) : static int windowId = 0; + const Utils::Id windowContext + = Utils::Id("EditorManager.ExternalWindow.").withSuffix(++windowId); ICore::registerWindow(this, - Context(Utils::Id("EditorManager.ExternalWindow.").withSuffix(++windowId), - Constants::C_EDITORMANAGER)); + Context(windowContext, Constants::C_EDITORMANAGER), + Context(windowContext)); connect(m_area, &EditorArea::windowTitleNeedsUpdate, this, &EditorWindow::updateWindowTitle); diff --git a/src/plugins/coreplugin/icore.cpp b/src/plugins/coreplugin/icore.cpp index abee4c08ab0..ef11fd6d161 100644 --- a/src/plugins/coreplugin/icore.cpp +++ b/src/plugins/coreplugin/icore.cpp @@ -1011,14 +1011,15 @@ void ICore::removeAdditionalContext(const Context &context) Registers a \a window with the specified \a context. Registered windows are shown in the \uicontrol Window menu and get registered for the various window related actions, like the minimize, zoom, fullscreen and close - actions. + actions. The context for the actions is \a context by default, but can be + overridden with \a actionContext. Whenever the application focus is in \a window, its \a context is made active. */ -void ICore::registerWindow(QWidget *window, const Context &context) +void ICore::registerWindow(QWidget *window, const Context &context, const Context &actionContext) { - new WindowSupport(window, context); // deletes itself when widget is destroyed + new WindowSupport(window, context, actionContext); // deletes itself when widget is destroyed } /*! diff --git a/src/plugins/coreplugin/icore.h b/src/plugins/coreplugin/icore.h index 215cb94ba86..8c713e156f4 100644 --- a/src/plugins/coreplugin/icore.h +++ b/src/plugins/coreplugin/icore.h @@ -98,7 +98,9 @@ public: static void addContextObject(IContext *context); static void removeContextObject(IContext *context); - static void registerWindow(QWidget *window, const Context &context); + static void registerWindow(QWidget *window, + const Context &context, + const Context &actionContext = {}); static void restartTrimmer(); enum OpenFilesFlags { diff --git a/src/plugins/coreplugin/windowsupport.cpp b/src/plugins/coreplugin/windowsupport.cpp index 4cbfb57d038..25ab34793c7 100644 --- a/src/plugins/coreplugin/windowsupport.cpp +++ b/src/plugins/coreplugin/windowsupport.cpp @@ -28,9 +28,9 @@ namespace Internal { Q_GLOBAL_STATIC(WindowList, m_windowList) -WindowSupport::WindowSupport(QWidget *window, const Context &context) - : QObject(window), - m_window(window) +WindowSupport::WindowSupport(QWidget *window, const Context &context, const Context &actionContext) + : QObject(window) + , m_window(window) { m_window->installEventFilter(this); @@ -38,14 +38,15 @@ WindowSupport::WindowSupport(QWidget *window, const Context &context) m_contextObject->setWidget(window); m_contextObject->setContext(context); ICore::addContextObject(m_contextObject); + const Context ac = actionContext.isEmpty() ? context : actionContext; if (useMacShortcuts) { m_minimizeAction = new QAction(this); - ActionManager::registerAction(m_minimizeAction, Constants::MINIMIZE_WINDOW, context); + ActionManager::registerAction(m_minimizeAction, Constants::MINIMIZE_WINDOW, ac); connect(m_minimizeAction, &QAction::triggered, m_window, &QWidget::showMinimized); m_zoomAction = new QAction(this); - ActionManager::registerAction(m_zoomAction, Constants::ZOOM_WINDOW, context); + ActionManager::registerAction(m_zoomAction, Constants::ZOOM_WINDOW, ac); connect(m_zoomAction, &QAction::triggered, m_window, [this] { if (m_window->isMaximized()) { // similar to QWidget::showMaximized @@ -58,13 +59,13 @@ WindowSupport::WindowSupport(QWidget *window, const Context &context) }); m_closeAction = new QAction(this); - ActionManager::registerAction(m_closeAction, Constants::CLOSE_WINDOW, context); + ActionManager::registerAction(m_closeAction, Constants::CLOSE_WINDOW, ac); connect(m_closeAction, &QAction::triggered, m_window, &QWidget::close, Qt::QueuedConnection); } m_toggleFullScreenAction = new QAction(this); updateFullScreenAction(); - ActionManager::registerAction(m_toggleFullScreenAction, Constants::TOGGLE_FULLSCREEN, context); + ActionManager::registerAction(m_toggleFullScreenAction, Constants::TOGGLE_FULLSCREEN, ac); connect(m_toggleFullScreenAction, &QAction::triggered, this, &WindowSupport::toggleFullScreen); m_windowList->addWindow(window); diff --git a/src/plugins/coreplugin/windowsupport.h b/src/plugins/coreplugin/windowsupport.h index c1b48d39179..bfdc969ffb0 100644 --- a/src/plugins/coreplugin/windowsupport.h +++ b/src/plugins/coreplugin/windowsupport.h @@ -40,7 +40,7 @@ class WindowSupport : public QObject { Q_OBJECT public: - WindowSupport(QWidget *window, const Context &context); + WindowSupport(QWidget *window, const Context &context, const Context &actionContext = {}); ~WindowSupport() override; void setCloseActionEnabled(bool enabled); From 814e84a5e7e1898962a989432f9d67f0bc3128c7 Mon Sep 17 00:00:00 2001 From: Eike Ziller Date: Mon, 19 Feb 2024 09:39:22 +0100 Subject: [PATCH 066/243] Fix the window list when windows are closed After a window is closed we don't only have to update the texts of the action, but also update their visibility state and the checked item. Fixes: QTCREATORBUG-30381 Change-Id: Id0c343b8a5930ec2e3de03f71bdc8f2628b492b3 Reviewed-by: David Schulz Reviewed-by: Qt CI Bot --- src/plugins/coreplugin/windowsupport.cpp | 42 ++++++++++++++---------- src/plugins/coreplugin/windowsupport.h | 5 +-- 2 files changed, 27 insertions(+), 20 deletions(-) diff --git a/src/plugins/coreplugin/windowsupport.cpp b/src/plugins/coreplugin/windowsupport.cpp index 25ab34793c7..ad296e65819 100644 --- a/src/plugins/coreplugin/windowsupport.cpp +++ b/src/plugins/coreplugin/windowsupport.cpp @@ -15,8 +15,8 @@ #include #include +#include #include -#include #include #include #include @@ -106,11 +106,8 @@ bool WindowSupport::eventFilter(QObject *obj, QEvent *event) updateFullScreenAction(); } else if (event->type() == QEvent::WindowActivate) { m_windowList->setActiveWindow(m_window); - } else if (event->type() == QEvent::Hide) { - // minimized windows are hidden, but we still want to show them - m_windowList->setWindowVisible(m_window, m_window->isMinimized()); - } else if (event->type() == QEvent::Show) { - m_windowList->setWindowVisible(m_window, true); + } else if (event->type() == QEvent::Hide || event->type() == QEvent::Show) { + m_windowList->updateVisibility(m_window); } return false; } @@ -182,9 +179,9 @@ void WindowList::activateWindow(QAction *action) ICore::raiseWindow(m_windows.at(index)); } -void WindowList::updateTitle(QWidget *window) +void WindowList::updateTitle(QWidget *window, int i) { - int index = m_windows.indexOf(window); + const int index = i < 0 ? m_windows.indexOf(window) : i; QTC_ASSERT(index >= 0, return); QTC_ASSERT(index < m_windowActions.size(), return); QString title = window->windowTitle(); @@ -193,6 +190,19 @@ void WindowList::updateTitle(QWidget *window) m_windowActions.at(index)->setText(Utils::quoteAmpersands(title.trimmed())); } +void WindowList::updateVisibility(QWidget *window) +{ + updateVisibility(window, m_windows.indexOf(window)); +} + +void WindowList::updateVisibility(QWidget *window, int index) +{ + QTC_ASSERT(index >= 0, return); + QTC_ASSERT(index < m_windowActions.size(), return); + // minimized windows are hidden, but we still want to show them + m_windowActions.at(index)->setVisible(window->isVisible() || window->isMinimized()); +} + void WindowList::removeWindow(QWidget *window) { // remove window from list, @@ -207,8 +217,12 @@ void WindowList::removeWindow(QWidget *window) m_windows.removeOne(window); - for (int i = index; i < m_windows.size(); ++i) - updateTitle(m_windows.at(i)); + for (int i = index; i < m_windows.size(); ++i) { + QWidget *window = m_windows.at(i); + updateTitle(window, i); + updateVisibility(window, i); + } + setActiveWindow(QApplication::activeWindow()); } void WindowList::setActiveWindow(QWidget *window) @@ -217,13 +231,5 @@ void WindowList::setActiveWindow(QWidget *window) m_windowActions.at(i)->setChecked(m_windows.at(i) == window); } -void WindowList::setWindowVisible(QWidget *window, bool visible) -{ - int index = m_windows.indexOf(window); - QTC_ASSERT(index >= 0, return); - QTC_ASSERT(index < m_windowActions.size(), return); - m_windowActions.at(index)->setVisible(visible); -} - } // Internal } // Core diff --git a/src/plugins/coreplugin/windowsupport.h b/src/plugins/coreplugin/windowsupport.h index bfdc969ffb0..8b7eb026afd 100644 --- a/src/plugins/coreplugin/windowsupport.h +++ b/src/plugins/coreplugin/windowsupport.h @@ -24,11 +24,12 @@ public: void addWindow(QWidget *window); void removeWindow(QWidget *window); void setActiveWindow(QWidget *window); - void setWindowVisible(QWidget *window, bool visible); + void updateVisibility(QWidget *window); private: void activateWindow(QAction *action); - void updateTitle(QWidget *window); + void updateTitle(QWidget *window, int index = -1); + void updateVisibility(QWidget *window, int index); QMenu *m_dockMenu = nullptr; QList m_windows; From 8a6d94235bb90f8fdea760ce7e75023270658d59 Mon Sep 17 00:00:00 2001 From: Eike Ziller Date: Mon, 19 Feb 2024 09:47:06 +0100 Subject: [PATCH 067/243] Fix that window actions did not bring up minimized windows Selecting a window from the Window menu didn't bring up minimized windows from their minimized state, and resulted in two items being checked in the window list (because the active window did not change, so the checkmarks where not updated). Change-Id: Ie89b87fa1273378bb99f69026a58ee92ea0b8f50 Reviewed-by: Qt CI Bot Reviewed-by: David Schulz --- src/plugins/coreplugin/windowsupport.cpp | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/src/plugins/coreplugin/windowsupport.cpp b/src/plugins/coreplugin/windowsupport.cpp index ad296e65819..5c5cbbfe133 100644 --- a/src/plugins/coreplugin/windowsupport.cpp +++ b/src/plugins/coreplugin/windowsupport.cpp @@ -176,7 +176,10 @@ void WindowList::activateWindow(QAction *action) int index = m_windowActions.indexOf(action); QTC_ASSERT(index >= 0, return); QTC_ASSERT(index < m_windows.size(), return); - ICore::raiseWindow(m_windows.at(index)); + QWidget *window = m_windows.at(index); + if (window->isMinimized()) + window->setWindowState(window->windowState() & ~Qt::WindowMinimized); + ICore::raiseWindow(window); } void WindowList::updateTitle(QWidget *window, int i) From 76539a659e9cc10a6019b3f5d3a5851b761e58f5 Mon Sep 17 00:00:00 2001 From: Leena Miettinen Date: Thu, 15 Feb 2024 17:00:09 +0100 Subject: [PATCH 068/243] Doc: Update the IDE Overview Use sections instead of a table and move or copy text from other topics. This is to create a place for information that becomes homeless when I remove other topics. Task-number: QTCREATORBUG-29361 Change-Id: Ib3fcc2c345080e05f9f7ad4ed78e049c899e0855 Reviewed-by: Eike Ziller --- doc/qtcreator/images/heartgame-start.webp | Bin 0 -> 25644 bytes doc/qtcreator/images/qt-app-dev-flow.webp | Bin 0 -> 123844 bytes doc/qtcreator/images/qt-tools.webp | Bin 0 -> 53570 bytes .../creator-only/creator-debugger.qdoc | 12 - .../src/editors/creator-code-refactoring.qdoc | 14 - .../creator-only/creator-getting-started.qdoc | 4 +- .../creator-only/creator-overview.qdoc | 326 ++++++++++++------ .../creator-only/creator-testing.qdoc | 2 +- doc/qtcreator/src/qtcreator-toc.qdoc | 2 +- doc/qtcreator/src/qtcreator.qdoc | 2 +- 10 files changed, 216 insertions(+), 146 deletions(-) create mode 100644 doc/qtcreator/images/heartgame-start.webp create mode 100644 doc/qtcreator/images/qt-app-dev-flow.webp create mode 100644 doc/qtcreator/images/qt-tools.webp diff --git a/doc/qtcreator/images/heartgame-start.webp b/doc/qtcreator/images/heartgame-start.webp new file mode 100644 index 0000000000000000000000000000000000000000..9fef6fe00579fcc7917e8e3e7f5ef6c1628cf496 GIT binary patch literal 25644 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

~^I8!DQR-HzyyBy!YFHAOomyBoG5O}3) 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 literal 0 HcmV?d00001 diff --git a/doc/qtcreator/images/qt-app-dev-flow.webp b/doc/qtcreator/images/qt-app-dev-flow.webp new file mode 100644 index 0000000000000000000000000000000000000000..14be8fb3d70f5e2fc397f0eb5abdd4dd79667286 GIT binary patch literal 123844 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 Di@l9X literal 0 HcmV?d00001 diff --git a/doc/qtcreator/images/qt-tools.webp b/doc/qtcreator/images/qt-tools.webp new file mode 100644 index 0000000000000000000000000000000000000000..986846140fae6d8222333ba94d4b0abcbc52325c GIT binary patch literal 53570 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 literal 0 HcmV?d00001 diff --git a/doc/qtcreator/src/debugger/creator-only/creator-debugger.qdoc b/doc/qtcreator/src/debugger/creator-only/creator-debugger.qdoc index 0676655ec52..914ee674650 100644 --- a/doc/qtcreator/src/debugger/creator-only/creator-debugger.qdoc +++ b/doc/qtcreator/src/debugger/creator-only/creator-debugger.qdoc @@ -14,18 +14,6 @@ \title Debugging - A debugger lets you see what happens \e inside an application while it runs - or when it crashes. A debugger can do the following to help you find errors - in the application: - - \list - \li Start the application with parameters that specify its behavior. - \li Stop the application when conditions are met. - \li Examine what happens when the application stops. - \li Make changes in the application when you fix an error and continue - to find the next one. - \endlist - The \QC debugger plugin acts as an interface between the \QC core and external native debuggers that you can use to: diff --git a/doc/qtcreator/src/editors/creator-code-refactoring.qdoc b/doc/qtcreator/src/editors/creator-code-refactoring.qdoc index 285c36166bd..413ffe9ef54 100644 --- a/doc/qtcreator/src/editors/creator-code-refactoring.qdoc +++ b/doc/qtcreator/src/editors/creator-code-refactoring.qdoc @@ -8,20 +8,6 @@ \title Refactoring - \e {Code refactoring} is the process of improving and simplifying code - without modifying the existing functionality of an application. You - can easily find and rename symbols and apply predefined actions to - refactor code. - - Refactor code to: - - \list - \li Improve internal quality of your application - \li Improve performance and extensibility - \li Improve code readability and maintainability - \li Simplify code structure - \endlist - To quickly and conveniently apply actions to refactor your code, \l{Apply quick fixes}{select quick fixes in a context menu}. diff --git a/doc/qtcreator/src/overview/creator-only/creator-getting-started.qdoc b/doc/qtcreator/src/overview/creator-only/creator-getting-started.qdoc index 68ca9e4ef54..115e666d0b9 100644 --- a/doc/qtcreator/src/overview/creator-only/creator-getting-started.qdoc +++ b/doc/qtcreator/src/overview/creator-only/creator-getting-started.qdoc @@ -25,11 +25,11 @@ \li \inlineimage front-ui.png \li \inlineimage front-advanced.png \row - \li \b {\l{IDE Overview}} + \li \b {\l{Overview}} If you have not used an integrated development environment (IDE) before, or want to know what kind of IDE \QC is, go to - \l{IDE Overview}. + \l{Overview}. \li \b {\l{User Interface}} If you have not used \QC before, and want to become familiar diff --git a/doc/qtcreator/src/overview/creator-only/creator-overview.qdoc b/doc/qtcreator/src/overview/creator-only/creator-overview.qdoc index f951b4b52a7..eb0bcf8ec36 100644 --- a/doc/qtcreator/src/overview/creator-only/creator-overview.qdoc +++ b/doc/qtcreator/src/overview/creator-only/creator-overview.qdoc @@ -1,4 +1,4 @@ -// Copyright (C) 2023 The Qt Company Ltd. +// Copyright (C) 2024 The Qt Company Ltd. // SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GFDL-1.3-no-invariants-only // ********************************************************************** @@ -12,147 +12,243 @@ \page creator-overview.html \nextpage creator-quick-tour.html - \title IDE Overview + \title Overview - \QC is an integrated development environment (IDE) that has tools for - designing and developing applications with the Qt application framework. - With Qt you can develop applications and user interfaces once and deploy - them to several desktop, embedded, and mobile operating systems or - web browsers (experimental). \QC has the tools for accomplishing your tasks + \QC is a cross-platform, complete integrated development environment + (IDE) that you can use to create applications for desktop, embedded, + and mobile operating systems, or web browsers. + + With Qt, you can develop applications and user interfaces once and deploy + them to many platforms. \QC has the tools for accomplishing your tasks throughout the whole application development life-cycle, from creating a - project to deploying the application to the target platforms. + project, designing a UI, and writing code to building applications and + deploying them to the target platforms for running and debugging. - \table - \row - \li \inlineimage front-projects.png - \li \inlineimage front-ui.png - \li \inlineimage front-coding.png - \row - \li \b {Managing Projects} + \image qt-app-dev-flow.webp {Application development life-cycle} + \caption Application development life-cycle - To be able to build and run applications, \QC needs the same - information as a compiler would need. It stores the information - in the project settings. + \section1 Projects - You can share projects with other designers and developers across - different development platforms with a common tool for design, - development, and debugging. + First, you need a \e project. \QC relies on a separate build system, such as + CMake, qmake, or Qbs for building the project. From the build system, \QC + gets most of the information it needs to offer services for writing, editing, + and navigating source code, as well as to deploy and run applications. It + stores additional information in the project settings. - \list - \li \l{Creating Projects} + Share projects with other designers and developers across different + development platforms with a common tool for design, development, and + debugging. - To set up a project, you first have to decide what kind - of an application you want to develop: do you want a user - interface based on \l{User Interfaces} - {Qt Quick or Qt Widgets}. Second, you have to choose the - programming language to implement the application logic: - C++ or Python. - \li \l{Version Control Systems} + \list + \li \l{Creating Projects} - The recommended way to set up a project is to use a - version control system. Store and edit only project - source files and configuration files. Do not store - generated files. - \li \l{Configuring Projects} + To set up a project, you first have to decide what kind + of an application you want to develop: do you want a user + interface based on \l{User Interfaces} + {Qt Quick or Qt Widgets}. Second, you have to choose the + programming language to implement the application logic: + C++ or Python. + \li \l{Version Control Systems} - Installation programs and project wizards create default - configurations for \QC and your projects. You can change - the configurations in the \uicontrol Projects mode. - \endlist - For more information, see \l{Manage Projects} - {How To: Manage Projects}. - \li \b {Designing User Interfaces} + The recommended way to set up a project is to use a + version control system. Store and edit only project + source files and configuration files. Do not store + generated files. + \li \l{Configuring Projects} - To create intuitive, modern-looking, fluid user interfaces, you - can use \l{Qt Quick} and \l{Qt Design Studio Manual}{\QDS}: + Installation programs and project wizards create default + configurations for \QC and your projects. Change the + configurations in the \uicontrol Projects mode. + \endlist - \list - \li \l {\QMLD} + For more information, see \l{Manage Projects}{How To: Manage Projects}. - Or, you can enable the \QMLD plugin to visually edit - \l{UI Files}{UI files} (.ui.qml). - \li \l {Converting UI Projects to Applications} + \section1 User Interfaces - Qt Quick UI Prototype projects (.qmlproject) are useful - for creating user interfaces. To use them for application - development, you have to convert them to Qt Quick - Application projects that have project configuration - files (CMakeLists.txt or .pro), .cpp, and .qrc files. - \li \l {UI Files} + \image heartgame-start.webp {Heart Rate Game} - If you switch between \QC and \QDS or cooperate with - designers on a project, you might encounter .ui.qml files. - They are intended to be edited in \QDS only, so you need - to be careful not to break the code. To visually edit the - files in \QC, enable the \QMLD plugin. - \li \l{Using QML Modules with Plugins} + To create intuitive, modern-looking, fluid user interfaces, use \l{Qt Quick} + and \l{Qt Design Studio Manual}{\QDS}: - You can load C++ plugins for QML to simulate data. - \endlist + \list + \li \l {\QMLD} - If you need a traditional user interface that has a clear - structure and enforces a platform look and feel, use - \l{Qt Widgets} and the integrated \l{\QD}. + Or, enable the \QMLD plugin to visually edit \l{UI Files}{UI files} + (.ui.qml). + \li \l {Converting UI Projects to Applications} - For more information, see - \l{Design UIs}{How To: Design UIs}. - \li \b {\l{Coding}} + Qt Quick UI Prototype projects (.qmlproject) are useful + for creating user interfaces. To use them for application + development, you have to convert them to Qt Quick + Application projects that have project configuration + files (CMakeLists.txt or .pro), .cpp, and .qrc files. + \li \l {UI Files} - As an IDE, \QC differs from a text editor in that it knows how - to build and run applications. It understands the C++ and QML - languages as code, not just as plain text. Therefore, it can - offer useful features, such as semantic highlighting, - checking code syntax, code completion, and refactoring actions. - \QC supports some of these services also for other programming - languages, such as Python, for which a \e {language server} is - available that provides information about the code to IDEs. + If you switch between \QC and \QDS or cooperate with + designers on a project, you might encounter .ui.qml files. + They are intended to be edited in \QDS only, so you need + to be careful not to break the code. To visually edit the + files in \QC, enable the \QMLD plugin. + \li \l{Using QML Modules with Plugins} - For more information, see \l{Edit Code}{How To: Edit Code}. - \row - \li \inlineimage front-preview.png - \li \inlineimage front-testing.png - \li \inlineimage front-publishing.png - \row - \li \b {\l{Building and Running}} + Load C++ plugins for QML to simulate data. + \endlist - \QC integrates cross-platform systems for build - automation: qmake, Qbs, CMake, and Autotools. In addition, you - can import - projects as \e {generic projects} and fully control the steps - and commands used to build the project. + If you need a traditional user interface that has a clear structure and + enforces a platform look and feel, use \l{Qt Widgets} and the integrated + \l{\QD}. - You can build applications for, deploy them to, and run them on - the desktop environment or a \l{glossary-device}{device}. - \l{glossary-buildandrun-kit}{Kits}, build, run, and deployment - settings allow you to quickly switch between different setups and - target platforms. + For more information, see \l{Design UIs}{How To: Design UIs} and + \l{UI Design}. - For more information, see \l{Build and Run} - {How To: Build and Run}. - \li \b {\l{Testing}} + \section1 Code - \QC integrates several external native debuggers that you can use - to inspect the state of your application while debugging. + Writing, editing, and navigating in source code are core tasks in application + development. Therefore, the code editor is one of the key components of \QC. + Use the code editor in the \l {Edit Mode}{Edit mode}. - Devices have limited memory and CPU power, so you should use them - carefully. \QC integrates code analysis tools for detecting - memory leaks, profiling function execution, analyzing CPU use, - and eliminating unnecessary complexity of code. Other tools - provide code coverage and visualize trace events. + As an IDE, \QC differs from a text editor in that it knows how to build and + run applications. It understands the C++ and QML languages as code, not just + as plain text. Therefore, it can offer useful features, such as semantic + highlighting, checking code syntax, code completion, and refactoring actions. - \QC integrates several testing frameworks for unit testing - applications and libraries. You can use \QC to create, build, - and run autotests. + \QC supports some of these services also for other programming languages, + such as Python, for which a \e {language server} is available that provides + information about the code to IDEs. - For more information, see \l{Testing}. - \li \b {Publishing} + \section2 Find - \QC enables you to create installation packages for mobile - devices that you can publish to application stores - and other channels. You must make sure that the package contents - meet the requirements for publishing on the channel. + Use the incremental and advanced search to search in currently open projects + or files on the file system or use the locator to browse through projects, + files, classes, functions, documentation, and file systems. - For more information, see \l{Publishing to Google Play}. -\endtable + \section2 Refactor + \e {Code refactoring} is the process of improving and simplifying code + without modifying the existing functionality of an application. Find + and rename symbols and apply predefined actions to refactor code. + + Refactor code to: + + \list + \li Improve internal quality of your application + \li Improve performance and extensibility + \li Improve code readability and maintainability + \li Simplify code structure + \endlist + + \section2 Configure the Editor + + Configure the text editor to suit your specific needs. Change the fonts, + colors, highlighting, and indentation. + + If you are used to the Vim editor, run the main editor in the + \l {FakeVim Modes and Commands}{FakeVim mode}. + + For more information, see \l{Edit Code}{How To: Edit Code} and \l{Editors}. + + \section1 Build, Deploy, and Run + + Run and deploy Qt applications that you build for different target + platforms or with different compilers, debuggers, or Qt versions. + \l{glossary-buildandrun-kit}{Kits} define the tools, \l{glossary-device} + {device} type and other settings to use when building and running your + project. + + \QC integrates cross-platform systems for build automation: CMake, + qmake, Qbs, and Autotools. In addition, you can import projects as + \e {generic projects} and fully control the steps and commands to + build the project. + + Build applications for, deploy them to, and run them on the desktop + environment or a device. With kits, as well as build, run, and deployment + configurations, you can quickly switch between different setups and + target platforms. + + For more information, see \l{Build and Run}{How To: Build and Run}, + \l{Build Systems}, \l{Build Configurations}, and \l{Run Configurations}. + + \section2 On Devices + + When you install tool chains for device types as part of a Qt distribution, + the build and run configurations for the devices might be set up + automatically. However, you might need to install and configure some + additional software on the devices to be able to connect to them + from the computer. + + Deployment configurations handle the packaging and copying of the necessary + files to a location you want to run the executable at, such as the file + system of a device. + + For more information, see \l{Connecting Devices} and \l{Deploying to Devices}. + + \section2 Preview QML + + Use the QML live preview to preview a QML file or an entire Qt Quick + application on the desktop, as well as on Android and embedded Linux + devices. The changes you make to the UI are instantly visible to you + in the preview. + + For more information, see \l{Validating with Target Hardware}. + + \section1 Debug + + A debugger lets you see what happens \e inside an application while it runs + or when it crashes. A debugger can do the following to help you find errors + in the application: + + \list + \li Start the application with parameters that specify its behavior. + \li Stop the application when conditions are met. + \li Examine what happens when the application stops. + \li Make changes in the application when you fix an error and continue + to find the next one. + \endlist + + \QC integrates several external native debuggers for inspecting the state of + your application while debugging. The debugger plugin automatically selects + a suitable native debugger for each kit from the ones it finds on the + computer. Edit the kits to override this choice. + + Connect devices to your computer to debug processes running on the devices. + + For more information, see \l{Debugging}. + + \section1 Analyze + + Devices have limited memory and CPU power, so you should use them carefully. + \QC integrates code analysis tools for detecting memory leaks, profiling + function execution, analyzing CPU use, and eliminating unnecessary complexity + of code. Other tools provide code coverage and visualize trace events. + + Install and configure the tools on your system to use them from \QC. + However, the QML Profiler is installed as part of \QC for profiling + Qt Quick applications. + + For more information, see \l{Analyzing Code}. + + \section1 Autotest + + Create, build and run Qt tests, Qt Quick tests, Google tests, and Boost tests + to unit test applications and libraries. + + Map AUTs (Application Under Test) to \QC and run Squish test suites + and cases from it. + + For more information, see \l{Running Autotests} and \l{Using Squish}. + + \section1 Publish + + Create installation packages for mobile devices that you publish to + application stores and other channels. You must make sure that the + package contents meet the requirements for publishing on the channel. + + For more information, see \l{Publishing to Google Play}. + + \section1 Qt Tools + + \QC is one of many Qt tools for designing and developing applications. + + \image qt-tools.webp {Tools for Qt application development} + \caption Tools for Qt application development */ diff --git a/doc/qtcreator/src/overview/creator-only/creator-testing.qdoc b/doc/qtcreator/src/overview/creator-only/creator-testing.qdoc index ec77c0c54aa..26ef6701d69 100644 --- a/doc/qtcreator/src/overview/creator-only/creator-testing.qdoc +++ b/doc/qtcreator/src/overview/creator-only/creator-testing.qdoc @@ -20,7 +20,7 @@ \li \l{Debugging} - If you install \QC as part of \QSDK, the GNU Symbolic Debugger + If you install \QC with \QOI, the GNU Symbolic Debugger is installed automatically and you should be ready to start debugging after you create a new project. However, you can change the setup to use debugging tools for Windows, for diff --git a/doc/qtcreator/src/qtcreator-toc.qdoc b/doc/qtcreator/src/qtcreator-toc.qdoc index 9038a168073..933fadb3a0e 100644 --- a/doc/qtcreator/src/qtcreator-toc.qdoc +++ b/doc/qtcreator/src/qtcreator-toc.qdoc @@ -15,7 +15,7 @@ \list \li \l{Getting Started} \list - \li \l{IDE Overview} + \li \l{Overview} \list \li \l{Creating Projects} \li \l{Configuring Projects} diff --git a/doc/qtcreator/src/qtcreator.qdoc b/doc/qtcreator/src/qtcreator.qdoc index 85c60896ac7..eaceebf177d 100644 --- a/doc/qtcreator/src/qtcreator.qdoc +++ b/doc/qtcreator/src/qtcreator.qdoc @@ -41,7 +41,7 @@ \row \li \b {\l{Getting Started}} \list - \li \l{IDE Overview} + \li \l{Overview} \li \l{User Interface} \li \l{Configuring Qt Creator} \li \l{Building and Running an Example} From 5e2854e6858d7145de6e2f9cdf2586fbeb139093 Mon Sep 17 00:00:00 2001 From: Jarek Kobus Date: Mon, 19 Feb 2024 13:27:47 +0100 Subject: [PATCH 069/243] SemanticHighlighter: Don't delete the watcher from its signal handler Use std::unique_ptr instead, as QScopedPointer doesn't offer release(). Change-Id: I8e885e477d1aeb8ce9462e8fd249a5196424df18 Reviewed-by: Qt CI Bot Reviewed-by: Christian Kandeler --- src/plugins/cppeditor/semantichighlighter.cpp | 10 +++++----- src/plugins/cppeditor/semantichighlighter.h | 4 ++-- 2 files changed, 7 insertions(+), 7 deletions(-) diff --git a/src/plugins/cppeditor/semantichighlighter.cpp b/src/plugins/cppeditor/semantichighlighter.cpp index fe52bbdebd4..4cafaecd46f 100644 --- a/src/plugins/cppeditor/semantichighlighter.cpp +++ b/src/plugins/cppeditor/semantichighlighter.cpp @@ -232,25 +232,25 @@ void SemanticHighlighter::onHighlighterFinished() TextDocumentLayout::setParentheses(currentBlock, getClearedParentheses(currentBlock)); } - m_watcher.reset(); + m_watcher.release()->deleteLater(); qCDebug(log) << "onHighlighterFinished() took" << t.elapsed() << "ms"; } void SemanticHighlighter::connectWatcher() { using Watcher = QFutureWatcher; - connect(m_watcher.data(), &Watcher::resultsReadyAt, + connect(m_watcher.get(), &Watcher::resultsReadyAt, this, &SemanticHighlighter::onHighlighterResultAvailable); - connect(m_watcher.data(), &Watcher::finished, + connect(m_watcher.get(), &Watcher::finished, this, &SemanticHighlighter::onHighlighterFinished); } void SemanticHighlighter::disconnectWatcher() { using Watcher = QFutureWatcher; - disconnect(m_watcher.data(), &Watcher::resultsReadyAt, + disconnect(m_watcher.get(), &Watcher::resultsReadyAt, this, &SemanticHighlighter::onHighlighterResultAvailable); - disconnect(m_watcher.data(), &Watcher::finished, + disconnect(m_watcher.get(), &Watcher::finished, this, &SemanticHighlighter::onHighlighterFinished); } diff --git a/src/plugins/cppeditor/semantichighlighter.h b/src/plugins/cppeditor/semantichighlighter.h index ea49f289a01..a0d8e8db9ee 100644 --- a/src/plugins/cppeditor/semantichighlighter.h +++ b/src/plugins/cppeditor/semantichighlighter.h @@ -6,11 +6,11 @@ #include "cppeditor_global.h" #include -#include #include #include #include +#include #include namespace TextEditor { @@ -80,7 +80,7 @@ private: TextEditor::TextDocument *m_baseTextDocument; unsigned m_revision = 0; - QScopedPointer> m_watcher; + std::unique_ptr> m_watcher; QHash m_formatMap; std::set m_seenBlocks; int m_nextResultToHandle = 0; From 5b48d23a0ab8a75cd4edd159162e988466bdac75 Mon Sep 17 00:00:00 2001 From: Jarek Kobus Date: Sat, 17 Feb 2024 08:16:24 +0100 Subject: [PATCH 070/243] Axivion: Fix CredentialOperation::Get Don't report an error on non-existing key read. Finish with success and provide empty optional data in this case. Change-Id: I7c4ea50c0f05e13ce793384ec57d50dfff600c9a Reviewed-by: hjk --- src/plugins/axivion/credentialquery.cpp | 10 ++++++---- src/plugins/axivion/credentialquery.h | 4 ++-- 2 files changed, 8 insertions(+), 6 deletions(-) diff --git a/src/plugins/axivion/credentialquery.cpp b/src/plugins/axivion/credentialquery.cpp index 7393845819a..14aabc3958e 100644 --- a/src/plugins/axivion/credentialquery.cpp +++ b/src/plugins/axivion/credentialquery.cpp @@ -24,7 +24,8 @@ void CredentialQueryTaskAdapter::start() } case CredentialOperation::Set: { WritePasswordJob *writer = new WritePasswordJob(task()->m_service); - writer->setBinaryData(task()->m_data); + if (task()->m_data) + writer->setBinaryData(*task()->m_data); job = writer; break; } @@ -38,11 +39,12 @@ void CredentialQueryTaskAdapter::start() m_guard.reset(job); connect(job, &Job::finished, this, [this, reader](Job *job) { - if (job->error() != NoError) + const bool success = job->error() == NoError || job->error() == EntryNotFound; + if (!success) task()->m_errorString = job->errorString(); - else if (reader) + else if (reader && job->error() == NoError) task()->m_data = reader->binaryData(); - emit done(toDoneResult(job->error() == NoError)); + emit done(toDoneResult(success)); m_guard.release()->deleteLater(); }); job->start(); diff --git a/src/plugins/axivion/credentialquery.h b/src/plugins/axivion/credentialquery.h index 6440cd51043..6b23c5f4669 100644 --- a/src/plugins/axivion/credentialquery.h +++ b/src/plugins/axivion/credentialquery.h @@ -17,14 +17,14 @@ public: void setKey(const QString &key) { m_key = key; } void setData(const QByteArray &data) { m_data = data; } - QByteArray data() const { return m_data; } + std::optional data() const { return m_data; } QString errorString() const { return m_errorString; } private: CredentialOperation m_operation = CredentialOperation::Get; QString m_service; QString m_key; - QByteArray m_data; // Used for input when Set and for output when Get. + std::optional m_data; // Used for input when Set and for output when Get. QString m_errorString; friend class CredentialQueryTaskAdapter; }; From 35c49afae2e0a1120a6d098e48a00130a74940dc Mon Sep 17 00:00:00 2001 From: Jarek Kobus Date: Sun, 11 Feb 2024 18:22:39 +0100 Subject: [PATCH 071/243] Axivion: Implement ApiToken querying and storing The ApiToken is stored locally safely by using QKeychain lib. If the local store doesn't contain the ApiToken, we show the password input dialog to the user. If the user pressed OK, we send a network query to axivion server to retrieve the ApiToken for the username + password. Change-Id: I0dc19aea67750cd674ae4db9a9f469e4621c713b Reviewed-by: hjk --- src/plugins/axivion/axivionplugin.cpp | 177 +++++++++++++++++++++----- 1 file changed, 148 insertions(+), 29 deletions(-) diff --git a/src/plugins/axivion/axivionplugin.cpp b/src/plugins/axivion/axivionplugin.cpp index 9b333af7c3e..9891bdc3c65 100644 --- a/src/plugins/axivion/axivionplugin.cpp +++ b/src/plugins/axivion/axivionplugin.cpp @@ -7,6 +7,7 @@ #include "axivionprojectsettings.h" #include "axivionsettings.h" #include "axiviontr.h" +#include "credentialquery.h" #include "dashboard/dto.h" #include "dashboard/error.h" @@ -31,11 +32,13 @@ #include #include +#include #include #include #include #include +#include #include #include #include @@ -43,7 +46,8 @@ #include -constexpr char AxivionTextMarkId[] = "AxivionTextMark"; +constexpr char s_axivionTextMarkId[] = "AxivionTextMark"; +constexpr char s_axivionKeychainService[] = "keychain.axivion.qtcreator"; using namespace Core; using namespace ProjectExplorer; @@ -96,6 +100,42 @@ QString anyToSimpleString(const Dto::Any &any) return {}; } +static QString apiTokenDescription() +{ + const QString ua = "Axivion" + QCoreApplication::applicationName() + "Plugin/" + + QCoreApplication::applicationVersion(); + QString user = Utils::qtcEnvironmentVariable("USERNAME"); + if (user.isEmpty()) + user = Utils::qtcEnvironmentVariable("USER"); + return "Automatically created by " + ua + " on " + user + "@" + QSysInfo::machineHostName(); +} + +static QString credentialKey() +{ + const auto escape = [](const QString &string) { + QString escaped = string; + return escaped.replace('\\', "\\\\").replace('@', "\\@"); + }; + return escape(settings().server.dashboard) + '@' + escape(settings().server.username); +} + +static DashboardInfo toDashboardInfo(const QUrl &source, const Dto::DashboardInfoDto &infoDto) +{ + const QVersionNumber versionNumber = infoDto.dashboardVersionNumber + ? QVersionNumber::fromString(*infoDto.dashboardVersionNumber) : QVersionNumber(); + + QStringList projects; + QHash projectUrls; + + if (infoDto.projects) { + for (const Dto::ProjectReferenceDto &project : *infoDto.projects) { + projects.push_back(project.name); + projectUrls.insert(project.name, project.url); + } + } + return {source, versionNumber, projects, projectUrls, infoDto.checkCredentialsUrl}; +} + QString IssueListSearch::toQuery() const { if (kind.isEmpty()) @@ -142,6 +182,7 @@ public: void handleIssuesForFile(const Dto::FileViewDto &fileView); void fetchIssueInfo(const QString &id); + std::optional m_apiToken; // TODO: Should be cleared on settings modification NetworkAccessManager m_networkAccessManager; AxivionOutputPane m_axivionOutputPane; std::optional m_dashboardInfo; @@ -159,7 +200,7 @@ class AxivionTextMark : public TextMark { public: AxivionTextMark(const FilePath &filePath, const Dto::LineMarkerDto &issue) - : TextMark(filePath, issue.startLine, {Tr::tr("Axivion"), AxivionTextMarkId}) + : TextMark(filePath, issue.startLine, {Tr::tr("Axivion"), s_axivionTextMarkId}) { const QString markText = issue.description; const QString id = issue.kind + QString::number(issue.id.value_or(-1)); @@ -278,6 +319,7 @@ static Group fetchHtmlRecipe(const QUrl &url, const std::function storage; + // TODO: Refactor so that it's a common code with fetchDataRecipe(). const auto onCredentialSetup = [storage] { storage->credentials = QByteArrayLiteral("AxToken ") + settings().server.token.toUtf8(); }; @@ -383,15 +425,23 @@ static Group getDtoRecipe(const Storage> &dtoStorage) const auto onDeserializeSetup = [storage](Async &task) { const auto deserialize = [](QPromise &promise, const QByteArray &input) { - promise.addResult(DtoType::deserialize(input)); + try { + promise.addResult(DtoType::deserialize(input)); + } catch (const Dto::invalid_dto_exception &) { + promise.future().cancel(); + } }; task.setFutureSynchronizer(ExtensionSystem::PluginManager::futureSynchronizer()); task.setConcurrentCallData(deserialize, *storage); }; const auto onDeserializeDone = [dtoStorage](const Async &task, DoneWith doneWith) { - if (doneWith == DoneWith::Success) - dtoStorage->dtoData = task.future().result(); + if (doneWith == DoneWith::Success && task.isResultAvailable()) { + dtoStorage->dtoData = task.result(); + } else { + MessageManager::writeFlashing(QString("Axivion: %1") + .arg(Tr::tr("Deserialization of an unexpected Dto structure."))); + } }; const Group recipe { @@ -424,6 +474,7 @@ static Group postDtoRecipe(const Storage> &dtoStorage) const QByteArray ua = "Axivion" + QCoreApplication::applicationName().toUtf8() + "Plugin/" + QCoreApplication::applicationVersion().toUtf8(); request.setRawHeader("X-Axivion-User-Agent", ua); + request.setRawHeader("Content-Type", "application/json"); request.setRawHeader("AX-CSRF-Token", dtoStorage->csrfToken); query.setRequest(request); query.setWriteData(dtoStorage->writeData); @@ -493,47 +544,115 @@ static Group postDtoRecipe(const Storage> &dtoStorage) template static Group fetchDataRecipe(const QUrl &url, const std::function &handler) { + const Storage passwordStorage; + const Storage> dashboardStorage; + const Storage> apiTokenStorage; const Storage> dtoStorage; - const auto onCredentialSetup = [dtoStorage, url] { - dtoStorage->credential = QByteArrayLiteral("AxToken ") + settings().server.token.toUtf8(); - dtoStorage->url = url; + const auto onGetCredentialSetup = [](CredentialQuery &credential) { + credential.setOperation(CredentialOperation::Get); + credential.setService(s_axivionKeychainService); + credential.setKey(credentialKey()); + }; + const auto onGetCredentialDone = [](const CredentialQuery &credential, DoneWith result) { + if (result == DoneWith::Success) + dd->m_apiToken = credential.data(); + // TODO: Show the message about keystore error and info that we can't authorize without it. + }; + const auto onDashboardGroupSetup = [passwordStorage, dashboardStorage] { + if (dd->m_apiToken) + return SetupResult::StopWithSuccess; + + bool ok = false; + const QString text(Tr::tr("Enter the password for:\nDashboard: %1\nUser: %2") + .arg(settings().server.dashboard, settings().server.username)); + *passwordStorage = QInputDialog::getText(ICore::mainWindow(), + Tr::tr("Axivion Server Password"), text, QLineEdit::Password, {}, &ok); + if (!ok) + return SetupResult::StopWithError; + + const QString credential = settings().server.username + ':' + *passwordStorage; + dashboardStorage->credential = "Basic " + credential.toUtf8().toBase64(); + dashboardStorage->url = QUrl(settings().server.dashboard); + return SetupResult::Continue; }; + const auto onApiTokenGroupSetup = [passwordStorage, dashboardStorage, apiTokenStorage] { + if (!dashboardStorage->dtoData) + return SetupResult::StopWithSuccess; + + dd->m_dashboardInfo = toDashboardInfo(settings().server.dashboard, + *dashboardStorage->dtoData); + + const Dto::DashboardInfoDto &dashboardDto = *dashboardStorage->dtoData; + if (!dashboardDto.userApiTokenUrl) + return SetupResult::StopWithError; + + apiTokenStorage->credential = dashboardStorage->credential; + apiTokenStorage->url + = QUrl(settings().server.dashboard).resolved(*dashboardDto.userApiTokenUrl); + apiTokenStorage->csrfToken = dashboardDto.csrfToken.toUtf8(); + const Dto::ApiTokenCreationRequestDto requestDto{*passwordStorage, "IdePlugin", + apiTokenDescription(), 0}; + apiTokenStorage->writeData = requestDto.serialize(); + return SetupResult::Continue; + }; + + const auto onSetCredentialSetup = [apiTokenStorage](CredentialQuery &credential) { + if (!apiTokenStorage->dtoData || !apiTokenStorage->dtoData->token) + return SetupResult::StopWithSuccess; + + dd->m_apiToken = apiTokenStorage->dtoData->token->toUtf8(); + credential.setOperation(CredentialOperation::Set); + credential.setService(s_axivionKeychainService); + credential.setKey(credentialKey()); + credential.setData(*dd->m_apiToken); + return SetupResult::Continue; + }; + + const auto onDtoSetup = [dtoStorage, url] { + if (!dd->m_apiToken) + return SetupResult::StopWithError; + + dtoStorage->credential = "AxToken " + *dd->m_apiToken; + dtoStorage->url = url; + return SetupResult::Continue; + }; const auto onDtoDone = [dtoStorage, handler] { if (dtoStorage->dtoData) handler(*dtoStorage->dtoData); }; const Group recipe { - dtoStorage, - Sync(onCredentialSetup), Group { + LoopUntil([](int) { return !dd->m_apiToken; }), + CredentialQueryTask(onGetCredentialSetup, onGetCredentialDone), + Group { + passwordStorage, + dashboardStorage, + onGroupSetup(onDashboardGroupSetup), + Group { // GET DashboardInfoDto + finishAllAndSuccess, + getDtoRecipe(dashboardStorage), + }, + Group { // POST ApiTokenCreationRequestDto, GET ApiTokenInfoDto. + apiTokenStorage, + onGroupSetup(onApiTokenGroupSetup), + postDtoRecipe(apiTokenStorage), + CredentialQueryTask(onSetCredentialSetup) + } + } + }, + Group { + dtoStorage, + onGroupSetup(onDtoSetup), getDtoRecipe(dtoStorage), onGroupDone(onDtoDone) } }; - return recipe; } -static DashboardInfo toDashboardInfo(const QUrl &source, const Dto::DashboardInfoDto &infoDto) -{ - const QVersionNumber versionNumber = infoDto.dashboardVersionNumber - ? QVersionNumber::fromString(*infoDto.dashboardVersionNumber) : QVersionNumber(); - - QStringList projects; - QHash projectUrls; - - if (infoDto.projects) { - for (const Dto::ProjectReferenceDto &project : *infoDto.projects) { - projects.push_back(project.name); - projectUrls.insert(project.name, project.url); - } - } - return {source, versionNumber, projects, projectUrls, infoDto.checkCredentialsUrl}; -} - Group dashboardInfoRecipe(const DashboardInfoHandler &handler) { const auto onSetup = [handler] { @@ -718,7 +837,7 @@ void AxivionPluginPrivate::onDocumentClosed(IDocument *doc) const TextMarks &marks = document->marks(); for (TextMark *mark : marks) { - if (mark->category().id == AxivionTextMarkId) + if (mark->category().id == s_axivionTextMarkId) delete mark; } } From f790e337bafc86adcf9df82895db2baf8444179a Mon Sep 17 00:00:00 2001 From: Jarek Kobus Date: Fri, 16 Feb 2024 15:22:41 +0100 Subject: [PATCH 072/243] Axivion: Isolate authorization recipe It's going to be used in other recipes. Change-Id: I314f97cc596ce158b7d20e3bb963ca4e35bcb818 Reviewed-by: hjk --- src/plugins/axivion/axivionplugin.cpp | 45 ++++++++++++++++----------- 1 file changed, 27 insertions(+), 18 deletions(-) diff --git a/src/plugins/axivion/axivionplugin.cpp b/src/plugins/axivion/axivionplugin.cpp index 9891bdc3c65..32b356847a8 100644 --- a/src/plugins/axivion/axivionplugin.cpp +++ b/src/plugins/axivion/axivionplugin.cpp @@ -541,13 +541,11 @@ static Group postDtoRecipe(const Storage> &dtoStorage) return recipe; }; -template -static Group fetchDataRecipe(const QUrl &url, const std::function &handler) +static Group authorizationRecipe() { const Storage passwordStorage; const Storage> dashboardStorage; const Storage> apiTokenStorage; - const Storage> dtoStorage; const auto onGetCredentialSetup = [](CredentialQuery &credential) { credential.setOperation(CredentialOperation::Get); @@ -610,20 +608,8 @@ static Group fetchDataRecipe(const QUrl &url, const std::functionm_apiToken) - return SetupResult::StopWithError; - - dtoStorage->credential = "AxToken " + *dd->m_apiToken; - dtoStorage->url = url; - return SetupResult::Continue; - }; - const auto onDtoDone = [dtoStorage, handler] { - if (dtoStorage->dtoData) - handler(*dtoStorage->dtoData); - }; - - const Group recipe { + return { + // TODO: Try unauthorized access first Group { LoopUntil([](int) { return !dd->m_apiToken; }), CredentialQueryTask(onGetCredentialSetup, onGetCredentialDone), @@ -642,7 +628,30 @@ static Group fetchDataRecipe(const QUrl &url, const std::function +static Group fetchDataRecipe(const QUrl &url, const std::function &handler) +{ + const Storage> dtoStorage; + + const auto onDtoSetup = [dtoStorage, url] { + if (!dd->m_apiToken) + return SetupResult::StopWithError; + + dtoStorage->credential = "AxToken " + *dd->m_apiToken; + dtoStorage->url = url; + return SetupResult::Continue; + }; + const auto onDtoDone = [dtoStorage, handler] { + if (dtoStorage->dtoData) + handler(*dtoStorage->dtoData); + }; + + const Group recipe { + authorizationRecipe(), Group { dtoStorage, onGroupSetup(onDtoSetup), From b508d2e959c6348767518b71e7447ad610b15fb9 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Robert=20L=C3=B6hning?= Date: Thu, 15 Feb 2024 23:03:04 +0100 Subject: [PATCH 073/243] SquishTests: Remove one iteration loop Qt Quick Application projects only allow CMake. Change-Id: I27ee545a572eadcf98e1ec8188a0d77a9872aa14 Reviewed-by: Reviewed-by: Jukka Nokso Reviewed-by: Christian Stenger --- .../tst_save_before_build/test.py | 69 ++++++++----------- 1 file changed, 30 insertions(+), 39 deletions(-) diff --git a/tests/system/suite_general/tst_save_before_build/test.py b/tests/system/suite_general/tst_save_before_build/test.py index 87c2d56d39a..0f5c1971433 100644 --- a/tests/system/suite_general/tst_save_before_build/test.py +++ b/tests/system/suite_general/tst_save_before_build/test.py @@ -29,44 +29,35 @@ def main(): if not startedWithoutPluginError(): return verifySaveBeforeBuildChecked(False) - for buildSystem in ["CMake"]: - projectName = "SampleApp-" + buildSystem - ensureSaveBeforeBuildChecked(False) - # create qt quick application - createNewQtQuickApplication(tempDir(), projectName, buildSystem=buildSystem) - lineForIteration = 1 # qbs project file holds line number of definition start - for expectDialog in [True, False]: - verifySaveBeforeBuildChecked(not expectDialog) - if buildSystem == "CMake": - files = ["%s.CMakeLists\\.txt" % projectName, - "%s.app%s.Source Files.main\\.cpp" % (projectName, projectName), - "%s.app%s.Main\\.qml" % (projectName, projectName)] - elif buildSystem == "Qbs": - lineForIteration += 1 # after opening the file we'll add a newline - lowerPN = projectName.lower() - files = ["%s.%s\\.qbs:%d" % (lowerPN, lowerPN, lineForIteration), - "%s.%s.main\\.cpp" % (lowerPN, lowerPN), - "%s.%s.Group 1.Main\\.qml" % (lowerPN, lowerPN)] - for i, file in enumerate(files): - if not openDocument(file): - test.fatal("Could not open file '%s'" % simpleFileName(file)) - continue + projectName = "SampleApp-CMake" + ensureSaveBeforeBuildChecked(False) + # create qt quick application + createNewQtQuickApplication(tempDir(), projectName) + for expectDialog in [True, False]: + verifySaveBeforeBuildChecked(not expectDialog) + files = ["%s.CMakeLists\\.txt" % projectName, + "%s.app%s.Source Files.main\\.cpp" % (projectName, projectName), + "%s.app%s.Main\\.qml" % (projectName, projectName)] + for i, file in enumerate(files): + if not openDocument(file): + test.fatal("Could not open file '%s'" % simpleFileName(file)) + continue - matching = re.match("^(.+)(:\\d+)", file) - if matching is not None: - file = matching.group(1) - test.log("Changing file '%s'" % simpleFileName(file)) - typeLines(getEditorForFileSuffix(file, True), "") - # try to compile - clickButton(waitForObject(":*Qt Creator.Build Project_Core::Internal::FancyToolButton")) - try: - ensureChecked(":Save Changes.Always save files before build_QCheckBox", - i == len(files) - 1, 5000) # At the last iteration, check the box - clickButton(waitForObject(":Save Changes.Save All_QPushButton")) - test.verify(expectDialog, "The 'Save Changes' dialog was shown.") - except: - test.verify(not expectDialog, "The 'Save Changes' dialog was not shown.") - waitForCompile() - verifySaveBeforeBuildChecked(True) - invokeMenuItem("File", "Close All Projects and Editors") + matching = re.match("^(.+)(:\\d+)", file) + if matching is not None: + file = matching.group(1) + test.log("Changing file '%s'" % simpleFileName(file)) + typeLines(getEditorForFileSuffix(file, True), "") + # try to compile + clickButton(waitForObject(":*Qt Creator.Build Project_Core::Internal::FancyToolButton")) + try: + ensureChecked(":Save Changes.Always save files before build_QCheckBox", + i == len(files) - 1, 5000) # At the last iteration, check the box + clickButton(waitForObject(":Save Changes.Save All_QPushButton")) + test.verify(expectDialog, "The 'Save Changes' dialog was shown.") + except: + test.verify(not expectDialog, "The 'Save Changes' dialog was not shown.") + waitForCompile() + verifySaveBeforeBuildChecked(True) + invokeMenuItem("File", "Close All Projects and Editors") invokeMenuItem("File", "Exit") From 84f4fb081878a173759bfd6a73415c5b2f4ceb36 Mon Sep 17 00:00:00 2001 From: Michael Weghorn Date: Fri, 16 Feb 2024 15:23:41 +0100 Subject: [PATCH 074/243] Debugger: Fix building custom allocator dumper tests for MSVC 3b5c377ce5d19531b15eb3969ee43620da77ca7f had fixed them for GCC >= 13, but unfortunately made them no longer compile on Windows with MSVC as reported in the Gerrit change, error below. Align the implementation of the custom allocator more with the "23_containers/vector/52591.cc" [1] ones referred to in the GCC commit [2], in particular define ctors, so this compiles with both GCC on Linux and MSVC on Windows. Move the definition of that custom allocator to a new macro "MY_ALLOCATOR" to avoid duplication. Previous error with MSVC: C:\Program Files\Microsoft Visual Studio\2022\Preview\VC\Tools\MSVC\14.38.33130\include\xstring(3141): error C2440: 'static_cast': cannot convert from 'myallocator' to 'myallocator<_Tp1>' with [ _Tp1=std::_Container_proxy ] C:\Program Files\Microsoft Visual Studio\2022\Preview\VC\Tools\MSVC\14.38.33130\include\xstring(3141): note: 'myallocator<_Tp1>::myallocator': no overloaded function could convert all the argument types with [ _Tp1=std::_Container_proxy ] C:\Users\davschul\Downloads\Archive\main.cpp(8): note: could be 'myallocator<_Tp1>::myallocator(myallocator<_Tp1> &&)' with [ _Tp1=std::_Container_proxy ] C:\Program Files\Microsoft Visual Studio\2022\Preview\VC\Tools\MSVC\14.38.33130\include\xstring(3141): note: 'myallocator<_Tp1>::myallocator(myallocator<_Tp1> &&)': cannot convert argument 1 from 'myallocator' to 'myallocator<_Tp1> &&' with [ _Tp1=std::_Container_proxy ] C:\Program Files\Microsoft Visual Studio\2022\Preview\VC\Tools\MSVC\14.38.33130\include\xstring(3141): note: Reason: cannot convert from 'myallocator' to 'myallocator<_Tp1>' with [ _Tp1=std::_Container_proxy ] C:\Program Files\Microsoft Visual Studio\2022\Preview\VC\Tools\MSVC\14.38.33130\include\xstring(3141): note: No user-defined-conversion operator available that can perform this conversion, or the operator cannot be called C:\Users\davschul\Downloads\Archive\main.cpp(8): note: or 'myallocator<_Tp1>::myallocator(const myallocator<_Tp1> &)' with [ _Tp1=std::_Container_proxy ] C:\Program Files\Microsoft Visual Studio\2022\Preview\VC\Tools\MSVC\14.38.33130\include\xstring(3141): note: 'myallocator<_Tp1>::myallocator(const myallocator<_Tp1> &)': cannot convert argument 1 from 'myallocator' to 'const myallocator<_Tp1> &' with [ _Tp1=std::_Container_proxy ] C:\Program Files\Microsoft Visual Studio\2022\Preview\VC\Tools\MSVC\14.38.33130\include\xstring(3141): note: Reason: cannot convert from 'myallocator' to 'const myallocator<_Tp1>' with [ _Tp1=std::_Container_proxy ] [1] https://gcc.gnu.org/git/?p=gcc.git;a=blob;f=libstdc%2B%2B-v3/testsuite/23_containers/vector/52591.cc;h=ea80bb277c1f49190ae21b64e738428066eba1e0;hb=64c986b49558a7 [2] https://gcc.gnu.org/git/?p=gcc.git;a=commit;h=64c986b49558a7 Change-Id: I13a3ed226a411479ea1d24a2eda490c8f293bf8f Reviewed-by: David Schulz --- tests/auto/debugger/tst_dumpers.cpp | 26 +++++++++++--------------- 1 file changed, 11 insertions(+), 15 deletions(-) diff --git a/tests/auto/debugger/tst_dumpers.cpp b/tests/auto/debugger/tst_dumpers.cpp index 1cf8f1bbf2f..3f3c1daabaf 100644 --- a/tests/auto/debugger/tst_dumpers.cpp +++ b/tests/auto/debugger/tst_dumpers.cpp @@ -41,6 +41,15 @@ enum class Language Fortran90 }; +// for tests using custom allocator +#define MY_ALLOCATOR \ + "template\n" \ + "struct myallocator : public std::allocator {\n" \ + "template struct rebind { typedef myallocator other; };\n" \ + "myallocator() = default;\n" \ + "template myallocator(const myallocator&) {}\n" \ + "};\n" + // Copied from msvctoolchain.cpp to avoid plugin dependency. static bool generateEnvironmentSettings(Utils::Environment &env, const QString &batchFile, @@ -5263,13 +5272,7 @@ void tst_Dumpers::dumper_data() QTest::newRow("StdBasicString") << Data("#include \n" - "template\n" - "class myallocator : public std::allocator {\n" - "template\n" - "struct rebind {\n" - "typedef myallocator<_Tp1> other;\n" - "};\n" - "};\n", + MY_ALLOCATOR, "std::basic_string, myallocator> str(\"hello\");", @@ -5432,14 +5435,7 @@ void tst_Dumpers::dumper_data() QTest::newRow("StdVector") << Data("#include \n" "#include \n" - "template\n" - "class myallocator : public std::allocator {\n" - "using std::allocator::allocator;\n" - "template\n" - "struct rebind {\n" - "typedef myallocator<_Tp1> other;\n" - "};\n" - "};\n", + MY_ALLOCATOR, "std::vector v0, v1;\n" "v1.push_back(1);\n" From bc63b678bdc3e80b9d9e95d71e3f519ac522cb8d Mon Sep 17 00:00:00 2001 From: Jarek Kobus Date: Fri, 16 Feb 2024 16:17:27 +0100 Subject: [PATCH 075/243] Axivion: Implement trial connection with no authentication Introduce ServerAccess enum indicating the authentication method. Change-Id: Ic67bbf94504ec317cb6bf819cbc9dba34a01419c Reviewed-by: hjk --- src/plugins/axivion/axivionplugin.cpp | 54 ++++++++++++++++++++++----- 1 file changed, 44 insertions(+), 10 deletions(-) diff --git a/src/plugins/axivion/axivionplugin.cpp b/src/plugins/axivion/axivionplugin.cpp index 32b356847a8..90c02ccead5 100644 --- a/src/plugins/axivion/axivionplugin.cpp +++ b/src/plugins/axivion/axivionplugin.cpp @@ -168,6 +168,8 @@ QString IssueListSearch::toQuery() const return result; } +enum class ServerAccess { Unknown, NoAuthorization, WithAuthorization }; + class AxivionPluginPrivate : public QObject { public: @@ -182,7 +184,10 @@ public: void handleIssuesForFile(const Dto::FileViewDto &fileView); void fetchIssueInfo(const QString &id); - std::optional m_apiToken; // TODO: Should be cleared on settings modification + // TODO: Should be set to Unknown on server address change in settings. + ServerAccess m_serverAccess = ServerAccess::Unknown; + // TODO: Should be cleared on username change in settings. + std::optional m_apiToken; NetworkAccessManager m_networkAccessManager; AxivionOutputPane m_axivionOutputPane; std::optional m_dashboardInfo; @@ -364,8 +369,8 @@ static Group fetchHtmlRecipe(const QUrl &url, const std::function struct GetDtoStorage { - QByteArray credential; QUrl url; + std::optional credential; std::optional dtoData; }; @@ -377,7 +382,8 @@ static Group getDtoRecipe(const Storage> &dtoStorage) const auto onNetworkQuerySetup = [dtoStorage](NetworkQuery &query) { QNetworkRequest request(dtoStorage->url); request.setRawHeader("Accept", s_jsonContentType); - request.setRawHeader("Authorization", dtoStorage->credential); + if (dtoStorage->credential) // Unauthorized access otherwise + request.setRawHeader("Authorization", *dtoStorage->credential); const QByteArray ua = "Axivion" + QCoreApplication::applicationName().toUtf8() + "Plugin/" + QCoreApplication::applicationVersion().toUtf8(); request.setRawHeader("X-Axivion-User-Agent", ua); @@ -455,8 +461,8 @@ static Group getDtoRecipe(const Storage> &dtoStorage) template struct PostDtoStorage { - QByteArray credential; QUrl url; + std::optional credential; QByteArray csrfToken; QByteArray writeData; std::optional dtoData; @@ -470,7 +476,8 @@ static Group postDtoRecipe(const Storage> &dtoStorage) const auto onNetworkQuerySetup = [dtoStorage](NetworkQuery &query) { QNetworkRequest request(dtoStorage->url); request.setRawHeader("Accept", s_jsonContentType); - request.setRawHeader("Authorization", dtoStorage->credential); + if (dtoStorage->credential) // Unauthorized access otherwise + request.setRawHeader("Authorization", *dtoStorage->credential); const QByteArray ua = "Axivion" + QCoreApplication::applicationName().toUtf8() + "Plugin/" + QCoreApplication::applicationVersion().toUtf8(); request.setRawHeader("X-Axivion-User-Agent", ua); @@ -543,10 +550,28 @@ static Group postDtoRecipe(const Storage> &dtoStorage) static Group authorizationRecipe() { - const Storage passwordStorage; - const Storage> dashboardStorage; - const Storage> apiTokenStorage; + const Storage> unauthorizedDashboardStorage; + const auto onUnauthorizedGroupSetup = [unauthorizedDashboardStorage] { + if (dd->m_serverAccess != ServerAccess::NoAuthorization) + return SetupResult::StopWithSuccess; + unauthorizedDashboardStorage->url = QUrl(settings().server.dashboard); + return SetupResult::Continue; + }; + const auto onUnauthorizedGroupDone = [unauthorizedDashboardStorage] { + if (unauthorizedDashboardStorage->dtoData) { + dd->m_serverAccess = ServerAccess::NoAuthorization; + dd->m_dashboardInfo = toDashboardInfo(settings().server.dashboard, + *unauthorizedDashboardStorage->dtoData); + } else { + dd->m_serverAccess = ServerAccess::WithAuthorization; + } + return DoneResult::Success; + }; + + const auto onCredentialLoopCondition = [](int) { + return dd->m_serverAccess == ServerAccess::WithAuthorization && !dd->m_apiToken; + }; const auto onGetCredentialSetup = [](CredentialQuery &credential) { credential.setOperation(CredentialOperation::Get); credential.setService(s_axivionKeychainService); @@ -557,6 +582,9 @@ static Group authorizationRecipe() dd->m_apiToken = credential.data(); // TODO: Show the message about keystore error and info that we can't authorize without it. }; + + const Storage passwordStorage; + const Storage> dashboardStorage; const auto onDashboardGroupSetup = [passwordStorage, dashboardStorage] { if (dd->m_apiToken) return SetupResult::StopWithSuccess; @@ -575,6 +603,7 @@ static Group authorizationRecipe() return SetupResult::Continue; }; + const Storage> apiTokenStorage; const auto onApiTokenGroupSetup = [passwordStorage, dashboardStorage, apiTokenStorage] { if (!dashboardStorage->dtoData) return SetupResult::StopWithSuccess; @@ -609,9 +638,14 @@ static Group authorizationRecipe() }; return { - // TODO: Try unauthorized access first Group { - LoopUntil([](int) { return !dd->m_apiToken; }), + unauthorizedDashboardStorage, + onGroupSetup(onUnauthorizedGroupSetup), + getDtoRecipe(unauthorizedDashboardStorage), + onGroupDone(onUnauthorizedGroupDone) + }, + Group { + LoopUntil(onCredentialLoopCondition), CredentialQueryTask(onGetCredentialSetup, onGetCredentialDone), Group { passwordStorage, From ae20f9494988a75057358bf6bf1c51a589878b03 Mon Sep 17 00:00:00 2001 From: Jarek Kobus Date: Thu, 15 Feb 2024 00:08:16 +0100 Subject: [PATCH 076/243] Axivion: Reuse AxivionPluginPrivate::m_apiToken field in fetchHtmlRecipe Change-Id: I6bb37678000ba755d65b0275c4350815a9047880 Reviewed-by: Reviewed-by: hjk --- src/plugins/axivion/axivionplugin.cpp | 28 +++++++-------------------- 1 file changed, 7 insertions(+), 21 deletions(-) diff --git a/src/plugins/axivion/axivionplugin.cpp b/src/plugins/axivion/axivionplugin.cpp index 90c02ccead5..8060c7b7535 100644 --- a/src/plugins/axivion/axivionplugin.cpp +++ b/src/plugins/axivion/axivionplugin.cpp @@ -317,29 +317,22 @@ constexpr char s_jsonContentType[] = "application/json"; static Group fetchHtmlRecipe(const QUrl &url, const std::function &handler) { - struct StorageData - { - QByteArray credentials; - }; - - const Storage storage; - // TODO: Refactor so that it's a common code with fetchDataRecipe(). - const auto onCredentialSetup = [storage] { - storage->credentials = QByteArrayLiteral("AxToken ") + settings().server.token.toUtf8(); - }; + const auto onQuerySetup = [url](NetworkQuery &query) { + if (dd->m_serverAccess == ServerAccess::Unknown) + return SetupResult::StopWithError; // TODO: start authorizationRecipe()? - const auto onQuerySetup = [storage, url](NetworkQuery &query) { QNetworkRequest request(url); request.setRawHeader("Accept", s_htmlContentType); - request.setRawHeader("Authorization", storage->credentials); + if (dd->m_serverAccess == ServerAccess::WithAuthorization && dd->m_apiToken) + request.setRawHeader("Authorization", "AxToken " + *dd->m_apiToken); const QByteArray ua = "Axivion" + QCoreApplication::applicationName().toUtf8() + "Plugin/" + QCoreApplication::applicationVersion().toUtf8(); request.setRawHeader("X-Axivion-User-Agent", ua); query.setRequest(request); query.setNetworkAccessManager(&dd->m_networkAccessManager); + return SetupResult::Continue; }; - const auto onQueryDone = [url, handler](const NetworkQuery &query, DoneWith doneWith) { QNetworkReply *reply = query.reply(); const int statusCode = reply->attribute(QNetworkRequest::HttpStatusCodeAttribute).toInt(); @@ -356,14 +349,7 @@ static Group fetchHtmlRecipe(const QUrl &url, const std::function From 0b2f7dd6fe777a5eab7709caf2675fb4fb586e2b Mon Sep 17 00:00:00 2001 From: Jarek Kobus Date: Thu, 15 Feb 2024 00:11:25 +0100 Subject: [PATCH 077/243] Axivion: Get rid of AxivionServer::token setting Remove it also from aspect container. Change-Id: I0af093bbd5654083dac581e5793ec57e1c7a7b3d Reviewed-by: Andreas Loth Reviewed-by: hjk --- .../axivion/axivionprojectsettings.cpp | 3 +-- src/plugins/axivion/axivionsettings.cpp | 20 +++---------------- src/plugins/axivion/axivionsettings.h | 1 - 3 files changed, 4 insertions(+), 20 deletions(-) diff --git a/src/plugins/axivion/axivionprojectsettings.cpp b/src/plugins/axivion/axivionprojectsettings.cpp index 14d47eca53a..1413b3cfd3a 100644 --- a/src/plugins/axivion/axivionprojectsettings.cpp +++ b/src/plugins/axivion/axivionprojectsettings.cpp @@ -220,8 +220,7 @@ void AxivionProjectSettingsWidget::updateUi() void AxivionProjectSettingsWidget::updateEnabledStates() { - const bool hasDashboardSettings = !settings().server.dashboard.isEmpty() - && !settings().server.token.isEmpty(); + const bool hasDashboardSettings = !settings().server.dashboard.isEmpty(); const bool linked = !m_projectSettings->dashboardProjectName().isEmpty(); const bool linkable = m_dashboardProjects->topLevelItemCount() && !m_dashboardProjects->selectedItems().isEmpty(); diff --git a/src/plugins/axivion/axivionsettings.cpp b/src/plugins/axivion/axivionsettings.cpp index f742f0c5626..5958bfd4deb 100644 --- a/src/plugins/axivion/axivionsettings.cpp +++ b/src/plugins/axivion/axivionsettings.cpp @@ -28,7 +28,7 @@ namespace Axivion::Internal { bool AxivionServer::operator==(const AxivionServer &other) const { return id == other.id && dashboard == other.dashboard && username == other.username - && description == other.description && token == other.token; + && description == other.description; } bool AxivionServer::operator!=(const AxivionServer &other) const @@ -43,7 +43,6 @@ QJsonObject AxivionServer::toJson() const result.insert("dashboard", dashboard); result.insert("username", username); result.insert("description", description); - result.insert("token", token); return result; } @@ -62,11 +61,8 @@ AxivionServer AxivionServer::fromJson(const QJsonObject &json) const QJsonValue description = json.value("description"); if (description == QJsonValue::Undefined) return invalidServer; - const QJsonValue token = json.value("token"); - if (token == QJsonValue::Undefined) - return invalidServer; return {Id::fromString(id.toString()), dashboard.toString(), username.toString(), - description.toString(), token.toString()}; + description.toString()}; } static FilePath tokensFilePath() @@ -162,7 +158,6 @@ private: StringAspect m_dashboardUrl; StringAspect m_username; StringAspect m_description; - StringAspect m_token; BoolAspect m_valid; }; @@ -185,18 +180,12 @@ DashboardSettingsWidget::DashboardSettingsWidget(Mode mode, QWidget *parent, QPu m_description.setDisplayStyle(labelStyle); m_description.setPlaceHolderText(Tr::tr("Non-empty description")); - m_token.setLabelText(Tr::tr("Access token:")); - m_token.setDisplayStyle(labelStyle); - m_token.setPlaceHolderText(Tr::tr("IDE Access Token")); - m_token.setVisible(mode == Edit); - using namespace Layouting; Form { m_dashboardUrl, br, m_username, br, m_description, br, - m_token, br, mode == Edit ? normalMargin : noMargin }.attachTo(this); @@ -209,7 +198,6 @@ DashboardSettingsWidget::DashboardSettingsWidget(Mode mode, QWidget *parent, QPu connect(&m_dashboardUrl, &BaseAspect::changed, this, checkValidity); connect(&m_username, &BaseAspect::changed, this, checkValidity); connect(&m_description, &BaseAspect::changed, this, checkValidity); - connect(&m_token, &BaseAspect::changed, this, checkValidity); } } @@ -223,7 +211,6 @@ AxivionServer DashboardSettingsWidget::dashboardServer() const result.dashboard = m_dashboardUrl(); result.username = m_username(); result.description = m_description(); - result.token = m_token(); return result; } @@ -233,12 +220,11 @@ void DashboardSettingsWidget::setDashboardServer(const AxivionServer &server) m_dashboardUrl.setValue(server.dashboard); m_username.setValue(server.username); m_description.setValue(server.description); - m_token.setValue(server.token); } bool DashboardSettingsWidget::isValid() const { - return !m_token().isEmpty() && !m_description().isEmpty() && isUrlValid(m_dashboardUrl()); + return !m_description().isEmpty() && isUrlValid(m_dashboardUrl()); } class AxivionSettingsWidget : public IOptionsPageWidget diff --git a/src/plugins/axivion/axivionsettings.h b/src/plugins/axivion/axivionsettings.h index 00a93843816..d692fde4a51 100644 --- a/src/plugins/axivion/axivionsettings.h +++ b/src/plugins/axivion/axivionsettings.h @@ -27,7 +27,6 @@ public: QString dashboard; QString username; QString description; - QString token; bool validateCert = true; }; From 065debd163dc98b9679cc2c751c1451499db099c Mon Sep 17 00:00:00 2001 From: Christian Kandeler Date: Wed, 14 Feb 2024 14:48:13 +0100 Subject: [PATCH 078/243] RemoteLinux: Speed up rsync transfer Group files with the same target directory into a single rsync invocation. Fixes: QTCREATORBUG-29988 Change-Id: I3fc7883e55c9c3105d403d19d0b59cc70d158d6d Reviewed-by: Qt CI Bot Reviewed-by: Jarek Kobus Reviewed-by: --- src/plugins/remotelinux/linuxdevice.cpp | 44 +++++++++++++------------ 1 file changed, 23 insertions(+), 21 deletions(-) diff --git a/src/plugins/remotelinux/linuxdevice.cpp b/src/plugins/remotelinux/linuxdevice.cpp index 0872ff54d3d..dbad2b5bb18 100644 --- a/src/plugins/remotelinux/linuxdevice.cpp +++ b/src/plugins/remotelinux/linuxdevice.cpp @@ -1485,23 +1485,24 @@ public: private: void startImpl() final { - m_currentIndex = 0; - startNextFile(); + // 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_setup.m_files.size() == 0 || m_currentIndex == m_setup.m_files.size() - 1) + if (m_batches.isEmpty()) return handleDone(); if (handleError()) return; - ++m_currentIndex; - startNextFile(); + startNextBatch(); } - void startNextFile() + void startNextBatch() { process().close(); @@ -1510,12 +1511,14 @@ private: << fullConnectionOptions(), OsTypeLinux); QStringList options{"-e", sshCmdLine, m_setup.m_rsyncFlags}; - if (!m_setup.m_files.isEmpty()) { // NormalRun - const FileToTransfer file = m_setup.m_files.at(m_currentIndex); - const FileToTransfer fixedFile = fixLocalFileOnWindows(file, options); - const auto fixedPaths = fixPaths(fixedFile, userAtHost()); - - options << fixedPaths.first << fixedPaths.second; + 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 << fixedLocalPath(fixedFile.m_source); + } + options << fixedRemotePath(batchIt.key(), userAtHost()); + m_batches.erase(batchIt); } else { // TestRun options << "-n" << "--exclude=*" << (userAtHost() + ":/tmp"); } @@ -1542,18 +1545,17 @@ private: return fixedFile; } - QPair fixPaths(const FileToTransfer &file, const QString &remoteHost) const + QString fixedLocalPath(const FilePath &file) const { - FilePath localPath = file.m_source; - FilePath remotePath = file.m_target; - const QString local = (localPath.isDir() && localPath.path().back() != '/') - ? localPath.path() + '/' : localPath.path(); - const QString remote = remoteHost + ':' + remotePath.path(); - - return qMakePair(local, remote); + return file.isDir() && file.path().back() != '/' ? file.path() + '/' : file.path(); } - int m_currentIndex = 0; + QString fixedRemotePath(const FilePath &file, const QString &remoteHost) const + { + return remoteHost + ':' + file.path(); + } + + QHash m_batches; }; class GenericTransferImpl : public FileTransferInterface From a69f7019a23a92e62f628b3991ce256e4ec3602e Mon Sep 17 00:00:00 2001 From: Jarek Kobus Date: Fri, 16 Feb 2024 19:21:38 +0100 Subject: [PATCH 079/243] Axivion: Limit code repetition Introduce dtoRecipe() function which replaces both getDtoRecipe() and postDtoRecipe(). Change-Id: Icbf97779869598c4fcc9bc19a520c9bd67df75d4 Reviewed-by: hjk --- src/plugins/axivion/axivionplugin.cpp | 123 ++++++-------------------- 1 file changed, 25 insertions(+), 98 deletions(-) diff --git a/src/plugins/axivion/axivionplugin.cpp b/src/plugins/axivion/axivionplugin.cpp index 8060c7b7535..ec64dcc4ba5 100644 --- a/src/plugins/axivion/axivionplugin.cpp +++ b/src/plugins/axivion/axivionplugin.cpp @@ -361,7 +361,17 @@ struct GetDtoStorage }; template -static Group getDtoRecipe(const Storage> &dtoStorage) +struct PostDtoStorage +{ + QUrl url; + std::optional credential; + QByteArray csrfToken; + QByteArray writeData; + std::optional dtoData; +}; + +template typename DtoStorageType> +static Group dtoRecipe(const Storage> &dtoStorage) { const Storage storage; @@ -373,6 +383,14 @@ static Group getDtoRecipe(const Storage> &dtoStorage) const QByteArray ua = "Axivion" + QCoreApplication::applicationName().toUtf8() + "Plugin/" + QCoreApplication::applicationVersion().toUtf8(); request.setRawHeader("X-Axivion-User-Agent", ua); + + if constexpr (std::is_same_v, PostDtoStorage>) { + request.setRawHeader("Content-Type", "application/json"); + request.setRawHeader("AX-CSRF-Token", dtoStorage->csrfToken); + query.setWriteData(dtoStorage->writeData); + query.setOperation(NetworkOperation::Post); + } + query.setRequest(request); query.setNetworkAccessManager(&dd->m_networkAccessManager); }; @@ -436,103 +454,12 @@ static Group getDtoRecipe(const Storage> &dtoStorage) } }; - const Group recipe { + return { storage, NetworkQueryTask(onNetworkQuerySetup, onNetworkQueryDone), AsyncTask(onDeserializeSetup, onDeserializeDone) }; - return recipe; -}; - -template -struct PostDtoStorage -{ - QUrl url; - std::optional credential; - QByteArray csrfToken; - QByteArray writeData; - std::optional dtoData; -}; - -template -static Group postDtoRecipe(const Storage> &dtoStorage) -{ - const Storage storage; - - const auto onNetworkQuerySetup = [dtoStorage](NetworkQuery &query) { - QNetworkRequest request(dtoStorage->url); - request.setRawHeader("Accept", s_jsonContentType); - if (dtoStorage->credential) // Unauthorized access otherwise - request.setRawHeader("Authorization", *dtoStorage->credential); - const QByteArray ua = "Axivion" + QCoreApplication::applicationName().toUtf8() + - "Plugin/" + QCoreApplication::applicationVersion().toUtf8(); - request.setRawHeader("X-Axivion-User-Agent", ua); - request.setRawHeader("Content-Type", "application/json"); - request.setRawHeader("AX-CSRF-Token", dtoStorage->csrfToken); - query.setRequest(request); - query.setWriteData(dtoStorage->writeData); - query.setOperation(NetworkOperation::Post); - query.setNetworkAccessManager(&dd->m_networkAccessManager); - }; - - const auto onNetworkQueryDone = [storage](const NetworkQuery &query, DoneWith doneWith) { - QNetworkReply *reply = query.reply(); - const QNetworkReply::NetworkError error = reply->error(); - const int statusCode = reply->attribute(QNetworkRequest::HttpStatusCodeAttribute).toInt(); - const QString contentType = reply->header(QNetworkRequest::ContentTypeHeader) - .toString() - .split(';') - .constFirst() - .trimmed() - .toLower(); - if (doneWith == DoneWith::Success && statusCode == httpStatusCodeOk - && contentType == s_jsonContentType) { - *storage = reply->readAll(); - return DoneResult::Success; - } - - const auto getError = [&]() -> Error { - if (contentType == s_jsonContentType) { - try { - return DashboardError(reply->url(), statusCode, - reply->attribute(QNetworkRequest::HttpReasonPhraseAttribute).toString(), - Dto::ErrorDto::deserialize(reply->readAll())); - } catch (const Dto::invalid_dto_exception &) { - // ignore - } - } - if (statusCode != 0) { - return HttpError(reply->url(), statusCode, - reply->attribute(QNetworkRequest::HttpReasonPhraseAttribute).toString(), - QString::fromUtf8(reply->readAll())); // encoding? - } - return NetworkError(reply->url(), error, reply->errorString()); - }; - - MessageManager::writeFlashing(QStringLiteral("Axivion: %1").arg(getError().message())); - return DoneResult::Error; - }; - - const auto onDeserializeSetup = [storage](Async &task) { - const auto deserialize = [](QPromise &promise, const QByteArray &input) { - promise.addResult(DtoType::deserialize(input)); - }; - task.setFutureSynchronizer(ExtensionSystem::PluginManager::futureSynchronizer()); - task.setConcurrentCallData(deserialize, *storage); - }; - - const auto onDeserializeDone = [dtoStorage](const Async &task, DoneWith doneWith) { - if (doneWith == DoneWith::Success) - dtoStorage->dtoData = task.future().result(); - }; - - const Group recipe { - storage, - NetworkQueryTask(onNetworkQuerySetup, onNetworkQueryDone), - AsyncTask(onDeserializeSetup, onDeserializeDone) - }; - return recipe; -}; +} static Group authorizationRecipe() { @@ -627,7 +554,7 @@ static Group authorizationRecipe() Group { unauthorizedDashboardStorage, onGroupSetup(onUnauthorizedGroupSetup), - getDtoRecipe(unauthorizedDashboardStorage), + dtoRecipe(unauthorizedDashboardStorage), onGroupDone(onUnauthorizedGroupDone) }, Group { @@ -639,12 +566,12 @@ static Group authorizationRecipe() onGroupSetup(onDashboardGroupSetup), Group { // GET DashboardInfoDto finishAllAndSuccess, - getDtoRecipe(dashboardStorage), + dtoRecipe(dashboardStorage) }, Group { // POST ApiTokenCreationRequestDto, GET ApiTokenInfoDto. apiTokenStorage, onGroupSetup(onApiTokenGroupSetup), - postDtoRecipe(apiTokenStorage), + dtoRecipe(apiTokenStorage), CredentialQueryTask(onSetCredentialSetup) } } @@ -675,7 +602,7 @@ static Group fetchDataRecipe(const QUrl &url, const std::function Date: Mon, 19 Feb 2024 17:01:47 +0100 Subject: [PATCH 080/243] Doc: Describe new functions in the Markdown editor - Activate the locator to jump to a line and column - Follow links to web sites Task-number: QTCREATORBUG-30209 Change-Id: I2514fb44c8216c9f40ad14a58450f9d5ce06922c Reviewed-by: Eike Ziller --- .../creator-only/creator-markdown-editor.qdoc | 24 +++++++++++++++---- 1 file changed, 20 insertions(+), 4 deletions(-) diff --git a/doc/qtcreator/src/editors/creator-only/creator-markdown-editor.qdoc b/doc/qtcreator/src/editors/creator-only/creator-markdown-editor.qdoc index 1942ec84af7..8f959548e98 100644 --- a/doc/qtcreator/src/editors/creator-only/creator-markdown-editor.qdoc +++ b/doc/qtcreator/src/editors/creator-only/creator-markdown-editor.qdoc @@ -1,4 +1,4 @@ -// Copyright (C) 2023 The Qt Company Ltd. +// Copyright (C) 2024 The Qt Company Ltd. // SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GFDL-1.3-no-invariants-only /*! @@ -9,9 +9,9 @@ \title Edit Markdown files - Open \l{https://www.markdownguide.org/basic-syntax/}{Markdown} (.md) files - or select \uicontrol File > \uicontrol {New File} > \uicontrol {General} > - \uicontrol {Markdown File} to create a new file. + Open \l{https://www.markdownguide.org/basic-syntax/}{Markdown} (.md) files, + or go to \uicontrol File > \uicontrol {New File} and select + \uicontrol {General} > \uicontrol {Markdown File} to create a new file. \image qtcreator-markdown-editor.webp {Markdown file in Preview and Editor views} @@ -26,4 +26,20 @@ Use the buttons on the editor toolbar to format text as italic (i), bold (b), or inline code (`), and to create links to web sites (\inlineimage icons/linkicon.png). + + \section1 Move to a line and column + + The line and column indicator shows information about the current cursor + position. Select it to activate the locator, and enter a line and column + number to move there. + + \section1 Follow links to web sites + + To follow a link to a web site in the editor: + + \list 1 + \li Place the cursor on the link. + \li Go to \uicontrol {Follow Symbol Under Cursor} in the context menu, or + press \key F2. + \endlist */ From a4f600c14d7be575d59b8d888d69804fdede45f9 Mon Sep 17 00:00:00 2001 From: Jarek Kobus Date: Sat, 17 Feb 2024 10:10:30 +0100 Subject: [PATCH 081/243] Axivion: Show error messages on CredentialQuery errors Use more writeDisrupting() for logging Axivion errors. Don't translate "Axivion". Change-Id: Ic04ff0afe66d79be3d319b16948f7861225e8927 Reviewed-by: hjk Reviewed-by: --- src/plugins/axivion/axivionplugin.cpp | 15 +++++++++------ 1 file changed, 9 insertions(+), 6 deletions(-) diff --git a/src/plugins/axivion/axivionplugin.cpp b/src/plugins/axivion/axivionplugin.cpp index ec64dcc4ba5..f3246fb8dc3 100644 --- a/src/plugins/axivion/axivionplugin.cpp +++ b/src/plugins/axivion/axivionplugin.cpp @@ -205,7 +205,7 @@ class AxivionTextMark : public TextMark { public: AxivionTextMark(const FilePath &filePath, const Dto::LineMarkerDto &issue) - : TextMark(filePath, issue.startLine, {Tr::tr("Axivion"), s_axivionTextMarkId}) + : TextMark(filePath, issue.startLine, {QString("Axivion"), s_axivionTextMarkId}) { const QString markText = issue.description; const QString id = issue.kind + QString::number(issue.id.value_or(-1)); @@ -308,7 +308,7 @@ static QUrl urlForProject(const QString &projectName) QString dashboard = settings().server.dashboard; if (!dashboard.endsWith(QLatin1Char('/'))) dashboard += QLatin1Char('/'); - return QUrl(dashboard).resolved(QStringLiteral("api/projects/")).resolved(projectName); + return QUrl(dashboard).resolved(QString("api/projects/")).resolved(projectName); } static constexpr int httpStatusCodeOk = 200; @@ -428,8 +428,7 @@ static Group dtoRecipe(const Storage> &dtoStorage) } return NetworkError(reply->url(), error, reply->errorString()); }; - - MessageManager::writeFlashing(QStringLiteral("Axivion: %1").arg(getError().message())); + MessageManager::writeDisrupting(QString("Axivion: %1").arg(getError().message())); return DoneResult::Error; }; @@ -493,7 +492,8 @@ static Group authorizationRecipe() const auto onGetCredentialDone = [](const CredentialQuery &credential, DoneWith result) { if (result == DoneWith::Success) dd->m_apiToken = credential.data(); - // TODO: Show the message about keystore error and info that we can't authorize without it. + else + MessageManager::writeDisrupting(QString("Axivion: %1").arg(credential.errorString())); }; const Storage passwordStorage; @@ -549,6 +549,9 @@ static Group authorizationRecipe() credential.setData(*dd->m_apiToken); return SetupResult::Continue; }; + const auto onSetCredentialDone = [](const CredentialQuery &credential) { + MessageManager::writeDisrupting(QString("Axivion: %1").arg(credential.errorString())); + }; return { Group { @@ -572,7 +575,7 @@ static Group authorizationRecipe() apiTokenStorage, onGroupSetup(onApiTokenGroupSetup), dtoRecipe(apiTokenStorage), - CredentialQueryTask(onSetCredentialSetup) + CredentialQueryTask(onSetCredentialSetup, onSetCredentialDone, CallDoneIf::Error) } } } From 31007b825987083eb5a3da037955f1349848f1ca Mon Sep 17 00:00:00 2001 From: Jarek Kobus Date: Sun, 18 Feb 2024 11:47:41 +0100 Subject: [PATCH 082/243] TaskTree: Introduce ExecutableItem ExecutableItem is a common base for Group, CustomTask and Sync elements. Move withTimeout() here, as this is relevant only for executable items. It's going to be a place for additional API, e.g. withLog(). Task-number: QTCREATORBUG-28741 Change-Id: Ibcd6b34c389af4f41f56fd242b14fad6c0c579b2 Reviewed-by: Reviewed-by: Qt CI Bot Reviewed-by: hjk --- src/libs/solutions/tasking/tasktree.cpp | 6 ++--- src/libs/solutions/tasking/tasktree.h | 34 ++++++++++++------------- 2 files changed, 19 insertions(+), 21 deletions(-) diff --git a/src/libs/solutions/tasking/tasktree.cpp b/src/libs/solutions/tasking/tasktree.cpp index 255fe5243a8..d5d6903093b 100644 --- a/src/libs/solutions/tasking/tasktree.cpp +++ b/src/libs/solutions/tasking/tasktree.cpp @@ -1402,8 +1402,8 @@ void GroupItem::addChildren(const QList &children) } } -GroupItem GroupItem::withTimeout(const GroupItem &item, milliseconds timeout, - const std::function &handler) +ExecutableItem ExecutableItem::withTimeout(milliseconds timeout, + const std::function &handler) const { const auto onSetup = [timeout](milliseconds &timeoutData) { timeoutData = timeout; }; return Group { @@ -1414,7 +1414,7 @@ GroupItem GroupItem::withTimeout(const GroupItem &item, milliseconds timeout, handler ? TimeoutTask(onSetup, [handler] { handler(); }, CallDoneIf::Success) : TimeoutTask(onSetup) }, - item + *this }; } diff --git a/src/libs/solutions/tasking/tasktree.h b/src/libs/solutions/tasking/tasktree.h index 7295c47e1ea..7b5c9058dae 100644 --- a/src/libs/solutions/tasking/tasktree.h +++ b/src/libs/solutions/tasking/tasktree.h @@ -261,8 +261,6 @@ protected: static GroupItem groupHandler(const GroupHandler &handler) { return GroupItem({handler}); } static GroupItem parallelLimit(int limit) { return GroupItem({{}, limit}); } static GroupItem workflowPolicy(WorkflowPolicy policy) { return GroupItem({{}, {}, policy}); } - static GroupItem withTimeout(const GroupItem &item, std::chrono::milliseconds timeout, - const std::function &handler = {}); // Checks if Function may be invoked with Args and if Function's return type is Result. template &handler = {}) const; + +protected: + ExecutableItem() = default; + ExecutableItem(const TaskHandler &handler) : GroupItem(handler) {} +}; + +class TASKING_EXPORT Group : public ExecutableItem { public: Group(const QList &children) { addChildren(children); } @@ -304,11 +313,6 @@ public: using GroupItem::parallelLimit; // Default: 1 (sequential). 0 means unlimited (parallel). using GroupItem::workflowPolicy; // Default: WorkflowPolicy::StopOnError. - GroupItem withTimeout(std::chrono::milliseconds timeout, - const std::function &handler = {}) const { - return GroupItem::withTimeout(*this, timeout, handler); - } - private: template static GroupSetupHandler wrapGroupSetup(Handler &&handler) @@ -387,7 +391,7 @@ public: }; // Synchronous invocation. Similarly to Group - isn't counted as a task inside taskCount() -class TASKING_EXPORT Sync final : public GroupItem +class TASKING_EXPORT Sync final : public ExecutableItem { public: template @@ -431,7 +435,7 @@ private: }; template -class CustomTask final : public GroupItem +class CustomTask final : public ExecutableItem { public: using Task = typename Adapter::TaskType; @@ -445,16 +449,10 @@ public: template CustomTask(SetupHandler &&setup = TaskSetupHandler(), DoneHandler &&done = TaskDoneHandler(), CallDoneIf callDoneIf = CallDoneIf::SuccessOrError) - : GroupItem({&createAdapter, wrapSetup(std::forward(setup)), - wrapDone(std::forward(done)), callDoneIf}) + : ExecutableItem({&createAdapter, wrapSetup(std::forward(setup)), + wrapDone(std::forward(done)), callDoneIf}) {} - GroupItem withTimeout(std::chrono::milliseconds timeout, - const std::function &handler = {}) const - { - return GroupItem::withTimeout(*this, timeout, handler); - } - private: static Adapter *createAdapter() { return new Adapter; } From 243b268bea9d27d9bb53544a4917b2d929b5b01b Mon Sep 17 00:00:00 2001 From: Jarek Kobus Date: Sun, 18 Feb 2024 13:06:22 +0100 Subject: [PATCH 083/243] TaskTree: Add withLog() function This addresses the 7th and 8th points in the bugreport below. Task-number: QTCREATORBUG-28741 Change-Id: I6430bf330d117258654bf3fe101511d4bea68358 Reviewed-by: Reviewed-by: Qt CI Bot Reviewed-by: hjk --- src/libs/solutions/tasking/tasktree.cpp | 26 +++++++++++++++++++++++++ src/libs/solutions/tasking/tasktree.h | 1 + 2 files changed, 27 insertions(+) diff --git a/src/libs/solutions/tasking/tasktree.cpp b/src/libs/solutions/tasking/tasktree.cpp index d5d6903093b..865b541de47 100644 --- a/src/libs/solutions/tasking/tasktree.cpp +++ b/src/libs/solutions/tasking/tasktree.cpp @@ -7,10 +7,12 @@ #include #include #include +#include #include #include #include #include +#include #include using namespace std::chrono; @@ -1418,6 +1420,30 @@ ExecutableItem ExecutableItem::withTimeout(milliseconds timeout, }; } +static QString currentTime() { return QTime::currentTime().toString(Qt::ISODateWithMs); } + +ExecutableItem ExecutableItem::withLog(const QString &logName) const +{ + const auto header = [logName] { + return QString("TASK TREE LOG [%1] \"%2\"").arg(currentTime(), logName); + }; + const Storage> storage; + return Group { + storage, + onGroupSetup([storage, header] { + *storage = system_clock::now(); + qDebug().noquote() << header() << "started."; + }), + *this, + onGroupDone([storage, header](DoneWith result) { + const auto elapsed = duration_cast(system_clock::now() - *storage); + const QMetaEnum doneWithEnum = QMetaEnum::fromType(); + qDebug().noquote().nospace() << header() << " finished with " + << doneWithEnum.valueToKey(int(result)) << " within " << elapsed.count() << "ms."; + }) + }; +} + class TaskTreePrivate; class TaskNode; class RuntimeContainer; diff --git a/src/libs/solutions/tasking/tasktree.h b/src/libs/solutions/tasking/tasktree.h index 7b5c9058dae..4b067a03c4a 100644 --- a/src/libs/solutions/tasking/tasktree.h +++ b/src/libs/solutions/tasking/tasktree.h @@ -289,6 +289,7 @@ class TASKING_EXPORT ExecutableItem : public GroupItem public: ExecutableItem withTimeout(std::chrono::milliseconds timeout, const std::function &handler = {}) const; + ExecutableItem withLog(const QString &logName) const; protected: ExecutableItem() = default; From 47b3017979ecd8a1d321baf9e307f20469bf06df Mon Sep 17 00:00:00 2001 From: Leena Miettinen Date: Tue, 20 Feb 2024 10:36:37 +0100 Subject: [PATCH 084/243] Doc: Add more options for following links to web sites in MD editor Task-number: QTCREATORBUG-30209 Change-Id: I0c9f49775377bfd3e8061112a77995a647590c1c Reviewed-by: Eike Ziller --- .../editors/creator-only/creator-markdown-editor.qdoc | 9 +++++++-- 1 file changed, 7 insertions(+), 2 deletions(-) diff --git a/doc/qtcreator/src/editors/creator-only/creator-markdown-editor.qdoc b/doc/qtcreator/src/editors/creator-only/creator-markdown-editor.qdoc index 8f959548e98..a5cbf186f99 100644 --- a/doc/qtcreator/src/editors/creator-only/creator-markdown-editor.qdoc +++ b/doc/qtcreator/src/editors/creator-only/creator-markdown-editor.qdoc @@ -39,7 +39,12 @@ \list 1 \li Place the cursor on the link. - \li Go to \uicontrol {Follow Symbol Under Cursor} in the context menu, or - press \key F2. + \li Then, do one of the following: + \list + \li Press \key {Ctrl+Click} (or \key {Cmd+Click} on \macos). + \li Press \key F2. + \li Go to \uicontrol {Follow Symbol Under Cursor} in the context + menu. + \endlist \endlist */ From 7261c2889cd3988ac0aa3ba5001f708d3974762a Mon Sep 17 00:00:00 2001 From: Christian Stenger Date: Tue, 20 Feb 2024 11:10:04 +0100 Subject: [PATCH 085/243] Tests: Fix missing include Avoids a compile issue before being able to execute the test. Change-Id: Ibc76c16229107e2c23757de682bc78bfe4b7d6e7 Reviewed-by: David Schulz Reviewed-by: hjk --- tests/auto/debugger/tst_dumpers.cpp | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/tests/auto/debugger/tst_dumpers.cpp b/tests/auto/debugger/tst_dumpers.cpp index 3f3c1daabaf..efd4e66a8ed 100644 --- a/tests/auto/debugger/tst_dumpers.cpp +++ b/tests/auto/debugger/tst_dumpers.cpp @@ -5352,7 +5352,8 @@ void tst_Dumpers::dumper_data() QTest::newRow("StdTuple") - << Data("#include \n", + << Data("#include \n" + "#include \n", "std::tuple tuple = std::make_tuple(123, std::string(\"hello\"), 456);\n", From 721d87911562a5dcc2ae3a4091e1f66be0204bcd Mon Sep 17 00:00:00 2001 From: Christian Stenger Date: Mon, 19 Feb 2024 13:37:20 +0100 Subject: [PATCH 086/243] Axivion: Move issue details widget Although it is not a navigation widget as such, it is expected to have this separated and beside the editor. This patch moves the widget to the right side bar by default. Change-Id: If46bedaf7bf475a46dbfd8bee1e121c659740856 Reviewed-by: hjk --- src/plugins/axivion/axivionoutputpane.cpp | 14 ------- src/plugins/axivion/axivionoutputpane.h | 1 - src/plugins/axivion/axivionplugin.cpp | 46 ++++++++++++++++++++++- 3 files changed, 45 insertions(+), 16 deletions(-) diff --git a/src/plugins/axivion/axivionoutputpane.cpp b/src/plugins/axivion/axivionoutputpane.cpp index 9bd50784f3a..df8d87accdc 100644 --- a/src/plugins/axivion/axivionoutputpane.cpp +++ b/src/plugins/axivion/axivionoutputpane.cpp @@ -30,7 +30,6 @@ #include #include #include -#include #include #include @@ -615,8 +614,6 @@ AxivionOutputPane::AxivionOutputPane(QObject *parent) m_outputWidget->addWidget(dashboardWidget); IssuesWidget *issuesWidget = new IssuesWidget(m_outputWidget); m_outputWidget->addWidget(issuesWidget); - QTextBrowser *browser = new QTextBrowser(m_outputWidget); - m_outputWidget->addWidget(browser); } AxivionOutputPane::~AxivionOutputPane() @@ -709,15 +706,4 @@ void AxivionOutputPane::updateDashboard() } } -void AxivionOutputPane::updateAndShowRule(const QString &ruleHtml) -{ - if (auto browser = static_cast(m_outputWidget->widget(2))) { - browser->setText(ruleHtml); - if (!ruleHtml.isEmpty()) { - m_outputWidget->setCurrentIndex(2); - popup(IOutputPane::NoModeSwitch); - } - } -} - } // Axivion::Internal diff --git a/src/plugins/axivion/axivionoutputpane.h b/src/plugins/axivion/axivionoutputpane.h index 140d50b7235..87000e5e187 100644 --- a/src/plugins/axivion/axivionoutputpane.h +++ b/src/plugins/axivion/axivionoutputpane.h @@ -32,7 +32,6 @@ public: void goToPrev() override; void updateDashboard(); - void updateAndShowRule(const QString &ruleHtml); private: QStackedWidget *m_outputWidget = nullptr; }; diff --git a/src/plugins/axivion/axivionplugin.cpp b/src/plugins/axivion/axivionplugin.cpp index f3246fb8dc3..d7ce85baf6f 100644 --- a/src/plugins/axivion/axivionplugin.cpp +++ b/src/plugins/axivion/axivionplugin.cpp @@ -14,7 +14,9 @@ #include #include #include +#include #include +#include #include #include @@ -42,6 +44,7 @@ #include #include #include +#include #include #include @@ -172,6 +175,7 @@ enum class ServerAccess { Unknown, NoAuthorization, WithAuthorization }; class AxivionPluginPrivate : public QObject { + Q_OBJECT public: AxivionPluginPrivate(); void handleSslErrors(QNetworkReply *reply, const QList &errors); @@ -183,7 +187,12 @@ public: void clearAllMarks(); void handleIssuesForFile(const Dto::FileViewDto &fileView); void fetchIssueInfo(const QString &id); + void setIssueDetails(const QString &issueDetailsHtml); +signals: + void issueDetailsChanged(const QString &issueDetailsHtml); + +public: // TODO: Should be set to Unknown on server address change in settings. ServerAccess m_serverAccess = ServerAccess::Unknown; // TODO: Should be cleared on username change in settings. @@ -739,12 +748,19 @@ void AxivionPluginPrivate::fetchIssueInfo(const QString &id) const int idx = htmlText.indexOf("

"); if (idx >= 0) fixedHtml = "" + htmlText.mid(idx); - dd->m_axivionOutputPane.updateAndShowRule(QString::fromUtf8(fixedHtml)); + + NavigationWidget::activateSubWidget("Axivion.Issue", Side::Right); + dd->setIssueDetails(QString::fromUtf8(fixedHtml)); }; m_issueInfoRunner.start(issueHtmlRecipe(id, ruleHandler)); } +void AxivionPluginPrivate::setIssueDetails(const QString &issueDetailsHtml) +{ + emit issueDetailsChanged(issueDetailsHtml); +} + void AxivionPluginPrivate::handleOpenedDocs() { const QList openDocuments = DocumentModel::openedDocuments(); @@ -820,6 +836,33 @@ void AxivionPluginPrivate::handleIssuesForFile(const Dto::FileViewDto &fileView) } } +class AxivionIssueWidgetFactory final : public INavigationWidgetFactory +{ +public: + AxivionIssueWidgetFactory() + { + setDisplayName(Tr::tr("Axivion")); + setId("Axivion.Issue"); + setPriority(555); + } + + NavigationView createWidget() final + { + QTC_ASSERT(dd, return {}); + QTextBrowser *browser = new QTextBrowser; + browser->setOpenLinks(false); + NavigationView view; + view.widget = browser; + connect(dd, &AxivionPluginPrivate::issueDetailsChanged, browser, &QTextBrowser::setHtml); + return view; + } +}; + +void setupAxivionIssueWidgetFactory() +{ + static AxivionIssueWidgetFactory issueWidgetFactory; +} + class AxivionPlugin final : public ExtensionSystem::IPlugin { Q_OBJECT @@ -837,6 +880,7 @@ class AxivionPlugin final : public ExtensionSystem::IPlugin dd = new AxivionPluginPrivate; AxivionProjectSettings::setupProjectPanel(); + setupAxivionIssueWidgetFactory(); connect(ProjectManager::instance(), &ProjectManager::startupProjectChanged, dd, &AxivionPluginPrivate::onStartupProjectChanged); From 6561d3f691db7687b9f8ac1148322eeed802b90a Mon Sep 17 00:00:00 2001 From: Christian Kandeler Date: Tue, 20 Feb 2024 10:15:13 +0100 Subject: [PATCH 087/243] Update clang-format test file ... such that it represents the output from a current clang-format with our current settings. Change-Id: I0bc75c80b01e991c10bc490f4dc0270b8292fae3 Reviewed-by: Reviewed-by: Eike Ziller --- tests/manual/clang-format-for-qtc/test.cpp | 16 ++++++---------- 1 file changed, 6 insertions(+), 10 deletions(-) diff --git a/tests/manual/clang-format-for-qtc/test.cpp b/tests/manual/clang-format-for-qtc/test.cpp index e205651a569..02119baef30 100644 --- a/tests/manual/clang-format-for-qtc/test.cpp +++ b/tests/manual/clang-format-for-qtc/test.cpp @@ -68,7 +68,7 @@ void lala(int foo) { Q_UNUSED(foo) Q_UNUSED(foo); - QTC_ASSERT(true, return ); // NOTE: Ops, extra space with QTC_ASSERT macro and return keyword + QTC_ASSERT(true, return); QTC_ASSERT(true, return;); while (true) QTC_ASSERT(true, break); // ...but this is fine @@ -184,7 +184,7 @@ template void fancyTemplateFunction(); template -void variadicTemplateFunction(Type *... arg); +void variadicTemplateFunction(Type *...arg); // ------------------------------------------------------------------------------------------------- // Inside functions @@ -325,11 +325,8 @@ void penaltyTests(bool isThatTrue) : (QIODevice::ReadOnly | QIODevice::Text); const auto someValue10 = functionToCall(valueX, valueY, valueXTimesY); - const auto someValue11 = functionToCall(valueX, - valueY, - valueXTimesY, - unbelievableBigValue, - unbelievableBigValue); + const auto someValue11 + = functionToCall(valueX, valueY, valueXTimesY, unbelievableBigValue, unbelievableBigValue); const auto someValue12 = functionToCall(valueX, valueY, valueXTimesY, @@ -370,9 +367,8 @@ void penaltyTests(bool isThatTrue) | unlimitedValueunbelievableBigValue); const QString path; - const bool someLongerNameNNNNNNNNNN = functionToCallSt(path, - QStringList( - QLatin1String("-print-env"))); + const bool someLongerNameNNNNNNNNNN + = functionToCallSt(path, QStringList(QLatin1String("-print-env"))); } // ------------------------------------------------------------------------------------------------- From fc5083cde9010b547e2150e68e473a1c274b7220 Mon Sep 17 00:00:00 2001 From: Jarek Kobus Date: Fri, 16 Feb 2024 13:27:36 +0100 Subject: [PATCH 088/243] Axivion: Get rid of AxivionServer::description setting Remove it also from aspect container. Change-Id: I948b79bc6b2ba3ae3d26a19fa61be5e4bd672a2a Reviewed-by: Christian Stenger --- src/plugins/axivion/axivionsettings.cpp | 21 +++------------------ src/plugins/axivion/axivionsettings.h | 1 - 2 files changed, 3 insertions(+), 19 deletions(-) diff --git a/src/plugins/axivion/axivionsettings.cpp b/src/plugins/axivion/axivionsettings.cpp index 5958bfd4deb..3701a81d16d 100644 --- a/src/plugins/axivion/axivionsettings.cpp +++ b/src/plugins/axivion/axivionsettings.cpp @@ -27,8 +27,7 @@ namespace Axivion::Internal { bool AxivionServer::operator==(const AxivionServer &other) const { - return id == other.id && dashboard == other.dashboard && username == other.username - && description == other.description; + return id == other.id && dashboard == other.dashboard && username == other.username; } bool AxivionServer::operator!=(const AxivionServer &other) const @@ -42,7 +41,6 @@ QJsonObject AxivionServer::toJson() const result.insert("id", id.toString()); result.insert("dashboard", dashboard); result.insert("username", username); - result.insert("description", description); return result; } @@ -58,11 +56,7 @@ AxivionServer AxivionServer::fromJson(const QJsonObject &json) const QJsonValue username = json.value("username"); if (username == QJsonValue::Undefined) return invalidServer; - const QJsonValue description = json.value("description"); - if (description == QJsonValue::Undefined) - return invalidServer; - return {Id::fromString(id.toString()), dashboard.toString(), username.toString(), - description.toString()}; + return {Id::fromString(id.toString()), dashboard.toString(), username.toString()}; } static FilePath tokensFilePath() @@ -157,7 +151,6 @@ private: Id m_id; StringAspect m_dashboardUrl; StringAspect m_username; - StringAspect m_description; BoolAspect m_valid; }; @@ -176,16 +169,11 @@ DashboardSettingsWidget::DashboardSettingsWidget(Mode mode, QWidget *parent, QPu m_username.setDisplayStyle(labelStyle); m_username.setPlaceHolderText(Tr::tr("User name")); - m_description.setLabelText(Tr::tr("Description:")); - m_description.setDisplayStyle(labelStyle); - m_description.setPlaceHolderText(Tr::tr("Non-empty description")); - using namespace Layouting; Form { m_dashboardUrl, br, m_username, br, - m_description, br, mode == Edit ? normalMargin : noMargin }.attachTo(this); @@ -197,7 +185,6 @@ DashboardSettingsWidget::DashboardSettingsWidget(Mode mode, QWidget *parent, QPu }; connect(&m_dashboardUrl, &BaseAspect::changed, this, checkValidity); connect(&m_username, &BaseAspect::changed, this, checkValidity); - connect(&m_description, &BaseAspect::changed, this, checkValidity); } } @@ -210,7 +197,6 @@ AxivionServer DashboardSettingsWidget::dashboardServer() const result.id = m_mode == Edit ? Id::fromName(QUuid::createUuid().toByteArray()) : m_id; result.dashboard = m_dashboardUrl(); result.username = m_username(); - result.description = m_description(); return result; } @@ -219,12 +205,11 @@ void DashboardSettingsWidget::setDashboardServer(const AxivionServer &server) m_id = server.id; m_dashboardUrl.setValue(server.dashboard); m_username.setValue(server.username); - m_description.setValue(server.description); } bool DashboardSettingsWidget::isValid() const { - return !m_description().isEmpty() && isUrlValid(m_dashboardUrl()); + return isUrlValid(m_dashboardUrl()); } class AxivionSettingsWidget : public IOptionsPageWidget diff --git a/src/plugins/axivion/axivionsettings.h b/src/plugins/axivion/axivionsettings.h index d692fde4a51..b4231aff901 100644 --- a/src/plugins/axivion/axivionsettings.h +++ b/src/plugins/axivion/axivionsettings.h @@ -26,7 +26,6 @@ public: Utils::Id id; QString dashboard; QString username; - QString description; bool validateCert = true; }; From accb8dc150aa3c156addcb6e23442d47762cbca5 Mon Sep 17 00:00:00 2001 From: Marcus Tillmanns Date: Thu, 15 Feb 2024 12:54:43 +0100 Subject: [PATCH 089/243] CPaster: Remove unused class Change-Id: I5b22a1bc616f3418fbc5298acb5c33ef01382555 Reviewed-by: Qt CI Bot Reviewed-by: Christian Stenger Reviewed-by: --- src/plugins/cpaster/CMakeLists.txt | 1 - src/plugins/cpaster/cpaster.qbs | 2 - .../cpaster/stickynotespasteprotocol.cpp | 249 ------------------ .../cpaster/stickynotespasteprotocol.h | 44 ---- 4 files changed, 296 deletions(-) delete mode 100644 src/plugins/cpaster/stickynotespasteprotocol.cpp delete mode 100644 src/plugins/cpaster/stickynotespasteprotocol.h diff --git a/src/plugins/cpaster/CMakeLists.txt b/src/plugins/cpaster/CMakeLists.txt index 2455ea28d6f..690862877e4 100644 --- a/src/plugins/cpaster/CMakeLists.txt +++ b/src/plugins/cpaster/CMakeLists.txt @@ -22,7 +22,6 @@ add_qtc_plugin(CodePaster pasteview.cpp pasteview.h protocol.cpp protocol.h settings.cpp settings.h - stickynotespasteprotocol.cpp stickynotespasteprotocol.h urlopenprotocol.cpp urlopenprotocol.h ../../shared/cpaster/cgi.cpp ../../shared/cpaster/cgi.h diff --git a/src/plugins/cpaster/cpaster.qbs b/src/plugins/cpaster/cpaster.qbs index 6862eacabdd..f2241ba1d0d 100644 --- a/src/plugins/cpaster/cpaster.qbs +++ b/src/plugins/cpaster/cpaster.qbs @@ -35,8 +35,6 @@ QtcPlugin { "protocol.h", "settings.cpp", "settings.h", - "stickynotespasteprotocol.cpp", - "stickynotespasteprotocol.h", "urlopenprotocol.cpp", "urlopenprotocol.h", ] diff --git a/src/plugins/cpaster/stickynotespasteprotocol.cpp b/src/plugins/cpaster/stickynotespasteprotocol.cpp deleted file mode 100644 index 5e3b2074a51..00000000000 --- a/src/plugins/cpaster/stickynotespasteprotocol.cpp +++ /dev/null @@ -1,249 +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 "stickynotespasteprotocol.h" - -#include "cpastertr.h" - -#include -#include - -#include -#include -#include -#include -#include -#include -#include -#include - -#include - -enum { debug = 0 }; - -namespace CodePaster { - -static QByteArray expiryParameter(int daysRequested) -{ - // Obtained by 'pastebin.kde.org/api/json/parameter/expire' on 26.03.2014 - static const int expiryTimesSec[] = {1800, 21600, 86400, 604800, 2592000, 31536000}; - const int *end = expiryTimesSec + sizeof(expiryTimesSec) / sizeof(expiryTimesSec[0]); - // Find the first element >= requested span, search up to n - 1 such that 'end' defaults to last value. - const int *match = std::lower_bound(expiryTimesSec, end - 1, 24 * 60 * 60 * daysRequested); - return QByteArray("expire=") + QByteArray::number(*match); -} - -void StickyNotesPasteProtocol::setHostUrl(const QString &hostUrl) -{ - m_hostUrl = hostUrl; - if (!m_hostUrl.endsWith(QLatin1Char('/'))) - m_hostUrl.append(QLatin1Char('/')); -} - -unsigned StickyNotesPasteProtocol::capabilities() const -{ - return ListCapability | PostDescriptionCapability; -} - -bool StickyNotesPasteProtocol::checkConfiguration(QString *errorMessage) -{ - if (m_hostChecked) // Check the host once. - return true; - const bool ok = httpStatus(m_hostUrl, errorMessage, true); - if (ok) - m_hostChecked = true; - return ok; -} - -// Query 'http://pastebin.kde.org/api/json/parameter/language' to obtain the valid values. -static inline QByteArray pasteLanguage(Protocol::ContentType ct) -{ - switch (ct) { - case Protocol::Text: - break; - case Protocol::C: - return "language=c"; - case Protocol::Cpp: - return "language=cpp-qt"; - case Protocol::JavaScript: - return "language=javascript"; - case Protocol::Diff: - return "language=diff"; - case Protocol::Xml: - return "language=xml"; - } - return QByteArray("language=text"); -} - -void StickyNotesPasteProtocol::paste( - const QString &text, - ContentType ct, - int expiryDays, - const QString &username, - const QString &comment, - const QString &description - ) -{ - enum { maxDescriptionLength = 30 }; // Length of description is limited. - - Q_UNUSED(username) - Q_UNUSED(comment) - QTC_ASSERT(!m_pasteReply, return); - - // Format body - QByteArray pasteData = "&data="; - pasteData += QUrl::toPercentEncoding(fixNewLines(text)); - pasteData += '&'; - pasteData += pasteLanguage(ct); - pasteData += '&'; - pasteData += expiryParameter(expiryDays); - if (!description.isEmpty()) { - pasteData += "&title="; - pasteData += QUrl::toPercentEncoding(description.left(maxDescriptionLength)); - } - - m_pasteReply = httpPost(m_hostUrl + QLatin1String("api/json/create"), pasteData, true); - connect(m_pasteReply, &QNetworkReply::finished, this, &StickyNotesPasteProtocol::pasteFinished); - if (debug) - qDebug() << "paste: sending " << m_pasteReply << pasteData; -} - -// Parse for an element and return its contents -static QString parseElement(QIODevice *device, const QString &elementName) -{ - const QJsonDocument doc = QJsonDocument::fromJson(device->readAll()); - if (doc.isEmpty() || !doc.isObject()) - return QString(); - - QJsonObject obj= doc.object(); - const QString resultKey = QLatin1String("result"); - - if (obj.contains(resultKey)) { - QJsonValue value = obj.value(resultKey); - if (value.isObject()) { - obj = value.toObject(); - if (obj.contains(elementName)) { - value = obj.value(elementName); - return value.toString(); - } - } else if (value.isArray()) { - qWarning() << "JsonArray not expected."; - } - } - - return QString(); -} - -void StickyNotesPasteProtocol::pasteFinished() -{ - if (m_pasteReply->error()) { - qWarning("%s protocol error: %s", qPrintable(name()),qPrintable(m_pasteReply->errorString())); - } else { - // Parse id from '143204' - // No useful error reports have been observed. - const QString id = parseElement(m_pasteReply, QLatin1String("id")); - if (id.isEmpty()) - qWarning("%s protocol error: Could not send entry.", qPrintable(name())); - else - emit pasteDone(m_hostUrl + id); - } - - m_pasteReply->deleteLater(); - m_pasteReply = nullptr; -} - -void StickyNotesPasteProtocol::fetch(const QString &id) -{ - QTC_ASSERT(!m_fetchReply, return); - - // Did we get a complete URL or just an id? - m_fetchId = id; - const int lastSlashPos = m_fetchId.lastIndexOf(QLatin1Char('/')); - if (lastSlashPos != -1) - m_fetchId.remove(0, lastSlashPos + 1); - QString url = m_hostUrl + QLatin1String("api/json/show/") + m_fetchId; - if (debug) - qDebug() << "fetch: sending " << url; - - m_fetchReply = httpGet(url); - connect(m_fetchReply, &QNetworkReply::finished, - this, &StickyNotesPasteProtocol::fetchFinished); -} - -// Parse: '143228foo1320661026text -// bar' - -void StickyNotesPasteProtocol::fetchFinished() -{ - const QString title = name() + QLatin1String(": ") + m_fetchId; - QString content; - const bool error = m_fetchReply->error(); - if (error) { - content = m_fetchReply->errorString(); - if (debug) - qDebug() << "fetchFinished: error" << m_fetchId << content; - } else { - content = parseElement(m_fetchReply, QLatin1String("data")); - content.remove(QLatin1Char('\r')); - } - m_fetchReply->deleteLater(); - m_fetchReply = nullptr; - emit fetchDone(title, content, error); -} - -void StickyNotesPasteProtocol::list() -{ - QTC_ASSERT(!m_listReply, return); - - // Trailing slash is important to prevent redirection. - QString url = m_hostUrl + QLatin1String("api/json/list"); - m_listReply = httpGet(url); - connect(m_listReply, &QNetworkReply::finished, - this, &StickyNotesPasteProtocol::listFinished); - if (debug) - qDebug() << "list: sending " << url << m_listReply; -} - -// Parse 'result>id1id2...' -static inline QStringList parseList(QIODevice *device) -{ - QStringList result; - const QJsonDocument doc = QJsonDocument::fromJson(device->readAll()); - if (doc.isEmpty() || !doc.isObject()) - return result; - - QJsonObject obj= doc.object(); - const QString resultKey = QLatin1String("result"); - const QString pastesKey = QLatin1String("pastes"); - - if (obj.contains(resultKey)) { - QJsonValue value = obj.value(resultKey); - if (value.isObject()) { - obj = value.toObject(); - if (obj.contains(pastesKey)) { - value = obj.value(pastesKey); - if (value.isArray()) { - const QJsonArray array = value.toArray(); - for (const QJsonValue &val : array) - result.append(val.toString()); - } - } - } - } - return result; -} - -void StickyNotesPasteProtocol::listFinished() -{ - const bool error = m_listReply->error(); - if (error) { - if (debug) - qDebug() << "listFinished: error" << m_listReply->errorString(); - } else { - emit listDone(name(), parseList(m_listReply)); - } - m_listReply->deleteLater(); - m_listReply = nullptr; -} - -} // CodePaster diff --git a/src/plugins/cpaster/stickynotespasteprotocol.h b/src/plugins/cpaster/stickynotespasteprotocol.h deleted file mode 100644 index f212c883ef2..00000000000 --- a/src/plugins/cpaster/stickynotespasteprotocol.h +++ /dev/null @@ -1,44 +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 "protocol.h" - -namespace CodePaster { - -class StickyNotesPasteProtocol : public NetworkProtocol -{ -public: - unsigned capabilities() const override; - - void fetch(const QString &id) override; - void paste(const QString &text, - ContentType ct = Text, - int expiryDays = 1, - const QString &username = QString(), - const QString &comment = QString(), - const QString &description = QString()) override; - void list() override; - - QString hostUrl() const { return m_hostUrl; } - void setHostUrl(const QString &hostUrl); - -private: - bool checkConfiguration(QString *errorMessage = nullptr) override; - - void fetchFinished(); - void pasteFinished(); - void listFinished(); - - QString m_hostUrl; - - QNetworkReply *m_fetchReply = nullptr; - QNetworkReply *m_pasteReply = nullptr; - QNetworkReply *m_listReply = nullptr; - - QString m_fetchId; - bool m_hostChecked = false; -}; - -} // CodePaster From 62a203c926c5d4ed565733a63f5a94a2e737d4df Mon Sep 17 00:00:00 2001 From: Jarek Kobus Date: Sun, 18 Feb 2024 16:15:48 +0100 Subject: [PATCH 090/243] TaskTree: Add tests for withLog() function This addresses the 7th and 8th points in the bugreport below. Task-number: QTCREATORBUG-28741 Change-Id: I5fe09227c1118e66c38bbe98ef720b21823c28ed Reviewed-by: hjk Reviewed-by: Reviewed-by: Qt CI Bot --- tests/auto/solutions/tasking/tst_tasking.cpp | 193 ++++++++++++++++++- 1 file changed, 188 insertions(+), 5 deletions(-) diff --git a/tests/auto/solutions/tasking/tst_tasking.cpp b/tests/auto/solutions/tasking/tst_tasking.cpp index 2c20ce14d30..e95635b6dc8 100644 --- a/tests/auto/solutions/tasking/tst_tasking.cpp +++ b/tests/auto/solutions/tasking/tst_tasking.cpp @@ -63,6 +63,7 @@ Q_ENUM_NS(ThreadResult); using namespace PrintableEnums; using Log = QList>; +using MessageLog = QList>; struct CustomStorage { @@ -82,7 +83,8 @@ struct TestData Group root; Log expectedLog; int taskCount = 0; - DoneWith onDone = DoneWith::Success; + DoneWith result = DoneWith::Success; + std::optional messageLog = {}; }; class tst_Tasking : public QObject @@ -2970,6 +2972,84 @@ void tst_Tasking::testTree_data() << TestData{storage, recipe(false), {}, 0, DoneWith::Success}; } + { + // These tests confirms the expected message log + + const TestData testSuccess { + storage, + Group { + storage, + Group { + createSuccessTask(1, 2ms).withLog("Task 1") + }.withLog("Group 1") + }, + Log { + {1, Handler::Setup}, + {1, Handler::Success} + }, + 1, + DoneWith::Success, + MessageLog { + {"Group 1", Handler::Setup}, + {"Task 1", Handler::Setup}, + {"Task 1", Handler::Success}, + {"Group 1", Handler::Success} + } + }; + const TestData testError { + storage, + Group { + storage, + Group { + createFailingTask(1, 1ms).withLog("Task 1") + }.withLog("Group 1") + }, + Log { + {1, Handler::Setup}, + {1, Handler::Error} + }, + 1, + DoneWith::Error, + MessageLog { + {"Group 1", Handler::Setup}, + {"Task 1", Handler::Setup}, + {"Task 1", Handler::Error}, + {"Group 1", Handler::Error} + } + }; + const TestData testCancel { + storage, + Group { + storage, + parallel, + Group { + createSuccessTask(1).withLog("Task 1"), + }.withLog("Group 1"), + createSyncWithTweak(2, DoneResult::Error).withLog("Task 2") + }, + Log { + {1, Handler::Setup}, + {2, Handler::Sync}, + {2, Handler::TweakDoneToError}, + {1, Handler::Canceled} + }, + 1, + DoneWith::Error, + MessageLog { + {"Group 1", Handler::Setup}, + {"Task 1", Handler::Setup}, + {"Task 2", Handler::Setup}, + {"Task 2", Handler::Error}, + {"Task 1", Handler::Canceled}, + {"Group 1", Handler::Canceled} + } + }; + + QTest::newRow("LogSuccess") << testSuccess; + QTest::newRow("LogError") << testError; + QTest::newRow("LogCancel") << testCancel; + } + { const auto createRoot = [=](DoneResult doneResult, CallDoneIf callDoneIf) { return Group { @@ -3023,12 +3103,98 @@ void tst_Tasking::testTree_data() QTest::newRow("StorageShadowing") << storageShadowingData(); } + +static QtMessageHandler s_oldMessageHandler = nullptr; +static QStringList s_messages; + +class LogMessageHandler +{ +public: + LogMessageHandler() + { + s_messages.clear(); + s_oldMessageHandler = qInstallMessageHandler(handler); + } + ~LogMessageHandler() { qInstallMessageHandler(s_oldMessageHandler); } + +private: + static void handler(QtMsgType type, const QMessageLogContext &context, const QString &msg) + { + QString message = msg; + message.remove('\r'); + s_messages.append(message); + // Defer to old message handler. + if (s_oldMessageHandler) + s_oldMessageHandler(type, context, msg); + } +}; + +static const QList s_logHandlers + = {Handler::Setup, Handler::Success, Handler::Error, Handler::Canceled}; + +static QString handlerToName(Handler handler) +{ + if (handler == Handler::Setup) + return "started"; + + DoneWith doneWith; + switch (handler) { + case Handler::Success: + doneWith = DoneWith::Success; + break; + case Handler::Error: + doneWith = DoneWith::Error; + break; + case Handler::Canceled: + doneWith = DoneWith::Cancel; + break; + default: + return {}; + } + const QMetaEnum doneWithEnum = QMetaEnum::fromType(); + return QString("finished with %1").arg(doneWithEnum.valueToKey(int(doneWith))); +} + +static bool matchesLogPattern(const QString &log, const QPair &pattern) +{ + QStringView message(log); + const static QLatin1StringView part1("TASK TREE LOG ["); + if (!message.startsWith(part1)) + return false; + + message = message.mid(part1.size()); + const static QLatin1StringView part2("HH:mm:ss.zzz"); // check only size + + message = message.mid(part2.size()); + const QString part3 = QString("] \"%1\" ").arg(pattern.first); + if (!message.startsWith(part3)) + return false; + + message = message.mid(part3.size()); + const QString part4(handlerToName(pattern.second)); + if (!message.startsWith(part4)) + return false; + + message = message.mid(part4.size()); + if (pattern.second == Handler::Setup) + return message == QLatin1StringView("."); + + const static QLatin1StringView part5(" within "); + if (!message.startsWith(part5)) + return false; + + return message.endsWith(QLatin1StringView("ms.")); +} + void tst_Tasking::testTree() { QFETCH(TestData, testData); + LogMessageHandler handler; + TaskTree taskTree({testData.root.withTimeout(1000ms)}); - QCOMPARE(taskTree.taskCount() - 1, testData.taskCount); // -1 for the timeout task above + const int taskCount = taskTree.taskCount() - 1; // -1 for the timeout task above + QCOMPARE(taskCount, testData.taskCount); Log actualLog; const auto collectLog = [&actualLog](const CustomStorage &storage) { actualLog = storage.m_log; @@ -3041,7 +3207,24 @@ void tst_Tasking::testTree() QCOMPARE(actualLog, testData.expectedLog); QCOMPARE(CustomStorage::instanceCount(), 0); - QCOMPARE(result, testData.onDone); + QCOMPARE(result, testData.result); + + if (testData.messageLog) { + QCOMPARE(s_messages.count(), testData.messageLog->count()); + + for (int i = 0; i < s_messages.count(); ++i) { + const auto &message = testData.messageLog->at(i); + QVERIFY(s_logHandlers.contains(message.second)); + const QString &log = s_messages.at(i); + if (!matchesLogPattern(log, message)) { + const QString failMessage + = QString("The log message at index %1: \"%2\" doesn't match the expected " + "pattern: \"%3\" %4.").arg(i) + .arg(log, message.first, handlerToName(message.second)); + QFAIL(failMessage.toUtf8()); + } + } + } } void tst_Tasking::testInThread_data() @@ -3094,7 +3277,7 @@ static void runInThread(QPromise &promise, const TestData &testData) promise.addResult(TestResult{i, ThreadResult::FailOnLogCheck, actualLog}); return; } - if (result != testData.onDone) { + if (result != testData.result) { promise.addResult(TestResult{i, ThreadResult::FailOnDoneStatusCheck}); return; } @@ -3126,7 +3309,7 @@ void tst_Tasking::testInThread() QCOMPARE(taskTree.isRunning(), false); QCOMPARE(CustomStorage::instanceCount(), 0); - QCOMPARE(result, testData.onDone); + QCOMPARE(result, testData.result); } struct StorageIO From b74bb782bbc001839502f879d97e07b4433d4a45 Mon Sep 17 00:00:00 2001 From: Jarek Kobus Date: Mon, 19 Feb 2024 23:52:17 +0100 Subject: [PATCH 091/243] TaskTree: Implement asyncCount() This might be useful for checking the integrality of tasks' invocations and detecting the unwanted asynchronity in the task tree execution. Example: we may want to ensure that the setup handler of the 2nd task was executed synchronously after the done handler of the 1st task, without returning the control to the event loop. This addresses the 34th point in the bugreport below. Task-number: QTCREATORBUG-28741 Change-Id: I7213ee62a7555818cbe18fd7bb8362353a3be8ae Reviewed-by: hjk --- src/libs/solutions/tasking/tasktree.cpp | 74 +++++++++++++++++++------ src/libs/solutions/tasking/tasktree.h | 2 + 2 files changed, 58 insertions(+), 18 deletions(-) diff --git a/src/libs/solutions/tasking/tasktree.cpp b/src/libs/solutions/tasking/tasktree.cpp index 865b541de47..390c4382057 100644 --- a/src/libs/solutions/tasking/tasktree.cpp +++ b/src/libs/solutions/tasking/tasktree.cpp @@ -1516,9 +1516,8 @@ public: void start(); void stop(); + void bumpAsyncCount(); void advanceProgress(int byValue); - void emitStartedAndProgress(); - void emitProgress(); void emitDone(DoneWith result); void callSetupHandler(StorageBase storage, StoragePtr storagePtr) { callStorageHandler(storage, storagePtr, &StorageHandler::m_setupHandler); @@ -1578,6 +1577,7 @@ public: TaskTree *q = nullptr; Guard m_guard; int m_progressValue = 0; + int m_asyncCount = 0; QSet m_storages; QHash m_storageHandlers; std::optional m_root; @@ -1722,8 +1722,14 @@ void TaskTreePrivate::start() { QT_ASSERT(m_root, return); QT_ASSERT(!m_runtimeRoot, return); + m_asyncCount = 0; m_progressValue = 0; - emitStartedAndProgress(); + { + GuardLocker locker(m_guard); + emit q->started(); + emit q->asyncCountChanged(m_asyncCount); + emit q->progressValueChanged(m_progressValue); + } // TODO: check storage handlers for not existing storages in tree for (auto it = m_storageHandlers.cbegin(); it != m_storageHandlers.cend(); ++it) { QT_ASSERT(m_storages.contains(it.key()), qWarning("The registered storage doesn't " @@ -1731,6 +1737,7 @@ void TaskTreePrivate::start() } m_runtimeRoot.reset(new RuntimeTask{*m_root}); start(m_runtimeRoot.get()); + bumpAsyncCount(); } void TaskTreePrivate::stop() @@ -1743,6 +1750,15 @@ void TaskTreePrivate::stop() emitDone(DoneWith::Cancel); } +void TaskTreePrivate::bumpAsyncCount() +{ + if (!m_runtimeRoot) + return; + ++m_asyncCount; + GuardLocker locker(m_guard); + emit q->asyncCountChanged(m_asyncCount); +} + void TaskTreePrivate::advanceProgress(int byValue) { if (byValue == 0) @@ -1750,18 +1766,6 @@ void TaskTreePrivate::advanceProgress(int byValue) QT_CHECK(byValue > 0); QT_CHECK(m_progressValue + byValue <= m_root->taskCount()); m_progressValue += byValue; - emitProgress(); -} - -void TaskTreePrivate::emitStartedAndProgress() -{ - GuardLocker locker(m_guard); - emit q->started(); - emit q->progressValueChanged(m_progressValue); -} - -void TaskTreePrivate::emitProgress() -{ GuardLocker locker(m_guard); emit q->progressValueChanged(m_progressValue); } @@ -2063,10 +2067,12 @@ SetupResult TaskTreePrivate::start(RuntimeTask *node) node->m_task.release()->deleteLater(); RuntimeIteration *parentIteration = node->m_parentIteration; parentIteration->deleteChild(node); - if (parentIteration->m_container->isStarting()) + if (parentIteration->m_container->isStarting()) { *unwindAction = toSetupResult(result); - else + } else { childDone(parentIteration, result); + bumpAsyncCount(); + } }); node->m_task->start(); @@ -2987,6 +2993,38 @@ DoneWith TaskTree::runBlocking(const Group &recipe, const QFuture &future, return taskTree.runBlocking(future); } +/*! + Returns the current real count of asynchronous chains of invocations. + + The returned value indicates how many times the control has returned to the caller's + event loop while the task tree is running. Initially, this value is 0. + If the execution of the task tree finishes fully synchronously, this value remains 0. + If the task tree contains any asynchronous task that is successfully started during + a call to start(), this value is bumped to 1 just before the call to start() finishes. + Later, when any asynchronous task finishes and any possible continuations are started, + this value is bumped again. The bumping continues until the task tree finishes. + After the task tree emitted the done() signal, this value isn't bumped anymore. + The asyncCountChanged() signal is emitted on every bump of this value. + + \sa asyncCountChanged() +*/ +int TaskTree::asyncCount() const +{ + return d->m_asyncCount; +} + +/*! + \fn void TaskTree::asyncCountChanged(int count) + + This signal is emitted when the running task tree is about to return control to the caller's + event loop. When the task tree is started, this signal is emitted with the value of 0, + and emitted later on every asyncCount() value bump. Every signal sent + (except the initial one with the value of 0) guarantees that the task tree is still running + asynchronously after the emission. + + \sa asyncCount() +*/ + /*! Returns the number of asynchronous tasks contained in the stored recipe. @@ -3032,7 +3070,7 @@ int TaskTree::taskCount() const When the task tree is started, this number is set to \c 0. When the task tree is finished, this number always equals progressMaximum(). - \sa progressMaximum() + \sa progressMaximum(), progressValueChanged() */ int TaskTree::progressValue() const { diff --git a/src/libs/solutions/tasking/tasktree.h b/src/libs/solutions/tasking/tasktree.h index 4b067a03c4a..8ea255303ba 100644 --- a/src/libs/solutions/tasking/tasktree.h +++ b/src/libs/solutions/tasking/tasktree.h @@ -541,6 +541,7 @@ public: static DoneWith runBlocking(const Group &recipe, const QFuture &future, std::chrono::milliseconds timeout = std::chrono::milliseconds::max()); + int asyncCount() const; int taskCount() const; int progressMaximum() const { return taskCount(); } int progressValue() const; // all finished / skipped / stopped tasks, groups itself excluded @@ -565,6 +566,7 @@ public: signals: void started(); void done(DoneWith result); + void asyncCountChanged(int count); void progressValueChanged(int value); // updated whenever task finished / skipped / stopped private: From 042d87a1e11bac17a0be8758a93620e2efdbe3bb Mon Sep 17 00:00:00 2001 From: Jarek Kobus Date: Mon, 19 Feb 2024 13:42:37 +0100 Subject: [PATCH 092/243] CppUseSelectionsUpdater: Don't delete the watcher from its signal handler Use std::unique_ptr instead, as QScopedPointer doesn't offer release(). Task-number: QTCREATORBUG-30401 Change-Id: If8f922fb52363a2e866cfacf770f617a00aa7fe5 Reviewed-by: Reviewed-by: Christian Kandeler Reviewed-by: Qt CI Bot --- src/plugins/cppeditor/cppuseselectionsupdater.cpp | 10 ++++------ src/plugins/cppeditor/cppuseselectionsupdater.h | 2 +- 2 files changed, 5 insertions(+), 7 deletions(-) diff --git a/src/plugins/cppeditor/cppuseselectionsupdater.cpp b/src/plugins/cppeditor/cppuseselectionsupdater.cpp index e03475ea80d..3b9fe40a89e 100644 --- a/src/plugins/cppeditor/cppuseselectionsupdater.cpp +++ b/src/plugins/cppeditor/cppuseselectionsupdater.cpp @@ -3,18 +3,16 @@ #include "cppuseselectionsupdater.h" -#include "cppeditorwidget.h" #include "cppeditordocument.h" +#include "cppeditorwidget.h" #include "cppmodelmanager.h" -#include "cpptoolsreuse.h" +#include #include #include #include -#include - enum { updateUseSelectionsInternalInMs = 500 }; namespace CppEditor { @@ -67,7 +65,7 @@ CppUseSelectionsUpdater::RunnerInfo CppUseSelectionsUpdater::update(CallType cal m_runnerWatcher->cancel(); m_runnerWatcher.reset(new QFutureWatcher); - connect(m_runnerWatcher.data(), &QFutureWatcherBase::finished, + connect(m_runnerWatcher.get(), &QFutureWatcherBase::finished, this, &CppUseSelectionsUpdater::onFindUsesFinished); m_runnerRevision = m_editorWidget->document()->revision(); @@ -142,7 +140,7 @@ void CppUseSelectionsUpdater::onFindUsesFinished() processResults(m_runnerWatcher->result()); - m_runnerWatcher.reset(); + m_runnerWatcher.release()->deleteLater(); } CppUseSelectionsUpdater::ExtraSelections diff --git a/src/plugins/cppeditor/cppuseselectionsupdater.h b/src/plugins/cppeditor/cppuseselectionsupdater.h index b303ce7c25e..88205c8974b 100644 --- a/src/plugins/cppeditor/cppuseselectionsupdater.h +++ b/src/plugins/cppeditor/cppuseselectionsupdater.h @@ -54,7 +54,7 @@ private: QTimer m_timer; - QScopedPointer> m_runnerWatcher; + std::unique_ptr> m_runnerWatcher; int m_runnerRevision = -1; int m_runnerWordStartPosition = -1; bool m_updateSelections = true; From e42fa739f0f88201dc91f179bd34ce3ee9657f71 Mon Sep 17 00:00:00 2001 From: Jarek Kobus Date: Mon, 19 Feb 2024 22:16:36 +0100 Subject: [PATCH 093/243] Axivion: Automatically fix the dashboard url Remove trailing spaces. Ensure the address ends with '/'. Change-Id: I5f51e89183e0e62c8d7d5c0cb7871477542e37d5 Reviewed-by: Christian Stenger --- src/plugins/axivion/axivionplugin.cpp | 19 +++++-------------- src/plugins/axivion/axivionsettings.cpp | 11 +++++++++-- 2 files changed, 14 insertions(+), 16 deletions(-) diff --git a/src/plugins/axivion/axivionplugin.cpp b/src/plugins/axivion/axivionplugin.cpp index d7ce85baf6f..0ac6e6a8573 100644 --- a/src/plugins/axivion/axivionplugin.cpp +++ b/src/plugins/axivion/axivionplugin.cpp @@ -214,7 +214,7 @@ class AxivionTextMark : public TextMark { public: AxivionTextMark(const FilePath &filePath, const Dto::LineMarkerDto &issue) - : TextMark(filePath, issue.startLine, {QString("Axivion"), s_axivionTextMarkId}) + : TextMark(filePath, issue.startLine, {"Axivion", s_axivionTextMarkId}) { const QString markText = issue.description; const QString id = issue.kind + QString::number(issue.id.value_or(-1)); @@ -314,10 +314,7 @@ void AxivionPluginPrivate::onStartupProjectChanged(Project *project) static QUrl urlForProject(const QString &projectName) { - QString dashboard = settings().server.dashboard; - if (!dashboard.endsWith(QLatin1Char('/'))) - dashboard += QLatin1Char('/'); - return QUrl(dashboard).resolved(QString("api/projects/")).resolved(projectName); + return QUrl(settings().server.dashboard).resolved(QString("api/projects/")).resolved(projectName); } static constexpr int httpStatusCodeOk = 200; @@ -636,17 +633,15 @@ Group dashboardInfoRecipe(const DashboardInfoHandler &handler) handler(make_unexpected(QString("Error"))); // TODO: Collect error message in the storage. }; - const QUrl url(settings().server.dashboard); - - const auto resultHandler = [handler, url](const Dto::DashboardInfoDto &data) { - dd->m_dashboardInfo = toDashboardInfo(url, data); + const auto resultHandler = [handler](const Dto::DashboardInfoDto &data) { + dd->m_dashboardInfo = toDashboardInfo(settings().server.dashboard, data); if (handler) handler(*dd->m_dashboardInfo); }; const Group root { onGroupSetup(onSetup), // Stops if cache exists. - fetchDataRecipe(url, resultHandler), + fetchDataRecipe(settings().server.dashboard, resultHandler), onGroupDone(onDone, CallDoneIf::Error) }; return root; @@ -681,10 +676,6 @@ Group issueHtmlRecipe(const QString &issueId, const HtmlHandler &handler) { QTC_ASSERT(dd->m_currentProjectInfo, return {}); // TODO: Call handler with unexpected? - QString dashboard = settings().server.dashboard; - if (!dashboard.endsWith(QLatin1Char('/'))) - dashboard += QLatin1Char('/'); - const QUrl url = urlForProject(dd->m_currentProjectInfo.value().name + '/') .resolved(QString("issues/")) .resolved(QString(issueId + '/')) diff --git a/src/plugins/axivion/axivionsettings.cpp b/src/plugins/axivion/axivionsettings.cpp index 3701a81d16d..86c821c439b 100644 --- a/src/plugins/axivion/axivionsettings.cpp +++ b/src/plugins/axivion/axivionsettings.cpp @@ -10,6 +10,7 @@ #include #include +#include #include #include @@ -44,6 +45,12 @@ QJsonObject AxivionServer::toJson() const return result; } +static QString fixUrl(const QString &url) +{ + const QString trimmed = Utils::trimBack(url, ' '); + return trimmed.endsWith('/') ? trimmed : trimmed + '/'; +} + AxivionServer AxivionServer::fromJson(const QJsonObject &json) { const AxivionServer invalidServer; @@ -56,7 +63,7 @@ AxivionServer AxivionServer::fromJson(const QJsonObject &json) const QJsonValue username = json.value("username"); if (username == QJsonValue::Undefined) return invalidServer; - return {Id::fromString(id.toString()), dashboard.toString(), username.toString()}; + return {Id::fromString(id.toString()), fixUrl(dashboard.toString()), username.toString()}; } static FilePath tokensFilePath() @@ -195,7 +202,7 @@ AxivionServer DashboardSettingsWidget::dashboardServer() const result.id = m_id; else result.id = m_mode == Edit ? Id::fromName(QUuid::createUuid().toByteArray()) : m_id; - result.dashboard = m_dashboardUrl(); + result.dashboard = fixUrl(m_dashboardUrl()); result.username = m_username(); return result; } From c63acd9924d8617ab8332156e38c72110ed3d142 Mon Sep 17 00:00:00 2001 From: Andreas Loth Date: Tue, 20 Feb 2024 13:50:24 +0100 Subject: [PATCH 094/243] Axivion: Remove false throws comments As all dtos are json objects (or at least json arrays), the std::domain_error shouldn't appear in the wild either. Change-Id: Ib926e0c454f9eacabf8546fb0a4038fcd153715b Reviewed-by: Jarek Kobus --- src/plugins/axivion/dashboard/dto.cpp | 54 +++------------------------ 1 file changed, 5 insertions(+), 49 deletions(-) diff --git a/src/plugins/axivion/dashboard/dto.cpp b/src/plugins/axivion/dashboard/dto.cpp index 11494e67aef..3b0623fc044 100644 --- a/src/plugins/axivion/dashboard/dto.cpp +++ b/src/plugins/axivion/dashboard/dto.cpp @@ -158,6 +158,7 @@ namespace Axivion::Internal::Dto { return de_serializer::serialize(value); } + // throws std::domain_error template static QByteArray serialize_bytes(const T &value) { @@ -647,10 +648,10 @@ namespace Axivion::Internal::Dto { // version - constexpr std::array ApiVersion::number{7,7,2,13780}; - const QLatin1String ApiVersion::string{"7.7.2.13780"}; - const QLatin1String ApiVersion::name{"7.7.2"}; - const QLatin1String ApiVersion::timestamp{"2024-01-10 07:39:35 +00:00"}; + constexpr std::array ApiVersion::number{7,7,3,3857}; + const QLatin1String ApiVersion::string{"7.7.3.13857"}; + const QLatin1String ApiVersion::name{"7.7.3"}; + const QLatin1String ApiVersion::timestamp{"2024-02-07 09:28:43 +00:00"}; // AnalyzedFileDto @@ -700,7 +701,6 @@ namespace Axivion::Internal::Dto { languageName(std::move(languageName)) { } - // throws Axivion::Internal::Dto::invalid_dto_exception QByteArray AnalyzedFileDto::serialize() const { return serialize_bytes(*this); @@ -805,7 +805,6 @@ namespace Axivion::Internal::Dto { newPassword(std::move(newPassword)) { } - // throws Axivion::Internal::Dto::invalid_dto_exception QByteArray ChangePasswordFormDto::serialize() const { return serialize_bytes(*this); @@ -936,7 +935,6 @@ namespace Axivion::Internal::Dto { displayColor(std::move(displayColor)) { } - // throws Axivion::Internal::Dto::invalid_dto_exception QByteArray ColumnTypeOptionDto::serialize() const { return serialize_bytes(*this); @@ -980,7 +978,6 @@ namespace Axivion::Internal::Dto { text(std::move(text)) { } - // throws Axivion::Internal::Dto::invalid_dto_exception QByteArray CommentRequestDto::serialize() const { return serialize_bytes(*this); @@ -1024,7 +1021,6 @@ namespace Axivion::Internal::Dto { csrfToken(std::move(csrfToken)) { } - // throws Axivion::Internal::Dto::invalid_dto_exception QByteArray CsrfTokenDto::serialize() const { return serialize_bytes(*this); @@ -1088,7 +1084,6 @@ namespace Axivion::Internal::Dto { line(std::move(line)) { } - // throws Axivion::Internal::Dto::invalid_dto_exception QByteArray EntityDto::serialize() const { return serialize_bytes(*this); @@ -1172,7 +1167,6 @@ namespace Axivion::Internal::Dto { data(std::move(data)) { } - // throws Axivion::Internal::Dto::invalid_dto_exception QByteArray ErrorDto::serialize() const { return serialize_bytes(*this); @@ -1246,7 +1240,6 @@ namespace Axivion::Internal::Dto { commentDeletionId(std::move(commentDeletionId)) { } - // throws Axivion::Internal::Dto::invalid_dto_exception QByteArray IssueCommentDto::serialize() const { return serialize_bytes(*this); @@ -1453,7 +1446,6 @@ namespace Axivion::Internal::Dto { endColumn(std::move(endColumn)) { } - // throws Axivion::Internal::Dto::invalid_dto_exception QByteArray IssueSourceLocationDto::serialize() const { return serialize_bytes(*this); @@ -1502,7 +1494,6 @@ namespace Axivion::Internal::Dto { color(std::move(color)) { } - // throws Axivion::Internal::Dto::invalid_dto_exception QByteArray IssueTagDto::serialize() const { return serialize_bytes(*this); @@ -1571,7 +1562,6 @@ namespace Axivion::Internal::Dto { selected(std::move(selected)) { } - // throws Axivion::Internal::Dto::invalid_dto_exception QByteArray IssueTagTypeDto::serialize() const { return serialize_bytes(*this); @@ -1686,7 +1676,6 @@ namespace Axivion::Internal::Dto { maxValue(std::move(maxValue)) { } - // throws Axivion::Internal::Dto::invalid_dto_exception QByteArray MetricDto::serialize() const { return serialize_bytes(*this); @@ -1760,7 +1749,6 @@ namespace Axivion::Internal::Dto { entityId(std::move(entityId)) { } - // throws Axivion::Internal::Dto::invalid_dto_exception QByteArray MetricValueTableRowDto::serialize() const { return serialize_bytes(*this); @@ -1846,7 +1834,6 @@ namespace Axivion::Internal::Dto { groups(std::move(groups)) { } - // throws Axivion::Internal::Dto::invalid_dto_exception QByteArray NamedFilterVisibilityDto::serialize() const { return serialize_bytes(*this); @@ -1895,7 +1882,6 @@ namespace Axivion::Internal::Dto { url(std::move(url)) { } - // throws Axivion::Internal::Dto::invalid_dto_exception QByteArray ProjectReferenceDto::serialize() const { return serialize_bytes(*this); @@ -1949,7 +1935,6 @@ namespace Axivion::Internal::Dto { disabled(std::move(disabled)) { } - // throws Axivion::Internal::Dto::invalid_dto_exception QByteArray RuleDto::serialize() const { return serialize_bytes(*this); @@ -2080,7 +2065,6 @@ namespace Axivion::Internal::Dto { buildDate(std::move(buildDate)) { } - // throws Axivion::Internal::Dto::invalid_dto_exception QByteArray ToolsVersionDto::serialize() const { return serialize_bytes(*this); @@ -2176,7 +2160,6 @@ namespace Axivion::Internal::Dto { Removed(std::move(Removed)) { } - // throws Axivion::Internal::Dto::invalid_dto_exception QByteArray VersionKindCountDto::serialize() const { return serialize_bytes(*this); @@ -2260,7 +2243,6 @@ namespace Axivion::Internal::Dto { cloneRatio(std::move(cloneRatio)) { } - // throws Axivion::Internal::Dto::invalid_dto_exception QByteArray AnalysisVersionDto::serialize() const { return serialize_bytes(*this); @@ -2351,7 +2333,6 @@ namespace Axivion::Internal::Dto { type = ApiTokenTypeMeta::enumToStr(newValue); } - // throws Axivion::Internal::Dto::invalid_dto_exception QByteArray ApiTokenCreationRequestDto::serialize() const { return serialize_bytes(*this); @@ -2505,7 +2486,6 @@ namespace Axivion::Internal::Dto { type = ApiTokenTypeMeta::enumToStr(newValue); } - // throws Axivion::Internal::Dto::invalid_dto_exception QByteArray ApiTokenInfoDto::serialize() const { return serialize_bytes(*this); @@ -2658,7 +2638,6 @@ namespace Axivion::Internal::Dto { type = ColumnTypeMeta::enumToStr(newValue); } - // throws Axivion::Internal::Dto::invalid_dto_exception QByteArray ColumnInfoDto::serialize() const { return serialize_bytes(*this); @@ -2772,7 +2751,6 @@ namespace Axivion::Internal::Dto { csrfTokenUrl(std::move(csrfTokenUrl)) { } - // throws Axivion::Internal::Dto::invalid_dto_exception QByteArray DashboardInfoDto::serialize() const { return serialize_bytes(*this); @@ -2816,7 +2794,6 @@ namespace Axivion::Internal::Dto { comments(std::move(comments)) { } - // throws Axivion::Internal::Dto::invalid_dto_exception QByteArray IssueCommentListDto::serialize() const { return serialize_bytes(*this); @@ -2900,7 +2877,6 @@ namespace Axivion::Internal::Dto { prefix = IssueKindMeta::enumToStr(newValue); } - // throws Axivion::Internal::Dto::invalid_dto_exception QByteArray IssueKindInfoDto::serialize() const { return serialize_bytes(*this); @@ -2944,7 +2920,6 @@ namespace Axivion::Internal::Dto { tags(std::move(tags)) { } - // throws Axivion::Internal::Dto::invalid_dto_exception QByteArray IssueTagTypeListDto::serialize() const { return serialize_bytes(*this); @@ -3070,7 +3045,6 @@ namespace Axivion::Internal::Dto { kind = IssueKindMeta::enumToStr(newValue); } - // throws Axivion::Internal::Dto::invalid_dto_exception QByteArray LineMarkerDto::serialize() const { return serialize_bytes(*this); @@ -3147,7 +3121,6 @@ namespace Axivion::Internal::Dto { severity = MessageSeverityMeta::enumToStr(newValue); } - // throws Axivion::Internal::Dto::invalid_dto_exception QByteArray RepositoryUpdateMessageDto::serialize() const { return serialize_bytes(*this); @@ -3191,7 +3164,6 @@ namespace Axivion::Internal::Dto { rules(std::move(rules)) { } - // throws Axivion::Internal::Dto::invalid_dto_exception QByteArray RuleListDto::serialize() const { return serialize_bytes(*this); @@ -3268,7 +3240,6 @@ namespace Axivion::Internal::Dto { direction = SortDirectionMeta::enumToStr(newValue); } - // throws Axivion::Internal::Dto::invalid_dto_exception QByteArray SortInfoDto::serialize() const { return serialize_bytes(*this); @@ -3361,7 +3332,6 @@ namespace Axivion::Internal::Dto { type = UserRefTypeMeta::enumToStr(newValue); } - // throws Axivion::Internal::Dto::invalid_dto_exception QByteArray UserRefDto::serialize() const { return serialize_bytes(*this); @@ -3410,7 +3380,6 @@ namespace Axivion::Internal::Dto { rows(std::move(rows)) { } - // throws Axivion::Internal::Dto::invalid_dto_exception QByteArray AnalyzedFileListDto::serialize() const { return serialize_bytes(*this); @@ -3459,7 +3428,6 @@ namespace Axivion::Internal::Dto { entities(std::move(entities)) { } - // throws Axivion::Internal::Dto::invalid_dto_exception QByteArray EntityListDto::serialize() const { return serialize_bytes(*this); @@ -3518,7 +3486,6 @@ namespace Axivion::Internal::Dto { lineMarkers(std::move(lineMarkers)) { } - // throws Axivion::Internal::Dto::invalid_dto_exception QByteArray FileViewDto::serialize() const { return serialize_bytes(*this); @@ -3630,7 +3597,6 @@ namespace Axivion::Internal::Dto { kind = IssueKindMeta::enumToStr(newValue); } - // throws Axivion::Internal::Dto::invalid_dto_exception QByteArray IssueDto::serialize() const { return serialize_bytes(*this); @@ -3709,7 +3675,6 @@ namespace Axivion::Internal::Dto { totalRemovedCount(std::move(totalRemovedCount)) { } - // throws Axivion::Internal::Dto::invalid_dto_exception QByteArray IssueTableDto::serialize() const { return serialize_bytes(*this); @@ -3758,7 +3723,6 @@ namespace Axivion::Internal::Dto { metrics(std::move(metrics)) { } - // throws Axivion::Internal::Dto::invalid_dto_exception QByteArray MetricListDto::serialize() const { return serialize_bytes(*this); @@ -3822,7 +3786,6 @@ namespace Axivion::Internal::Dto { values(std::move(values)) { } - // throws Axivion::Internal::Dto::invalid_dto_exception QByteArray MetricValueRangeDto::serialize() const { return serialize_bytes(*this); @@ -3871,7 +3834,6 @@ namespace Axivion::Internal::Dto { rows(std::move(rows)) { } - // throws Axivion::Internal::Dto::invalid_dto_exception QByteArray MetricValueTableDto::serialize() const { return serialize_bytes(*this); @@ -3969,7 +3931,6 @@ namespace Axivion::Internal::Dto { kind = IssueKindForNamedFilterCreationMeta::enumToStr(newValue); } - // throws Axivion::Internal::Dto::invalid_dto_exception QByteArray NamedFilterCreateDto::serialize() const { return serialize_bytes(*this); @@ -4111,7 +4072,6 @@ namespace Axivion::Internal::Dto { type = NamedFilterTypeMeta::enumToStr(newValue); } - // throws Axivion::Internal::Dto::invalid_dto_exception QByteArray NamedFilterInfoDto::serialize() const { return serialize_bytes(*this); @@ -4170,7 +4130,6 @@ namespace Axivion::Internal::Dto { visibility(std::move(visibility)) { } - // throws Axivion::Internal::Dto::invalid_dto_exception QByteArray NamedFilterUpdateDto::serialize() const { return serialize_bytes(*this); @@ -4244,7 +4203,6 @@ namespace Axivion::Internal::Dto { hasHiddenIssues(std::move(hasHiddenIssues)) { } - // throws Axivion::Internal::Dto::invalid_dto_exception QByteArray ProjectInfoDto::serialize() const { return serialize_bytes(*this); @@ -4298,7 +4256,6 @@ namespace Axivion::Internal::Dto { hasWarnings(std::move(hasWarnings)) { } - // throws Axivion::Internal::Dto::invalid_dto_exception QByteArray RepositoryUpdateResponseDto::serialize() const { return serialize_bytes(*this); @@ -4367,7 +4324,6 @@ namespace Axivion::Internal::Dto { axivionDefaultFilter(std::move(axivionDefaultFilter)) { } - // throws Axivion::Internal::Dto::invalid_dto_exception QByteArray TableInfoDto::serialize() const { return serialize_bytes(*this); From 2e276fb8a6842ae2fe1ad87fb1f44044acf671ad Mon Sep 17 00:00:00 2001 From: Christian Stenger Date: Tue, 13 Feb 2024 14:20:23 +0100 Subject: [PATCH 095/243] Axivion: Allow highlighting marks Adds a setting to enable highlighting issue markers on the highlighter scrollbar. Change-Id: I173510ccb75e684325135d8e587e8920ad22bd86 Reviewed-by: Jarek Kobus --- src/plugins/axivion/axivionplugin.cpp | 13 +++++++++---- src/plugins/axivion/axivionsettings.cpp | 17 +++++++++++++---- src/plugins/axivion/axivionsettings.h | 1 + 3 files changed, 23 insertions(+), 8 deletions(-) diff --git a/src/plugins/axivion/axivionplugin.cpp b/src/plugins/axivion/axivionplugin.cpp index 0ac6e6a8573..1cd8c9fc140 100644 --- a/src/plugins/axivion/axivionplugin.cpp +++ b/src/plugins/axivion/axivionplugin.cpp @@ -213,13 +213,16 @@ static AxivionPluginPrivate *dd = nullptr; class AxivionTextMark : public TextMark { public: - AxivionTextMark(const FilePath &filePath, const Dto::LineMarkerDto &issue) + AxivionTextMark(const FilePath &filePath, const Dto::LineMarkerDto &issue, + std::optional color) : TextMark(filePath, issue.startLine, {"Axivion", s_axivionTextMarkId}) { const QString markText = issue.description; const QString id = issue.kind + QString::number(issue.id.value_or(-1)); - setToolTip(id + markText); + setToolTip(id + '\n' + markText); setIcon(iconForIssue(issue.kind)); + if (color) + setColor(*color); setPriority(TextMark::NormalPriority); setLineAnnotation(markText); setActionsProvider([id] { @@ -818,12 +821,14 @@ void AxivionPluginPrivate::handleIssuesForFile(const Dto::FileViewDto &fileView) return; const FilePath filePath = project->projectDirectory().pathAppended(fileView.fileName); - + std::optional color = std::nullopt; + if (settings().highlightMarks()) + color.emplace(Theme::Color(Theme::Bookmarks_TextMarkColor)); // FIXME! for (const Dto::LineMarkerDto &marker : std::as_const(fileView.lineMarkers)) { // FIXME the line location can be wrong (even the whole issue could be wrong) // depending on whether this line has been changed since the last axivion run and the // current state of the file - some magic has to happen here - new AxivionTextMark(filePath, marker); + new AxivionTextMark(filePath, marker, color); } } diff --git a/src/plugins/axivion/axivionsettings.cpp b/src/plugins/axivion/axivionsettings.cpp index 86c821c439b..a4db242c2dd 100644 --- a/src/plugins/axivion/axivionsettings.cpp +++ b/src/plugins/axivion/axivionsettings.cpp @@ -106,6 +106,10 @@ AxivionSettings::AxivionSettings() { setSettingsGroup("Axivion"); + highlightMarks.setSettingsKey("HighlightMarks"); + highlightMarks.setLabelText(Tr::tr("Highlight marks")); + highlightMarks.setToolTip(Tr::tr("Check to enable issue marks on the scroll bar.")); + highlightMarks.setDefaultValue(false); AspectContainer::readSettings(); server = readTokenFile(tokensFilePath()); @@ -240,10 +244,15 @@ AxivionSettingsWidget::AxivionSettingsWidget() m_dashboardDisplay = new DashboardSettingsWidget(DashboardSettingsWidget::Display, this); m_dashboardDisplay->setDashboardServer(settings().server); m_edit = new QPushButton(Tr::tr("Edit..."), this); - Row { - Form { - m_dashboardDisplay, br, - }, Column { m_edit, st } + Column { + Row { + Form { + m_dashboardDisplay, br + }, st, + Column { m_edit }, + }, + Space(10), br, + Row { settings().highlightMarks }, st }.attachTo(this); connect(m_edit, &QPushButton::clicked, this, &AxivionSettingsWidget::showEditServerDialog); diff --git a/src/plugins/axivion/axivionsettings.h b/src/plugins/axivion/axivionsettings.h index b4231aff901..257b4056c56 100644 --- a/src/plugins/axivion/axivionsettings.h +++ b/src/plugins/axivion/axivionsettings.h @@ -38,6 +38,7 @@ public: void toSettings() const; AxivionServer server; // shall we have more than one? + Utils::BoolAspect highlightMarks{this}; }; AxivionSettings &settings(); From 5d630786852e1d653acea5e94cacfbb30d2dc791 Mon Sep 17 00:00:00 2001 From: Jarek Kobus Date: Mon, 19 Feb 2024 14:47:02 +0100 Subject: [PATCH 096/243] SemanticHighlighter: Simplify disconnecting from the watcher Change-Id: I92c78f71a209ac428354284649e0f4b6522a947f Reviewed-by: Christian Kandeler --- src/plugins/cppeditor/semantichighlighter.cpp | 27 +++++-------------- src/plugins/cppeditor/semantichighlighter.h | 3 --- 2 files changed, 6 insertions(+), 24 deletions(-) diff --git a/src/plugins/cppeditor/semantichighlighter.cpp b/src/plugins/cppeditor/semantichighlighter.cpp index 4cafaecd46f..17cfb2c40e4 100644 --- a/src/plugins/cppeditor/semantichighlighter.cpp +++ b/src/plugins/cppeditor/semantichighlighter.cpp @@ -39,7 +39,7 @@ SemanticHighlighter::SemanticHighlighter(TextDocument *baseTextDocument) SemanticHighlighter::~SemanticHighlighter() { if (m_watcher) { - disconnectWatcher(); + m_watcher->disconnect(this); m_watcher->cancel(); m_watcher->waitForFinished(); } @@ -57,11 +57,14 @@ void SemanticHighlighter::run() qCDebug(log) << "SemanticHighlighter: run()"; if (m_watcher) { - disconnectWatcher(); + m_watcher->disconnect(this); m_watcher->cancel(); } m_watcher.reset(new QFutureWatcher); - connectWatcher(); + connect(m_watcher.get(), &QFutureWatcherBase::resultsReadyAt, + this, &SemanticHighlighter::onHighlighterResultAvailable); + connect(m_watcher.get(), &QFutureWatcherBase::finished, + this, &SemanticHighlighter::onHighlighterFinished); m_revision = documentRevision(); m_seenBlocks.clear(); @@ -236,24 +239,6 @@ void SemanticHighlighter::onHighlighterFinished() qCDebug(log) << "onHighlighterFinished() took" << t.elapsed() << "ms"; } -void SemanticHighlighter::connectWatcher() -{ - using Watcher = QFutureWatcher; - connect(m_watcher.get(), &Watcher::resultsReadyAt, - this, &SemanticHighlighter::onHighlighterResultAvailable); - connect(m_watcher.get(), &Watcher::finished, - this, &SemanticHighlighter::onHighlighterFinished); -} - -void SemanticHighlighter::disconnectWatcher() -{ - using Watcher = QFutureWatcher; - disconnect(m_watcher.get(), &Watcher::resultsReadyAt, - this, &SemanticHighlighter::onHighlighterResultAvailable); - disconnect(m_watcher.get(), &Watcher::finished, - this, &SemanticHighlighter::onHighlighterFinished); -} - unsigned SemanticHighlighter::documentRevision() const { return m_baseTextDocument->document()->revision(); diff --git a/src/plugins/cppeditor/semantichighlighter.h b/src/plugins/cppeditor/semantichighlighter.h index a0d8e8db9ee..60edcb22159 100644 --- a/src/plugins/cppeditor/semantichighlighter.h +++ b/src/plugins/cppeditor/semantichighlighter.h @@ -70,9 +70,6 @@ private: void handleHighlighterResults(); void onHighlighterFinished(); - void connectWatcher(); - void disconnectWatcher(); - unsigned documentRevision() const; QVector getClearedParentheses(const QTextBlock &block); From 7d035f34d408294b26c2f36223948285bcef93f2 Mon Sep 17 00:00:00 2001 From: Jarek Kobus Date: Tue, 20 Feb 2024 14:55:56 +0100 Subject: [PATCH 097/243] TaskTree: Fix docs for asyncCount() Amends b74bb782bbc001839502f879d97e07b4433d4a45 Change-Id: I6da60e283c6bbd85ed109e37302611786f42c012 Reviewed-by: Leena Miettinen --- src/libs/solutions/tasking/tasktree.cpp | 14 +++++++------- 1 file changed, 7 insertions(+), 7 deletions(-) diff --git a/src/libs/solutions/tasking/tasktree.cpp b/src/libs/solutions/tasking/tasktree.cpp index 390c4382057..112c6dca75f 100644 --- a/src/libs/solutions/tasking/tasktree.cpp +++ b/src/libs/solutions/tasking/tasktree.cpp @@ -2996,14 +2996,14 @@ DoneWith TaskTree::runBlocking(const Group &recipe, const QFuture &future, /*! Returns the current real count of asynchronous chains of invocations. - The returned value indicates how many times the control has returned to the caller's + The returned value indicates how many times the control returns to the caller's event loop while the task tree is running. Initially, this value is 0. If the execution of the task tree finishes fully synchronously, this value remains 0. - If the task tree contains any asynchronous task that is successfully started during + If the task tree contains any asynchronous tasks that are successfully started during a call to start(), this value is bumped to 1 just before the call to start() finishes. Later, when any asynchronous task finishes and any possible continuations are started, this value is bumped again. The bumping continues until the task tree finishes. - After the task tree emitted the done() signal, this value isn't bumped anymore. + When the task tree emits the done() signal, the bumping stops. The asyncCountChanged() signal is emitted on every bump of this value. \sa asyncCountChanged() @@ -3017,10 +3017,10 @@ int TaskTree::asyncCount() const \fn void TaskTree::asyncCountChanged(int count) This signal is emitted when the running task tree is about to return control to the caller's - event loop. When the task tree is started, this signal is emitted with the value of 0, - and emitted later on every asyncCount() value bump. Every signal sent - (except the initial one with the value of 0) guarantees that the task tree is still running - asynchronously after the emission. + event loop. When the task tree is started, this signal is emitted with \a count value of 0, + and emitted later on every asyncCount() value bump with an updated \a count value. + Every signal sent (except the initial one with the value of 0) guarantees that the task tree + is still running asynchronously after the emission. \sa asyncCount() */ From e930b29d669af8bb03c59728c406446e3da3a9e5 Mon Sep 17 00:00:00 2001 From: Christian Kandeler Date: Tue, 20 Feb 2024 09:55:10 +0100 Subject: [PATCH 098/243] CppEditor: Do not access document manager when gathering local symbols As it turns out, that code runs in a dedicated thread. Task-number: QTCREATORBUG-30401 Change-Id: I66236fa00b8ddb55276d822357517fdccb0e61df Reviewed-by: Reviewed-by: Jarek Kobus Reviewed-by: Qt CI Bot --- src/plugins/cppeditor/builtincursorinfo.cpp | 42 ++++++++++++++----- src/plugins/cppeditor/builtincursorinfo.h | 2 +- .../builtineditordocumentprocessor.cpp | 2 +- src/plugins/cppeditor/cppchecksymbols.cpp | 30 +++++++++---- src/plugins/cppeditor/cppchecksymbols.h | 4 ++ .../cppeditor/cppfunctiondecldeflink.cpp | 2 +- src/plugins/cppeditor/cppindexingsupport.cpp | 2 +- src/plugins/cppeditor/cpplocalsymbols.cpp | 36 +++++++--------- src/plugins/cppeditor/cpplocalsymbols.h | 2 +- .../cppeditor/cpplocalsymbols_test.cpp | 2 +- .../checksymbols/tst_checksymbols.cpp | 2 +- 11 files changed, 78 insertions(+), 48 deletions(-) diff --git a/src/plugins/cppeditor/builtincursorinfo.cpp b/src/plugins/cppeditor/builtincursorinfo.cpp index 15e1e0f4921..0bff4406e76 100644 --- a/src/plugins/cppeditor/builtincursorinfo.cpp +++ b/src/plugins/cppeditor/builtincursorinfo.cpp @@ -135,17 +135,28 @@ private: class FindUses { public: - static CursorInfo find(const Document::Ptr document, const Snapshot &snapshot, - int line, int column, Scope *scope, const QString &expression) + static CursorInfo find(const Document::Ptr document, + const QString &content, + const Snapshot &snapshot, + int line, + int column, + Scope *scope, + const QString &expression) { - FindUses findUses(document, snapshot, line, column, scope, expression); + FindUses findUses(document, content, snapshot, line, column, scope, expression); return findUses.doFind(); } private: - FindUses(const Document::Ptr document, const Snapshot &snapshot, int line, int column, - Scope *scope, const QString &expression) + FindUses(const Document::Ptr document, + const QString &content, + const Snapshot &snapshot, + int line, + int column, + Scope *scope, + const QString &expression) : m_document(document) + , m_content(content) , m_line(line) , m_column(column) , m_scope(scope) @@ -160,7 +171,7 @@ private: // findLocalUses operates with 1-based line and 0-based column const SemanticInfo::LocalUseMap localUses - = BuiltinCursorInfo::findLocalUses(m_document, m_line, m_column - 1); + = BuiltinCursorInfo::findLocalUses(m_document, m_content, m_line, m_column - 1); result.localUses = localUses; splitLocalUses(localUses, &result.useRanges, &result.unusedVariablesRanges); @@ -230,6 +241,8 @@ private: // Shared Document::Ptr m_document; + const QString m_content; + // For local use calculation int m_line; int m_column; @@ -322,11 +335,20 @@ QFuture BuiltinCursorInfo::run(const CursorInfoParams &cursorInfoPar QString expression; Scope *scope = canonicalSymbol.getScopeAndExpression(textCursor, &expression); - return Utils::asyncRun(&FindUses::find, document, snapshot, line, column + 1, scope, expression); + return Utils::asyncRun(&FindUses::find, + document, + textCursor.document()->toPlainText(), + snapshot, + line, + column + 1, + scope, + expression); } -SemanticInfo::LocalUseMap -BuiltinCursorInfo::findLocalUses(const Document::Ptr &document, int line, int column) +SemanticInfo::LocalUseMap BuiltinCursorInfo::findLocalUses(const Document::Ptr &document, + const QString &content, + int line, + int column) { if (!document || !document->translationUnit() || !document->translationUnit()->ast()) return SemanticInfo::LocalUseMap(); @@ -334,7 +356,7 @@ BuiltinCursorInfo::findLocalUses(const Document::Ptr &document, int line, int co AST *ast = document->translationUnit()->ast(); FunctionDefinitionUnderCursor functionDefinitionUnderCursor(document->translationUnit()); DeclarationAST *declaration = functionDefinitionUnderCursor(ast, line, column); - return Internal::LocalSymbols(document, declaration).uses; + return Internal::LocalSymbols(document, content, declaration).uses; } } // namespace CppEditor diff --git a/src/plugins/cppeditor/builtincursorinfo.h b/src/plugins/cppeditor/builtincursorinfo.h index 4258f4854c2..731c66f4c17 100644 --- a/src/plugins/cppeditor/builtincursorinfo.h +++ b/src/plugins/cppeditor/builtincursorinfo.h @@ -18,7 +18,7 @@ public: static QFuture run(const CursorInfoParams ¶ms); static SemanticInfo::LocalUseMap - findLocalUses(const CPlusPlus::Document::Ptr &document, int line, int column); + findLocalUses(const CPlusPlus::Document::Ptr &document, const QString &content, int line, int column); }; } // namespace CppEditor diff --git a/src/plugins/cppeditor/builtineditordocumentprocessor.cpp b/src/plugins/cppeditor/builtineditordocumentprocessor.cpp index 4d43546334a..b934d1e7aed 100644 --- a/src/plugins/cppeditor/builtineditordocumentprocessor.cpp +++ b/src/plugins/cppeditor/builtineditordocumentprocessor.cpp @@ -126,7 +126,7 @@ CheckSymbols *createHighlighter(const CPlusPlus::Document::Ptr &doc, } LookupContext context(doc, snapshot); - return CheckSymbols::create(doc, context, macroUses); + return CheckSymbols::create(doc, textDocument->toPlainText(), context, macroUses); } QList toTextEditorBlocks( diff --git a/src/plugins/cppeditor/cppchecksymbols.cpp b/src/plugins/cppeditor/cppchecksymbols.cpp index e9334b0db29..7fa1ed3f5bd 100644 --- a/src/plugins/cppeditor/cppchecksymbols.cpp +++ b/src/plugins/cppeditor/cppchecksymbols.cpp @@ -270,28 +270,40 @@ static bool acceptName(NameAST *ast, unsigned *referenceToken) && !ast->asOperatorFunctionId(); } -CheckSymbols::Future CheckSymbols::go(Document::Ptr doc, const LookupContext &context, const QList ¯oUses) +CheckSymbols::Future CheckSymbols::go(Document::Ptr doc, + const QString &content, + const LookupContext &context, + const QList ¯oUses) { QTC_ASSERT(doc, return Future()); QTC_ASSERT(doc->translationUnit(), return Future()); QTC_ASSERT(doc->translationUnit()->ast(), return Future()); - return (new CheckSymbols(doc, context, macroUses))->start(); + return (new CheckSymbols(doc, content, context, macroUses))->start(); } -CheckSymbols * CheckSymbols::create(Document::Ptr doc, const LookupContext &context, - const QList ¯oUses) +CheckSymbols *CheckSymbols::create(Document::Ptr doc, + const QString &content, + const LookupContext &context, + const QList ¯oUses) { QTC_ASSERT(doc, return nullptr); QTC_ASSERT(doc->translationUnit(), return nullptr); QTC_ASSERT(doc->translationUnit()->ast(), return nullptr); - return new CheckSymbols(doc, context, macroUses); + return new CheckSymbols(doc, content, context, macroUses); } -CheckSymbols::CheckSymbols(Document::Ptr doc, const LookupContext &context, const QList ¯oUses) - : ASTVisitor(doc->translationUnit()), _doc(doc), _context(context) - , _lineOfLastUsage(0), _macroUses(macroUses) +CheckSymbols::CheckSymbols(Document::Ptr doc, + const QString &content, + const LookupContext &context, + const QList ¯oUses) + : ASTVisitor(doc->translationUnit()) + , _doc(doc) + , _content(content) + , _context(context) + , _lineOfLastUsage(0) + , _macroUses(macroUses) { int line = 0; getTokenEndPosition(translationUnit()->ast()->lastToken(), &line, nullptr); @@ -1114,7 +1126,7 @@ bool CheckSymbols::visit(FunctionDefinitionAST *ast) accept(ast->ctor_initializer); accept(ast->function_body); - const Internal::LocalSymbols locals(_doc, ast); + const Internal::LocalSymbols locals(_doc, _content, ast); for (const QList &uses : std::as_const(locals.uses)) { for (const Result &u : uses) addUse(u); diff --git a/src/plugins/cppeditor/cppchecksymbols.h b/src/plugins/cppeditor/cppchecksymbols.h index f660da6dc90..38e04f989d6 100644 --- a/src/plugins/cppeditor/cppchecksymbols.h +++ b/src/plugins/cppeditor/cppchecksymbols.h @@ -42,9 +42,11 @@ public: } static Future go(CPlusPlus::Document::Ptr doc, + const QString &content, const CPlusPlus::LookupContext &context, const QList ¯oUses); static CheckSymbols * create(CPlusPlus::Document::Ptr doc, + const QString &content, const CPlusPlus::LookupContext &context, const QList ¯oUses); @@ -79,6 +81,7 @@ protected: }; CheckSymbols(CPlusPlus::Document::Ptr doc, + const QString &content, const CPlusPlus::LookupContext &context, const QList &otherUses); @@ -168,6 +171,7 @@ private: bool isConstructorDeclaration(CPlusPlus::Symbol *declaration); CPlusPlus::Document::Ptr _doc; + const QString _content; CPlusPlus::LookupContext _context; CPlusPlus::TypeOfExpression typeOfExpression; Utils::FilePath _filePath; diff --git a/src/plugins/cppeditor/cppfunctiondecldeflink.cpp b/src/plugins/cppeditor/cppfunctiondecldeflink.cpp index 4dc31087bc4..9552ba21984 100644 --- a/src/plugins/cppeditor/cppfunctiondecldeflink.cpp +++ b/src/plugins/cppeditor/cppfunctiondecldeflink.cpp @@ -890,7 +890,7 @@ ChangeSet FunctionDeclDefLink::changes(const Snapshot &snapshot, int targetOffse // for function definitions, rename the local usages FunctionDefinitionAST *targetDefinition = targetDeclaration->asFunctionDefinition(); if (targetDefinition && !renamedTargetParameters.isEmpty()) { - const LocalSymbols localSymbols(targetFile->cppDocument(), targetDefinition); + const LocalSymbols localSymbols(targetFile->cppDocument(), {}, targetDefinition); const int endOfArguments = targetFile->endOf(targetFunctionDeclarator->rparen_token); for (auto it = renamedTargetParameters.cbegin(), end = renamedTargetParameters.cend(); diff --git a/src/plugins/cppeditor/cppindexingsupport.cpp b/src/plugins/cppeditor/cppindexingsupport.cpp index 21a5da4109f..3a418a5b782 100644 --- a/src/plugins/cppeditor/cppindexingsupport.cpp +++ b/src/plugins/cppeditor/cppindexingsupport.cpp @@ -147,7 +147,7 @@ static void indexFindErrors(QPromise &promise, const ParseParams params) // Look up symbols CPlusPlus::LookupContext context(document, parser.snapshot()); - CheckSymbols::go(document, context, QList()).waitForFinished(); + CheckSymbols::go(document, {}, context, QList()).waitForFinished(); document->releaseSourceAndAST(); diff --git a/src/plugins/cppeditor/cpplocalsymbols.cpp b/src/plugins/cppeditor/cpplocalsymbols.cpp index 9983f9fba11..ec91dbe349a 100644 --- a/src/plugins/cppeditor/cpplocalsymbols.cpp +++ b/src/plugins/cppeditor/cpplocalsymbols.cpp @@ -7,12 +7,12 @@ #include "cpptoolsreuse.h" #include "semantichighlighter.h" -#include #include #include -#include #include +#include + using namespace CPlusPlus; namespace CppEditor::Internal { @@ -22,8 +22,8 @@ namespace { class FindLocalSymbols: protected ASTVisitor { public: - explicit FindLocalSymbols(Document::Ptr doc) - : ASTVisitor(doc->translationUnit()), _doc(doc) + explicit FindLocalSymbols(Document::Ptr doc, const QString &content) + : ASTVisitor(doc->translationUnit()), _doc(doc), _content(content) { } // local and external uses. @@ -49,35 +49,26 @@ public: if (localUses.isEmpty()) return; - // For tst_checkSymbols - if (!Core::DocumentManager::instance()) - return; - // Look for parameter occurrences in function comments. - const TextEditor::TextDocument * const editorDoc - = TextEditor::TextDocument::textDocumentForFilePath(_doc->filePath()); - if (!editorDoc) + if (_content.isEmpty()) return; - QTextDocument * const textDoc = editorDoc->document(); - if (!textDoc) - return; - const QString &content = textDoc->toPlainText(); - const QStringView docView(content); + QTextDocument textDoc(_content); + const QStringView docView(_content); for (auto it = localUses.begin(); it != localUses.end(); ++it) { Symbol * const symbol = it.key(); if (!symbol->asArgument()) continue; - const QList commentTokens = commentsForDeclaration(symbol, ast, *textDoc, _doc); + const QList commentTokens = commentsForDeclaration(symbol, ast, textDoc, _doc); if (commentTokens.isEmpty()) continue; const QString symbolName = Overview().prettyName(symbol->name()); for (const Token &tok : commentTokens) { - const int commentPos = translationUnit()->getTokenPositionInDocument(tok, textDoc); + const int commentPos = translationUnit()->getTokenPositionInDocument(tok, &textDoc); const int commentEndPos = translationUnit()->getTokenEndPositionInDocument( - tok, textDoc); + tok, &textDoc); const QStringView commentView = docView.mid(commentPos, commentEndPos - commentPos); const QList ranges = symbolOccurrencesInText( - *textDoc, commentView, commentPos, symbolName); + textDoc, commentView, commentPos, symbolName); for (const Utils::Text::Range &range : ranges) { it.value().append(HighlightingResult(range.begin.line, range.begin.column + 1, symbolName.size(), @@ -323,14 +314,15 @@ protected: private: QList _scopeStack; Document::Ptr _doc; + const QString _content; }; } // end of anonymous namespace -LocalSymbols::LocalSymbols(Document::Ptr doc, DeclarationAST *ast) +LocalSymbols::LocalSymbols(Document::Ptr doc, const QString &content, DeclarationAST *ast) { - FindLocalSymbols findLocalSymbols(doc); + FindLocalSymbols findLocalSymbols(doc, content); findLocalSymbols(ast); uses = findLocalSymbols.localUses; } diff --git a/src/plugins/cppeditor/cpplocalsymbols.h b/src/plugins/cppeditor/cpplocalsymbols.h index 3c178f2f40e..26cd185b729 100644 --- a/src/plugins/cppeditor/cpplocalsymbols.h +++ b/src/plugins/cppeditor/cpplocalsymbols.h @@ -12,7 +12,7 @@ class LocalSymbols Q_DISABLE_COPY(LocalSymbols) public: - LocalSymbols(CPlusPlus::Document::Ptr doc, CPlusPlus::DeclarationAST *ast); + LocalSymbols(CPlusPlus::Document::Ptr doc, const QString &content, CPlusPlus::DeclarationAST *ast); SemanticInfo::LocalUseMap uses; }; diff --git a/src/plugins/cppeditor/cpplocalsymbols_test.cpp b/src/plugins/cppeditor/cpplocalsymbols_test.cpp index 9605f24ffa8..740fd8233c9 100644 --- a/src/plugins/cppeditor/cpplocalsymbols_test.cpp +++ b/src/plugins/cppeditor/cpplocalsymbols_test.cpp @@ -160,7 +160,7 @@ void LocalSymbolsTest::test() FindFirstFunctionDefinition find(document->translationUnit()); CPlusPlus::DeclarationAST *functionDefinition = find(); - LocalSymbols localSymbols(document, functionDefinition); + LocalSymbols localSymbols(document, QString::fromUtf8(source), functionDefinition); const QList actualUses = Result::fromLocalUses(localSymbols.uses); // for (const Result &result : actualUses) diff --git a/tests/auto/cplusplus/checksymbols/tst_checksymbols.cpp b/tests/auto/cplusplus/checksymbols/tst_checksymbols.cpp index 0e0705c5e56..4a49e8852f4 100644 --- a/tests/auto/cplusplus/checksymbols/tst_checksymbols.cpp +++ b/tests/auto/cplusplus/checksymbols/tst_checksymbols.cpp @@ -109,7 +109,7 @@ public: const UseList &expectedUsesMacros = UseList()) { LookupContext context(document, snapshot); - CheckSymbols::Future future = CheckSymbols::go(document, context, expectedUsesMacros); + CheckSymbols::Future future = CheckSymbols::go(document, {}, context, expectedUsesMacros); future.waitForFinished(); return future; } From af54f62166c67b471243177b8caad21ac4634cf2 Mon Sep 17 00:00:00 2001 From: Jarek Kobus Date: Mon, 19 Feb 2024 14:54:25 +0100 Subject: [PATCH 099/243] SemanticHighlighter: Add internal FutureSynchronizer As it's not clear whether canceled future may continue to run when the SemanticHighlighter instance is destructed, add internal FutureSynchronizer that ensures that all old, canceled futures are finished from the SemanticHighlighter's d'tor. Change-Id: I3128999f1250d666fcc3aa04599bb4a9c675ca3e Reviewed-by: Christian Kandeler --- src/plugins/cppeditor/semantichighlighter.cpp | 14 +++----------- src/plugins/cppeditor/semantichighlighter.h | 5 ++++- 2 files changed, 7 insertions(+), 12 deletions(-) diff --git a/src/plugins/cppeditor/semantichighlighter.cpp b/src/plugins/cppeditor/semantichighlighter.cpp index 17cfb2c40e4..d841ae19c4e 100644 --- a/src/plugins/cppeditor/semantichighlighter.cpp +++ b/src/plugins/cppeditor/semantichighlighter.cpp @@ -36,14 +36,7 @@ SemanticHighlighter::SemanticHighlighter(TextDocument *baseTextDocument) updateFormatMapFromFontSettings(); } -SemanticHighlighter::~SemanticHighlighter() -{ - if (m_watcher) { - m_watcher->disconnect(this); - m_watcher->cancel(); - m_watcher->waitForFinished(); - } -} +SemanticHighlighter::~SemanticHighlighter() = default; void SemanticHighlighter::setHighlightingRunner(HighlightingRunner highlightingRunner) { @@ -56,10 +49,8 @@ void SemanticHighlighter::run() qCDebug(log) << "SemanticHighlighter: run()"; - if (m_watcher) { - m_watcher->disconnect(this); + if (m_watcher) m_watcher->cancel(); - } m_watcher.reset(new QFutureWatcher); connect(m_watcher.get(), &QFutureWatcherBase::resultsReadyAt, this, &SemanticHighlighter::onHighlighterResultAvailable); @@ -71,6 +62,7 @@ void SemanticHighlighter::run() m_nextResultToHandle = m_resultCount = 0; qCDebug(log) << "starting runner for document revision" << m_revision; m_watcher->setFuture(m_highlightingRunner()); + m_futureSynchronizer.addFuture(m_watcher->future()); } Parentheses SemanticHighlighter::getClearedParentheses(const QTextBlock &block) diff --git a/src/plugins/cppeditor/semantichighlighter.h b/src/plugins/cppeditor/semantichighlighter.h index 60edcb22159..f4fb25ddca3 100644 --- a/src/plugins/cppeditor/semantichighlighter.h +++ b/src/plugins/cppeditor/semantichighlighter.h @@ -5,6 +5,8 @@ #include "cppeditor_global.h" +#include + #include #include #include @@ -77,13 +79,14 @@ private: TextEditor::TextDocument *m_baseTextDocument; unsigned m_revision = 0; - std::unique_ptr> m_watcher; QHash m_formatMap; std::set m_seenBlocks; int m_nextResultToHandle = 0; int m_resultCount = 0; HighlightingRunner m_highlightingRunner; + Utils::FutureSynchronizer m_futureSynchronizer; // Keep before m_watcher. + std::unique_ptr> m_watcher; }; } // namespace CppEditor From 2cb18715ebbcacb99c5aec5db5e4ca12daad491f Mon Sep 17 00:00:00 2001 From: Jarek Kobus Date: Mon, 19 Feb 2024 13:49:03 +0100 Subject: [PATCH 100/243] CppUseSelectionsUpdater: Ensure the old futures are synchronized When scheduling a new async run (via FindUses::find()), keep track for the canceled futures, otherwise they may still be running after the shutdown. So, add all new futures into the future synchronizer (without canceling them). Task-number: QTCREATORBUG-30401 Change-Id: I83a82f706175060f7f29886b57c69c77667a0805 Reviewed-by: Christian Kandeler Reviewed-by: Qt CI Bot Reviewed-by: --- src/plugins/cppeditor/cppuseselectionsupdater.cpp | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/src/plugins/cppeditor/cppuseselectionsupdater.cpp b/src/plugins/cppeditor/cppuseselectionsupdater.cpp index 3b9fe40a89e..67fb6d7a1bc 100644 --- a/src/plugins/cppeditor/cppuseselectionsupdater.cpp +++ b/src/plugins/cppeditor/cppuseselectionsupdater.cpp @@ -7,6 +7,9 @@ #include "cppeditorwidget.h" #include "cppmodelmanager.h" +#include + +#include #include #include @@ -72,6 +75,7 @@ CppUseSelectionsUpdater::RunnerInfo CppUseSelectionsUpdater::update(CallType cal m_runnerWordStartPosition = params.textCursor.position(); m_runnerWatcher->setFuture(cppEditorDocument->cursorInfo(params)); + ExtensionSystem::PluginManager::futureSynchronizer()->addFuture(m_runnerWatcher->future()); return RunnerInfo::Started; } else { // synchronous case abortSchedule(); From 2ff4eec9ac4a2fd13db06c78d788996c7e7c4c5e Mon Sep 17 00:00:00 2001 From: Andreas Loth Date: Tue, 20 Feb 2024 16:13:34 +0100 Subject: [PATCH 101/243] Axivion: Provide non-throwing overloads for DTO deserializing Change-Id: I8dadd76b1e6f0b22293c4e8758759c2b86092926 Reviewed-by: Jarek Kobus --- src/plugins/axivion/dashboard/dto.cpp | 294 ++++++++++++++++++++++++++ src/plugins/axivion/dashboard/dto.h | 114 +++++++++- 2 files changed, 407 insertions(+), 1 deletion(-) diff --git a/src/plugins/axivion/dashboard/dto.cpp b/src/plugins/axivion/dashboard/dto.cpp index 3b0623fc044..d578e3dff10 100644 --- a/src/plugins/axivion/dashboard/dto.cpp +++ b/src/plugins/axivion/dashboard/dto.cpp @@ -127,6 +127,26 @@ namespace Axivion::Internal::Dto { return de_serializer::deserialize(json); } + template + static Utils::expected_str deserializeExp(const QByteArray &json) + { + try { + return T::deserialize(json); + } catch (const Dto::invalid_dto_exception &e) { + return Utils::make_unexpected(QString::fromUtf8(e.what())); + } + } + + template> + static std::optional strToOptionalEn(QAnyStringView str) + { + try { + return M::strToEnum(str); + } catch (const std::range_error &) { + return std::nullopt; + } + } + // throws Axivion::Internal::Dto::invalid_dto_exception template static T deserialize_bytes(const QByteArray &json) @@ -549,6 +569,10 @@ namespace Axivion::Internal::Dto { return deserialize_bytes(json); } + Utils::expected_str Any::deserializeExpected(const QByteArray &json) { + return deserializeExp(json); + } + Any::Any() {} Any::Any(QString value) : data(std::move(value)) {} @@ -691,6 +715,11 @@ namespace Axivion::Internal::Dto { return deserialize_bytes(json); } + Utils::expected_str AnalyzedFileDto::deserializeExpected(const QByteArray &json) + { + return deserializeExp(json); + } + AnalyzedFileDto::AnalyzedFileDto( QString path, std::optional isSystemHeader, @@ -740,6 +769,11 @@ namespace Axivion::Internal::Dto { throw std::range_error(concat({ "Unknown ApiTokenType str: ", to_std_string(str) })); } + std::optional ApiTokenTypeMeta::strToOptionalEnum(QAnyStringView str) + { + return strToOptionalEn(str); + } + QLatin1String ApiTokenTypeMeta::enumToStr(ApiTokenType e) { switch (e) @@ -797,6 +831,11 @@ namespace Axivion::Internal::Dto { return deserialize_bytes(json); } + Utils::expected_str ChangePasswordFormDto::deserializeExpected(const QByteArray &json) + { + return deserializeExp(json); + } + ChangePasswordFormDto::ChangePasswordFormDto( QString currentPassword, QString newPassword @@ -859,6 +898,11 @@ namespace Axivion::Internal::Dto { throw std::range_error(concat({ "Unknown ColumnType str: ", to_std_string(str) })); } + std::optional ColumnTypeMeta::strToOptionalEnum(QAnyStringView str) + { + return strToOptionalEn(str); + } + QLatin1String ColumnTypeMeta::enumToStr(ColumnType e) { switch (e) @@ -925,6 +969,11 @@ namespace Axivion::Internal::Dto { return deserialize_bytes(json); } + Utils::expected_str ColumnTypeOptionDto::deserializeExpected(const QByteArray &json) + { + return deserializeExp(json); + } + ColumnTypeOptionDto::ColumnTypeOptionDto( QString key, std::optional displayName, @@ -972,6 +1021,11 @@ namespace Axivion::Internal::Dto { return deserialize_bytes(json); } + Utils::expected_str CommentRequestDto::deserializeExpected(const QByteArray &json) + { + return deserializeExp(json); + } + CommentRequestDto::CommentRequestDto( QString text ) : @@ -1015,6 +1069,11 @@ namespace Axivion::Internal::Dto { return deserialize_bytes(json); } + Utils::expected_str CsrfTokenDto::deserializeExpected(const QByteArray &json) + { + return deserializeExp(json); + } + CsrfTokenDto::CsrfTokenDto( QString csrfToken ) : @@ -1070,6 +1129,11 @@ namespace Axivion::Internal::Dto { return deserialize_bytes(json); } + Utils::expected_str EntityDto::deserializeExpected(const QByteArray &json) + { + return deserializeExp(json); + } + EntityDto::EntityDto( QString id, QString name, @@ -1145,6 +1209,11 @@ namespace Axivion::Internal::Dto { return deserialize_bytes(json); } + Utils::expected_str ErrorDto::deserializeExpected(const QByteArray &json) + { + return deserializeExp(json); + } + ErrorDto::ErrorDto( std::optional dashboardVersionNumber, QString type, @@ -1222,6 +1291,11 @@ namespace Axivion::Internal::Dto { return deserialize_bytes(json); } + Utils::expected_str IssueCommentDto::deserializeExpected(const QByteArray &json) + { + return deserializeExp(json); + } + IssueCommentDto::IssueCommentDto( QString username, QString userDisplayName, @@ -1284,6 +1358,11 @@ namespace Axivion::Internal::Dto { throw std::range_error(concat({ "Unknown IssueKind str: ", to_std_string(str) })); } + std::optional IssueKindMeta::strToOptionalEnum(QAnyStringView str) + { + return strToOptionalEn(str); + } + QLatin1String IssueKindMeta::enumToStr(IssueKind e) { switch (e) @@ -1352,6 +1431,11 @@ namespace Axivion::Internal::Dto { throw std::range_error(concat({ "Unknown IssueKindForNamedFilterCreation str: ", to_std_string(str) })); } + std::optional IssueKindForNamedFilterCreationMeta::strToOptionalEnum(QAnyStringView str) + { + return strToOptionalEn(str); + } + QLatin1String IssueKindForNamedFilterCreationMeta::enumToStr(IssueKindForNamedFilterCreation e) { switch (e) @@ -1428,6 +1512,11 @@ namespace Axivion::Internal::Dto { return deserialize_bytes(json); } + Utils::expected_str IssueSourceLocationDto::deserializeExpected(const QByteArray &json) + { + return deserializeExp(json); + } + IssueSourceLocationDto::IssueSourceLocationDto( QString fileName, std::optional role, @@ -1486,6 +1575,11 @@ namespace Axivion::Internal::Dto { return deserialize_bytes(json); } + Utils::expected_str IssueTagDto::deserializeExpected(const QByteArray &json) + { + return deserializeExp(json); + } + IssueTagDto::IssueTagDto( QString tag, QString color @@ -1546,6 +1640,11 @@ namespace Axivion::Internal::Dto { return deserialize_bytes(json); } + Utils::expected_str IssueTagTypeDto::deserializeExpected(const QByteArray &json) + { + return deserializeExp(json); + } + IssueTagTypeDto::IssueTagTypeDto( QString id, std::optional text, @@ -1601,6 +1700,11 @@ namespace Axivion::Internal::Dto { throw std::range_error(concat({ "Unknown MessageSeverity str: ", to_std_string(str) })); } + std::optional MessageSeverityMeta::strToOptionalEnum(QAnyStringView str) + { + return strToOptionalEn(str); + } + QLatin1String MessageSeverityMeta::enumToStr(MessageSeverity e) { switch (e) @@ -1664,6 +1768,11 @@ namespace Axivion::Internal::Dto { return deserialize_bytes(json); } + Utils::expected_str MetricDto::deserializeExpected(const QByteArray &json) + { + return deserializeExp(json); + } + MetricDto::MetricDto( QString name, QString displayName, @@ -1731,6 +1840,11 @@ namespace Axivion::Internal::Dto { return deserialize_bytes(json); } + Utils::expected_str MetricValueTableRowDto::deserializeExpected(const QByteArray &json) + { + return deserializeExp(json); + } + MetricValueTableRowDto::MetricValueTableRowDto( QString metric, std::optional path, @@ -1778,6 +1892,11 @@ namespace Axivion::Internal::Dto { throw std::range_error(concat({ "Unknown NamedFilterType str: ", to_std_string(str) })); } + std::optional NamedFilterTypeMeta::strToOptionalEnum(QAnyStringView str) + { + return strToOptionalEn(str); + } + QLatin1String NamedFilterTypeMeta::enumToStr(NamedFilterType e) { switch (e) @@ -1828,6 +1947,11 @@ namespace Axivion::Internal::Dto { return deserialize_bytes(json); } + Utils::expected_str NamedFilterVisibilityDto::deserializeExpected(const QByteArray &json) + { + return deserializeExp(json); + } + NamedFilterVisibilityDto::NamedFilterVisibilityDto( std::optional> groups ) : @@ -1874,6 +1998,11 @@ namespace Axivion::Internal::Dto { return deserialize_bytes(json); } + Utils::expected_str ProjectReferenceDto::deserializeExpected(const QByteArray &json) + { + return deserializeExp(json); + } + ProjectReferenceDto::ProjectReferenceDto( QString name, QString url @@ -1925,6 +2054,11 @@ namespace Axivion::Internal::Dto { return deserialize_bytes(json); } + Utils::expected_str RuleDto::deserializeExpected(const QByteArray &json) + { + return deserializeExp(json); + } + RuleDto::RuleDto( QString name, QString original_name, @@ -1959,6 +2093,11 @@ namespace Axivion::Internal::Dto { throw std::range_error(concat({ "Unknown SortDirection str: ", to_std_string(str) })); } + std::optional SortDirectionMeta::strToOptionalEnum(QAnyStringView str) + { + return strToOptionalEn(str); + } + QLatin1String SortDirectionMeta::enumToStr(SortDirection e) { switch (e) @@ -1999,6 +2138,11 @@ namespace Axivion::Internal::Dto { throw std::range_error(concat({ "Unknown TableCellAlignment str: ", to_std_string(str) })); } + std::optional TableCellAlignmentMeta::strToOptionalEnum(QAnyStringView str) + { + return strToOptionalEn(str); + } + QLatin1String TableCellAlignmentMeta::enumToStr(TableCellAlignment e) { switch (e) @@ -2055,6 +2199,11 @@ namespace Axivion::Internal::Dto { return deserialize_bytes(json); } + Utils::expected_str ToolsVersionDto::deserializeExpected(const QByteArray &json) + { + return deserializeExp(json); + } + ToolsVersionDto::ToolsVersionDto( QString name, QString number, @@ -2094,6 +2243,11 @@ namespace Axivion::Internal::Dto { throw std::range_error(concat({ "Unknown UserRefType str: ", to_std_string(str) })); } + std::optional UserRefTypeMeta::strToOptionalEnum(QAnyStringView str) + { + return strToOptionalEn(str); + } + QLatin1String UserRefTypeMeta::enumToStr(UserRefType e) { switch (e) @@ -2150,6 +2304,11 @@ namespace Axivion::Internal::Dto { return deserialize_bytes(json); } + Utils::expected_str VersionKindCountDto::deserializeExpected(const QByteArray &json) + { + return deserializeExp(json); + } + VersionKindCountDto::VersionKindCountDto( qint32 Total, qint32 Added, @@ -2221,6 +2380,11 @@ namespace Axivion::Internal::Dto { return deserialize_bytes(json); } + Utils::expected_str AnalysisVersionDto::deserializeExpected(const QByteArray &json) + { + return deserializeExp(json); + } + AnalysisVersionDto::AnalysisVersionDto( QString date, std::optional label, @@ -2289,6 +2453,11 @@ namespace Axivion::Internal::Dto { return deserialize_bytes(json); } + Utils::expected_str ApiTokenCreationRequestDto::deserializeExpected(const QByteArray &json) + { + return deserializeExp(json); + } + ApiTokenCreationRequestDto::ApiTokenCreationRequestDto( QString password, QString type, @@ -2406,6 +2575,11 @@ namespace Axivion::Internal::Dto { return deserialize_bytes(json); } + Utils::expected_str ApiTokenInfoDto::deserializeExpected(const QByteArray &json) + { + return deserializeExp(json); + } + ApiTokenInfoDto::ApiTokenInfoDto( QString id, QString url, @@ -2550,6 +2724,11 @@ namespace Axivion::Internal::Dto { return deserialize_bytes(json); } + Utils::expected_str ColumnInfoDto::deserializeExpected(const QByteArray &json) + { + return deserializeExp(json); + } + ColumnInfoDto::ColumnInfoDto( QString key, std::optional header, @@ -2717,6 +2896,11 @@ namespace Axivion::Internal::Dto { return deserialize_bytes(json); } + Utils::expected_str DashboardInfoDto::deserializeExpected(const QByteArray &json) + { + return deserializeExp(json); + } + DashboardInfoDto::DashboardInfoDto( std::optional mainUrl, QString dashboardVersion, @@ -2788,6 +2972,11 @@ namespace Axivion::Internal::Dto { return deserialize_bytes(json); } + Utils::expected_str IssueCommentListDto::deserializeExpected(const QByteArray &json) + { + return deserializeExp(json); + } + IssueCommentListDto::IssueCommentListDto( std::vector comments ) : @@ -2837,6 +3026,11 @@ namespace Axivion::Internal::Dto { return deserialize_bytes(json); } + Utils::expected_str IssueKindInfoDto::deserializeExpected(const QByteArray &json) + { + return deserializeExp(json); + } + IssueKindInfoDto::IssueKindInfoDto( QString prefix, QString niceSingularName, @@ -2914,6 +3108,11 @@ namespace Axivion::Internal::Dto { return deserialize_bytes(json); } + Utils::expected_str IssueTagTypeListDto::deserializeExpected(const QByteArray &json) + { + return deserializeExp(json); + } + IssueTagTypeListDto::IssueTagTypeListDto( std::vector tags ) : @@ -2981,6 +3180,11 @@ namespace Axivion::Internal::Dto { return deserialize_bytes(json); } + Utils::expected_str LineMarkerDto::deserializeExpected(const QByteArray &json) + { + return deserializeExp(json); + } + LineMarkerDto::LineMarkerDto( QString kind, std::optional id, @@ -3085,6 +3289,11 @@ namespace Axivion::Internal::Dto { return deserialize_bytes(json); } + Utils::expected_str RepositoryUpdateMessageDto::deserializeExpected(const QByteArray &json) + { + return deserializeExp(json); + } + RepositoryUpdateMessageDto::RepositoryUpdateMessageDto( QString severity, QString message @@ -3158,6 +3367,11 @@ namespace Axivion::Internal::Dto { return deserialize_bytes(json); } + Utils::expected_str RuleListDto::deserializeExpected(const QByteArray &json) + { + return deserializeExp(json); + } + RuleListDto::RuleListDto( std::vector rules ) : @@ -3204,6 +3418,11 @@ namespace Axivion::Internal::Dto { return deserialize_bytes(json); } + Utils::expected_str SortInfoDto::deserializeExpected(const QByteArray &json) + { + return deserializeExp(json); + } + SortInfoDto::SortInfoDto( QString key, QString direction @@ -3286,6 +3505,11 @@ namespace Axivion::Internal::Dto { return deserialize_bytes(json); } + Utils::expected_str UserRefDto::deserializeExpected(const QByteArray &json) + { + return deserializeExp(json); + } + UserRefDto::UserRefDto( QString name, QString displayName, @@ -3372,6 +3596,11 @@ namespace Axivion::Internal::Dto { return deserialize_bytes(json); } + Utils::expected_str AnalyzedFileListDto::deserializeExpected(const QByteArray &json) + { + return deserializeExp(json); + } + AnalyzedFileListDto::AnalyzedFileListDto( AnalysisVersionDto version, std::vector rows @@ -3420,6 +3649,11 @@ namespace Axivion::Internal::Dto { return deserialize_bytes(json); } + Utils::expected_str EntityListDto::deserializeExpected(const QByteArray &json) + { + return deserializeExp(json); + } + EntityListDto::EntityListDto( std::optional version, std::vector entities @@ -3474,6 +3708,11 @@ namespace Axivion::Internal::Dto { return deserialize_bytes(json); } + Utils::expected_str FileViewDto::deserializeExpected(const QByteArray &json) + { + return deserializeExp(json); + } + FileViewDto::FileViewDto( QString fileName, std::optional version, @@ -3541,6 +3780,11 @@ namespace Axivion::Internal::Dto { return deserialize_bytes(json); } + Utils::expected_str IssueDto::deserializeExpected(const QByteArray &json) + { + return deserializeExp(json); + } + IssueDto::IssueDto( QString kind, qint64 id, @@ -3655,6 +3899,11 @@ namespace Axivion::Internal::Dto { return deserialize_bytes(json); } + Utils::expected_str IssueTableDto::deserializeExpected(const QByteArray &json) + { + return deserializeExp(json); + } + IssueTableDto::IssueTableDto( std::optional startVersion, AnalysisVersionDto endVersion, @@ -3715,6 +3964,11 @@ namespace Axivion::Internal::Dto { return deserialize_bytes(json); } + Utils::expected_str MetricListDto::deserializeExpected(const QByteArray &json) + { + return deserializeExp(json); + } + MetricListDto::MetricListDto( std::optional version, std::vector metrics @@ -3772,6 +4026,11 @@ namespace Axivion::Internal::Dto { return deserialize_bytes(json); } + Utils::expected_str MetricValueRangeDto::deserializeExpected(const QByteArray &json) + { + return deserializeExp(json); + } + MetricValueRangeDto::MetricValueRangeDto( AnalysisVersionDto startVersion, AnalysisVersionDto endVersion, @@ -3826,6 +4085,11 @@ namespace Axivion::Internal::Dto { return deserialize_bytes(json); } + Utils::expected_str MetricValueTableDto::deserializeExpected(const QByteArray &json) + { + return deserializeExp(json); + } + MetricValueTableDto::MetricValueTableDto( std::vector columns, std::vector rows @@ -3883,6 +4147,11 @@ namespace Axivion::Internal::Dto { return deserialize_bytes(json); } + Utils::expected_str NamedFilterCreateDto::deserializeExpected(const QByteArray &json) + { + return deserializeExp(json); + } + NamedFilterCreateDto::NamedFilterCreateDto( QString displayName, QString kind, @@ -3998,6 +4267,11 @@ namespace Axivion::Internal::Dto { return deserialize_bytes(json); } + Utils::expected_str NamedFilterInfoDto::deserializeExpected(const QByteArray &json) + { + return deserializeExp(json); + } + NamedFilterInfoDto::NamedFilterInfoDto( QString key, QString displayName, @@ -4118,6 +4392,11 @@ namespace Axivion::Internal::Dto { return deserialize_bytes(json); } + Utils::expected_str NamedFilterUpdateDto::deserializeExpected(const QByteArray &json) + { + return deserializeExp(json); + } + NamedFilterUpdateDto::NamedFilterUpdateDto( std::optional name, std::optional> filters, @@ -4185,6 +4464,11 @@ namespace Axivion::Internal::Dto { return deserialize_bytes(json); } + Utils::expected_str ProjectInfoDto::deserializeExpected(const QByteArray &json) + { + return deserializeExp(json); + } + ProjectInfoDto::ProjectInfoDto( QString name, std::optional issueFilterHelp, @@ -4246,6 +4530,11 @@ namespace Axivion::Internal::Dto { return deserialize_bytes(json); } + Utils::expected_str RepositoryUpdateResponseDto::deserializeExpected(const QByteArray &json) + { + return deserializeExp(json); + } + RepositoryUpdateResponseDto::RepositoryUpdateResponseDto( std::vector messages, bool hasErrors, @@ -4308,6 +4597,11 @@ namespace Axivion::Internal::Dto { return deserialize_bytes(json); } + Utils::expected_str TableInfoDto::deserializeExpected(const QByteArray &json) + { + return deserializeExp(json); + } + TableInfoDto::TableInfoDto( QString tableDataUri, std::optional issueBaseViewUri, diff --git a/src/plugins/axivion/dashboard/dto.h b/src/plugins/axivion/dashboard/dto.h index fea5ab4ee18..8617d2d61df 100644 --- a/src/plugins/axivion/dashboard/dto.h +++ b/src/plugins/axivion/dashboard/dto.h @@ -14,6 +14,8 @@ * /projects/libs/dashboard_cpp_api/generator/generate_dashboard_cpp_api.py */ +#include + #include #include #include @@ -70,6 +72,8 @@ namespace Axivion::Internal::Dto // Throws Axivion::Internal::Dto::invalid_dto_exception static Any deserialize(const QByteArray &json); + static Utils::expected_str deserializeExpected(const QByteArray &json); + Any(); Any(QString value); @@ -171,6 +175,8 @@ namespace Axivion::Internal::Dto // Throws Axivion::Internal::Dto::invalid_dto_exception static AnalyzedFileDto deserialize(const QByteArray &json); + Utils::expected_str deserializeExpected(const QByteArray &json); + AnalyzedFileDto( QString path, std::optional isSystemHeader, @@ -219,6 +225,8 @@ namespace Axivion::Internal::Dto // Throws std::range_error static ApiTokenType strToEnum(QAnyStringView str); + static std::optional strToOptionalEnum(QAnyStringView str); + static QLatin1String enumToStr(ApiTokenType e); ApiTokenTypeMeta() = delete; @@ -245,6 +253,8 @@ namespace Axivion::Internal::Dto // Throws Axivion::Internal::Dto::invalid_dto_exception static ChangePasswordFormDto deserialize(const QByteArray &json); + Utils::expected_str deserializeExpected(const QByteArray &json); + ChangePasswordFormDto( QString currentPassword, QString newPassword @@ -295,6 +305,8 @@ namespace Axivion::Internal::Dto // Throws std::range_error static ColumnType strToEnum(QAnyStringView str); + static std::optional strToOptionalEnum(QAnyStringView str); + static QLatin1String enumToStr(ColumnType e); ColumnTypeMeta() = delete; @@ -332,6 +344,8 @@ namespace Axivion::Internal::Dto // Throws Axivion::Internal::Dto::invalid_dto_exception static ColumnTypeOptionDto deserialize(const QByteArray &json); + Utils::expected_str deserializeExpected(const QByteArray &json); + ColumnTypeOptionDto( QString key, std::optional displayName, @@ -356,6 +370,8 @@ namespace Axivion::Internal::Dto // Throws Axivion::Internal::Dto::invalid_dto_exception static CommentRequestDto deserialize(const QByteArray &json); + Utils::expected_str deserializeExpected(const QByteArray &json); + CommentRequestDto( QString text ); @@ -384,6 +400,8 @@ namespace Axivion::Internal::Dto // Throws Axivion::Internal::Dto::invalid_dto_exception static CsrfTokenDto deserialize(const QByteArray &json); + Utils::expected_str deserializeExpected(const QByteArray &json); + CsrfTokenDto( QString csrfToken ); @@ -427,6 +445,8 @@ namespace Axivion::Internal::Dto // Throws Axivion::Internal::Dto::invalid_dto_exception static EntityDto deserialize(const QByteArray &json); + Utils::expected_str deserializeExpected(const QByteArray &json); + EntityDto( QString id, QString name, @@ -544,6 +564,8 @@ namespace Axivion::Internal::Dto // Throws Axivion::Internal::Dto::invalid_dto_exception static ErrorDto deserialize(const QByteArray &json); + Utils::expected_str deserializeExpected(const QByteArray &json); + ErrorDto( std::optional dashboardVersionNumber, QString type, @@ -613,6 +635,8 @@ namespace Axivion::Internal::Dto // Throws Axivion::Internal::Dto::invalid_dto_exception static IssueCommentDto deserialize(const QByteArray &json); + Utils::expected_str deserializeExpected(const QByteArray &json); + IssueCommentDto( QString username, QString userDisplayName, @@ -654,6 +678,8 @@ namespace Axivion::Internal::Dto // Throws std::range_error static IssueKind strToEnum(QAnyStringView str); + static std::optional strToOptionalEnum(QAnyStringView str); + static QLatin1String enumToStr(IssueKind e); IssueKindMeta() = delete; @@ -690,6 +716,8 @@ namespace Axivion::Internal::Dto // Throws std::range_error static IssueKindForNamedFilterCreation strToEnum(QAnyStringView str); + static std::optional strToOptionalEnum(QAnyStringView str); + static QLatin1String enumToStr(IssueKindForNamedFilterCreation e); IssueKindForNamedFilterCreationMeta() = delete; @@ -759,6 +787,8 @@ namespace Axivion::Internal::Dto // Throws Axivion::Internal::Dto::invalid_dto_exception static IssueSourceLocationDto deserialize(const QByteArray &json); + Utils::expected_str deserializeExpected(const QByteArray &json); + IssueSourceLocationDto( QString fileName, std::optional role, @@ -795,6 +825,8 @@ namespace Axivion::Internal::Dto // Throws Axivion::Internal::Dto::invalid_dto_exception static IssueTagDto deserialize(const QByteArray &json); + Utils::expected_str deserializeExpected(const QByteArray &json); + IssueTagDto( QString tag, QString color @@ -851,6 +883,8 @@ namespace Axivion::Internal::Dto // Throws Axivion::Internal::Dto::invalid_dto_exception static IssueTagTypeDto deserialize(const QByteArray &json); + Utils::expected_str deserializeExpected(const QByteArray &json); + IssueTagTypeDto( QString id, std::optional text, @@ -893,6 +927,8 @@ namespace Axivion::Internal::Dto // Throws std::range_error static MessageSeverity strToEnum(QAnyStringView str); + static std::optional strToOptionalEnum(QAnyStringView str); + static QLatin1String enumToStr(MessageSeverity e); MessageSeverityMeta() = delete; @@ -937,6 +973,8 @@ namespace Axivion::Internal::Dto // Throws Axivion::Internal::Dto::invalid_dto_exception static MetricDto deserialize(const QByteArray &json); + Utils::expected_str deserializeExpected(const QByteArray &json); + MetricDto( QString name, QString displayName, @@ -996,6 +1034,8 @@ namespace Axivion::Internal::Dto // Throws Axivion::Internal::Dto::invalid_dto_exception static MetricValueTableRowDto deserialize(const QByteArray &json); + Utils::expected_str deserializeExpected(const QByteArray &json); + MetricValueTableRowDto( QString metric, std::optional path, @@ -1033,6 +1073,8 @@ namespace Axivion::Internal::Dto // Throws std::range_error static NamedFilterType strToEnum(QAnyStringView str); + static std::optional strToOptionalEnum(QAnyStringView str); + static QLatin1String enumToStr(NamedFilterType e); NamedFilterTypeMeta() = delete; @@ -1062,6 +1104,8 @@ namespace Axivion::Internal::Dto // Throws Axivion::Internal::Dto::invalid_dto_exception static NamedFilterVisibilityDto deserialize(const QByteArray &json); + Utils::expected_str deserializeExpected(const QByteArray &json); + NamedFilterVisibilityDto( std::optional> groups ); @@ -1089,6 +1133,8 @@ namespace Axivion::Internal::Dto // Throws Axivion::Internal::Dto::invalid_dto_exception static ProjectReferenceDto deserialize(const QByteArray &json); + Utils::expected_str deserializeExpected(const QByteArray &json); + ProjectReferenceDto( QString name, QString url @@ -1127,6 +1173,8 @@ namespace Axivion::Internal::Dto // Throws Axivion::Internal::Dto::invalid_dto_exception static RuleDto deserialize(const QByteArray &json); + Utils::expected_str deserializeExpected(const QByteArray &json); + RuleDto( QString name, QString original_name, @@ -1157,6 +1205,8 @@ namespace Axivion::Internal::Dto // Throws std::range_error static SortDirection strToEnum(QAnyStringView str); + static std::optional strToOptionalEnum(QAnyStringView str); + static QLatin1String enumToStr(SortDirection e); SortDirectionMeta() = delete; @@ -1187,6 +1237,8 @@ namespace Axivion::Internal::Dto // Throws std::range_error static TableCellAlignment strToEnum(QAnyStringView str); + static std::optional strToOptionalEnum(QAnyStringView str); + static QLatin1String enumToStr(TableCellAlignment e); TableCellAlignmentMeta() = delete; @@ -1218,6 +1270,8 @@ namespace Axivion::Internal::Dto // Throws Axivion::Internal::Dto::invalid_dto_exception static ToolsVersionDto deserialize(const QByteArray &json); + Utils::expected_str deserializeExpected(const QByteArray &json); + ToolsVersionDto( QString name, QString number, @@ -1253,6 +1307,8 @@ namespace Axivion::Internal::Dto // Throws std::range_error static UserRefType strToEnum(QAnyStringView str); + static std::optional strToOptionalEnum(QAnyStringView str); + static QLatin1String enumToStr(UserRefType e); UserRefTypeMeta() = delete; @@ -1284,6 +1340,8 @@ namespace Axivion::Internal::Dto // Throws Axivion::Internal::Dto::invalid_dto_exception static VersionKindCountDto deserialize(const QByteArray &json); + Utils::expected_str deserializeExpected(const QByteArray &json); + VersionKindCountDto( qint32 Total, qint32 Added, @@ -1392,6 +1450,8 @@ namespace Axivion::Internal::Dto // Throws Axivion::Internal::Dto::invalid_dto_exception static AnalysisVersionDto deserialize(const QByteArray &json); + Utils::expected_str deserializeExpected(const QByteArray &json); + AnalysisVersionDto( QString date, std::optional label, @@ -1450,6 +1510,8 @@ namespace Axivion::Internal::Dto // Throws Axivion::Internal::Dto::invalid_dto_exception static ApiTokenCreationRequestDto deserialize(const QByteArray &json); + Utils::expected_str deserializeExpected(const QByteArray &json); + ApiTokenCreationRequestDto( QString password, QString type, @@ -1568,6 +1630,8 @@ namespace Axivion::Internal::Dto // Throws Axivion::Internal::Dto::invalid_dto_exception static ApiTokenInfoDto deserialize(const QByteArray &json); + Utils::expected_str deserializeExpected(const QByteArray &json); + ApiTokenInfoDto( QString id, QString url, @@ -1693,6 +1757,8 @@ namespace Axivion::Internal::Dto // Throws Axivion::Internal::Dto::invalid_dto_exception static ColumnInfoDto deserialize(const QByteArray &json); + Utils::expected_str deserializeExpected(const QByteArray &json); + ColumnInfoDto( QString key, std::optional header, @@ -1726,7 +1792,7 @@ namespace Axivion::Internal::Dto void setAlignmentEnum(TableCellAlignment newValue); - // Throws std::range_error + // Throws std::range_error ColumnType getTypeEnum() const; std::optional getOptionalTypeEnum() const; @@ -1859,6 +1925,8 @@ namespace Axivion::Internal::Dto // Throws Axivion::Internal::Dto::invalid_dto_exception static DashboardInfoDto deserialize(const QByteArray &json); + Utils::expected_str deserializeExpected(const QByteArray &json); + DashboardInfoDto( std::optional mainUrl, QString dashboardVersion, @@ -1895,6 +1963,8 @@ namespace Axivion::Internal::Dto // Throws Axivion::Internal::Dto::invalid_dto_exception static IssueCommentListDto deserialize(const QByteArray &json); + Utils::expected_str deserializeExpected(const QByteArray &json); + IssueCommentListDto( std::vector comments ); @@ -1929,6 +1999,8 @@ namespace Axivion::Internal::Dto // Throws Axivion::Internal::Dto::invalid_dto_exception static IssueKindInfoDto deserialize(const QByteArray &json); + Utils::expected_str deserializeExpected(const QByteArray &json); + IssueKindInfoDto( QString prefix, QString niceSingularName, @@ -1966,6 +2038,8 @@ namespace Axivion::Internal::Dto // Throws Axivion::Internal::Dto::invalid_dto_exception static IssueTagTypeListDto deserialize(const QByteArray &json); + Utils::expected_str deserializeExpected(const QByteArray &json); + IssueTagTypeListDto( std::vector tags ); @@ -2056,6 +2130,8 @@ namespace Axivion::Internal::Dto // Throws Axivion::Internal::Dto::invalid_dto_exception static LineMarkerDto deserialize(const QByteArray &json); + Utils::expected_str deserializeExpected(const QByteArray &json); + LineMarkerDto( QString kind, std::optional id, @@ -2115,6 +2191,8 @@ namespace Axivion::Internal::Dto // Throws Axivion::Internal::Dto::invalid_dto_exception static RepositoryUpdateMessageDto deserialize(const QByteArray &json); + Utils::expected_str deserializeExpected(const QByteArray &json); + RepositoryUpdateMessageDto( QString severity, QString message @@ -2150,6 +2228,8 @@ namespace Axivion::Internal::Dto // Throws Axivion::Internal::Dto::invalid_dto_exception static RuleListDto deserialize(const QByteArray &json); + Utils::expected_str deserializeExpected(const QByteArray &json); + RuleListDto( std::vector rules ); @@ -2179,6 +2259,8 @@ namespace Axivion::Internal::Dto // Throws Axivion::Internal::Dto::invalid_dto_exception static SortInfoDto deserialize(const QByteArray &json); + Utils::expected_str deserializeExpected(const QByteArray &json); + SortInfoDto( QString key, QString direction @@ -2235,6 +2317,8 @@ namespace Axivion::Internal::Dto // Throws Axivion::Internal::Dto::invalid_dto_exception static UserRefDto deserialize(const QByteArray &json); + Utils::expected_str deserializeExpected(const QByteArray &json); + UserRefDto( QString name, QString displayName, @@ -2279,6 +2363,8 @@ namespace Axivion::Internal::Dto // Throws Axivion::Internal::Dto::invalid_dto_exception static AnalyzedFileListDto deserialize(const QByteArray &json); + Utils::expected_str deserializeExpected(const QByteArray &json); + AnalyzedFileListDto( AnalysisVersionDto version, std::vector rows @@ -2307,6 +2393,8 @@ namespace Axivion::Internal::Dto // Throws Axivion::Internal::Dto::invalid_dto_exception static EntityListDto deserialize(const QByteArray &json); + Utils::expected_str deserializeExpected(const QByteArray &json); + EntityListDto( std::optional version, std::vector entities @@ -2355,6 +2443,8 @@ namespace Axivion::Internal::Dto // Throws Axivion::Internal::Dto::invalid_dto_exception static FileViewDto deserialize(const QByteArray &json); + Utils::expected_str deserializeExpected(const QByteArray &json); + FileViewDto( QString fileName, std::optional version, @@ -2418,6 +2508,8 @@ namespace Axivion::Internal::Dto // Throws Axivion::Internal::Dto::invalid_dto_exception static IssueDto deserialize(const QByteArray &json); + Utils::expected_str deserializeExpected(const QByteArray &json); + IssueDto( QString kind, qint64 id, @@ -2532,6 +2624,8 @@ namespace Axivion::Internal::Dto // Throws Axivion::Internal::Dto::invalid_dto_exception static IssueTableDto deserialize(const QByteArray &json); + Utils::expected_str deserializeExpected(const QByteArray &json); + IssueTableDto( std::optional startVersion, AnalysisVersionDto endVersion, @@ -2566,6 +2660,8 @@ namespace Axivion::Internal::Dto // Throws Axivion::Internal::Dto::invalid_dto_exception static MetricListDto deserialize(const QByteArray &json); + Utils::expected_str deserializeExpected(const QByteArray &json); + MetricListDto( std::optional version, std::vector metrics @@ -2617,6 +2713,8 @@ namespace Axivion::Internal::Dto // Throws Axivion::Internal::Dto::invalid_dto_exception static MetricValueRangeDto deserialize(const QByteArray &json); + Utils::expected_str deserializeExpected(const QByteArray &json); + MetricValueRangeDto( AnalysisVersionDto startVersion, AnalysisVersionDto endVersion, @@ -2650,6 +2748,8 @@ namespace Axivion::Internal::Dto // Throws Axivion::Internal::Dto::invalid_dto_exception static MetricValueTableDto deserialize(const QByteArray &json); + Utils::expected_str deserializeExpected(const QByteArray &json); + MetricValueTableDto( std::vector columns, std::vector rows @@ -2712,6 +2812,8 @@ namespace Axivion::Internal::Dto // Throws Axivion::Internal::Dto::invalid_dto_exception static NamedFilterCreateDto deserialize(const QByteArray &json); + Utils::expected_str deserializeExpected(const QByteArray &json); + NamedFilterCreateDto( QString displayName, QString kind, @@ -2834,6 +2936,8 @@ namespace Axivion::Internal::Dto // Throws Axivion::Internal::Dto::invalid_dto_exception static NamedFilterInfoDto deserialize(const QByteArray &json); + Utils::expected_str deserializeExpected(const QByteArray &json); + NamedFilterInfoDto( QString key, QString displayName, @@ -2924,6 +3028,8 @@ namespace Axivion::Internal::Dto // Throws Axivion::Internal::Dto::invalid_dto_exception static NamedFilterUpdateDto deserialize(const QByteArray &json); + Utils::expected_str deserializeExpected(const QByteArray &json); + NamedFilterUpdateDto( std::optional name, std::optional> filters, @@ -2983,6 +3089,8 @@ namespace Axivion::Internal::Dto // Throws Axivion::Internal::Dto::invalid_dto_exception static ProjectInfoDto deserialize(const QByteArray &json); + Utils::expected_str deserializeExpected(const QByteArray &json); + ProjectInfoDto( QString name, std::optional issueFilterHelp, @@ -3024,6 +3132,8 @@ namespace Axivion::Internal::Dto // Throws Axivion::Internal::Dto::invalid_dto_exception static RepositoryUpdateResponseDto deserialize(const QByteArray &json); + Utils::expected_str deserializeExpected(const QByteArray &json); + RepositoryUpdateResponseDto( std::vector messages, bool hasErrors, @@ -3091,6 +3201,8 @@ namespace Axivion::Internal::Dto // Throws Axivion::Internal::Dto::invalid_dto_exception static TableInfoDto deserialize(const QByteArray &json); + Utils::expected_str deserializeExpected(const QByteArray &json); + TableInfoDto( QString tableDataUri, std::optional issueBaseViewUri, From c76fc8e1e53ce45261b8a64edd663efd06ca487b Mon Sep 17 00:00:00 2001 From: David Schulz Date: Mon, 19 Feb 2024 09:50:25 +0100 Subject: [PATCH 102/243] Debugger: fix dumping char arrays The calculation for the size of the memory to fetch for the dumper was missing the char size information. Amends a26aff7afd17b1f7ddda917ad07e1c1a9292ec9d Change-Id: I8ceb127efaf7effa94fc53e6782f75580ab8cdb4 Reviewed-by: Reviewed-by: hjk --- share/qtcreator/debugger/dumper.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/share/qtcreator/debugger/dumper.py b/share/qtcreator/debugger/dumper.py index ad25ad2dbeb..ca6b7f40737 100644 --- a/share/qtcreator/debugger/dumper.py +++ b/share/qtcreator/debugger/dumper.py @@ -635,7 +635,7 @@ class DumperBase(): def putCharArrayValue(self, data, length, charSize, displayFormat=DisplayFormat.Automatic): shown = self.computeLimit(length, self.displayStringLimit) - mem = self.readMemory(data, shown) + mem = self.readMemory(data, shown * charSize) if charSize == 1: if displayFormat in (DisplayFormat.Latin1String, DisplayFormat.SeparateLatin1String): encodingType = 'latin1' From 5c8b87bf9de775ede865b90496270d707e5af8ed Mon Sep 17 00:00:00 2001 From: Jarek Kobus Date: Tue, 20 Feb 2024 21:29:18 +0100 Subject: [PATCH 103/243] TaskTree: Simplify some test code Change-Id: Id81969d00a6e183e0d7cdcfddc64fc65aab6e020 Reviewed-by: hjk --- tests/auto/solutions/tasking/tst_tasking.cpp | 205 ++++++++----------- 1 file changed, 84 insertions(+), 121 deletions(-) diff --git a/tests/auto/solutions/tasking/tst_tasking.cpp b/tests/auto/solutions/tasking/tst_tasking.cpp index e95635b6dc8..f9d9cef5071 100644 --- a/tests/auto/solutions/tasking/tst_tasking.cpp +++ b/tests/auto/solutions/tasking/tst_tasking.cpp @@ -990,148 +990,111 @@ void tst_Tasking::testTree_data() } { - const auto createRoot = [storage, groupDone](WorkflowPolicy policy) { - return Group { + const auto testData = [storage, groupDone](WorkflowPolicy policy, DoneWith result) { + return TestData { storage, - workflowPolicy(policy), - groupDone(0) + Group { + storage, + workflowPolicy(policy), + groupDone(0) + }, + Log {{0, result == DoneWith::Success ? Handler::GroupSuccess : Handler::GroupError}}, + 0, + result }; }; const Log doneLog = {{0, Handler::GroupSuccess}}; const Log errorLog = {{0, Handler::GroupError}}; - const Group root1 = createRoot(WorkflowPolicy::StopOnError); - QTest::newRow("EmptyStopOnError") << TestData{storage, root1, doneLog, 0, - DoneWith::Success}; - - const Group root2 = createRoot(WorkflowPolicy::ContinueOnError); - QTest::newRow("EmptyContinueOnError") << TestData{storage, root2, doneLog, 0, - DoneWith::Success}; - - const Group root3 = createRoot(WorkflowPolicy::StopOnSuccess); - QTest::newRow("EmptyStopOnSuccess") << TestData{storage, root3, errorLog, 0, - DoneWith::Error}; - - const Group root4 = createRoot(WorkflowPolicy::ContinueOnSuccess); - QTest::newRow("EmptyContinueOnSuccess") << TestData{storage, root4, errorLog, 0, - DoneWith::Error}; - - const Group root5 = createRoot(WorkflowPolicy::StopOnSuccessOrError); - QTest::newRow("EmptyStopOnSuccessOrError") << TestData{storage, root5, errorLog, 0, - DoneWith::Error}; - - const Group root6 = createRoot(WorkflowPolicy::FinishAllAndSuccess); - QTest::newRow("EmptyFinishAllAndSuccess") << TestData{storage, root6, doneLog, 0, - DoneWith::Success}; - - const Group root7 = createRoot(WorkflowPolicy::FinishAllAndError); - QTest::newRow("EmptyFinishAllAndError") << TestData{storage, root7, errorLog, 0, - DoneWith::Error}; + QTest::newRow("EmptyStopOnError") + << testData(WorkflowPolicy::StopOnError, DoneWith::Success); + QTest::newRow("EmptyContinueOnError") + << testData(WorkflowPolicy::ContinueOnError, DoneWith::Success); + QTest::newRow("EmptyStopOnSuccess") + << testData(WorkflowPolicy::StopOnSuccess, DoneWith::Error); + QTest::newRow("EmptyContinueOnSuccess") + << testData(WorkflowPolicy::ContinueOnSuccess, DoneWith::Error); + QTest::newRow("EmptyStopOnSuccessOrError") + << testData(WorkflowPolicy::StopOnSuccessOrError, DoneWith::Error); + QTest::newRow("EmptyFinishAllAndSuccess") + << testData(WorkflowPolicy::FinishAllAndSuccess, DoneWith::Success); + QTest::newRow("EmptyFinishAllAndError") + << testData(WorkflowPolicy::FinishAllAndError, DoneWith::Error); } { - const auto createRoot = [storage, createSuccessTask, groupDone]( - WorkflowPolicy policy) { - return Group { + const auto testData = [storage, groupDone, createSuccessTask](WorkflowPolicy policy, + DoneWith result) { + return TestData { storage, - workflowPolicy(policy), - createSuccessTask(1), - groupDone(0) + Group { + storage, + workflowPolicy(policy), + createSuccessTask(1), + groupDone(0) + }, + Log { + {1, Handler::Setup}, + {1, Handler::Success}, + {0, result == DoneWith::Success ? Handler::GroupSuccess : Handler::GroupError} + }, + 1, + result }; }; - const Log doneLog = { - {1, Handler::Setup}, - {1, Handler::Success}, - {0, Handler::GroupSuccess} - }; - - const Log errorLog = { - {1, Handler::Setup}, - {1, Handler::Success}, - {0, Handler::GroupError} - }; - - const Group root1 = createRoot(WorkflowPolicy::StopOnError); - QTest::newRow("DoneStopOnError") << TestData{storage, root1, doneLog, 1, - DoneWith::Success}; - - const Group root2 = createRoot(WorkflowPolicy::ContinueOnError); - QTest::newRow("DoneContinueOnError") << TestData{storage, root2, doneLog, 1, - DoneWith::Success}; - - const Group root3 = createRoot(WorkflowPolicy::StopOnSuccess); - QTest::newRow("DoneStopOnSuccess") << TestData{storage, root3, doneLog, 1, - DoneWith::Success}; - - const Group root4 = createRoot(WorkflowPolicy::ContinueOnSuccess); - QTest::newRow("DoneContinueOnSuccess") << TestData{storage, root4, doneLog, 1, - DoneWith::Success}; - - const Group root5 = createRoot(WorkflowPolicy::StopOnSuccessOrError); - QTest::newRow("DoneStopOnSuccessOrError") << TestData{storage, root5, doneLog, 1, - DoneWith::Success}; - - const Group root6 = createRoot(WorkflowPolicy::FinishAllAndSuccess); - QTest::newRow("DoneFinishAllAndSuccess") << TestData{storage, root6, doneLog, 1, - DoneWith::Success}; - - const Group root7 = createRoot(WorkflowPolicy::FinishAllAndError); - QTest::newRow("DoneFinishAllAndError") << TestData{storage, root7, errorLog, 1, - DoneWith::Error}; + QTest::newRow("DoneStopOnError") + << testData(WorkflowPolicy::StopOnError, DoneWith::Success); + QTest::newRow("DoneContinueOnError") + << testData(WorkflowPolicy::ContinueOnError, DoneWith::Success); + QTest::newRow("DoneStopOnSuccess") + << testData(WorkflowPolicy::StopOnSuccess, DoneWith::Success); + QTest::newRow("DoneContinueOnSuccess") + << testData(WorkflowPolicy::ContinueOnSuccess, DoneWith::Success); + QTest::newRow("DoneStopOnSuccessOrError") + << testData(WorkflowPolicy::StopOnSuccessOrError, DoneWith::Success); + QTest::newRow("DoneFinishAllAndSuccess") + << testData(WorkflowPolicy::FinishAllAndSuccess, DoneWith::Success); + QTest::newRow("DoneFinishAllAndError") + << testData(WorkflowPolicy::FinishAllAndError, DoneWith::Error); } { - const auto createRoot = [storage, createFailingTask, groupDone]( - WorkflowPolicy policy) { - return Group { + const auto testData = [storage, groupDone, createFailingTask](WorkflowPolicy policy, + DoneWith result) { + return TestData { storage, - workflowPolicy(policy), - createFailingTask(1), - groupDone(0) + Group { + storage, + workflowPolicy(policy), + createFailingTask(1), + groupDone(0) + }, + Log { + {1, Handler::Setup}, + {1, Handler::Error}, + {0, result == DoneWith::Success ? Handler::GroupSuccess : Handler::GroupError} + }, + 1, + result }; }; - const Log doneLog = { - {1, Handler::Setup}, - {1, Handler::Error}, - {0, Handler::GroupSuccess} - }; - - const Log errorLog = { - {1, Handler::Setup}, - {1, Handler::Error}, - {0, Handler::GroupError} - }; - - const Group root1 = createRoot(WorkflowPolicy::StopOnError); - QTest::newRow("ErrorStopOnError") << TestData{storage, root1, errorLog, 1, - DoneWith::Error}; - - const Group root2 = createRoot(WorkflowPolicy::ContinueOnError); - QTest::newRow("ErrorContinueOnError") << TestData{storage, root2, errorLog, 1, - DoneWith::Error}; - - const Group root3 = createRoot(WorkflowPolicy::StopOnSuccess); - QTest::newRow("ErrorStopOnSuccess") << TestData{storage, root3, errorLog, 1, - DoneWith::Error}; - - const Group root4 = createRoot(WorkflowPolicy::ContinueOnSuccess); - QTest::newRow("ErrorContinueOnSuccess") << TestData{storage, root4, errorLog, 1, - DoneWith::Error}; - - const Group root5 = createRoot(WorkflowPolicy::StopOnSuccessOrError); - QTest::newRow("ErrorStopOnSuccessOrError") << TestData{storage, root5, errorLog, 1, - DoneWith::Error}; - - const Group root6 = createRoot(WorkflowPolicy::FinishAllAndSuccess); - QTest::newRow("ErrorFinishAllAndSuccess") << TestData{storage, root6, doneLog, 1, - DoneWith::Success}; - - const Group root7 = createRoot(WorkflowPolicy::FinishAllAndError); - QTest::newRow("ErrorFinishAllAndError") << TestData{storage, root7, errorLog, 1, - DoneWith::Error}; + QTest::newRow("ErrorStopOnError") + << testData(WorkflowPolicy::StopOnError, DoneWith::Error); + QTest::newRow("ErrorContinueOnError") + << testData(WorkflowPolicy::ContinueOnError, DoneWith::Error); + QTest::newRow("ErrorStopOnSuccess") + << testData(WorkflowPolicy::StopOnSuccess, DoneWith::Error); + QTest::newRow("ErrorContinueOnSuccess") + << testData(WorkflowPolicy::ContinueOnSuccess, DoneWith::Error); + QTest::newRow("ErrorStopOnSuccessOrError") + << testData(WorkflowPolicy::StopOnSuccessOrError, DoneWith::Error); + QTest::newRow("ErrorFinishAllAndSuccess") + << testData(WorkflowPolicy::FinishAllAndSuccess, DoneWith::Success); + QTest::newRow("ErrorFinishAllAndError") + << testData(WorkflowPolicy::FinishAllAndError, DoneWith::Error); } { From d4b5a1efdaa5ec9eee0256cde573d9703f915f88 Mon Sep 17 00:00:00 2001 From: Jarek Kobus Date: Tue, 20 Feb 2024 21:53:49 +0100 Subject: [PATCH 104/243] TaskTree: Check the right asyncCount() in tests This is quite crucial test checking the right internal behavior. The expected asyncCount numbers were added to these tests after processing each recipe by hand and deducing the expected scenario and the number of times each recipe should return the control to the main event loop before the task tree finished. Be very careful when correcting any of these numbers - this might mean the internal change inside the task tree forcing the asyncCount adjustment may break the task tree architecture. Change-Id: Ia3acfbf3cb232ed95df97fe5822305df98e2271a Reviewed-by: Qt CI Bot Reviewed-by: Reviewed-by: hjk --- tests/auto/solutions/tasking/tst_tasking.cpp | 298 ++++++++++--------- 1 file changed, 154 insertions(+), 144 deletions(-) diff --git a/tests/auto/solutions/tasking/tst_tasking.cpp b/tests/auto/solutions/tasking/tst_tasking.cpp index f9d9cef5071..b2e99a7c220 100644 --- a/tests/auto/solutions/tasking/tst_tasking.cpp +++ b/tests/auto/solutions/tasking/tst_tasking.cpp @@ -84,6 +84,7 @@ struct TestData Log expectedLog; int taskCount = 0; DoneWith result = DoneWith::Success; + std::optional asyncCount = {}; std::optional messageLog = {}; }; @@ -472,7 +473,7 @@ static TestData storageShadowingData() {1, Handler::Storage}, }; - return {storage, root, log, 0, DoneWith::Success}; + return {storage, root, log, 0, DoneWith::Success, 0}; } static TestData parallelData() @@ -653,10 +654,10 @@ void tst_Tasking::testTree_data() const Log logDone {{0, Handler::GroupSuccess}}; const Log logError {{0, Handler::GroupError}}; - QTest::newRow("Empty") << TestData{storage, root1, logDone, 0, DoneWith::Success}; - QTest::newRow("EmptyContinue") << TestData{storage, root2, logDone, 0, DoneWith::Success}; - QTest::newRow("EmptyDone") << TestData{storage, root3, logDone, 0, DoneWith::Success}; - QTest::newRow("EmptyError") << TestData{storage, root4, logError, 0, DoneWith::Error}; + QTest::newRow("Empty") << TestData{storage, root1, logDone, 0, DoneWith::Success, 0}; + QTest::newRow("EmptyContinue") << TestData{storage, root2, logDone, 0, DoneWith::Success, 0}; + QTest::newRow("EmptyDone") << TestData{storage, root3, logDone, 0, DoneWith::Success, 0}; + QTest::newRow("EmptyError") << TestData{storage, root4, logError, 0, DoneWith::Error, 0}; } { @@ -671,11 +672,11 @@ void tst_Tasking::testTree_data() const auto doneData = [storage, setupGroup](WorkflowPolicy policy) { return TestData{storage, setupGroup(SetupResult::StopWithSuccess, policy), - Log{{0, Handler::GroupSuccess}}, 0, DoneWith::Success}; + Log{{0, Handler::GroupSuccess}}, 0, DoneWith::Success, 0}; }; const auto errorData = [storage, setupGroup](WorkflowPolicy policy) { return TestData{storage, setupGroup(SetupResult::StopWithError, policy), - Log{{0, Handler::GroupError}}, 0, DoneWith::Error}; + Log{{0, Handler::GroupError}}, 0, DoneWith::Error, 0}; }; QTest::newRow("DoneAndStopOnError") << doneData(WorkflowPolicy::StopOnError); @@ -707,7 +708,7 @@ void tst_Tasking::testTree_data() {2, Handler::Setup}, {2, Handler::TweakSetupToSuccess} }; - QTest::newRow("TweakTaskSuccess") << TestData{storage, root, log, 2, DoneWith::Success}; + QTest::newRow("TweakTaskSuccess") << TestData{storage, root, log, 2, DoneWith::Success, 0}; } { @@ -720,7 +721,7 @@ void tst_Tasking::testTree_data() {1, Handler::Setup}, {1, Handler::TweakSetupToError} }; - QTest::newRow("TweakTaskError") << TestData{storage, root, log, 2, DoneWith::Error}; + QTest::newRow("TweakTaskError") << TestData{storage, root, log, 2, DoneWith::Error, 0}; } { @@ -741,7 +742,7 @@ void tst_Tasking::testTree_data() {3, Handler::Setup}, {3, Handler::TweakSetupToError} }; - QTest::newRow("TweakMixed") << TestData{storage, root, log, 4, DoneWith::Error}; + QTest::newRow("TweakMixed") << TestData{storage, root, log, 4, DoneWith::Error, 2}; } { @@ -763,7 +764,7 @@ void tst_Tasking::testTree_data() {1, Handler::Canceled}, {2, Handler::Canceled} }; - QTest::newRow("TweakParallel") << TestData{storage, root, log, 4, DoneWith::Error}; + QTest::newRow("TweakParallel") << TestData{storage, root, log, 4, DoneWith::Error, 0}; } { @@ -787,7 +788,7 @@ void tst_Tasking::testTree_data() {1, Handler::Canceled}, {2, Handler::Canceled} }; - QTest::newRow("TweakParallelGroup") << TestData{storage, root, log, 4, DoneWith::Error}; + QTest::newRow("TweakParallelGroup") << TestData{storage, root, log, 4, DoneWith::Error, 0}; } { @@ -813,7 +814,7 @@ void tst_Tasking::testTree_data() {2, Handler::Canceled} }; QTest::newRow("TweakParallelGroupSetup") - << TestData{storage, root, log, 4, DoneWith::Error}; + << TestData{storage, root, log, 4, DoneWith::Error, 0}; } { @@ -857,7 +858,7 @@ void tst_Tasking::testTree_data() {1, Handler::GroupSuccess}, {0, Handler::GroupSuccess} }; - QTest::newRow("Nested") << TestData{storage, root, log, 1, DoneWith::Success}; + QTest::newRow("Nested") << TestData{storage, root, log, 1, DoneWith::Success, 1}; } QTest::newRow("Parallel") << parallelData(); @@ -915,10 +916,10 @@ void tst_Tasking::testTree_data() {5, Handler::Success}, {0, Handler::GroupSuccess} }; - QTest::newRow("Sequential") << TestData{storage, root1, log, 5, DoneWith::Success}; - QTest::newRow("SequentialEncapsulated") << TestData{storage, root2, log, 5, DoneWith::Success}; + QTest::newRow("Sequential") << TestData{storage, root1, log, 5, DoneWith::Success, 5}; + QTest::newRow("SequentialEncapsulated") << TestData{storage, root2, log, 5, DoneWith::Success, 5}; // We don't inspect subtrees, so taskCount is 3, not 5. - QTest::newRow("SequentialSubTree") << TestData{storage, root3, log, 3, DoneWith::Success}; + QTest::newRow("SequentialSubTree") << TestData{storage, root3, log, 3, DoneWith::Success, 3}; } { @@ -964,7 +965,7 @@ void tst_Tasking::testTree_data() {1, Handler::GroupSuccess}, {0, Handler::GroupSuccess} }; - QTest::newRow("SequentialNested") << TestData{storage, root, log, 5, DoneWith::Success}; + QTest::newRow("SequentialNested") << TestData{storage, root, log, 5, DoneWith::Success, 5}; } { @@ -986,7 +987,7 @@ void tst_Tasking::testTree_data() {3, Handler::Error}, {0, Handler::GroupError} }; - QTest::newRow("SequentialError") << TestData{storage, root, log, 5, DoneWith::Error}; + QTest::newRow("SequentialError") << TestData{storage, root, log, 5, DoneWith::Error, 3}; } { @@ -1000,7 +1001,8 @@ void tst_Tasking::testTree_data() }, Log {{0, result == DoneWith::Success ? Handler::GroupSuccess : Handler::GroupError}}, 0, - result + result, + 0 }; }; @@ -1040,7 +1042,8 @@ void tst_Tasking::testTree_data() {0, result == DoneWith::Success ? Handler::GroupSuccess : Handler::GroupError} }, 1, - result + result, + 1 }; }; @@ -1077,7 +1080,8 @@ void tst_Tasking::testTree_data() {0, result == DoneWith::Success ? Handler::GroupSuccess : Handler::GroupError} }, 1, - result + result, + 1 }; }; @@ -1139,31 +1143,31 @@ void tst_Tasking::testTree_data() const Group root1 = createRoot(WorkflowPolicy::StopOnError); QTest::newRow("StopRootWithStopOnError") - << TestData{storage, root1, errorErrorLog, 2, DoneWith::Error}; + << TestData{storage, root1, errorErrorLog, 2, DoneWith::Error, 1}; const Group root2 = createRoot(WorkflowPolicy::ContinueOnError); QTest::newRow("StopRootWithContinueOnError") - << TestData{storage, root2, errorDoneLog, 2, DoneWith::Error}; + << TestData{storage, root2, errorDoneLog, 2, DoneWith::Error, 2}; const Group root3 = createRoot(WorkflowPolicy::StopOnSuccess); QTest::newRow("StopRootWithStopOnSuccess") - << TestData{storage, root3, doneLog, 2, DoneWith::Success}; + << TestData{storage, root3, doneLog, 2, DoneWith::Success, 2}; const Group root4 = createRoot(WorkflowPolicy::ContinueOnSuccess); QTest::newRow("StopRootWithContinueOnSuccess") - << TestData{storage, root4, doneLog, 2, DoneWith::Success}; + << TestData{storage, root4, doneLog, 2, DoneWith::Success, 2}; const Group root5 = createRoot(WorkflowPolicy::StopOnSuccessOrError); QTest::newRow("StopRootWithStopOnSuccessOrError") - << TestData{storage, root5, errorErrorLog, 2, DoneWith::Error}; + << TestData{storage, root5, errorErrorLog, 2, DoneWith::Error, 1}; const Group root6 = createRoot(WorkflowPolicy::FinishAllAndSuccess); QTest::newRow("StopRootWithFinishAllAndSuccess") - << TestData{storage, root6, doneLog, 2, DoneWith::Success}; + << TestData{storage, root6, doneLog, 2, DoneWith::Success, 2}; const Group root7 = createRoot(WorkflowPolicy::FinishAllAndError); QTest::newRow("StopRootWithFinishAllAndError") - << TestData{storage, root7, errorDoneLog, 2, DoneWith::Error}; + << TestData{storage, root7, errorDoneLog, 2, DoneWith::Error, 2}; } { @@ -1226,31 +1230,31 @@ void tst_Tasking::testTree_data() const Group root1 = createRoot(WorkflowPolicy::StopOnError); QTest::newRow("StopRootAfterDoneWithStopOnError") - << TestData{storage, root1, errorErrorLog, 3, DoneWith::Error}; + << TestData{storage, root1, errorErrorLog, 3, DoneWith::Error, 2}; const Group root2 = createRoot(WorkflowPolicy::ContinueOnError); QTest::newRow("StopRootAfterDoneWithContinueOnError") - << TestData{storage, root2, errorDoneLog, 3, DoneWith::Error}; + << TestData{storage, root2, errorDoneLog, 3, DoneWith::Error, 3}; const Group root3 = createRoot(WorkflowPolicy::StopOnSuccess); QTest::newRow("StopRootAfterDoneWithStopOnSuccess") - << TestData{storage, root3, doneErrorLog, 3, DoneWith::Success}; + << TestData{storage, root3, doneErrorLog, 3, DoneWith::Success, 1}; const Group root4 = createRoot(WorkflowPolicy::ContinueOnSuccess); QTest::newRow("StopRootAfterDoneWithContinueOnSuccess") - << TestData{storage, root4, doneDoneLog, 3, DoneWith::Success}; + << TestData{storage, root4, doneDoneLog, 3, DoneWith::Success, 3}; const Group root5 = createRoot(WorkflowPolicy::StopOnSuccessOrError); QTest::newRow("StopRootAfterDoneWithStopOnSuccessOrError") - << TestData{storage, root5, doneErrorLog, 3, DoneWith::Success}; + << TestData{storage, root5, doneErrorLog, 3, DoneWith::Success, 1}; const Group root6 = createRoot(WorkflowPolicy::FinishAllAndSuccess); QTest::newRow("StopRootAfterDoneWithFinishAllAndSuccess") - << TestData{storage, root6, doneDoneLog, 3, DoneWith::Success}; + << TestData{storage, root6, doneDoneLog, 3, DoneWith::Success, 3}; const Group root7 = createRoot(WorkflowPolicy::FinishAllAndError); QTest::newRow("StopRootAfterDoneWithFinishAllAndError") - << TestData{storage, root7, errorDoneLog, 3, DoneWith::Error}; + << TestData{storage, root7, errorDoneLog, 3, DoneWith::Error, 3}; } { @@ -1283,33 +1287,33 @@ void tst_Tasking::testTree_data() const Group root1 = createRoot(WorkflowPolicy::StopOnError); QTest::newRow("StopGroupWithStopOnError") - << TestData{storage, root1, log, 2, DoneWith::Error}; + << TestData{storage, root1, log, 2, DoneWith::Error, 1}; const Group root2 = createRoot(WorkflowPolicy::ContinueOnError); QTest::newRow("StopGroupWithContinueOnError") - << TestData{storage, root2, log, 2, DoneWith::Error}; + << TestData{storage, root2, log, 2, DoneWith::Error, 1}; const Group root3 = createRoot(WorkflowPolicy::StopOnSuccess); QTest::newRow("StopGroupWithStopOnSuccess") - << TestData{storage, root3, log, 2, DoneWith::Error}; + << TestData{storage, root3, log, 2, DoneWith::Error, 1}; const Group root4 = createRoot(WorkflowPolicy::ContinueOnSuccess); QTest::newRow("StopGroupWithContinueOnSuccess") - << TestData{storage, root4, log, 2, DoneWith::Error}; + << TestData{storage, root4, log, 2, DoneWith::Error, 1}; const Group root5 = createRoot(WorkflowPolicy::StopOnSuccessOrError); QTest::newRow("StopGroupWithStopOnSuccessOrError") - << TestData{storage, root5, log, 2, DoneWith::Error}; + << TestData{storage, root5, log, 2, DoneWith::Error, 1}; // TODO: Behavioral change! Fix Docs! // Cancellation always invokes error handler (i.e. DoneWith is Canceled) const Group root6 = createRoot(WorkflowPolicy::FinishAllAndSuccess); QTest::newRow("StopGroupWithFinishAllAndSuccess") - << TestData{storage, root6, log, 2, DoneWith::Error}; + << TestData{storage, root6, log, 2, DoneWith::Error, 1}; const Group root7 = createRoot(WorkflowPolicy::FinishAllAndError); QTest::newRow("StopGroupWithFinishAllAndError") - << TestData{storage, root7, log, 2, DoneWith::Error}; + << TestData{storage, root7, log, 2, DoneWith::Error, 1}; } { @@ -1354,33 +1358,33 @@ void tst_Tasking::testTree_data() const Group root1 = createRoot(WorkflowPolicy::StopOnError); QTest::newRow("StopGroupAfterDoneWithStopOnError") - << TestData{storage, root1, errorLog, 3, DoneWith::Error}; + << TestData{storage, root1, errorLog, 3, DoneWith::Error, 2}; const Group root2 = createRoot(WorkflowPolicy::ContinueOnError); QTest::newRow("StopGroupAfterDoneWithContinueOnError") - << TestData{storage, root2, errorLog, 3, DoneWith::Error}; + << TestData{storage, root2, errorLog, 3, DoneWith::Error, 2}; const Group root3 = createRoot(WorkflowPolicy::StopOnSuccess); QTest::newRow("StopGroupAfterDoneWithStopOnSuccess") - << TestData{storage, root3, doneLog, 3, DoneWith::Error}; + << TestData{storage, root3, doneLog, 3, DoneWith::Error, 2}; // TODO: Behavioral change! const Group root4 = createRoot(WorkflowPolicy::ContinueOnSuccess); QTest::newRow("StopGroupAfterDoneWithContinueOnSuccess") - << TestData{storage, root4, errorLog, 3, DoneWith::Error}; + << TestData{storage, root4, errorLog, 3, DoneWith::Error, 2}; const Group root5 = createRoot(WorkflowPolicy::StopOnSuccessOrError); QTest::newRow("StopGroupAfterDoneWithStopOnSuccessOrError") - << TestData{storage, root5, doneLog, 3, DoneWith::Error}; + << TestData{storage, root5, doneLog, 3, DoneWith::Error, 2}; // TODO: Behavioral change! const Group root6 = createRoot(WorkflowPolicy::FinishAllAndSuccess); QTest::newRow("StopGroupAfterDoneWithFinishAllAndSuccess") - << TestData{storage, root6, errorLog, 3, DoneWith::Error}; + << TestData{storage, root6, errorLog, 3, DoneWith::Error, 2}; const Group root7 = createRoot(WorkflowPolicy::FinishAllAndError); QTest::newRow("StopGroupAfterDoneWithFinishAllAndError") - << TestData{storage, root7, errorLog, 3, DoneWith::Error}; + << TestData{storage, root7, errorLog, 3, DoneWith::Error, 2}; } { @@ -1425,32 +1429,32 @@ void tst_Tasking::testTree_data() const Group root1 = createRoot(WorkflowPolicy::StopOnError); QTest::newRow("StopGroupAfterErrorWithStopOnError") - << TestData{storage, root1, shortLog, 3, DoneWith::Error}; + << TestData{storage, root1, shortLog, 3, DoneWith::Error, 1}; const Group root2 = createRoot(WorkflowPolicy::ContinueOnError); QTest::newRow("StopGroupAfterErrorWithContinueOnError") - << TestData{storage, root2, longLog, 3, DoneWith::Error}; + << TestData{storage, root2, longLog, 3, DoneWith::Error, 2}; const Group root3 = createRoot(WorkflowPolicy::StopOnSuccess); QTest::newRow("StopGroupAfterErrorWithStopOnSuccess") - << TestData{storage, root3, longLog, 3, DoneWith::Error}; + << TestData{storage, root3, longLog, 3, DoneWith::Error, 2}; const Group root4 = createRoot(WorkflowPolicy::ContinueOnSuccess); QTest::newRow("StopGroupAfterErrorWithContinueOnSuccess") - << TestData{storage, root4, longLog, 3, DoneWith::Error}; + << TestData{storage, root4, longLog, 3, DoneWith::Error, 2}; const Group root5 = createRoot(WorkflowPolicy::StopOnSuccessOrError); QTest::newRow("StopGroupAfterErrorWithStopOnSuccessOrError") - << TestData{storage, root5, shortLog, 3, DoneWith::Error}; + << TestData{storage, root5, shortLog, 3, DoneWith::Error, 1}; // TODO: Behavioral change! const Group root6 = createRoot(WorkflowPolicy::FinishAllAndSuccess); QTest::newRow("StopGroupAfterErrorWithFinishAllAndSuccess") - << TestData{storage, root6, longLog, 3, DoneWith::Error}; + << TestData{storage, root6, longLog, 3, DoneWith::Error, 2}; const Group root7 = createRoot(WorkflowPolicy::FinishAllAndError); QTest::newRow("StopGroupAfterErrorWithFinishAllAndError") - << TestData{storage, root7, longLog, 3, DoneWith::Error}; + << TestData{storage, root7, longLog, 3, DoneWith::Error, 2}; } { @@ -1474,7 +1478,7 @@ void tst_Tasking::testTree_data() {2, Handler::Error}, {0, Handler::GroupError} }; - QTest::newRow("StopOnError") << TestData{storage, root1, log1, 3, DoneWith::Error}; + QTest::newRow("StopOnError") << TestData{storage, root1, log1, 3, DoneWith::Error, 2}; const Group root2 = createRoot(WorkflowPolicy::ContinueOnError); const Log errorLog { @@ -1486,7 +1490,7 @@ void tst_Tasking::testTree_data() {3, Handler::Success}, {0, Handler::GroupError} }; - QTest::newRow("ContinueOnError") << TestData{storage, root2, errorLog, 3, DoneWith::Error}; + QTest::newRow("ContinueOnError") << TestData{storage, root2, errorLog, 3, DoneWith::Error, 3}; const Group root3 = createRoot(WorkflowPolicy::StopOnSuccess); const Log log3 { @@ -1494,7 +1498,7 @@ void tst_Tasking::testTree_data() {1, Handler::Success}, {0, Handler::GroupSuccess} }; - QTest::newRow("StopOnSuccess") << TestData{storage, root3, log3, 3, DoneWith::Success}; + QTest::newRow("StopOnSuccess") << TestData{storage, root3, log3, 3, DoneWith::Success, 1}; const Group root4 = createRoot(WorkflowPolicy::ContinueOnSuccess); const Log doneLog { @@ -1506,7 +1510,7 @@ void tst_Tasking::testTree_data() {3, Handler::Success}, {0, Handler::GroupSuccess} }; - QTest::newRow("ContinueOnSuccess") << TestData{storage, root4, doneLog, 3, DoneWith::Success}; + QTest::newRow("ContinueOnSuccess") << TestData{storage, root4, doneLog, 3, DoneWith::Success, 3}; const Group root5 = createRoot(WorkflowPolicy::StopOnSuccessOrError); const Log log5 { @@ -1514,13 +1518,13 @@ void tst_Tasking::testTree_data() {1, Handler::Success}, {0, Handler::GroupSuccess} }; - QTest::newRow("StopOnSuccessOrError") << TestData{storage, root5, log5, 3, DoneWith::Success}; + QTest::newRow("StopOnSuccessOrError") << TestData{storage, root5, log5, 3, DoneWith::Success, 1}; const Group root6 = createRoot(WorkflowPolicy::FinishAllAndSuccess); - QTest::newRow("FinishAllAndSuccess") << TestData{storage, root6, doneLog, 3, DoneWith::Success}; + QTest::newRow("FinishAllAndSuccess") << TestData{storage, root6, doneLog, 3, DoneWith::Success, 3}; const Group root7 = createRoot(WorkflowPolicy::FinishAllAndError); - QTest::newRow("FinishAllAndError") << TestData{storage, root7, errorLog, 3, DoneWith::Error}; + QTest::newRow("FinishAllAndError") << TestData{storage, root7, errorLog, 3, DoneWith::Error, 3}; } { @@ -1557,13 +1561,13 @@ void tst_Tasking::testTree_data() }; QTest::newRow("StopOnSuccessOrError1") - << TestData{storage, root1, success, 2, DoneWith::Success}; + << TestData{storage, root1, success, 2, DoneWith::Success, 1}; QTest::newRow("StopOnSuccessOrError2") - << TestData{storage, root2, failure, 2, DoneWith::Error}; + << TestData{storage, root2, failure, 2, DoneWith::Error, 1}; QTest::newRow("StopOnSuccessOrError3") - << TestData{storage, root3, success, 2, DoneWith::Success}; + << TestData{storage, root3, success, 2, DoneWith::Success, 1}; QTest::newRow("StopOnSuccessOrError4") - << TestData{storage, root4, failure, 2, DoneWith::Error}; + << TestData{storage, root4, failure, 2, DoneWith::Error, 1}; } { @@ -1587,7 +1591,7 @@ void tst_Tasking::testTree_data() {0, Handler::GroupSuccess} }; QTest::newRow("GroupSetupTweakToSuccess") - << TestData{storage, root1, log1, 1, DoneWith::Success}; + << TestData{storage, root1, log1, 1, DoneWith::Success, 0}; const Group root2 = createRoot(SetupResult::StopWithError); const Log log2 { @@ -1596,7 +1600,7 @@ void tst_Tasking::testTree_data() {0, Handler::GroupError} }; QTest::newRow("GroupSetupTweakToError") - << TestData{storage, root2, log2, 1, DoneWith::Error}; + << TestData{storage, root2, log2, 1, DoneWith::Error, 0}; const Group root3 = createRoot(SetupResult::Continue); const Log log3 { @@ -1607,7 +1611,7 @@ void tst_Tasking::testTree_data() {0, Handler::GroupSuccess} }; QTest::newRow("GroupSetupTweakToContinue") - << TestData{storage, root3, log3, 1, DoneWith::Success}; + << TestData{storage, root3, log3, 1, DoneWith::Success, 1}; } { @@ -1633,7 +1637,7 @@ void tst_Tasking::testTree_data() {0, Handler::GroupSuccess} }; QTest::newRow("GroupDoneWithSuccessTweakToSuccess") - << TestData{storage, root1, log1, 1, DoneWith::Success}; + << TestData{storage, root1, log1, 1, DoneWith::Success, 1}; const Group root2 = createRoot(DoneResult::Success, DoneResult::Error); const Log log2 { @@ -1644,7 +1648,7 @@ void tst_Tasking::testTree_data() {0, Handler::GroupError} }; QTest::newRow("GroupDoneWithSuccessTweakToError") - << TestData{storage, root2, log2, 1, DoneWith::Error}; + << TestData{storage, root2, log2, 1, DoneWith::Error, 1}; const Group root3 = createRoot(DoneResult::Error, DoneResult::Success); const Log log3 { @@ -1655,7 +1659,7 @@ void tst_Tasking::testTree_data() {0, Handler::GroupSuccess} }; QTest::newRow("GroupDoneWithErrorTweakToSuccess") - << TestData{storage, root3, log3, 1, DoneWith::Success}; + << TestData{storage, root3, log3, 1, DoneWith::Success, 1}; const Group root4 = createRoot(DoneResult::Error, DoneResult::Error); const Log log4 { @@ -1666,7 +1670,7 @@ void tst_Tasking::testTree_data() {0, Handler::GroupError} }; QTest::newRow("GroupDoneWithErrorTweakToError") - << TestData{storage, root4, log4, 1, DoneWith::Error}; + << TestData{storage, root4, log4, 1, DoneWith::Error, 1}; } { @@ -1692,7 +1696,7 @@ void tst_Tasking::testTree_data() {0, Handler::GroupSuccess} }; QTest::newRow("TaskSetupTweakToSuccess") - << TestData{storage, root1, log1, 2, DoneWith::Success}; + << TestData{storage, root1, log1, 2, DoneWith::Success, 1}; const Group root2 = createRoot(SetupResult::StopWithError); const Log log2 { @@ -1701,7 +1705,7 @@ void tst_Tasking::testTree_data() {0, Handler::GroupError} }; QTest::newRow("TaskSetupTweakToError") - << TestData{storage, root2, log2, 2, DoneWith::Error}; + << TestData{storage, root2, log2, 2, DoneWith::Error, 0}; const Group root3 = createRoot(SetupResult::Continue); const Log log3 { @@ -1713,7 +1717,7 @@ void tst_Tasking::testTree_data() {0, Handler::GroupSuccess} }; QTest::newRow("TaskSetupTweakToContinue") - << TestData{storage, root3, log3, 2, DoneWith::Success}; + << TestData{storage, root3, log3, 2, DoneWith::Success, 2}; } { @@ -1751,7 +1755,7 @@ void tst_Tasking::testTree_data() {3, Handler::Success}, {4, Handler::Success} }; - QTest::newRow("NestedParallel") << TestData{storage, root, log, 4, DoneWith::Success}; + QTest::newRow("NestedParallel") << TestData{storage, root, log, 4, DoneWith::Success, 4}; } { @@ -1796,7 +1800,7 @@ void tst_Tasking::testTree_data() {4, Handler::Success}, {5, Handler::Success} }; - QTest::newRow("NestedParallelDone") << TestData{storage, root, log, 5, DoneWith::Success}; + QTest::newRow("NestedParallelDone") << TestData{storage, root, log, 5, DoneWith::Success, 4}; } { @@ -1926,11 +1930,11 @@ void tst_Tasking::testTree_data() {5, Handler::Success} }; QTest::newRow("NestedParallelError1") - << TestData{storage, root1, log1, 5, DoneWith::Error}; + << TestData{storage, root1, log1, 5, DoneWith::Error, 1}; QTest::newRow("NestedParallelError2") - << TestData{storage, root2, log2, 5, DoneWith::Error}; + << TestData{storage, root2, log2, 5, DoneWith::Error, 1}; QTest::newRow("NestedParallelError3") - << TestData{storage, root3, log3, 5, DoneWith::Error}; + << TestData{storage, root3, log3, 5, DoneWith::Error, 2}; } { @@ -1980,7 +1984,7 @@ void tst_Tasking::testTree_data() {3, Handler::Success}, {4, Handler::Success} }; - QTest::newRow("DeeplyNestedParallel") << TestData{storage, root, log, 4, DoneWith::Success}; + QTest::newRow("DeeplyNestedParallel") << TestData{storage, root, log, 4, DoneWith::Success, 4}; } { @@ -2026,7 +2030,7 @@ void tst_Tasking::testTree_data() {5, Handler::Success} }; QTest::newRow("DeeplyNestedParallelSuccess") - << TestData{storage, root, log, 5, DoneWith::Success}; + << TestData{storage, root, log, 5, DoneWith::Success, 4}; } { @@ -2066,7 +2070,7 @@ void tst_Tasking::testTree_data() {2, Handler::Canceled} }; QTest::newRow("DeeplyNestedParallelError") - << TestData{storage, root, log, 5, DoneWith::Error}; + << TestData{storage, root, log, 5, DoneWith::Error, 1}; } { @@ -2085,7 +2089,7 @@ void tst_Tasking::testTree_data() {4, Handler::Sync}, {5, Handler::Sync} }; - QTest::newRow("SyncSequential") << TestData{storage, root, log, 0, DoneWith::Success}; + QTest::newRow("SyncSequential") << TestData{storage, root, log, 0, DoneWith::Success, 0}; } { @@ -2109,7 +2113,7 @@ void tst_Tasking::testTree_data() {5, Handler::Sync}, {5, Handler::TweakDoneToSuccess} }; - QTest::newRow("SyncWithReturn") << TestData{storage, root, log, 0, DoneWith::Success}; + QTest::newRow("SyncWithReturn") << TestData{storage, root, log, 0, DoneWith::Success, 0}; } { @@ -2129,7 +2133,7 @@ void tst_Tasking::testTree_data() {4, Handler::Sync}, {5, Handler::Sync} }; - QTest::newRow("SyncParallel") << TestData{storage, root, log, 0, DoneWith::Success}; + QTest::newRow("SyncParallel") << TestData{storage, root, log, 0, DoneWith::Success, 0}; } { @@ -2148,7 +2152,7 @@ void tst_Tasking::testTree_data() {3, Handler::Sync}, {3, Handler::TweakDoneToError} }; - QTest::newRow("SyncError") << TestData{storage, root, log, 0, DoneWith::Error}; + QTest::newRow("SyncError") << TestData{storage, root, log, 0, DoneWith::Error, 0}; } { @@ -2171,7 +2175,7 @@ void tst_Tasking::testTree_data() {5, Handler::Sync}, {0, Handler::GroupSuccess} }; - QTest::newRow("SyncAndAsync") << TestData{storage, root, log, 2, DoneWith::Success}; + QTest::newRow("SyncAndAsync") << TestData{storage, root, log, 2, DoneWith::Success, 2}; } { @@ -2192,7 +2196,7 @@ void tst_Tasking::testTree_data() {3, Handler::TweakDoneToError}, {0, Handler::GroupError} }; - QTest::newRow("SyncAndAsyncError") << TestData{storage, root, log, 2, DoneWith::Error}; + QTest::newRow("SyncAndAsyncError") << TestData{storage, root, log, 2, DoneWith::Error, 1}; } { @@ -2343,15 +2347,15 @@ void tst_Tasking::testTree_data() // Notice the different log order for each scenario. QTest::newRow("BarrierSequential") - << TestData{storage, root1, log1, 4, DoneWith::Success}; + << TestData{storage, root1, log1, 4, DoneWith::Success, 3}; QTest::newRow("BarrierParallelAdvanceFirst") - << TestData{storage, root2, log2, 4, DoneWith::Success}; + << TestData{storage, root2, log2, 4, DoneWith::Success, 4}; QTest::newRow("BarrierParallelWaitForFirst") - << TestData{storage, root3, log3, 4, DoneWith::Success}; + << TestData{storage, root3, log3, 4, DoneWith::Success, 4}; QTest::newRow("BarrierParallelMultiWaitFor") - << TestData{storage, root4, log4, 5, DoneWith::Success}; + << TestData{storage, root4, log4, 5, DoneWith::Success, 5}; QTest::newRow("BarrierParallelTwoSingleBarriers") - << TestData{storage, root5, log5, 5, DoneWith::Success}; + << TestData{storage, root5, log5, 5, DoneWith::Success, 5}; } { @@ -2483,13 +2487,13 @@ void tst_Tasking::testTree_data() // Notice the different log order for each scenario. QTest::newRow("MultiBarrierSequential") - << TestData{storage, root1, log1, 5, DoneWith::Success}; + << TestData{storage, root1, log1, 5, DoneWith::Success, 4}; QTest::newRow("MultiBarrierParallelAdvanceFirst") - << TestData{storage, root2, log2, 5, DoneWith::Success}; + << TestData{storage, root2, log2, 5, DoneWith::Success, 5}; QTest::newRow("MultiBarrierParallelWaitForFirst") - << TestData{storage, root3, log3, 5, DoneWith::Success}; + << TestData{storage, root3, log3, 5, DoneWith::Success, 5}; QTest::newRow("MultiBarrierParallelMultiWaitFor") - << TestData{storage, root4, log4, 6, DoneWith::Success}; + << TestData{storage, root4, log4, 6, DoneWith::Success, 6}; } { @@ -2505,8 +2509,8 @@ void tst_Tasking::testTree_data() {1, Handler::Setup}, {1, Handler::Canceled} }; - QTest::newRow("TaskErrorWithTimeout") << TestData{storage, root1, log1, 2, - DoneWith::Error}; + QTest::newRow("TaskErrorWithTimeout") + << TestData{storage, root1, log1, 2, DoneWith::Error, 1}; const Group root2 { storage, @@ -2518,8 +2522,8 @@ void tst_Tasking::testTree_data() {1, Handler::Timeout}, {1, Handler::Canceled} }; - QTest::newRow("TaskErrorWithTimeoutHandler") << TestData{storage, root2, log2, 2, - DoneWith::Error}; + QTest::newRow("TaskErrorWithTimeoutHandler") + << TestData{storage, root2, log2, 2, DoneWith::Error, 1}; const Group root3 { storage, @@ -2530,16 +2534,16 @@ void tst_Tasking::testTree_data() {1, Handler::Setup}, {1, Handler::Success} }; - QTest::newRow("TaskDoneWithTimeout") << TestData{storage, root3, doneLog, 2, - DoneWith::Success}; + QTest::newRow("TaskDoneWithTimeout") + << TestData{storage, root3, doneLog, 2, DoneWith::Success, 1}; const Group root4 { storage, TestTask(setupTask(1, 1ms), setupDone(1)) .withTimeout(1000ms, setupTimeout(1)) }; - QTest::newRow("TaskDoneWithTimeoutHandler") << TestData{storage, root4, doneLog, 2, - DoneWith::Success}; + QTest::newRow("TaskDoneWithTimeoutHandler") + << TestData{storage, root4, doneLog, 2, DoneWith::Success, 1}; } { @@ -2556,8 +2560,8 @@ void tst_Tasking::testTree_data() {1, Handler::Setup}, {1, Handler::Canceled} }; - QTest::newRow("GroupErrorWithTimeout") << TestData{storage, root1, log1, 2, - DoneWith::Error}; + QTest::newRow("GroupErrorWithTimeout") + << TestData{storage, root1, log1, 2, DoneWith::Error, 1}; // Test Group::withTimeout(), passing custom handler const Group root2 { @@ -2571,8 +2575,8 @@ void tst_Tasking::testTree_data() {1, Handler::Timeout}, {1, Handler::Canceled} }; - QTest::newRow("GroupErrorWithTimeoutHandler") << TestData{storage, root2, log2, 2, - DoneWith::Error}; + QTest::newRow("GroupErrorWithTimeoutHandler") + << TestData{storage, root2, log2, 2, DoneWith::Error, 1}; const Group root3 { storage, @@ -2584,8 +2588,8 @@ void tst_Tasking::testTree_data() {1, Handler::Setup}, {1, Handler::Success} }; - QTest::newRow("GroupDoneWithTimeout") << TestData{storage, root3, doneLog, 2, - DoneWith::Success}; + QTest::newRow("GroupDoneWithTimeout") + << TestData{storage, root3, doneLog, 2, DoneWith::Success, 1}; // Test Group::withTimeout(), passing custom handler const Group root4 { @@ -2594,8 +2598,8 @@ void tst_Tasking::testTree_data() createSuccessTask(1, 1ms) }.withTimeout(1000ms, setupTimeout(1)) }; - QTest::newRow("GroupDoneWithTimeoutHandler") << TestData{storage, root4, doneLog, 2, - DoneWith::Success}; + QTest::newRow("GroupDoneWithTimeoutHandler") + << TestData{storage, root4, doneLog, 2, DoneWith::Success, 1}; } { @@ -2630,7 +2634,7 @@ void tst_Tasking::testTree_data() {1, Handler::GroupSetup}, {0, Handler::GroupSuccess} }; - QTest::newRow("CommonStorage") << TestData{storage, root, log, 0, DoneWith::Success}; + QTest::newRow("CommonStorage") << TestData{storage, root, log, 0, DoneWith::Success, 0}; } { @@ -2640,12 +2644,12 @@ void tst_Tasking::testTree_data() parallel, createSuccessTask(1, 100ms), Group { - createFailingTask(2, 10ms), - createSuccessTask(3, 10ms) + createFailingTask(2, 1ms), + createSuccessTask(3, 1ms) }, - createSuccessTask(4, 10ms) + createSuccessTask(4, 1ms) }, - createSuccessTask(5, 10ms) + createSuccessTask(5, 1ms) }; const Log log { {1, Handler::Setup}, @@ -2655,7 +2659,7 @@ void tst_Tasking::testTree_data() {1, Handler::Canceled}, {4, Handler::Canceled} }; - QTest::newRow("NestedCancel") << TestData{storage, root, log, 5, DoneWith::Error}; + QTest::newRow("NestedCancel") << TestData{storage, root, log, 5, DoneWith::Error, 1}; } { @@ -2758,17 +2762,17 @@ void tst_Tasking::testTree_data() }; QTest::newRow("RepeatSequentialSuccess") - << TestData{storage, rootSequentialSuccess, logSequentialSuccess, 4, DoneWith::Success}; + << TestData{storage, rootSequentialSuccess, logSequentialSuccess, 4, DoneWith::Success, 4}; QTest::newRow("RepeatParallelSuccess") - << TestData{storage, rootParallelSuccess, logParallelSuccess, 4, DoneWith::Success}; + << TestData{storage, rootParallelSuccess, logParallelSuccess, 4, DoneWith::Success, 4}; QTest::newRow("RepeatParallelLimitSuccess") - << TestData{storage, rootParallelLimitSuccess, logParallelLimitSuccess, 4, DoneWith::Success}; + << TestData{storage, rootParallelLimitSuccess, logParallelLimitSuccess, 4, DoneWith::Success, 4}; QTest::newRow("RepeatSequentialError") - << TestData{storage, rootSequentialError, logSequentialError, 4, DoneWith::Error}; + << TestData{storage, rootSequentialError, logSequentialError, 4, DoneWith::Error, 2}; QTest::newRow("RepeatParallelError") - << TestData{storage, rootParallelError, logParallelError, 4, DoneWith::Error}; + << TestData{storage, rootParallelError, logParallelError, 4, DoneWith::Error, 2}; QTest::newRow("RepeatParallelLimitError") - << TestData{storage, rootParallelLimitError, logParallelLimitError, 4, DoneWith::Error}; + << TestData{storage, rootParallelLimitError, logParallelLimitError, 4, DoneWith::Error, 2}; } { @@ -2859,11 +2863,11 @@ void tst_Tasking::testTree_data() }; QTest::newRow("LoopSequential") - << TestData{storage, rootSequential, logSequential, 2, DoneWith::Success}; + << TestData{storage, rootSequential, logSequential, 2, DoneWith::Success, 5}; QTest::newRow("LoopParallel") - << TestData{storage, rootParallel, logParallel, 2, DoneWith::Success}; + << TestData{storage, rootParallel, logParallel, 2, DoneWith::Success, 5}; QTest::newRow("LoopParallelLimit") - << TestData{storage, rootParallelLimit, logParallelLimit, 2, DoneWith::Success}; + << TestData{storage, rootParallelLimit, logParallelLimit, 2, DoneWith::Success, 5}; } { @@ -2874,7 +2878,7 @@ void tst_Tasking::testTree_data() createSuccessTask(1) }; QTest::newRow("ProgressWithLoopUntilFalse") - << TestData{storage, root, {}, 1, DoneWith::Success}; + << TestData{storage, root, {}, 1, DoneWith::Success, 0}; } { @@ -2888,7 +2892,7 @@ void tst_Tasking::testTree_data() } }; QTest::newRow("ProgressWithNestedLoopUntilFalse") - << TestData{storage, root, {}, 1, DoneWith::Success}; + << TestData{storage, root, {}, 1, DoneWith::Success, 0}; } { @@ -2899,7 +2903,7 @@ void tst_Tasking::testTree_data() createSuccessTask(1) }; QTest::newRow("ProgressWithGroupSetupFalse") - << TestData{storage, root, {}, 1, DoneWith::Success}; + << TestData{storage, root, {}, 1, DoneWith::Success, 0}; } { @@ -2913,7 +2917,7 @@ void tst_Tasking::testTree_data() } }; QTest::newRow("ProgressWithNestedGroupSetupFalse") - << TestData{storage, root, {}, 1, DoneWith::Success}; + << TestData{storage, root, {}, 1, DoneWith::Success, 0}; } { @@ -2930,9 +2934,9 @@ void tst_Tasking::testTree_data() }; QTest::newRow("RecipeWithTask") - << TestData{storage, recipe(true), withTaskLog, 1, DoneWith::Success}; + << TestData{storage, recipe(true), withTaskLog, 1, DoneWith::Success, 1}; QTest::newRow("RecipeWithNull") - << TestData{storage, recipe(false), {}, 0, DoneWith::Success}; + << TestData{storage, recipe(false), {}, 0, DoneWith::Success, 0}; } { @@ -2952,6 +2956,7 @@ void tst_Tasking::testTree_data() }, 1, DoneWith::Success, + 1, MessageLog { {"Group 1", Handler::Setup}, {"Task 1", Handler::Setup}, @@ -2973,6 +2978,7 @@ void tst_Tasking::testTree_data() }, 1, DoneWith::Error, + 1, MessageLog { {"Group 1", Handler::Setup}, {"Task 1", Handler::Setup}, @@ -2998,6 +3004,7 @@ void tst_Tasking::testTree_data() }, 1, DoneWith::Error, + 0, MessageLog { {"Group 1", Handler::Setup}, {"Task 1", Handler::Setup}, @@ -3044,22 +3051,22 @@ void tst_Tasking::testTree_data() }; QTest::newRow("CallDoneIfGroupSuccessOrErrorAfterSuccess") << TestData{storage, createRoot(DoneResult::Success, CallDoneIf::SuccessOrError), - logSuccessLong, 1, DoneWith::Success}; + logSuccessLong, 1, DoneWith::Success, 1}; QTest::newRow("CallDoneIfGroupSuccessAfterSuccess") << TestData{storage, createRoot(DoneResult::Success, CallDoneIf::Success), - logSuccessLong, 1, DoneWith::Success}; + logSuccessLong, 1, DoneWith::Success, 1}; QTest::newRow("CallDoneIfGroupErrorAfterSuccess") << TestData{storage, createRoot(DoneResult::Success, CallDoneIf::Error), - logSuccessShort, 1, DoneWith::Success}; + logSuccessShort, 1, DoneWith::Success, 1}; QTest::newRow("CallDoneIfGroupSuccessOrErrorAfterError") << TestData{storage, createRoot(DoneResult::Error, CallDoneIf::SuccessOrError), - logErrorLong, 1, DoneWith::Error}; + logErrorLong, 1, DoneWith::Error, 1}; QTest::newRow("CallDoneIfGroupSuccessAfterError") << TestData{storage, createRoot(DoneResult::Error, CallDoneIf::Success), - logErrorShort, 1, DoneWith::Error}; + logErrorShort, 1, DoneWith::Error, 1}; QTest::newRow("CallDoneIfGroupErrorAfterError") << TestData{storage, createRoot(DoneResult::Error, CallDoneIf::Error), - logErrorLong, 1, DoneWith::Error}; + logErrorLong, 1, DoneWith::Error, 1}; } // This test checks if storage shadowing works OK. @@ -3172,6 +3179,9 @@ void tst_Tasking::testTree() QCOMPARE(result, testData.result); + if (testData.asyncCount) + QCOMPARE(taskTree.asyncCount(), *testData.asyncCount); + if (testData.messageLog) { QCOMPARE(s_messages.count(), testData.messageLog->count()); From 7d5523a59b7da9512c2977f6f96f540364082785 Mon Sep 17 00:00:00 2001 From: hjk Date: Tue, 20 Feb 2024 13:22:32 +0100 Subject: [PATCH 105/243] Axivion: Use LayoutBuilder for project settings page Also, add a stretch at the end of the buttons row. Change-Id: I51392359b183462b52ad9d8b0775f59cf4a94a82 Reviewed-by: Reviewed-by: Jarek Kobus --- .../axivion/axivionprojectsettings.cpp | 26 +++++++++---------- 1 file changed, 13 insertions(+), 13 deletions(-) diff --git a/src/plugins/axivion/axivionprojectsettings.cpp b/src/plugins/axivion/axivionprojectsettings.cpp index 1413b3cfd3a..8cd63ba7ac0 100644 --- a/src/plugins/axivion/axivionprojectsettings.cpp +++ b/src/plugins/axivion/axivionprojectsettings.cpp @@ -14,6 +14,7 @@ #include #include +#include #include #include @@ -117,34 +118,33 @@ AxivionProjectSettingsWidget::AxivionProjectSettingsWidget(Project *project) setUseGlobalSettingsCheckBoxVisible(false); setUseGlobalSettingsLabelVisible(true); setGlobalSettingsId("Axivion.Settings.General"); // FIXME move id to constants - // setup ui - auto verticalLayout = new QVBoxLayout(this); - verticalLayout->setContentsMargins(0, 0, 0, 0); m_linkedProject = new QLabel(this); - verticalLayout->addWidget(m_linkedProject); m_dashboardProjects = new QTreeWidget(this); m_dashboardProjects->setHeaderHidden(true); m_dashboardProjects->setRootIsDecorated(false); - verticalLayout->addWidget(new QLabel(Tr::tr("Dashboard projects:"))); - verticalLayout->addWidget(m_dashboardProjects); m_infoLabel = new InfoLabel(this); m_infoLabel->setVisible(false); - verticalLayout->addWidget(m_infoLabel); - auto horizontalLayout = new QHBoxLayout; - horizontalLayout->setContentsMargins(0, 0, 0, 0); m_fetchProjects = new QPushButton(Tr::tr("Fetch Projects")); - horizontalLayout->addWidget(m_fetchProjects); + m_link = new QPushButton(Tr::tr("Link Project")); m_link->setEnabled(false); - horizontalLayout->addWidget(m_link); + m_unlink = new QPushButton(Tr::tr("Unlink Project")); m_unlink->setEnabled(false); - horizontalLayout->addWidget(m_unlink); - verticalLayout->addLayout(horizontalLayout); + + using namespace Layouting; + Column { + noMargin, + m_linkedProject, + Tr::tr("Dashboard projects:"), + m_dashboardProjects, + m_infoLabel, + Row { m_fetchProjects, m_link, m_unlink, st } + }.attachTo(this); connect(m_dashboardProjects, &QTreeWidget::itemSelectionChanged, this, &AxivionProjectSettingsWidget::updateEnabledStates); From 88aacbb562ea1a8fe736e181ff4ec3904d910d98 Mon Sep 17 00:00:00 2001 From: David Schulz Date: Tue, 20 Feb 2024 14:15:39 +0100 Subject: [PATCH 106/243] Debugger: fix char type dumper optimization Change-Id: I600f4ddc9a4539e19b70664fd9354c17e64cd0d6 Reviewed-by: Reviewed-by: Christian Stenger --- share/qtcreator/debugger/dumper.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/share/qtcreator/debugger/dumper.py b/share/qtcreator/debugger/dumper.py index ca6b7f40737..2fa7d31da50 100644 --- a/share/qtcreator/debugger/dumper.py +++ b/share/qtcreator/debugger/dumper.py @@ -420,7 +420,7 @@ class DumperBase(): def charType(self): result = self.lookupType('char') - self.intType = lambda: result + self.charType = lambda: result return result def ptrSize(self): From a1f317798dd698720bbfb1f7bee9cc9775e70cd1 Mon Sep 17 00:00:00 2001 From: Leena Miettinen Date: Tue, 20 Feb 2024 17:00:53 +0100 Subject: [PATCH 107/243] Doc: Link to "Add custom output parsers" ...from "CMake Build Configuration" Task-number: QTCREATORBUG-30209 Change-Id: Ic10125f84eee29ddae05b18d80512fbde530dd2d Reviewed-by: Cristian Adam --- doc/qtcreator/src/cmake/creator-projects-cmake-building.qdoc | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/doc/qtcreator/src/cmake/creator-projects-cmake-building.qdoc b/doc/qtcreator/src/cmake/creator-projects-cmake-building.qdoc index a51d6623f88..c8da5117fb6 100644 --- a/doc/qtcreator/src/cmake/creator-projects-cmake-building.qdoc +++ b/doc/qtcreator/src/cmake/creator-projects-cmake-building.qdoc @@ -275,6 +275,7 @@ The build errors and warnings are parsed and displayed in \l Issues. - \sa {Activate kits for a project}, {Configure projects for building}, - {Configure projects for running}, {Open projects}, {CMake} + \sa {Activate kits for a project}, {Add custom output parsers}, + {Configure projects for building}, {Configure projects for running}, + {Open projects}, {CMake} */ From f686ca7aa8e597fb2d6cc15d6e2116f6ee6c23c1 Mon Sep 17 00:00:00 2001 From: Knud Dollereder Date: Tue, 20 Feb 2024 12:15:36 +0100 Subject: [PATCH 108/243] Nanotrace: Add LGPL-3.0-only as a licensing option MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Change-Id: I203d93c23d5799835b6a122b9329f16af84c895c Reviewed-by: Eike Ziller Reviewed-by: Reviewed-by: Kai Köhne --- src/libs/nanotrace/nanotrace.cpp | 2 +- src/libs/nanotrace/nanotrace.h | 2 +- src/libs/nanotrace/nanotraceglobals.h | 2 +- src/libs/nanotrace/nanotracehr.cpp | 2 +- src/libs/nanotrace/nanotracehr.h | 2 +- src/libs/nanotrace/python/figures.py | 2 +- src/libs/nanotrace/python/nanotrace.py | 2 +- src/libs/nanotrace/python/reader.py | 2 +- 8 files changed, 8 insertions(+), 8 deletions(-) diff --git a/src/libs/nanotrace/nanotrace.cpp b/src/libs/nanotrace/nanotrace.cpp index c5adeb4d724..8a96b125845 100644 --- a/src/libs/nanotrace/nanotrace.cpp +++ b/src/libs/nanotrace/nanotrace.cpp @@ -1,5 +1,5 @@ // Copyright (C) 2022 The Qt Company Ltd. -// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only WITH Qt-GPL-exception-1.0 +// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only #include "nanotrace.h" diff --git a/src/libs/nanotrace/nanotrace.h b/src/libs/nanotrace/nanotrace.h index ed17797e344..76b0120ae1a 100644 --- a/src/libs/nanotrace/nanotrace.h +++ b/src/libs/nanotrace/nanotrace.h @@ -1,5 +1,5 @@ // Copyright (C) 2022 The Qt Company Ltd. -// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only WITH Qt-GPL-exception-1.0 +// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only #pragma once diff --git a/src/libs/nanotrace/nanotraceglobals.h b/src/libs/nanotrace/nanotraceglobals.h index 649408d69c9..64af31aab9d 100644 --- a/src/libs/nanotrace/nanotraceglobals.h +++ b/src/libs/nanotrace/nanotraceglobals.h @@ -1,5 +1,5 @@ // Copyright (C) 2023 The Qt Company Ltd. -// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only WITH Qt-GPL-exception-1.0 +// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only #pragma once diff --git a/src/libs/nanotrace/nanotracehr.cpp b/src/libs/nanotrace/nanotracehr.cpp index 3f02bd527d3..ada5bf65f52 100644 --- a/src/libs/nanotrace/nanotracehr.cpp +++ b/src/libs/nanotrace/nanotracehr.cpp @@ -1,5 +1,5 @@ // Copyright (C) 2023 The Qt Company Ltd. -// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only WITH Qt-GPL-exception-1.0 +// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only #include "nanotracehr.h" diff --git a/src/libs/nanotrace/nanotracehr.h b/src/libs/nanotrace/nanotracehr.h index 74b1381b064..62ec7dc03cd 100644 --- a/src/libs/nanotrace/nanotracehr.h +++ b/src/libs/nanotrace/nanotracehr.h @@ -1,5 +1,5 @@ // Copyright (C) 2022 The Qt Company Ltd. -// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only WITH Qt-GPL-exception-1.0 +// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only #pragma once diff --git a/src/libs/nanotrace/python/figures.py b/src/libs/nanotrace/python/figures.py index cb806ea40d6..7f92a3b57ee 100644 --- a/src/libs/nanotrace/python/figures.py +++ b/src/libs/nanotrace/python/figures.py @@ -1,5 +1,5 @@ # Copyright (C) 2022 The Qt Company Ltd. -# SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only WITH Qt-GPL-exception-1.0 +# SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only import pandas as pd import plotly.graph_objects as go import plotly.subplots as sp diff --git a/src/libs/nanotrace/python/nanotrace.py b/src/libs/nanotrace/python/nanotrace.py index 880f17d7bfc..a173c3c52b7 100644 --- a/src/libs/nanotrace/python/nanotrace.py +++ b/src/libs/nanotrace/python/nanotrace.py @@ -1,5 +1,5 @@ # Copyright (C) 2022 The Qt Company Ltd. -# SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only WITH Qt-GPL-exception-1.0 +# SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only import reader as rd import figures as fgs diff --git a/src/libs/nanotrace/python/reader.py b/src/libs/nanotrace/python/reader.py index 023bddb15f7..ed6b8b5b1e1 100644 --- a/src/libs/nanotrace/python/reader.py +++ b/src/libs/nanotrace/python/reader.py @@ -1,5 +1,5 @@ # Copyright (C) 2022 The Qt Company Ltd. -# SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only WITH Qt-GPL-exception-1.0 +# SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only import os import io import json From 2fe085871beebcfd23ae17fe3867a7c2caa4935b Mon Sep 17 00:00:00 2001 From: Jarek Kobus Date: Tue, 20 Feb 2024 15:22:13 +0100 Subject: [PATCH 109/243] Axivion: Fix internal layout of DashboardSettingsWidget Make internal margins a bit smaller so that they look consistent with the rest of UI coming from Qt. Change-Id: Iaeaccd1e0a4141a96657e32cebb619b969e43cab Reviewed-by: Reviewed-by: hjk --- src/plugins/axivion/axivionsettings.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/plugins/axivion/axivionsettings.cpp b/src/plugins/axivion/axivionsettings.cpp index a4db242c2dd..8597fac9150 100644 --- a/src/plugins/axivion/axivionsettings.cpp +++ b/src/plugins/axivion/axivionsettings.cpp @@ -185,7 +185,7 @@ DashboardSettingsWidget::DashboardSettingsWidget(Mode mode, QWidget *parent, QPu Form { m_dashboardUrl, br, m_username, br, - mode == Edit ? normalMargin : noMargin + noMargin }.attachTo(this); if (mode == Edit) { From 370fb4d550dafd8ededf4b2ecde23d3f48cbcb46 Mon Sep 17 00:00:00 2001 From: Christian Stenger Date: Wed, 21 Feb 2024 09:14:39 +0100 Subject: [PATCH 110/243] Axivion: Open issue information semi-automatic This patch adds another way of opening issue information. Double clicking an issue on the issues table will now open the related information automatically beside jumping to the respective location. The original way of using a button on the tool tip of the issue's text mark is clumsy, but still present. Change-Id: I7b0fcafb8b01675fc020f8cc8174121ba7f52adc Reviewed-by: hjk --- src/plugins/axivion/axivionoutputpane.cpp | 31 +++++++++++++++-------- src/plugins/axivion/axivionplugin.cpp | 6 +++++ src/plugins/axivion/axivionplugin.h | 1 + 3 files changed, 27 insertions(+), 11 deletions(-) diff --git a/src/plugins/axivion/axivionoutputpane.cpp b/src/plugins/axivion/axivionoutputpane.cpp index df8d87accdc..42046f78b14 100644 --- a/src/plugins/axivion/axivionoutputpane.cpp +++ b/src/plugins/axivion/axivionoutputpane.cpp @@ -189,28 +189,34 @@ void DashboardWidget::updateUi() class IssueTreeItem final : public StaticTreeItem { public: - IssueTreeItem(const QStringList &data, const QStringList &toolTips) + IssueTreeItem(const QString &id, const QStringList &data, const QStringList &toolTips) : StaticTreeItem(data, toolTips) + , m_id(id) {} void setLinks(const Links &links) { m_links = links; } bool setData(int column, const QVariant &value, int role) final { - if (role == BaseTreeView::ItemActivatedRole && !m_links.isEmpty()) { - // TODO for now only simple - just the first.. - Link link = m_links.first(); - Project *project = ProjectManager::startupProject(); - FilePath baseDir = project ? project->projectDirectory() : FilePath{}; - link.targetFilePath = baseDir.resolvePath(link.targetFilePath); - if (link.targetFilePath.exists()) - EditorManager::openEditorAt(link); + if (role == BaseTreeView::ItemActivatedRole) { + if (!m_links.isEmpty()) { + // TODO for now only simple - just the first.. + Link link = m_links.first(); + Project *project = ProjectManager::startupProject(); + FilePath baseDir = project ? project->projectDirectory() : FilePath{}; + link.targetFilePath = baseDir.resolvePath(link.targetFilePath); + if (link.targetFilePath.exists()) + EditorManager::openEditorAt(link); + } + if (!m_id.isEmpty()) + fetchIssueInfo(m_id); return true; } return StaticTreeItem::setData(column, value, role); } private: + const QString m_id; Links m_links; }; @@ -425,17 +431,20 @@ void IssuesWidget::addIssues(const Dto::IssueTableDto &dto) const std::vector &tableColumns = m_currentTableInfo->columns; const std::vector> &rows = dto.rows; for (const auto &row : rows) { + QString id; QStringList data; for (const auto &column : tableColumns) { const auto it = row.find(column.key); if (it != row.end()) { QString value = anyToSimpleString(it->second); - if (column.key == "id") + if (column.key == "id") { value.prepend(m_currentPrefix); + id = value; + } data << value; } } - IssueTreeItem *it = new IssueTreeItem(data, data); + IssueTreeItem *it = new IssueTreeItem(id, data, data); it->setLinks(linksForIssue(row)); m_issuesModel->rootItem()->appendChild(it); } diff --git a/src/plugins/axivion/axivionplugin.cpp b/src/plugins/axivion/axivionplugin.cpp index 1cd8c9fc140..6d6d5c98808 100644 --- a/src/plugins/axivion/axivionplugin.cpp +++ b/src/plugins/axivion/axivionplugin.cpp @@ -887,6 +887,12 @@ class AxivionPlugin final : public ExtensionSystem::IPlugin } }; +void fetchIssueInfo(const QString &id) +{ + QTC_ASSERT(dd, return); + dd->fetchIssueInfo(id); +} + } // Axivion::Internal #include "axivionplugin.moc" diff --git a/src/plugins/axivion/axivionplugin.h b/src/plugins/axivion/axivionplugin.h index 1d5245a5034..1d2ebe12129 100644 --- a/src/plugins/axivion/axivionplugin.h +++ b/src/plugins/axivion/axivionplugin.h @@ -72,6 +72,7 @@ bool handleCertificateIssue(); QIcon iconForIssue(const QString &prefix); QString anyToSimpleString(const Dto::Any &any); +void fetchIssueInfo(const QString &id); } // Axivion::Internal From a130343ab55b9edb4303edabf46b1b87340712f7 Mon Sep 17 00:00:00 2001 From: Eike Ziller Date: Wed, 21 Feb 2024 10:15:28 +0100 Subject: [PATCH 111/243] Fix i18n issues Fix some missing Tr::, and some namespace usages that confused lupdate. Change-Id: Ib5a411fc53a28a6b807600db50aacc68955ca5dc Reviewed-by: hjk Reviewed-by: Leena Miettinen --- src/libs/utils/macroexpander.cpp | 2 +- src/plugins/coreplugin/editormanager/editormanager.cpp | 6 +++--- src/plugins/coreplugin/find/ifindfilter.cpp | 2 +- src/plugins/cvs/cvsplugin.cpp | 10 +++++----- src/plugins/effectcomposer/effectcomposerview.h | 1 + src/plugins/languageclient/callhierarchy.cpp | 2 +- src/plugins/mercurial/mercurialplugin.cpp | 8 ++++---- .../projectexplorer/jsonwizard/jsonwizardfactory.cpp | 2 +- .../appmanagerinstallpackagestep.cpp | 4 ++-- .../qtapplicationmanager/appmanagerruncontrol.cpp | 2 +- src/plugins/remotelinux/linuxdevice.cpp | 4 ++-- src/plugins/subversion/subversionplugin.cpp | 6 +++--- 12 files changed, 25 insertions(+), 24 deletions(-) diff --git a/src/libs/utils/macroexpander.cpp b/src/libs/utils/macroexpander.cpp index f6d3dad3623..dd57cd6b5a0 100644 --- a/src/libs/utils/macroexpander.cpp +++ b/src/libs/utils/macroexpander.cpp @@ -375,7 +375,7 @@ void MacroExpander::registerIntVariable(const QByteArray &variable, * Convenience function to register several variables with the same \a prefix, that have a file * as a value. Takes the prefix and registers variables like \c{prefix:FilePath} and * \c{prefix:Path}, with descriptions that start with the given \a heading. - * For example \c{registerFileVariables("CurrentDocument", tr("Current Document"))} registers + * For example \c{registerFileVariables("CurrentDocument", Tr::tr("Current Document"))} registers * variables such as \c{CurrentDocument:FilePath} with description * "Current Document: Full path including file name." * diff --git a/src/plugins/coreplugin/editormanager/editormanager.cpp b/src/plugins/coreplugin/editormanager/editormanager.cpp index 10cec9f79ba..6ec37a6cb8c 100644 --- a/src/plugins/coreplugin/editormanager/editormanager.cpp +++ b/src/plugins/coreplugin/editormanager/editormanager.cpp @@ -579,7 +579,7 @@ void EditorManagerPrivate::init() // Go back in navigation history ActionBuilder goBack(this, Constants::GO_BACK); goBack.setIcon(Utils::Icons::PREV.icon()); - goBack.setText(Core::Tr::tr("Go Back")); + goBack.setText(::Core::Tr::tr("Go Back")); goBack.bindContextAction(&m_goBackAction); goBack.setContext(editDesignContext); goBack.setDefaultKeySequence(::Core::Tr::tr("Ctrl+Alt+Left"), ::Core::Tr::tr("Alt+Left")); @@ -589,7 +589,7 @@ void EditorManagerPrivate::init() // Go forward in navigation history ActionBuilder goForward(this, Constants::GO_FORWARD); goForward.setIcon(Utils::Icons::NEXT.icon()); - goForward.setText(Core::Tr::tr("Go Forward")); + goForward.setText(::Core::Tr::tr("Go Forward")); goForward.bindContextAction(&m_goForwardAction); goForward.setContext(editDesignContext); goForward.setDefaultKeySequence(::Core::Tr::tr("Ctrl+Alt+Right"), ::Core::Tr::tr("Alt+Right")); @@ -618,7 +618,7 @@ void EditorManagerPrivate::init() splitSideBySide.setText(::Core::Tr::tr("Split Side by Side")); splitSideBySide.bindContextAction(&m_splitSideBySideAction); splitSideBySide.setContext(editManagerContext); - splitSideBySide.setDefaultKeySequence(::Core::Tr::tr("Meta+E,3"), Core::Tr::tr("Ctrl+E,3")); + splitSideBySide.setDefaultKeySequence(::Core::Tr::tr("Meta+E,3"), ::Core::Tr::tr("Ctrl+E,3")); splitSideBySide.addToContainer(Constants::M_WINDOW, Constants::G_WINDOW_SPLIT); splitSideBySide.addOnTriggered(this, &EditorManager::splitSideBySide); diff --git a/src/plugins/coreplugin/find/ifindfilter.cpp b/src/plugins/coreplugin/find/ifindfilter.cpp index a849598cfdd..704f827bf83 100644 --- a/src/plugins/coreplugin/find/ifindfilter.cpp +++ b/src/plugins/coreplugin/find/ifindfilter.cpp @@ -92,7 +92,7 @@ using namespace Utils; Returns the name of the find filter or scope as presented to the user. This is the name that appears in the scope selection combo box, for example. - Always return a translatable string. That is, use \c tr() for the return + Always return a translatable string. That is, use \c {Tr::tr()} for the return value. */ diff --git a/src/plugins/cvs/cvsplugin.cpp b/src/plugins/cvs/cvsplugin.cpp index 4ca9dd83b39..2688def71e6 100644 --- a/src/plugins/cvs/cvsplugin.cpp +++ b/src/plugins/cvs/cvsplugin.cpp @@ -292,7 +292,7 @@ public: VcsEditorFactory commandLogEditorFactory {{ OtherContent, CVS_COMMANDLOG_EDITOR_ID, - VcsBase::Tr::tr("CVS Command Log Editor"), // display name + ::VcsBase::Tr::tr("CVS Command Log Editor"), // display name "text/vnd.qtcreator.cvs.commandlog", [] { return new CvsEditorWidget; }, std::bind(&CvsPluginPrivate::vcsDescribe, this, _1, _2) @@ -301,7 +301,7 @@ public: VcsEditorFactory logEditorFactory {{ LogOutput, CVS_FILELOG_EDITOR_ID, - VcsBase::Tr::tr("CVS File Log Editor"), // display name + ::VcsBase::Tr::tr("CVS File Log Editor"), // display name "text/vnd.qtcreator.cvs.log", [] { return new CvsEditorWidget; }, std::bind(&CvsPluginPrivate::vcsDescribe, this, _1, _2) @@ -310,7 +310,7 @@ public: VcsEditorFactory annotateEditorFactory {{ AnnotateOutput, CVS_ANNOTATION_EDITOR_ID, - VcsBase::Tr::tr("CVS Annotation Editor"), // display name + ::VcsBase::Tr::tr("CVS Annotation Editor"), // display name "text/vnd.qtcreator.cvs.annotation", [] { return new CvsEditorWidget; }, std::bind(&CvsPluginPrivate::vcsDescribe, this, _1, _2) @@ -319,7 +319,7 @@ public: VcsEditorFactory diffEditorFactory {{ DiffOutput, CVS_DIFF_EDITOR_ID, - VcsBase::Tr::tr("CVS Diff Editor"), // display name + ::VcsBase::Tr::tr("CVS Diff Editor"), // display name "text/x-patch", [] { return new CvsEditorWidget; }, std::bind(&CvsPluginPrivate::vcsDescribe, this, _1, _2) @@ -449,7 +449,7 @@ CvsPluginPrivate::CvsPluginPrivate() setupVcsSubmitEditor(this, { CVS_SUBMIT_MIMETYPE, CVSCOMMITEDITOR_ID, - VcsBase::Tr::tr("CVS Commit Editor"), + ::VcsBase::Tr::tr("CVS Commit Editor"), VcsBaseSubmitEditorParameters::DiffFiles, [] { return new CvsSubmitEditor; }, }); diff --git a/src/plugins/effectcomposer/effectcomposerview.h b/src/plugins/effectcomposer/effectcomposerview.h index a16225dfec4..c7a381cb7db 100644 --- a/src/plugins/effectcomposer/effectcomposerview.h +++ b/src/plugins/effectcomposer/effectcomposerview.h @@ -24,6 +24,7 @@ public: class EffectComposerView : public QmlDesigner::AbstractView { + Q_DECLARE_TR_FUNCTIONS(EffectComposer::EffectComposerView) public: EffectComposerView(QmlDesigner::ExternalDependenciesInterface &externalDependencies); ~EffectComposerView() override; diff --git a/src/plugins/languageclient/callhierarchy.cpp b/src/plugins/languageclient/callhierarchy.cpp index a310fde2a4e..32023e6a98f 100644 --- a/src/plugins/languageclient/callhierarchy.cpp +++ b/src/plugins/languageclient/callhierarchy.cpp @@ -280,7 +280,7 @@ public: Icons::RELOAD_TOOLBAR.icon(); auto button = new QToolButton; button->setIcon(Icons::RELOAD_TOOLBAR.icon()); - button->setToolTip(Tr::tr("Reloads the call hierarchy for the symbol under cursor position.")); + button->setToolTip(::LanguageClient::Tr::tr("Reloads the call hierarchy for the symbol under cursor position.")); connect(button, &QToolButton::clicked, this, [h] { h->updateHierarchyAtCursorPosition(); }); return {h, {button}}; } diff --git a/src/plugins/mercurial/mercurialplugin.cpp b/src/plugins/mercurial/mercurialplugin.cpp index 76c8f2ba8c8..a9ab891c023 100644 --- a/src/plugins/mercurial/mercurialplugin.cpp +++ b/src/plugins/mercurial/mercurialplugin.cpp @@ -146,7 +146,7 @@ public: VcsEditorFactory logEditorFactory {{ LogOutput, Constants::FILELOG_ID, - VcsBase::Tr::tr("Mercurial File Log Editor"), + ::VcsBase::Tr::tr("Mercurial File Log Editor"), Constants::LOGAPP, [] { return new MercurialEditorWidget; }, std::bind(&MercurialPluginPrivate::vcsDescribe, this, _1, _2) @@ -155,7 +155,7 @@ public: VcsEditorFactory annotateEditorFactory {{ AnnotateOutput, Constants::ANNOTATELOG_ID, - VcsBase::Tr::tr("Mercurial Annotation Editor"), + ::VcsBase::Tr::tr("Mercurial Annotation Editor"), Constants::ANNOTATEAPP, [] { return new MercurialEditorWidget; }, std::bind(&MercurialPluginPrivate::vcsDescribe, this, _1, _2) @@ -164,7 +164,7 @@ public: VcsEditorFactory diffEditorFactory {{ DiffOutput, Constants::DIFFLOG_ID, - VcsBase::Tr::tr("Mercurial Diff Editor"), + ::VcsBase::Tr::tr("Mercurial Diff Editor"), Constants::DIFFAPP, [] { return new MercurialEditorWidget; }, std::bind(&MercurialPluginPrivate::vcsDescribe, this, _1, _2) @@ -181,7 +181,7 @@ MercurialPluginPrivate::MercurialPluginPrivate() setupVcsSubmitEditor(this, { Constants::COMMITMIMETYPE, Constants::COMMIT_ID, - VcsBase::Tr::tr("Mercurial Commit Log Editor"), + ::VcsBase::Tr::tr("Mercurial Commit Log Editor"), VcsBaseSubmitEditorParameters::DiffFiles, [] { return new CommitEditor; } }); diff --git a/src/plugins/projectexplorer/jsonwizard/jsonwizardfactory.cpp b/src/plugins/projectexplorer/jsonwizard/jsonwizardfactory.cpp index 0febbcd4149..7f8ff6baf54 100644 --- a/src/plugins/projectexplorer/jsonwizard/jsonwizardfactory.cpp +++ b/src/plugins/projectexplorer/jsonwizard/jsonwizardfactory.cpp @@ -504,7 +504,7 @@ QList JsonWizardFactory::createWizardFactories() currentFile.parentDir(), &errorMessage); if (!factory) { - verboseLog.append(tr("* Failed to create: %1\n").arg(errorMessage)); + verboseLog.append(Tr::tr("* Failed to create: %1\n").arg(errorMessage)); continue; } diff --git a/src/plugins/qtapplicationmanager/appmanagerinstallpackagestep.cpp b/src/plugins/qtapplicationmanager/appmanagerinstallpackagestep.cpp index 0f995144ec9..f89514ba005 100644 --- a/src/plugins/qtapplicationmanager/appmanagerinstallpackagestep.cpp +++ b/src/plugins/qtapplicationmanager/appmanagerinstallpackagestep.cpp @@ -52,7 +52,7 @@ private: AppManagerInstallPackageStep::AppManagerInstallPackageStep(BuildStepList *bsl, Id id) : AbstractRemoteLinuxDeployStep(bsl, id) { - setDisplayName(tr("Install Application Manager package")); + setDisplayName(Tr::tr("Install Application Manager package")); controller.setDefaultPathValue(getToolFilePath(Constants::APPMAN_CONTROLLER, target()->kit(), @@ -125,7 +125,7 @@ GroupItem AppManagerInstallPackageStep::deployRecipe() }; const auto doneHandler = [this](const Process &process, DoneWith result) { if (result == DoneWith::Success) { - addProgressMessage(tr("Command finished successfully.")); + addProgressMessage(Tr::tr("Command finished successfully.")); } else { if (process.error() != QProcess::UnknownError || process.exitStatus() != QProcess::NormalExit) { diff --git a/src/plugins/qtapplicationmanager/appmanagerruncontrol.cpp b/src/plugins/qtapplicationmanager/appmanagerruncontrol.cpp index ec1aa7244ed..9c485536a44 100644 --- a/src/plugins/qtapplicationmanager/appmanagerruncontrol.cpp +++ b/src/plugins/qtapplicationmanager/appmanagerruncontrol.cpp @@ -232,7 +232,7 @@ private: void start() override { if (m_symbolFile.isEmpty()) { - reportFailure(tr("Cannot debug: Local executable is not set.")); + reportFailure(Tr::tr("Cannot debug: Local executable is not set.")); return; } diff --git a/src/plugins/remotelinux/linuxdevice.cpp b/src/plugins/remotelinux/linuxdevice.cpp index dbad2b5bb18..30fac20a9d9 100644 --- a/src/plugins/remotelinux/linuxdevice.cpp +++ b/src/plugins/remotelinux/linuxdevice.cpp @@ -476,8 +476,8 @@ ProcessResult SshProcessInterface::runInShell(const CommandLine &command, const using namespace std::chrono_literals; process.runBlocking(2s); if (process.result() == ProcessResult::Canceled) { - Core::MessageManager::writeFlashing(tr("Can't send control signal to the %1 device. " - "The device might have been disconnected.") + Core::MessageManager::writeFlashing(Tr::tr("Can't send control signal to the %1 device. " + "The device might have been disconnected.") .arg(d->m_device->displayName())); } return process.result(); diff --git a/src/plugins/subversion/subversionplugin.cpp b/src/plugins/subversion/subversionplugin.cpp index fc9d5ed1222..64f32a11ff2 100644 --- a/src/plugins/subversion/subversionplugin.cpp +++ b/src/plugins/subversion/subversionplugin.cpp @@ -248,7 +248,7 @@ public: VcsEditorFactory logEditorFactory {{ LogOutput, Constants::SUBVERSION_LOG_EDITOR_ID, - VcsBase::Tr::tr("Subversion File Log Editor"), + ::VcsBase::Tr::tr("Subversion File Log Editor"), Constants::SUBVERSION_LOG_MIMETYPE, [] { return new SubversionEditorWidget; }, std::bind(&SubversionPluginPrivate::vcsDescribe, this, _1, _2) @@ -257,7 +257,7 @@ public: VcsEditorFactory blameEditorFactory {{ AnnotateOutput, Constants::SUBVERSION_BLAME_EDITOR_ID, - VcsBase::Tr::tr("Subversion Annotation Editor"), + ::VcsBase::Tr::tr("Subversion Annotation Editor"), Constants::SUBVERSION_BLAME_MIMETYPE, [] { return new SubversionEditorWidget; }, std::bind(&SubversionPluginPrivate::vcsDescribe, this, _1, _2) @@ -468,7 +468,7 @@ SubversionPluginPrivate::SubversionPluginPrivate() setupVcsSubmitEditor(this, { Constants::SUBVERSION_SUBMIT_MIMETYPE, Constants::SUBVERSION_COMMIT_EDITOR_ID, - VcsBase::Tr::tr("Subversion Commit Editor"), + ::VcsBase::Tr::tr("Subversion Commit Editor"), VcsBaseSubmitEditorParameters::DiffFiles, [] { return new SubversionSubmitEditor; }, }); From 04beeaf082fa0a8f287b5b2605fe796cae009936 Mon Sep 17 00:00:00 2001 From: Christian Stenger Date: Wed, 21 Feb 2024 09:54:31 +0100 Subject: [PATCH 112/243] Axivion: Handle local URLs of issue details Issue details provide a usually at least one or depending on the issue kind more file locations related to the issue. Handle files which are present inside the current project. Change-Id: I375ee99dfa1ca697d04146efde3081360e6cb582 Reviewed-by: Jarek Kobus Reviewed-by: hjk --- src/plugins/axivion/axivionplugin.cpp | 21 +++++++++++++++++++++ 1 file changed, 21 insertions(+) diff --git a/src/plugins/axivion/axivionplugin.cpp b/src/plugins/axivion/axivionplugin.cpp index 6d6d5c98808..9f142a17671 100644 --- a/src/plugins/axivion/axivionplugin.cpp +++ b/src/plugins/axivion/axivionplugin.cpp @@ -46,6 +46,7 @@ #include #include #include +#include #include @@ -188,6 +189,7 @@ public: void handleIssuesForFile(const Dto::FileViewDto &fileView); void fetchIssueInfo(const QString &id); void setIssueDetails(const QString &issueDetailsHtml); + void handleAnchorClicked(const QUrl &url); signals: void issueDetailsChanged(const QString &issueDetailsHtml); @@ -832,6 +834,23 @@ void AxivionPluginPrivate::handleIssuesForFile(const Dto::FileViewDto &fileView) } } +void AxivionPluginPrivate::handleAnchorClicked(const QUrl &url) +{ + QTC_ASSERT(dd, return); + QTC_ASSERT(dd->m_project, return); + const QUrlQuery query(url); + if (query.isEmpty()) + return; + Link link; + if (const QString path = query.queryItemValue("filename", QUrl::FullyDecoded); !path.isEmpty()) + link.targetFilePath = m_project->projectDirectory().pathAppended(path); + if (const QString line = query.queryItemValue("line"); !line.isEmpty()) + link.targetLine = line.toInt(); + // column entry is wrong - so, ignore it + if (link.hasValidTarget() && link.targetFilePath.exists()) + EditorManager::openEditorAt(link); +} + class AxivionIssueWidgetFactory final : public INavigationWidgetFactory { public: @@ -850,6 +869,8 @@ public: NavigationView view; view.widget = browser; connect(dd, &AxivionPluginPrivate::issueDetailsChanged, browser, &QTextBrowser::setHtml); + connect(browser, &QTextBrowser::anchorClicked, + dd, &AxivionPluginPrivate::handleAnchorClicked); return view; } }; From 504bed284d17f2641c7c21200442a9dba3d786de Mon Sep 17 00:00:00 2001 From: Christian Stenger Date: Wed, 21 Feb 2024 10:40:02 +0100 Subject: [PATCH 113/243] Axivion: Allow opening external links ..outside of Qt Creator, by using the default browser or similar. Change-Id: Ibaa379d2a26976fe717ee38b056794dd54838685 Reviewed-by: hjk --- src/plugins/axivion/axivionplugin.cpp | 15 +++++++++++++++ 1 file changed, 15 insertions(+) diff --git a/src/plugins/axivion/axivionplugin.cpp b/src/plugins/axivion/axivionplugin.cpp index 9f142a17671..a5da9cdba2c 100644 --- a/src/plugins/axivion/axivionplugin.cpp +++ b/src/plugins/axivion/axivionplugin.cpp @@ -34,12 +34,14 @@ #include #include +#include #include #include #include #include #include +#include #include #include #include @@ -838,6 +840,19 @@ void AxivionPluginPrivate::handleAnchorClicked(const QUrl &url) { QTC_ASSERT(dd, return); QTC_ASSERT(dd->m_project, return); + if (!url.scheme().isEmpty()) { + const QString detail = Tr::tr("The activated link appears to be external.\n" + "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"), + detail, + Key("AxivionOpenExternalLinks")); + if (pressed == QMessageBox::Yes) + QDesktopServices::openUrl(url); + return; + } const QUrlQuery query(url); if (query.isEmpty()) return; From 1a7e1b5dbd9f2a8ac0cce1c9ec79ddea765485c1 Mon Sep 17 00:00:00 2001 From: David Schulz Date: Wed, 21 Feb 2024 08:54:54 +0100 Subject: [PATCH 114/243] Cmake: include textwrap in the generated python zip file textwrap is required for traceback that is used when the last command gets debugged Amends 0a2b6a910acd8d75bb14c1860c60c248aa5e073e Change-Id: I7d62dbe2bc0f4e1839f07b9bff687ee1f4e4c885 Reviewed-by: Cristian Adam Reviewed-by: --- cmake/CreatePythonXY.cmake | 56 +++++++++++++++++++------------------- 1 file changed, 28 insertions(+), 28 deletions(-) diff --git a/cmake/CreatePythonXY.cmake b/cmake/CreatePythonXY.cmake index 637c4940c83..4e234703cb8 100644 --- a/cmake/CreatePythonXY.cmake +++ b/cmake/CreatePythonXY.cmake @@ -24,34 +24,34 @@ function(create_python_xy PythonExe PythonZipFilePath) cgi.py nntplib.py tarfile.py cgitb.py nturl2path.py telnetlib.py chunk.py numbers.py tempfile.py - cmd.py optparse.py textwrap.py - code.py pathlib.py this.py - codeop.py pdb.py timeit.py - colorsys.py pickle.py trace.py - compileall.py pickletools.py tracemalloc.py - configparser.py pipes.py tty.py - contextvars.py plistlib.py turtle.py - cProfile.py poplib.py typing.py - crypt.py pprint.py uu.py - csv.py profile.py uuid.py - dataclasses.py pstats.py wave.py - datetime.py pty.py webbrowser.py - decimal.py pyclbr.py xdrlib.py - difflib.py py_compile.py zipapp.py - doctest.py queue.py zipfile.py - dummy_threading.py quopri.py zipimport.py - filecmp.py random.py _compat_pickle.py - fileinput.py rlcompleter.py _compression.py - formatter.py runpy.py _dummy_thread.py - fractions.py sched.py _markupbase.py - ftplib.py secrets.py _osx_support.py - getopt.py selectors.py _pydecimal.py - getpass.py shelve.py _pyio.py - gettext.py shlex.py _py_abc.py - gzip.py shutil.py _strptime.py - hashlib.py smtpd.py _threading_local.py - hmac.py smtplib.py __future__.py - imaplib.py sndhdr.py __phello__.foo.py + cmd.py optparse.py this.py + code.py pathlib.py timeit.py + codeop.py pdb.py trace.py + colorsys.py pickle.py tracemalloc.py + compileall.py pickletools.py tty.py + configparser.py pipes.py turtle.py + contextvars.py plistlib.py typing.py + cProfile.py poplib.py uu.py + crypt.py pprint.py uuid.py + csv.py profile.py wave.py + dataclasses.py pstats.py webbrowser.py + datetime.py pty.py xdrlib.py + decimal.py pyclbr.py zipapp.py + difflib.py py_compile.py zipfile.py + doctest.py queue.py zipimport.py + dummy_threading.py quopri.py _compat_pickle.py + filecmp.py random.py _compression.py + fileinput.py rlcompleter.py _dummy_thread.py + formatter.py runpy.py _markupbase.py + fractions.py sched.py _osx_support.py + ftplib.py secrets.py _pydecimal.py + getopt.py selectors.py _pyio.py + getpass.py shelve.py _py_abc.py + gettext.py shlex.py _strptime.py + gzip.py shutil.py _threading_local.py + hashlib.py smtpd.py __future__.py + hmac.py smtplib.py __phello__.foo.py + imaplib.py sndhdr.py ) list(FIND python_lib_files "${python_lib_dir}/${not_needed}" found_not_needed) if (NOT found_not_needed STREQUAL "-1") From c9208932d71eada289c47f876089168981aff20d Mon Sep 17 00:00:00 2001 From: Cristian Adam Date: Tue, 20 Feb 2024 13:45:48 +0100 Subject: [PATCH 115/243] CMakePM: Don't show anything but CMake Preset Kits during initial configure This is for projects that use CMake Presets, and matches the expectations of the users using CMake Presets. The user can still enable a Kit from the left list of Kits, which is not filtered. Amends 87c67fc6d7193883edb9a0244296cd429f0473de Task-number: QTCREATORBUG-29535 Change-Id: If97eef867a687c877b1cbd08cd4537fe6459136f Reviewed-by: Marcus Tillmanns Reviewed-by: --- src/plugins/cmakeprojectmanager/cmakeproject.cpp | 13 +++++++++++++ .../cmakeprojectmanager/cmakeprojectimporter.cpp | 4 +--- .../cmakeprojectmanager/cmakeprojectimporter.h | 1 - src/plugins/cmakeprojectmanager/presetsparser.h | 1 + 4 files changed, 15 insertions(+), 4 deletions(-) diff --git a/src/plugins/cmakeprojectmanager/cmakeproject.cpp b/src/plugins/cmakeprojectmanager/cmakeproject.cpp index 7318c7a791f..25352f0b5d6 100644 --- a/src/plugins/cmakeprojectmanager/cmakeproject.cpp +++ b/src/plugins/cmakeprojectmanager/cmakeproject.cpp @@ -7,6 +7,7 @@ #include "cmakeprojectconstants.h" #include "cmakeprojectimporter.h" #include "cmakeprojectmanagertr.h" +#include "presetsmacros.h" #include #include @@ -301,6 +302,18 @@ void CMakeProject::readPresets() m_presetsData = combinePresets(cmakePresetsData, cmakeUserPresetsData); setupBuildPresets(m_presetsData); + + for (const auto &configPreset : m_presetsData.configurePresets) { + if (configPreset.hidden.value()) + continue; + + if (configPreset.condition) { + if (!CMakePresets::Macros::evaluatePresetCondition(configPreset, projectFilePath())) + continue; + } + m_presetsData.havePresets = true; + break; + } } bool CMakeProject::setupTarget(Target *t) diff --git a/src/plugins/cmakeprojectmanager/cmakeprojectimporter.cpp b/src/plugins/cmakeprojectmanager/cmakeprojectimporter.cpp index 450d1540102..52ed82f8d77 100644 --- a/src/plugins/cmakeprojectmanager/cmakeprojectimporter.cpp +++ b/src/plugins/cmakeprojectmanager/cmakeprojectimporter.cpp @@ -201,8 +201,6 @@ FilePaths CMakeProjectImporter::presetCandidates() } } - m_hasCMakePresets = !candidates.isEmpty(); - return candidates; } @@ -223,7 +221,7 @@ Target *CMakeProjectImporter::preferredTarget(const QList &possibleTar bool CMakeProjectImporter::filter(ProjectExplorer::Kit *k) const { - if (!m_hasCMakePresets) + if (!m_project->presetsData().havePresets) return true; const auto presetConfigItem = CMakeConfigurationKitAspect::cmakePresetConfigItem(k); diff --git a/src/plugins/cmakeprojectmanager/cmakeprojectimporter.h b/src/plugins/cmakeprojectmanager/cmakeprojectimporter.h index 82e1835ba7b..63c2403f4b4 100644 --- a/src/plugins/cmakeprojectmanager/cmakeprojectimporter.h +++ b/src/plugins/cmakeprojectmanager/cmakeprojectimporter.h @@ -49,7 +49,6 @@ private: const CMakeProject *m_project; Utils::TemporaryDirectory m_presetsTempDir; - bool m_hasCMakePresets = false; }; #ifdef WITH_TESTS diff --git a/src/plugins/cmakeprojectmanager/presetsparser.h b/src/plugins/cmakeprojectmanager/presetsparser.h index 20d36e389ec..6df09014af3 100644 --- a/src/plugins/cmakeprojectmanager/presetsparser.h +++ b/src/plugins/cmakeprojectmanager/presetsparser.h @@ -140,6 +140,7 @@ class PresetsData { public: int version = 0; + bool havePresets = false; QVersionNumber cmakeMinimimRequired; QHash vendor; std::optional include; From 0f5eae1d33a87cea975d00f1975076f70abf1f0b Mon Sep 17 00:00:00 2001 From: Mehdi Salem Date: Wed, 21 Feb 2024 12:43:40 +0100 Subject: [PATCH 116/243] Axivion: use static for deserialize in dto classes Change-Id: Ide5b1ff535c1e2bdba7d7f480bf1c19fd3c19fb8 Reviewed-by: Jarek Kobus --- src/plugins/axivion/dashboard/dto.cpp | 282 +++++++++++++++++--------- src/plugins/axivion/dashboard/dto.h | 90 ++++---- 2 files changed, 233 insertions(+), 139 deletions(-) diff --git a/src/plugins/axivion/dashboard/dto.cpp b/src/plugins/axivion/dashboard/dto.cpp index d578e3dff10..747ea2d03da 100644 --- a/src/plugins/axivion/dashboard/dto.cpp +++ b/src/plugins/axivion/dashboard/dto.cpp @@ -77,7 +77,8 @@ namespace Axivion::Internal::Dto { // throws Axivion::Internal::Dto::invalid_dto_exception template - [[noreturn]] static void throw_json_type_conversion(QJsonValue::Type type) { + [[noreturn]] static void throw_json_type_conversion(QJsonValue::Type type) + { throw_invalid_dto_exception(concat({ "Error parsing JSON: Cannot convert type ", to_std_string(type) @@ -86,7 +87,8 @@ namespace Axivion::Internal::Dto { // throws Axivion::Internal::Dto::invalid_dto_exception template - [[noreturn]] static void throw_json_value_conversion(const V &raw_value) { + [[noreturn]] static void throw_json_value_conversion(const V &raw_value) + { throw_invalid_dto_exception(concat({ "Error parsing JSON: Cannot convert raw value ", to_std_string(raw_value) @@ -543,7 +545,8 @@ namespace Axivion::Internal::Dto { })); } - static QJsonValue serialize(const Any &value) { + static QJsonValue serialize(const Any &value) + { if (value.isNull()) return serialize_json(nullptr); if (value.isString()) @@ -569,7 +572,8 @@ namespace Axivion::Internal::Dto { return deserialize_bytes(json); } - Utils::expected_str Any::deserializeExpected(const QByteArray &json) { + Utils::expected_str Any::deserializeExpected(const QByteArray &json) + { return deserializeExp(json); } @@ -688,7 +692,8 @@ namespace Axivion::Internal::Dto { { public: // throws Axivion::Internal::Dto::invalid_dto_exception - static AnalyzedFileDto deserialize(const QJsonValue &json) { + static AnalyzedFileDto deserialize(const QJsonValue &json) + { const QJsonObject jo = toJsonObject(json); return { deserialize_field(jo, analyzedFileKeyPath), @@ -697,7 +702,8 @@ namespace Axivion::Internal::Dto { }; } - static QJsonValue serialize(const AnalyzedFileDto &value) { + static QJsonValue serialize(const AnalyzedFileDto &value) + { QJsonObject jo; serialize_field(jo, analyzedFileKeyPath, value.path); serialize_field(jo, analyzedFileKeyIsSystemHeader, value.isSystemHeader); @@ -806,7 +812,8 @@ namespace Axivion::Internal::Dto { { public: // throws Axivion::Internal::Dto::invalid_dto_exception - static ChangePasswordFormDto deserialize(const QJsonValue &json) { + static ChangePasswordFormDto deserialize(const QJsonValue &json) + { const QJsonObject jo = toJsonObject(json); return { deserialize_field(jo, changePasswordFormKeyCurrentPassword), @@ -814,7 +821,8 @@ namespace Axivion::Internal::Dto { }; } - static QJsonValue serialize(const ChangePasswordFormDto &value) { + static QJsonValue serialize(const ChangePasswordFormDto &value) + { QJsonObject jo; serialize_field(jo, changePasswordFormKeyCurrentPassword, value.currentPassword); serialize_field(jo, changePasswordFormKeyNewPassword, value.newPassword); @@ -942,7 +950,8 @@ namespace Axivion::Internal::Dto { { public: // throws Axivion::Internal::Dto::invalid_dto_exception - static ColumnTypeOptionDto deserialize(const QJsonValue &json) { + static ColumnTypeOptionDto deserialize(const QJsonValue &json) + { const QJsonObject jo = toJsonObject(json); return { deserialize_field(jo, columnTypeOptionKeyKey), @@ -951,7 +960,8 @@ namespace Axivion::Internal::Dto { }; } - static QJsonValue serialize(const ColumnTypeOptionDto &value) { + static QJsonValue serialize(const ColumnTypeOptionDto &value) + { QJsonObject jo; serialize_field(jo, columnTypeOptionKeyKey, value.key); serialize_field(jo, columnTypeOptionKeyDisplayName, value.displayName); @@ -998,14 +1008,16 @@ namespace Axivion::Internal::Dto { { public: // throws Axivion::Internal::Dto::invalid_dto_exception - static CommentRequestDto deserialize(const QJsonValue &json) { + static CommentRequestDto deserialize(const QJsonValue &json) + { const QJsonObject jo = toJsonObject(json); return { deserialize_field(jo, commentRequestKeyText) }; } - static QJsonValue serialize(const CommentRequestDto &value) { + static QJsonValue serialize(const CommentRequestDto &value) + { QJsonObject jo; serialize_field(jo, commentRequestKeyText, value.text); return { jo }; @@ -1046,14 +1058,16 @@ namespace Axivion::Internal::Dto { { public: // throws Axivion::Internal::Dto::invalid_dto_exception - static CsrfTokenDto deserialize(const QJsonValue &json) { + static CsrfTokenDto deserialize(const QJsonValue &json) + { const QJsonObject jo = toJsonObject(json); return { deserialize_field(jo, csrfTokenKeyCsrfToken) }; } - static QJsonValue serialize(const CsrfTokenDto &value) { + static QJsonValue serialize(const CsrfTokenDto &value) + { QJsonObject jo; serialize_field(jo, csrfTokenKeyCsrfToken, value.csrfToken); return { jo }; @@ -1098,7 +1112,8 @@ namespace Axivion::Internal::Dto { { public: // throws Axivion::Internal::Dto::invalid_dto_exception - static EntityDto deserialize(const QJsonValue &json) { + static EntityDto deserialize(const QJsonValue &json) + { const QJsonObject jo = toJsonObject(json); return { deserialize_field(jo, entityKeyId), @@ -1109,7 +1124,8 @@ namespace Axivion::Internal::Dto { }; } - static QJsonValue serialize(const EntityDto &value) { + static QJsonValue serialize(const EntityDto &value) + { QJsonObject jo; serialize_field(jo, entityKeyId, value.id); serialize_field(jo, entityKeyName, value.name); @@ -1170,7 +1186,8 @@ namespace Axivion::Internal::Dto { { public: // throws Axivion::Internal::Dto::invalid_dto_exception - static ErrorDto deserialize(const QJsonValue &json) { + static ErrorDto deserialize(const QJsonValue &json) + { const QJsonObject jo = toJsonObject(json); return { deserialize_field>(jo, errorKeyDashboardVersionNumber), @@ -1185,7 +1202,8 @@ namespace Axivion::Internal::Dto { }; } - static QJsonValue serialize(const ErrorDto &value) { + static QJsonValue serialize(const ErrorDto &value) + { QJsonObject jo; serialize_field(jo, errorKeyDashboardVersionNumber, value.dashboardVersionNumber); serialize_field(jo, errorKeyType, value.type); @@ -1256,7 +1274,8 @@ namespace Axivion::Internal::Dto { { public: // throws Axivion::Internal::Dto::invalid_dto_exception - static IssueCommentDto deserialize(const QJsonValue &json) { + static IssueCommentDto deserialize(const QJsonValue &json) + { const QJsonObject jo = toJsonObject(json); return { deserialize_field(jo, issueCommentKeyUsername), @@ -1269,7 +1288,8 @@ namespace Axivion::Internal::Dto { }; } - static QJsonValue serialize(const IssueCommentDto &value) { + static QJsonValue serialize(const IssueCommentDto &value) + { QJsonObject jo; serialize_field(jo, issueCommentKeyUsername, value.username); serialize_field(jo, issueCommentKeyUserDisplayName, value.userDisplayName); @@ -1477,7 +1497,8 @@ namespace Axivion::Internal::Dto { { public: // throws Axivion::Internal::Dto::invalid_dto_exception - static IssueSourceLocationDto deserialize(const QJsonValue &json) { + static IssueSourceLocationDto deserialize(const QJsonValue &json) + { const QJsonObject jo = toJsonObject(json); return { deserialize_field(jo, issueSourceLocationKeyFileName), @@ -1490,7 +1511,8 @@ namespace Axivion::Internal::Dto { }; } - static QJsonValue serialize(const IssueSourceLocationDto &value) { + static QJsonValue serialize(const IssueSourceLocationDto &value) + { QJsonObject jo; serialize_field(jo, issueSourceLocationKeyFileName, value.fileName); serialize_field(jo, issueSourceLocationKeyRole, value.role); @@ -1550,7 +1572,8 @@ namespace Axivion::Internal::Dto { { public: // throws Axivion::Internal::Dto::invalid_dto_exception - static IssueTagDto deserialize(const QJsonValue &json) { + static IssueTagDto deserialize(const QJsonValue &json) + { const QJsonObject jo = toJsonObject(json); return { deserialize_field(jo, issueTagKeyTag), @@ -1558,7 +1581,8 @@ namespace Axivion::Internal::Dto { }; } - static QJsonValue serialize(const IssueTagDto &value) { + static QJsonValue serialize(const IssueTagDto &value) + { QJsonObject jo; serialize_field(jo, issueTagKeyTag, value.tag); serialize_field(jo, issueTagKeyColor, value.color); @@ -1607,7 +1631,8 @@ namespace Axivion::Internal::Dto { { public: // throws Axivion::Internal::Dto::invalid_dto_exception - static IssueTagTypeDto deserialize(const QJsonValue &json) { + static IssueTagTypeDto deserialize(const QJsonValue &json) + { const QJsonObject jo = toJsonObject(json); return { deserialize_field(jo, issueTagTypeKeyId), @@ -1619,7 +1644,8 @@ namespace Axivion::Internal::Dto { }; } - static QJsonValue serialize(const IssueTagTypeDto &value) { + static QJsonValue serialize(const IssueTagTypeDto &value) + { QJsonObject jo; serialize_field(jo, issueTagTypeKeyId, value.id); serialize_field(jo, issueTagTypeKeyText, value.text); @@ -1739,7 +1765,8 @@ namespace Axivion::Internal::Dto { { public: // throws Axivion::Internal::Dto::invalid_dto_exception - static MetricDto deserialize(const QJsonValue &json) { + static MetricDto deserialize(const QJsonValue &json) + { const QJsonObject jo = toJsonObject(json); return { deserialize_field(jo, metricKeyName), @@ -1749,7 +1776,8 @@ namespace Axivion::Internal::Dto { }; } - static QJsonValue serialize(const MetricDto &value) { + static QJsonValue serialize(const MetricDto &value) + { QJsonObject jo; serialize_field(jo, metricKeyName, value.name); serialize_field(jo, metricKeyDisplayName, value.displayName); @@ -1805,7 +1833,8 @@ namespace Axivion::Internal::Dto { { public: // throws Axivion::Internal::Dto::invalid_dto_exception - static MetricValueTableRowDto deserialize(const QJsonValue &json) { + static MetricValueTableRowDto deserialize(const QJsonValue &json) + { const QJsonObject jo = toJsonObject(json); return { deserialize_field(jo, metricValueTableRowKeyMetric), @@ -1818,7 +1847,8 @@ namespace Axivion::Internal::Dto { }; } - static QJsonValue serialize(const MetricValueTableRowDto &value) { + static QJsonValue serialize(const MetricValueTableRowDto &value) + { QJsonObject jo; serialize_field(jo, metricValueTableRowKeyMetric, value.metric); serialize_field(jo, metricValueTableRowKeyPath, value.path); @@ -1924,14 +1954,16 @@ namespace Axivion::Internal::Dto { { public: // throws Axivion::Internal::Dto::invalid_dto_exception - static NamedFilterVisibilityDto deserialize(const QJsonValue &json) { + static NamedFilterVisibilityDto deserialize(const QJsonValue &json) + { const QJsonObject jo = toJsonObject(json); return { deserialize_field>>(jo, namedFilterVisibilityKeyGroups) }; } - static QJsonValue serialize(const NamedFilterVisibilityDto &value) { + static QJsonValue serialize(const NamedFilterVisibilityDto &value) + { QJsonObject jo; serialize_field(jo, namedFilterVisibilityKeyGroups, value.groups); return { jo }; @@ -1973,7 +2005,8 @@ namespace Axivion::Internal::Dto { { public: // throws Axivion::Internal::Dto::invalid_dto_exception - static ProjectReferenceDto deserialize(const QJsonValue &json) { + static ProjectReferenceDto deserialize(const QJsonValue &json) + { const QJsonObject jo = toJsonObject(json); return { deserialize_field(jo, projectReferenceKeyName), @@ -1981,7 +2014,8 @@ namespace Axivion::Internal::Dto { }; } - static QJsonValue serialize(const ProjectReferenceDto &value) { + static QJsonValue serialize(const ProjectReferenceDto &value) + { QJsonObject jo; serialize_field(jo, projectReferenceKeyName, value.name); serialize_field(jo, projectReferenceKeyUrl, value.url); @@ -2027,7 +2061,8 @@ namespace Axivion::Internal::Dto { { public: // throws Axivion::Internal::Dto::invalid_dto_exception - static RuleDto deserialize(const QJsonValue &json) { + static RuleDto deserialize(const QJsonValue &json) + { const QJsonObject jo = toJsonObject(json); return { deserialize_field(jo, ruleKeyName), @@ -2036,7 +2071,8 @@ namespace Axivion::Internal::Dto { }; } - static QJsonValue serialize(const RuleDto &value) { + static QJsonValue serialize(const RuleDto &value) + { QJsonObject jo; serialize_field(jo, ruleKeyName, value.name); serialize_field(jo, ruleKeyOriginal_name, value.original_name); @@ -2172,7 +2208,8 @@ namespace Axivion::Internal::Dto { { public: // throws Axivion::Internal::Dto::invalid_dto_exception - static ToolsVersionDto deserialize(const QJsonValue &json) { + static ToolsVersionDto deserialize(const QJsonValue &json) + { const QJsonObject jo = toJsonObject(json); return { deserialize_field(jo, toolsVersionKeyName), @@ -2181,7 +2218,8 @@ namespace Axivion::Internal::Dto { }; } - static QJsonValue serialize(const ToolsVersionDto &value) { + static QJsonValue serialize(const ToolsVersionDto &value) + { QJsonObject jo; serialize_field(jo, toolsVersionKeyName, value.name); serialize_field(jo, toolsVersionKeyNumber, value.number); @@ -2277,7 +2315,8 @@ namespace Axivion::Internal::Dto { { public: // throws Axivion::Internal::Dto::invalid_dto_exception - static VersionKindCountDto deserialize(const QJsonValue &json) { + static VersionKindCountDto deserialize(const QJsonValue &json) + { const QJsonObject jo = toJsonObject(json); return { deserialize_field(jo, versionKindCountKeyTotal), @@ -2286,7 +2325,8 @@ namespace Axivion::Internal::Dto { }; } - static QJsonValue serialize(const VersionKindCountDto &value) { + static QJsonValue serialize(const VersionKindCountDto &value) + { QJsonObject jo; serialize_field(jo, versionKindCountKeyTotal, value.Total); serialize_field(jo, versionKindCountKeyAdded, value.Added); @@ -2341,7 +2381,8 @@ namespace Axivion::Internal::Dto { { public: // throws Axivion::Internal::Dto::invalid_dto_exception - static AnalysisVersionDto deserialize(const QJsonValue &json) { + static AnalysisVersionDto deserialize(const QJsonValue &json) + { const QJsonObject jo = toJsonObject(json); return { deserialize_field(jo, analysisVersionKeyDate), @@ -2356,7 +2397,8 @@ namespace Axivion::Internal::Dto { }; } - static QJsonValue serialize(const AnalysisVersionDto &value) { + static QJsonValue serialize(const AnalysisVersionDto &value) + { QJsonObject jo; serialize_field(jo, analysisVersionKeyDate, value.date); serialize_field(jo, analysisVersionKeyLabel, value.label); @@ -2424,7 +2466,8 @@ namespace Axivion::Internal::Dto { { public: // throws Axivion::Internal::Dto::invalid_dto_exception - static ApiTokenCreationRequestDto deserialize(const QJsonValue &json) { + static ApiTokenCreationRequestDto deserialize(const QJsonValue &json) + { const QJsonObject jo = toJsonObject(json); return { deserialize_field(jo, apiTokenCreationRequestKeyPassword), @@ -2434,7 +2477,8 @@ namespace Axivion::Internal::Dto { }; } - static QJsonValue serialize(const ApiTokenCreationRequestDto &value) { + static QJsonValue serialize(const ApiTokenCreationRequestDto &value) + { QJsonObject jo; serialize_field(jo, apiTokenCreationRequestKeyPassword, value.password); serialize_field(jo, apiTokenCreationRequestKeyType, value.type); @@ -2528,7 +2572,8 @@ namespace Axivion::Internal::Dto { { public: // throws Axivion::Internal::Dto::invalid_dto_exception - static ApiTokenInfoDto deserialize(const QJsonValue &json) { + static ApiTokenInfoDto deserialize(const QJsonValue &json) + { const QJsonObject jo = toJsonObject(json); return { deserialize_field(jo, apiTokenInfoKeyId), @@ -2547,7 +2592,8 @@ namespace Axivion::Internal::Dto { }; } - static QJsonValue serialize(const ApiTokenInfoDto &value) { + static QJsonValue serialize(const ApiTokenInfoDto &value) + { QJsonObject jo; serialize_field(jo, apiTokenInfoKeyId, value.id); serialize_field(jo, apiTokenInfoKeyUrl, value.url); @@ -2683,7 +2729,8 @@ namespace Axivion::Internal::Dto { { public: // throws Axivion::Internal::Dto::invalid_dto_exception - static ColumnInfoDto deserialize(const QJsonValue &json) { + static ColumnInfoDto deserialize(const QJsonValue &json) + { const QJsonObject jo = toJsonObject(json); return { deserialize_field(jo, columnInfoKeyKey), @@ -2699,7 +2746,8 @@ namespace Axivion::Internal::Dto { }; } - static QJsonValue serialize(const ColumnInfoDto &value) { + static QJsonValue serialize(const ColumnInfoDto &value) + { QJsonObject jo; serialize_field(jo, columnInfoKeyKey, value.key); serialize_field(jo, columnInfoKeyHeader, value.header); @@ -2845,7 +2893,8 @@ namespace Axivion::Internal::Dto { { public: // throws Axivion::Internal::Dto::invalid_dto_exception - static DashboardInfoDto deserialize(const QJsonValue &json) { + static DashboardInfoDto deserialize(const QJsonValue &json) + { const QJsonObject jo = toJsonObject(json); return { deserialize_field>(jo, dashboardInfoKeyMainUrl), @@ -2866,7 +2915,8 @@ namespace Axivion::Internal::Dto { }; } - static QJsonValue serialize(const DashboardInfoDto &value) { + static QJsonValue serialize(const DashboardInfoDto &value) + { QJsonObject jo; serialize_field(jo, dashboardInfoKeyMainUrl, value.mainUrl); serialize_field(jo, dashboardInfoKeyDashboardVersion, value.dashboardVersion); @@ -2949,14 +2999,16 @@ namespace Axivion::Internal::Dto { { public: // throws Axivion::Internal::Dto::invalid_dto_exception - static IssueCommentListDto deserialize(const QJsonValue &json) { + static IssueCommentListDto deserialize(const QJsonValue &json) + { const QJsonObject jo = toJsonObject(json); return { deserialize_field>(jo, issueCommentListKeyComments) }; } - static QJsonValue serialize(const IssueCommentListDto &value) { + static QJsonValue serialize(const IssueCommentListDto &value) + { QJsonObject jo; serialize_field(jo, issueCommentListKeyComments, value.comments); return { jo }; @@ -2999,7 +3051,8 @@ namespace Axivion::Internal::Dto { { public: // throws Axivion::Internal::Dto::invalid_dto_exception - static IssueKindInfoDto deserialize(const QJsonValue &json) { + static IssueKindInfoDto deserialize(const QJsonValue &json) + { const QJsonObject jo = toJsonObject(json); return { deserialize_field(jo, issueKindInfoKeyPrefix), @@ -3008,7 +3061,8 @@ namespace Axivion::Internal::Dto { }; } - static QJsonValue serialize(const IssueKindInfoDto &value) { + static QJsonValue serialize(const IssueKindInfoDto &value) + { QJsonObject jo; serialize_field(jo, issueKindInfoKeyPrefix, value.prefix); serialize_field(jo, issueKindInfoKeyNiceSingularName, value.niceSingularName); @@ -3085,14 +3139,16 @@ namespace Axivion::Internal::Dto { { public: // throws Axivion::Internal::Dto::invalid_dto_exception - static IssueTagTypeListDto deserialize(const QJsonValue &json) { + static IssueTagTypeListDto deserialize(const QJsonValue &json) + { const QJsonObject jo = toJsonObject(json); return { deserialize_field>(jo, issueTagTypeListKeyTags) }; } - static QJsonValue serialize(const IssueTagTypeListDto &value) { + static QJsonValue serialize(const IssueTagTypeListDto &value) + { QJsonObject jo; serialize_field(jo, issueTagTypeListKeyTags, value.tags); return { jo }; @@ -3141,7 +3197,8 @@ namespace Axivion::Internal::Dto { { public: // throws Axivion::Internal::Dto::invalid_dto_exception - static LineMarkerDto deserialize(const QJsonValue &json) { + static LineMarkerDto deserialize(const QJsonValue &json) + { const QJsonObject jo = toJsonObject(json); return { deserialize_field(jo, lineMarkerKeyKind), @@ -3156,7 +3213,8 @@ namespace Axivion::Internal::Dto { }; } - static QJsonValue serialize(const LineMarkerDto &value) { + static QJsonValue serialize(const LineMarkerDto &value) + { QJsonObject jo; serialize_field(jo, lineMarkerKeyKind, value.kind); serialize_field(jo, lineMarkerKeyId, value.id); @@ -3264,7 +3322,8 @@ namespace Axivion::Internal::Dto { { public: // throws Axivion::Internal::Dto::invalid_dto_exception - static RepositoryUpdateMessageDto deserialize(const QJsonValue &json) { + static RepositoryUpdateMessageDto deserialize(const QJsonValue &json) + { const QJsonObject jo = toJsonObject(json); return { deserialize_field(jo, repositoryUpdateMessageKeySeverity), @@ -3272,7 +3331,8 @@ namespace Axivion::Internal::Dto { }; } - static QJsonValue serialize(const RepositoryUpdateMessageDto &value) { + static QJsonValue serialize(const RepositoryUpdateMessageDto &value) + { QJsonObject jo; serialize_field(jo, repositoryUpdateMessageKeySeverity, value.severity); serialize_field(jo, repositoryUpdateMessageKeyMessage, value.message); @@ -3344,14 +3404,16 @@ namespace Axivion::Internal::Dto { { public: // throws Axivion::Internal::Dto::invalid_dto_exception - static RuleListDto deserialize(const QJsonValue &json) { + static RuleListDto deserialize(const QJsonValue &json) + { const QJsonObject jo = toJsonObject(json); return { deserialize_field>(jo, ruleListKeyRules) }; } - static QJsonValue serialize(const RuleListDto &value) { + static QJsonValue serialize(const RuleListDto &value) + { QJsonObject jo; serialize_field(jo, ruleListKeyRules, value.rules); return { jo }; @@ -3393,7 +3455,8 @@ namespace Axivion::Internal::Dto { { public: // throws Axivion::Internal::Dto::invalid_dto_exception - static SortInfoDto deserialize(const QJsonValue &json) { + static SortInfoDto deserialize(const QJsonValue &json) + { const QJsonObject jo = toJsonObject(json); return { deserialize_field(jo, sortInfoKeyKey), @@ -3401,7 +3464,8 @@ namespace Axivion::Internal::Dto { }; } - static QJsonValue serialize(const SortInfoDto &value) { + static QJsonValue serialize(const SortInfoDto &value) + { QJsonObject jo; serialize_field(jo, sortInfoKeyKey, value.key); serialize_field(jo, sortInfoKeyDirection, value.direction); @@ -3476,7 +3540,8 @@ namespace Axivion::Internal::Dto { { public: // throws Axivion::Internal::Dto::invalid_dto_exception - static UserRefDto deserialize(const QJsonValue &json) { + static UserRefDto deserialize(const QJsonValue &json) + { const QJsonObject jo = toJsonObject(json); return { deserialize_field(jo, userRefKeyName), @@ -3486,7 +3551,8 @@ namespace Axivion::Internal::Dto { }; } - static QJsonValue serialize(const UserRefDto &value) { + static QJsonValue serialize(const UserRefDto &value) + { QJsonObject jo; serialize_field(jo, userRefKeyName, value.name); serialize_field(jo, userRefKeyDisplayName, value.displayName); @@ -3571,7 +3637,8 @@ namespace Axivion::Internal::Dto { { public: // throws Axivion::Internal::Dto::invalid_dto_exception - static AnalyzedFileListDto deserialize(const QJsonValue &json) { + static AnalyzedFileListDto deserialize(const QJsonValue &json) + { const QJsonObject jo = toJsonObject(json); return { deserialize_field(jo, analyzedFileListKeyVersion), @@ -3579,7 +3646,8 @@ namespace Axivion::Internal::Dto { }; } - static QJsonValue serialize(const AnalyzedFileListDto &value) { + static QJsonValue serialize(const AnalyzedFileListDto &value) + { QJsonObject jo; serialize_field(jo, analyzedFileListKeyVersion, value.version); serialize_field(jo, analyzedFileListKeyRows, value.rows); @@ -3624,7 +3692,8 @@ namespace Axivion::Internal::Dto { { public: // throws Axivion::Internal::Dto::invalid_dto_exception - static EntityListDto deserialize(const QJsonValue &json) { + static EntityListDto deserialize(const QJsonValue &json) + { const QJsonObject jo = toJsonObject(json); return { deserialize_field>(jo, entityListKeyVersion), @@ -3632,7 +3701,8 @@ namespace Axivion::Internal::Dto { }; } - static QJsonValue serialize(const EntityListDto &value) { + static QJsonValue serialize(const EntityListDto &value) + { QJsonObject jo; serialize_field(jo, entityListKeyVersion, value.version); serialize_field(jo, entityListKeyEntities, value.entities); @@ -3679,7 +3749,8 @@ namespace Axivion::Internal::Dto { { public: // throws Axivion::Internal::Dto::invalid_dto_exception - static FileViewDto deserialize(const QJsonValue &json) { + static FileViewDto deserialize(const QJsonValue &json) + { const QJsonObject jo = toJsonObject(json); return { deserialize_field(jo, fileViewKeyFileName), @@ -3689,7 +3760,8 @@ namespace Axivion::Internal::Dto { }; } - static QJsonValue serialize(const FileViewDto &value) { + static QJsonValue serialize(const FileViewDto &value) + { QJsonObject jo; serialize_field(jo, fileViewKeyFileName, value.fileName); serialize_field(jo, fileViewKeyVersion, value.version); @@ -3745,7 +3817,8 @@ namespace Axivion::Internal::Dto { { public: // throws Axivion::Internal::Dto::invalid_dto_exception - static IssueDto deserialize(const QJsonValue &json) { + static IssueDto deserialize(const QJsonValue &json) + { const QJsonObject jo = toJsonObject(json); return { deserialize_field(jo, issueKeyKind), @@ -3758,7 +3831,8 @@ namespace Axivion::Internal::Dto { }; } - static QJsonValue serialize(const IssueDto &value) { + static QJsonValue serialize(const IssueDto &value) + { QJsonObject jo; serialize_field(jo, issueKeyKind, value.kind); serialize_field(jo, issueKeyId, value.id); @@ -3862,7 +3936,8 @@ namespace Axivion::Internal::Dto { { public: // throws Axivion::Internal::Dto::invalid_dto_exception - static IssueTableDto deserialize(const QJsonValue &json) { + static IssueTableDto deserialize(const QJsonValue &json) + { const QJsonObject jo = toJsonObject(json); return { deserialize_field>(jo, issueTableKeyStartVersion), @@ -3876,7 +3951,8 @@ namespace Axivion::Internal::Dto { }; } - static QJsonValue serialize(const IssueTableDto &value) { + static QJsonValue serialize(const IssueTableDto &value) + { QJsonObject jo; serialize_field(jo, issueTableKeyStartVersion, value.startVersion); serialize_field(jo, issueTableKeyEndVersion, value.endVersion); @@ -3939,7 +4015,8 @@ namespace Axivion::Internal::Dto { { public: // throws Axivion::Internal::Dto::invalid_dto_exception - static MetricListDto deserialize(const QJsonValue &json) { + static MetricListDto deserialize(const QJsonValue &json) + { const QJsonObject jo = toJsonObject(json); return { deserialize_field>(jo, metricListKeyVersion), @@ -3947,7 +4024,8 @@ namespace Axivion::Internal::Dto { }; } - static QJsonValue serialize(const MetricListDto &value) { + static QJsonValue serialize(const MetricListDto &value) + { QJsonObject jo; serialize_field(jo, metricListKeyVersion, value.version); serialize_field(jo, metricListKeyMetrics, value.metrics); @@ -3995,7 +4073,8 @@ namespace Axivion::Internal::Dto { { public: // throws Axivion::Internal::Dto::invalid_dto_exception - static MetricValueRangeDto deserialize(const QJsonValue &json) { + static MetricValueRangeDto deserialize(const QJsonValue &json) + { const QJsonObject jo = toJsonObject(json); return { deserialize_field(jo, metricValueRangeKeyStartVersion), @@ -4006,7 +4085,8 @@ namespace Axivion::Internal::Dto { }; } - static QJsonValue serialize(const MetricValueRangeDto &value) { + static QJsonValue serialize(const MetricValueRangeDto &value) + { QJsonObject jo; serialize_field(jo, metricValueRangeKeyStartVersion, value.startVersion); serialize_field(jo, metricValueRangeKeyEndVersion, value.endVersion); @@ -4060,7 +4140,8 @@ namespace Axivion::Internal::Dto { { public: // throws Axivion::Internal::Dto::invalid_dto_exception - static MetricValueTableDto deserialize(const QJsonValue &json) { + static MetricValueTableDto deserialize(const QJsonValue &json) + { const QJsonObject jo = toJsonObject(json); return { deserialize_field>(jo, metricValueTableKeyColumns), @@ -4068,7 +4149,8 @@ namespace Axivion::Internal::Dto { }; } - static QJsonValue serialize(const MetricValueTableDto &value) { + static QJsonValue serialize(const MetricValueTableDto &value) + { QJsonObject jo; serialize_field(jo, metricValueTableKeyColumns, value.columns); serialize_field(jo, metricValueTableKeyRows, value.rows); @@ -4116,7 +4198,8 @@ namespace Axivion::Internal::Dto { { public: // throws Axivion::Internal::Dto::invalid_dto_exception - static NamedFilterCreateDto deserialize(const QJsonValue &json) { + static NamedFilterCreateDto deserialize(const QJsonValue &json) + { const QJsonObject jo = toJsonObject(json); return { deserialize_field(jo, namedFilterCreateKeyDisplayName), @@ -4127,7 +4210,8 @@ namespace Axivion::Internal::Dto { }; } - static QJsonValue serialize(const NamedFilterCreateDto &value) { + static QJsonValue serialize(const NamedFilterCreateDto &value) + { QJsonObject jo; serialize_field(jo, namedFilterCreateKeyDisplayName, value.displayName); serialize_field(jo, namedFilterCreateKeyKind, value.kind); @@ -4224,7 +4308,8 @@ namespace Axivion::Internal::Dto { { public: // throws Axivion::Internal::Dto::invalid_dto_exception - static NamedFilterInfoDto deserialize(const QJsonValue &json) { + static NamedFilterInfoDto deserialize(const QJsonValue &json) + { const QJsonObject jo = toJsonObject(json); return { deserialize_field(jo, namedFilterInfoKeyKey), @@ -4241,7 +4326,8 @@ namespace Axivion::Internal::Dto { }; } - static QJsonValue serialize(const NamedFilterInfoDto &value) { + static QJsonValue serialize(const NamedFilterInfoDto &value) + { QJsonObject jo; serialize_field(jo, namedFilterInfoKeyKey, value.key); serialize_field(jo, namedFilterInfoKeyDisplayName, value.displayName); @@ -4363,7 +4449,8 @@ namespace Axivion::Internal::Dto { { public: // throws Axivion::Internal::Dto::invalid_dto_exception - static NamedFilterUpdateDto deserialize(const QJsonValue &json) { + static NamedFilterUpdateDto deserialize(const QJsonValue &json) + { const QJsonObject jo = toJsonObject(json); return { deserialize_field>(jo, namedFilterUpdateKeyName), @@ -4373,7 +4460,8 @@ namespace Axivion::Internal::Dto { }; } - static QJsonValue serialize(const NamedFilterUpdateDto &value) { + static QJsonValue serialize(const NamedFilterUpdateDto &value) + { QJsonObject jo; serialize_field(jo, namedFilterUpdateKeyName, value.name); serialize_field(jo, namedFilterUpdateKeyFilters, value.filters); @@ -4429,7 +4517,8 @@ namespace Axivion::Internal::Dto { { public: // throws Axivion::Internal::Dto::invalid_dto_exception - static ProjectInfoDto deserialize(const QJsonValue &json) { + static ProjectInfoDto deserialize(const QJsonValue &json) + { const QJsonObject jo = toJsonObject(json); return { deserialize_field(jo, projectInfoKeyName), @@ -4442,7 +4531,8 @@ namespace Axivion::Internal::Dto { }; } - static QJsonValue serialize(const ProjectInfoDto &value) { + static QJsonValue serialize(const ProjectInfoDto &value) + { QJsonObject jo; serialize_field(jo, projectInfoKeyName, value.name); serialize_field(jo, projectInfoKeyIssueFilterHelp, value.issueFilterHelp); @@ -4503,7 +4593,8 @@ namespace Axivion::Internal::Dto { { public: // throws Axivion::Internal::Dto::invalid_dto_exception - static RepositoryUpdateResponseDto deserialize(const QJsonValue &json) { + static RepositoryUpdateResponseDto deserialize(const QJsonValue &json) + { const QJsonObject jo = toJsonObject(json); return { deserialize_field>(jo, repositoryUpdateResponseKeyMessages), @@ -4512,7 +4603,8 @@ namespace Axivion::Internal::Dto { }; } - static QJsonValue serialize(const RepositoryUpdateResponseDto &value) { + static QJsonValue serialize(const RepositoryUpdateResponseDto &value) + { QJsonObject jo; serialize_field(jo, repositoryUpdateResponseKeyMessages, value.messages); serialize_field(jo, repositoryUpdateResponseKeyHasErrors, value.hasErrors); @@ -4564,7 +4656,8 @@ namespace Axivion::Internal::Dto { { public: // throws Axivion::Internal::Dto::invalid_dto_exception - static TableInfoDto deserialize(const QJsonValue &json) { + static TableInfoDto deserialize(const QJsonValue &json) + { const QJsonObject jo = toJsonObject(json); return { deserialize_field(jo, tableInfoKeyTableDataUri), @@ -4576,7 +4669,8 @@ namespace Axivion::Internal::Dto { }; } - static QJsonValue serialize(const TableInfoDto &value) { + static QJsonValue serialize(const TableInfoDto &value) + { QJsonObject jo; serialize_field(jo, tableInfoKeyTableDataUri, value.tableDataUri); serialize_field(jo, tableInfoKeyIssueBaseViewUri, value.issueBaseViewUri); diff --git a/src/plugins/axivion/dashboard/dto.h b/src/plugins/axivion/dashboard/dto.h index 8617d2d61df..4543df7d541 100644 --- a/src/plugins/axivion/dashboard/dto.h +++ b/src/plugins/axivion/dashboard/dto.h @@ -175,7 +175,7 @@ namespace Axivion::Internal::Dto // Throws Axivion::Internal::Dto::invalid_dto_exception static AnalyzedFileDto deserialize(const QByteArray &json); - Utils::expected_str deserializeExpected(const QByteArray &json); + static Utils::expected_str deserializeExpected(const QByteArray &json); AnalyzedFileDto( QString path, @@ -253,7 +253,7 @@ namespace Axivion::Internal::Dto // Throws Axivion::Internal::Dto::invalid_dto_exception static ChangePasswordFormDto deserialize(const QByteArray &json); - Utils::expected_str deserializeExpected(const QByteArray &json); + static Utils::expected_str deserializeExpected(const QByteArray &json); ChangePasswordFormDto( QString currentPassword, @@ -344,7 +344,7 @@ namespace Axivion::Internal::Dto // Throws Axivion::Internal::Dto::invalid_dto_exception static ColumnTypeOptionDto deserialize(const QByteArray &json); - Utils::expected_str deserializeExpected(const QByteArray &json); + static Utils::expected_str deserializeExpected(const QByteArray &json); ColumnTypeOptionDto( QString key, @@ -370,7 +370,7 @@ namespace Axivion::Internal::Dto // Throws Axivion::Internal::Dto::invalid_dto_exception static CommentRequestDto deserialize(const QByteArray &json); - Utils::expected_str deserializeExpected(const QByteArray &json); + static Utils::expected_str deserializeExpected(const QByteArray &json); CommentRequestDto( QString text @@ -400,7 +400,7 @@ namespace Axivion::Internal::Dto // Throws Axivion::Internal::Dto::invalid_dto_exception static CsrfTokenDto deserialize(const QByteArray &json); - Utils::expected_str deserializeExpected(const QByteArray &json); + static Utils::expected_str deserializeExpected(const QByteArray &json); CsrfTokenDto( QString csrfToken @@ -445,7 +445,7 @@ namespace Axivion::Internal::Dto // Throws Axivion::Internal::Dto::invalid_dto_exception static EntityDto deserialize(const QByteArray &json); - Utils::expected_str deserializeExpected(const QByteArray &json); + static Utils::expected_str deserializeExpected(const QByteArray &json); EntityDto( QString id, @@ -564,7 +564,7 @@ namespace Axivion::Internal::Dto // Throws Axivion::Internal::Dto::invalid_dto_exception static ErrorDto deserialize(const QByteArray &json); - Utils::expected_str deserializeExpected(const QByteArray &json); + static Utils::expected_str deserializeExpected(const QByteArray &json); ErrorDto( std::optional dashboardVersionNumber, @@ -635,7 +635,7 @@ namespace Axivion::Internal::Dto // Throws Axivion::Internal::Dto::invalid_dto_exception static IssueCommentDto deserialize(const QByteArray &json); - Utils::expected_str deserializeExpected(const QByteArray &json); + static Utils::expected_str deserializeExpected(const QByteArray &json); IssueCommentDto( QString username, @@ -787,7 +787,7 @@ namespace Axivion::Internal::Dto // Throws Axivion::Internal::Dto::invalid_dto_exception static IssueSourceLocationDto deserialize(const QByteArray &json); - Utils::expected_str deserializeExpected(const QByteArray &json); + static Utils::expected_str deserializeExpected(const QByteArray &json); IssueSourceLocationDto( QString fileName, @@ -825,7 +825,7 @@ namespace Axivion::Internal::Dto // Throws Axivion::Internal::Dto::invalid_dto_exception static IssueTagDto deserialize(const QByteArray &json); - Utils::expected_str deserializeExpected(const QByteArray &json); + static Utils::expected_str deserializeExpected(const QByteArray &json); IssueTagDto( QString tag, @@ -883,7 +883,7 @@ namespace Axivion::Internal::Dto // Throws Axivion::Internal::Dto::invalid_dto_exception static IssueTagTypeDto deserialize(const QByteArray &json); - Utils::expected_str deserializeExpected(const QByteArray &json); + static Utils::expected_str deserializeExpected(const QByteArray &json); IssueTagTypeDto( QString id, @@ -973,7 +973,7 @@ namespace Axivion::Internal::Dto // Throws Axivion::Internal::Dto::invalid_dto_exception static MetricDto deserialize(const QByteArray &json); - Utils::expected_str deserializeExpected(const QByteArray &json); + static Utils::expected_str deserializeExpected(const QByteArray &json); MetricDto( QString name, @@ -1034,7 +1034,7 @@ namespace Axivion::Internal::Dto // Throws Axivion::Internal::Dto::invalid_dto_exception static MetricValueTableRowDto deserialize(const QByteArray &json); - Utils::expected_str deserializeExpected(const QByteArray &json); + static Utils::expected_str deserializeExpected(const QByteArray &json); MetricValueTableRowDto( QString metric, @@ -1104,7 +1104,7 @@ namespace Axivion::Internal::Dto // Throws Axivion::Internal::Dto::invalid_dto_exception static NamedFilterVisibilityDto deserialize(const QByteArray &json); - Utils::expected_str deserializeExpected(const QByteArray &json); + static Utils::expected_str deserializeExpected(const QByteArray &json); NamedFilterVisibilityDto( std::optional> groups @@ -1133,7 +1133,7 @@ namespace Axivion::Internal::Dto // Throws Axivion::Internal::Dto::invalid_dto_exception static ProjectReferenceDto deserialize(const QByteArray &json); - Utils::expected_str deserializeExpected(const QByteArray &json); + static Utils::expected_str deserializeExpected(const QByteArray &json); ProjectReferenceDto( QString name, @@ -1173,7 +1173,7 @@ namespace Axivion::Internal::Dto // Throws Axivion::Internal::Dto::invalid_dto_exception static RuleDto deserialize(const QByteArray &json); - Utils::expected_str deserializeExpected(const QByteArray &json); + static Utils::expected_str deserializeExpected(const QByteArray &json); RuleDto( QString name, @@ -1270,7 +1270,7 @@ namespace Axivion::Internal::Dto // Throws Axivion::Internal::Dto::invalid_dto_exception static ToolsVersionDto deserialize(const QByteArray &json); - Utils::expected_str deserializeExpected(const QByteArray &json); + static Utils::expected_str deserializeExpected(const QByteArray &json); ToolsVersionDto( QString name, @@ -1340,7 +1340,7 @@ namespace Axivion::Internal::Dto // Throws Axivion::Internal::Dto::invalid_dto_exception static VersionKindCountDto deserialize(const QByteArray &json); - Utils::expected_str deserializeExpected(const QByteArray &json); + static Utils::expected_str deserializeExpected(const QByteArray &json); VersionKindCountDto( qint32 Total, @@ -1450,7 +1450,7 @@ namespace Axivion::Internal::Dto // Throws Axivion::Internal::Dto::invalid_dto_exception static AnalysisVersionDto deserialize(const QByteArray &json); - Utils::expected_str deserializeExpected(const QByteArray &json); + static Utils::expected_str deserializeExpected(const QByteArray &json); AnalysisVersionDto( QString date, @@ -1510,7 +1510,7 @@ namespace Axivion::Internal::Dto // Throws Axivion::Internal::Dto::invalid_dto_exception static ApiTokenCreationRequestDto deserialize(const QByteArray &json); - Utils::expected_str deserializeExpected(const QByteArray &json); + static Utils::expected_str deserializeExpected(const QByteArray &json); ApiTokenCreationRequestDto( QString password, @@ -1630,7 +1630,7 @@ namespace Axivion::Internal::Dto // Throws Axivion::Internal::Dto::invalid_dto_exception static ApiTokenInfoDto deserialize(const QByteArray &json); - Utils::expected_str deserializeExpected(const QByteArray &json); + static Utils::expected_str deserializeExpected(const QByteArray &json); ApiTokenInfoDto( QString id, @@ -1757,7 +1757,7 @@ namespace Axivion::Internal::Dto // Throws Axivion::Internal::Dto::invalid_dto_exception static ColumnInfoDto deserialize(const QByteArray &json); - Utils::expected_str deserializeExpected(const QByteArray &json); + static Utils::expected_str deserializeExpected(const QByteArray &json); ColumnInfoDto( QString key, @@ -1925,7 +1925,7 @@ namespace Axivion::Internal::Dto // Throws Axivion::Internal::Dto::invalid_dto_exception static DashboardInfoDto deserialize(const QByteArray &json); - Utils::expected_str deserializeExpected(const QByteArray &json); + static Utils::expected_str deserializeExpected(const QByteArray &json); DashboardInfoDto( std::optional mainUrl, @@ -1963,7 +1963,7 @@ namespace Axivion::Internal::Dto // Throws Axivion::Internal::Dto::invalid_dto_exception static IssueCommentListDto deserialize(const QByteArray &json); - Utils::expected_str deserializeExpected(const QByteArray &json); + static Utils::expected_str deserializeExpected(const QByteArray &json); IssueCommentListDto( std::vector comments @@ -1999,7 +1999,7 @@ namespace Axivion::Internal::Dto // Throws Axivion::Internal::Dto::invalid_dto_exception static IssueKindInfoDto deserialize(const QByteArray &json); - Utils::expected_str deserializeExpected(const QByteArray &json); + static Utils::expected_str deserializeExpected(const QByteArray &json); IssueKindInfoDto( QString prefix, @@ -2038,7 +2038,7 @@ namespace Axivion::Internal::Dto // Throws Axivion::Internal::Dto::invalid_dto_exception static IssueTagTypeListDto deserialize(const QByteArray &json); - Utils::expected_str deserializeExpected(const QByteArray &json); + static Utils::expected_str deserializeExpected(const QByteArray &json); IssueTagTypeListDto( std::vector tags @@ -2130,7 +2130,7 @@ namespace Axivion::Internal::Dto // Throws Axivion::Internal::Dto::invalid_dto_exception static LineMarkerDto deserialize(const QByteArray &json); - Utils::expected_str deserializeExpected(const QByteArray &json); + static Utils::expected_str deserializeExpected(const QByteArray &json); LineMarkerDto( QString kind, @@ -2191,7 +2191,7 @@ namespace Axivion::Internal::Dto // Throws Axivion::Internal::Dto::invalid_dto_exception static RepositoryUpdateMessageDto deserialize(const QByteArray &json); - Utils::expected_str deserializeExpected(const QByteArray &json); + static Utils::expected_str deserializeExpected(const QByteArray &json); RepositoryUpdateMessageDto( QString severity, @@ -2228,7 +2228,7 @@ namespace Axivion::Internal::Dto // Throws Axivion::Internal::Dto::invalid_dto_exception static RuleListDto deserialize(const QByteArray &json); - Utils::expected_str deserializeExpected(const QByteArray &json); + static Utils::expected_str deserializeExpected(const QByteArray &json); RuleListDto( std::vector rules @@ -2259,7 +2259,7 @@ namespace Axivion::Internal::Dto // Throws Axivion::Internal::Dto::invalid_dto_exception static SortInfoDto deserialize(const QByteArray &json); - Utils::expected_str deserializeExpected(const QByteArray &json); + static Utils::expected_str deserializeExpected(const QByteArray &json); SortInfoDto( QString key, @@ -2317,7 +2317,7 @@ namespace Axivion::Internal::Dto // Throws Axivion::Internal::Dto::invalid_dto_exception static UserRefDto deserialize(const QByteArray &json); - Utils::expected_str deserializeExpected(const QByteArray &json); + static Utils::expected_str deserializeExpected(const QByteArray &json); UserRefDto( QString name, @@ -2363,7 +2363,7 @@ namespace Axivion::Internal::Dto // Throws Axivion::Internal::Dto::invalid_dto_exception static AnalyzedFileListDto deserialize(const QByteArray &json); - Utils::expected_str deserializeExpected(const QByteArray &json); + static Utils::expected_str deserializeExpected(const QByteArray &json); AnalyzedFileListDto( AnalysisVersionDto version, @@ -2393,7 +2393,7 @@ namespace Axivion::Internal::Dto // Throws Axivion::Internal::Dto::invalid_dto_exception static EntityListDto deserialize(const QByteArray &json); - Utils::expected_str deserializeExpected(const QByteArray &json); + static Utils::expected_str deserializeExpected(const QByteArray &json); EntityListDto( std::optional version, @@ -2443,7 +2443,7 @@ namespace Axivion::Internal::Dto // Throws Axivion::Internal::Dto::invalid_dto_exception static FileViewDto deserialize(const QByteArray &json); - Utils::expected_str deserializeExpected(const QByteArray &json); + static Utils::expected_str deserializeExpected(const QByteArray &json); FileViewDto( QString fileName, @@ -2508,7 +2508,7 @@ namespace Axivion::Internal::Dto // Throws Axivion::Internal::Dto::invalid_dto_exception static IssueDto deserialize(const QByteArray &json); - Utils::expected_str deserializeExpected(const QByteArray &json); + static Utils::expected_str deserializeExpected(const QByteArray &json); IssueDto( QString kind, @@ -2624,7 +2624,7 @@ namespace Axivion::Internal::Dto // Throws Axivion::Internal::Dto::invalid_dto_exception static IssueTableDto deserialize(const QByteArray &json); - Utils::expected_str deserializeExpected(const QByteArray &json); + static Utils::expected_str deserializeExpected(const QByteArray &json); IssueTableDto( std::optional startVersion, @@ -2660,7 +2660,7 @@ namespace Axivion::Internal::Dto // Throws Axivion::Internal::Dto::invalid_dto_exception static MetricListDto deserialize(const QByteArray &json); - Utils::expected_str deserializeExpected(const QByteArray &json); + static Utils::expected_str deserializeExpected(const QByteArray &json); MetricListDto( std::optional version, @@ -2713,7 +2713,7 @@ namespace Axivion::Internal::Dto // Throws Axivion::Internal::Dto::invalid_dto_exception static MetricValueRangeDto deserialize(const QByteArray &json); - Utils::expected_str deserializeExpected(const QByteArray &json); + static Utils::expected_str deserializeExpected(const QByteArray &json); MetricValueRangeDto( AnalysisVersionDto startVersion, @@ -2748,7 +2748,7 @@ namespace Axivion::Internal::Dto // Throws Axivion::Internal::Dto::invalid_dto_exception static MetricValueTableDto deserialize(const QByteArray &json); - Utils::expected_str deserializeExpected(const QByteArray &json); + static Utils::expected_str deserializeExpected(const QByteArray &json); MetricValueTableDto( std::vector columns, @@ -2812,7 +2812,7 @@ namespace Axivion::Internal::Dto // Throws Axivion::Internal::Dto::invalid_dto_exception static NamedFilterCreateDto deserialize(const QByteArray &json); - Utils::expected_str deserializeExpected(const QByteArray &json); + static Utils::expected_str deserializeExpected(const QByteArray &json); NamedFilterCreateDto( QString displayName, @@ -2936,7 +2936,7 @@ namespace Axivion::Internal::Dto // Throws Axivion::Internal::Dto::invalid_dto_exception static NamedFilterInfoDto deserialize(const QByteArray &json); - Utils::expected_str deserializeExpected(const QByteArray &json); + static Utils::expected_str deserializeExpected(const QByteArray &json); NamedFilterInfoDto( QString key, @@ -3028,7 +3028,7 @@ namespace Axivion::Internal::Dto // Throws Axivion::Internal::Dto::invalid_dto_exception static NamedFilterUpdateDto deserialize(const QByteArray &json); - Utils::expected_str deserializeExpected(const QByteArray &json); + static Utils::expected_str deserializeExpected(const QByteArray &json); NamedFilterUpdateDto( std::optional name, @@ -3089,7 +3089,7 @@ namespace Axivion::Internal::Dto // Throws Axivion::Internal::Dto::invalid_dto_exception static ProjectInfoDto deserialize(const QByteArray &json); - Utils::expected_str deserializeExpected(const QByteArray &json); + static Utils::expected_str deserializeExpected(const QByteArray &json); ProjectInfoDto( QString name, @@ -3132,7 +3132,7 @@ namespace Axivion::Internal::Dto // Throws Axivion::Internal::Dto::invalid_dto_exception static RepositoryUpdateResponseDto deserialize(const QByteArray &json); - Utils::expected_str deserializeExpected(const QByteArray &json); + static Utils::expected_str deserializeExpected(const QByteArray &json); RepositoryUpdateResponseDto( std::vector messages, @@ -3201,7 +3201,7 @@ namespace Axivion::Internal::Dto // Throws Axivion::Internal::Dto::invalid_dto_exception static TableInfoDto deserialize(const QByteArray &json); - Utils::expected_str deserializeExpected(const QByteArray &json); + static Utils::expected_str deserializeExpected(const QByteArray &json); TableInfoDto( QString tableDataUri, From f8b419138439ab659d230071fea5324c25e50a71 Mon Sep 17 00:00:00 2001 From: Jarek Kobus Date: Tue, 20 Feb 2024 18:45:03 +0100 Subject: [PATCH 117/243] Axivion: Show more detailed message on deserialization error Instead of a general deserialization error. Reuse newly added Dto::deserializeExpected() methods. Change-Id: Ie828b54b24659f2168aa7245a98ab92e71e7a3eb Reviewed-by: hjk Reviewed-by: Reviewed-by: Andreas Loth --- src/plugins/axivion/axivionplugin.cpp | 25 ++++++++++++++----------- 1 file changed, 14 insertions(+), 11 deletions(-) diff --git a/src/plugins/axivion/axivionplugin.cpp b/src/plugins/axivion/axivionplugin.cpp index a5da9cdba2c..77261faffc0 100644 --- a/src/plugins/axivion/axivionplugin.cpp +++ b/src/plugins/axivion/axivionplugin.cpp @@ -445,31 +445,34 @@ static Group dtoRecipe(const Storage> &dtoStorage) return DoneResult::Error; }; - const auto onDeserializeSetup = [storage](Async &task) { - const auto deserialize = [](QPromise &promise, const QByteArray &input) { - try { - promise.addResult(DtoType::deserialize(input)); - } catch (const Dto::invalid_dto_exception &) { - promise.future().cancel(); - } + const auto onDeserializeSetup = [storage](Async> &task) { + const auto deserialize = [](QPromise> &promise, const QByteArray &input) { + promise.addResult(DtoType::deserializeExpected(input)); }; task.setFutureSynchronizer(ExtensionSystem::PluginManager::futureSynchronizer()); task.setConcurrentCallData(deserialize, *storage); }; - const auto onDeserializeDone = [dtoStorage](const Async &task, DoneWith doneWith) { + const auto onDeserializeDone = [dtoStorage](const Async> &task, + DoneWith doneWith) { if (doneWith == DoneWith::Success && task.isResultAvailable()) { - dtoStorage->dtoData = task.result(); + const auto result = task.result(); + if (result) { + dtoStorage->dtoData = *result; + return DoneResult::Success; + } + MessageManager::writeFlashing(QString("Axivion: %1").arg(result.error())); } else { MessageManager::writeFlashing(QString("Axivion: %1") - .arg(Tr::tr("Deserialization of an unexpected Dto structure."))); + .arg(Tr::tr("Unknown Dto structure deserialization error."))); } + return DoneResult::Error; }; return { storage, NetworkQueryTask(onNetworkQuerySetup, onNetworkQueryDone), - AsyncTask(onDeserializeSetup, onDeserializeDone) + AsyncTask>(onDeserializeSetup, onDeserializeDone) }; } From d67290860848f4ade033555f591b2881b37fc2dd Mon Sep 17 00:00:00 2001 From: Jarek Kobus Date: Wed, 21 Feb 2024 10:13:03 +0100 Subject: [PATCH 118/243] TaskTree: Add info about sync/async execution into withLog() Add tests for it. This addresses the 35th point in the bugreport below. Task-number: QTCREATORBUG-28741 Change-Id: Id35d51155e0bfd413c06b3a2c5bb57b8bcea8487 Reviewed-by: hjk Reviewed-by: --- src/libs/solutions/tasking/tasktree.cpp | 53 +++++++++-- tests/auto/solutions/tasking/tst_tasking.cpp | 92 ++++++++++++-------- 2 files changed, 104 insertions(+), 41 deletions(-) diff --git a/src/libs/solutions/tasking/tasktree.cpp b/src/libs/solutions/tasking/tasktree.cpp index 112c6dca75f..c6e87d27746 100644 --- a/src/libs/solutions/tasking/tasktree.cpp +++ b/src/libs/solutions/tasking/tasktree.cpp @@ -1193,6 +1193,17 @@ const GroupItem stopOnSuccessOrError = workflowPolicy(WorkflowPolicy::StopOnSucc const GroupItem finishAllAndSuccess = workflowPolicy(WorkflowPolicy::FinishAllAndSuccess); const GroupItem finishAllAndError = workflowPolicy(WorkflowPolicy::FinishAllAndError); +// Please note the thread_local keyword below guarantees a separate instance per thread. +// The s_activeTaskTrees is currently used internally only and is not exposed in the public API. +// It serves for withLog() implementation now. Add a note here when a new usage is introduced. +static thread_local QList s_activeTaskTrees = {}; + +static TaskTree *activeTaskTree() +{ + QT_ASSERT(s_activeTaskTrees.size(), return nullptr); + return s_activeTaskTrees.back(); +} + DoneResult toDoneResult(bool success) { return success ? DoneResult::Success : DoneResult::Error; @@ -1427,18 +1438,28 @@ ExecutableItem ExecutableItem::withLog(const QString &logName) const const auto header = [logName] { return QString("TASK TREE LOG [%1] \"%2\"").arg(currentTime(), logName); }; - const Storage> storage; + struct LogStorage + { + time_point start; + int asyncCount = 0; + }; + const Storage storage; return Group { storage, onGroupSetup([storage, header] { - *storage = system_clock::now(); + storage->start = system_clock::now(); + storage->asyncCount = activeTaskTree()->asyncCount(); qDebug().noquote() << header() << "started."; }), *this, onGroupDone([storage, header](DoneWith result) { - const auto elapsed = duration_cast(system_clock::now() - *storage); + const auto elapsed = duration_cast(system_clock::now() - storage->start); + const int asyncCountDiff = activeTaskTree()->asyncCount() - storage->asyncCount; + QT_CHECK(asyncCountDiff >= 0); const QMetaEnum doneWithEnum = QMetaEnum::fromType(); - qDebug().noquote().nospace() << header() << " finished with " + const QString syncType = asyncCountDiff ? QString("asynchronously") + : QString("synchronously"); + qDebug().noquote().nospace() << header() << " finished " << syncType << " with " << doneWithEnum.valueToKey(int(result)) << " within " << elapsed.count() << "ms."; }) }; @@ -1453,16 +1474,26 @@ class RuntimeTask; class ExecutionContextActivator { public: - ExecutionContextActivator(RuntimeIteration *iteration) { activateContext(iteration); } - ExecutionContextActivator(RuntimeContainer *container) { activateContext(container); } + ExecutionContextActivator(RuntimeIteration *iteration) { + activateTaskTree(iteration); + activateContext(iteration); + } + ExecutionContextActivator(RuntimeContainer *container) { + activateTaskTree(container); + activateContext(container); + } ~ExecutionContextActivator() { for (int i = m_activeStorages.size() - 1; i >= 0; --i) // iterate in reverse order m_activeStorages[i].m_storageData->threadData().popStorage(); for (int i = m_activeLoops.size() - 1; i >= 0; --i) // iterate in reverse order m_activeLoops[i].m_loopData->threadData().popIteration(); + QT_ASSERT(s_activeTaskTrees.size(), return); + s_activeTaskTrees.pop_back(); } private: + void activateTaskTree(RuntimeIteration *iteration); + void activateTaskTree(RuntimeContainer *container); void activateContext(RuntimeIteration *iteration); void activateContext(RuntimeContainer *container); QList m_activeLoops; @@ -1692,6 +1723,16 @@ static bool isProgressive(RuntimeContainer *container) return iteration ? iteration->m_isProgressive : true; } +void ExecutionContextActivator::activateTaskTree(RuntimeIteration *iteration) +{ + activateTaskTree(iteration->m_container); +} + +void ExecutionContextActivator::activateTaskTree(RuntimeContainer *container) +{ + s_activeTaskTrees.push_back(container->m_containerNode.m_taskTreePrivate->q); +} + void ExecutionContextActivator::activateContext(RuntimeIteration *iteration) { std::optional loop = iteration->loop(); diff --git a/tests/auto/solutions/tasking/tst_tasking.cpp b/tests/auto/solutions/tasking/tst_tasking.cpp index b2e99a7c220..279400f0218 100644 --- a/tests/auto/solutions/tasking/tst_tasking.cpp +++ b/tests/auto/solutions/tasking/tst_tasking.cpp @@ -58,12 +58,26 @@ enum class ThreadResult }; Q_ENUM_NS(ThreadResult); +enum class Execution +{ + Sync, + Async +}; + } // namespace PrintableEnums using namespace PrintableEnums; using Log = QList>; -using MessageLog = QList>; + +struct Message +{ + QString name; + Handler handler; + std::optional execution = {}; +}; + +using MessageLog = QList; struct CustomStorage { @@ -2960,8 +2974,8 @@ void tst_Tasking::testTree_data() MessageLog { {"Group 1", Handler::Setup}, {"Task 1", Handler::Setup}, - {"Task 1", Handler::Success}, - {"Group 1", Handler::Success} + {"Task 1", Handler::Success, Execution::Async}, + {"Group 1", Handler::Success, Execution::Async} } }; const TestData testError { @@ -2982,8 +2996,8 @@ void tst_Tasking::testTree_data() MessageLog { {"Group 1", Handler::Setup}, {"Task 1", Handler::Setup}, - {"Task 1", Handler::Error}, - {"Group 1", Handler::Error} + {"Task 1", Handler::Error, Execution::Async}, + {"Group 1", Handler::Error, Execution::Async} } }; const TestData testCancel { @@ -3009,9 +3023,9 @@ void tst_Tasking::testTree_data() {"Group 1", Handler::Setup}, {"Task 1", Handler::Setup}, {"Task 2", Handler::Setup}, - {"Task 2", Handler::Error}, - {"Task 1", Handler::Canceled}, - {"Group 1", Handler::Canceled} + {"Task 2", Handler::Error, Execution::Sync}, + {"Task 1", Handler::Canceled, Execution::Sync}, + {"Group 1", Handler::Canceled, Execution::Sync} } }; @@ -3102,13 +3116,13 @@ private: static const QList s_logHandlers = {Handler::Setup, Handler::Success, Handler::Error, Handler::Canceled}; -static QString handlerToName(Handler handler) +static QString messageInfix(const Message &message) { - if (handler == Handler::Setup) + if (message.handler == Handler::Setup) return "started"; DoneWith doneWith; - switch (handler) { + switch (message.handler) { case Handler::Success: doneWith = DoneWith::Success; break; @@ -3121,41 +3135,46 @@ static QString handlerToName(Handler handler) default: return {}; } + + const QString execution = message.execution == Execution::Async ? "asynchronously" + : "synchronously"; const QMetaEnum doneWithEnum = QMetaEnum::fromType(); - return QString("finished with %1").arg(doneWithEnum.valueToKey(int(doneWith))); + return QString("finished %1 with %2").arg(execution, doneWithEnum.valueToKey(int(doneWith))); } -static bool matchesLogPattern(const QString &log, const QPair &pattern) +static bool matchesLogPattern(const QString &log, const Message &message) { - QStringView message(log); + QStringView logView(log); const static QLatin1StringView part1("TASK TREE LOG ["); - if (!message.startsWith(part1)) + if (!logView.startsWith(part1)) return false; - message = message.mid(part1.size()); + logView = logView.mid(part1.size()); const static QLatin1StringView part2("HH:mm:ss.zzz"); // check only size - message = message.mid(part2.size()); - const QString part3 = QString("] \"%1\" ").arg(pattern.first); - if (!message.startsWith(part3)) + logView = logView.mid(part2.size()); + const QString part3 = QString("] \"%1\" ").arg(message.name); + if (!logView.startsWith(part3)) return false; - message = message.mid(part3.size()); - const QString part4(handlerToName(pattern.second)); - if (!message.startsWith(part4)) + logView = logView.mid(part3.size()); + const QString part4(messageInfix(message)); + if (!logView.startsWith(part4)) return false; - message = message.mid(part4.size()); - if (pattern.second == Handler::Setup) - return message == QLatin1StringView("."); + logView = logView.mid(part4.size()); + if (message.handler == Handler::Setup) + return logView == QLatin1StringView("."); const static QLatin1StringView part5(" within "); - if (!message.startsWith(part5)) + if (!logView.startsWith(part5)) return false; - return message.endsWith(QLatin1StringView("ms.")); + return logView.endsWith(QLatin1StringView("ms.")); } +const QMetaEnum s_handlerEnum = QMetaEnum::fromType(); + void tst_Tasking::testTree() { QFETCH(TestData, testData); @@ -3187,15 +3206,18 @@ void tst_Tasking::testTree() for (int i = 0; i < s_messages.count(); ++i) { const auto &message = testData.messageLog->at(i); - QVERIFY(s_logHandlers.contains(message.second)); - const QString &log = s_messages.at(i); - if (!matchesLogPattern(log, message)) { - const QString failMessage - = QString("The log message at index %1: \"%2\" doesn't match the expected " - "pattern: \"%3\" %4.").arg(i) - .arg(log, message.first, handlerToName(message.second)); - QFAIL(failMessage.toUtf8()); + QVERIFY2(s_logHandlers.contains(message.handler), qPrintable(QString( + "The expected log message at index %1 contains invalid %2 handler.") + .arg(i).arg(s_handlerEnum.valueToKey(int(message.handler))))); + if (message.handler != Handler::Setup) { + QVERIFY2(message.execution, qPrintable(QString( + "The expected log message at index %1 of %2 type doesn't specify the required " + "execution mode.").arg(i).arg(s_handlerEnum.valueToKey(int(message.handler))))); } + const QString &log = s_messages.at(i); + QVERIFY2(matchesLogPattern(log, message), qPrintable(QString( + "The log message at index %1: \"%2\" doesn't match the expected pattern: " + "\"%3\" %4.").arg(i).arg(log, message.name, messageInfix(message)))); } } } From d02e75e7ab8baa95aabfa2dd6d978269c11441e9 Mon Sep 17 00:00:00 2001 From: Jarek Kobus Date: Wed, 21 Feb 2024 15:32:30 +0100 Subject: [PATCH 119/243] Axivion: Add more error messages on different failures Change-Id: Ibfb77b5921a58ba2d439a6d2e313538eb8484c3b Reviewed-by: hjk --- src/plugins/axivion/axivionplugin.cpp | 10 ++++++++-- 1 file changed, 8 insertions(+), 2 deletions(-) diff --git a/src/plugins/axivion/axivionplugin.cpp b/src/plugins/axivion/axivionplugin.cpp index 77261faffc0..0f39be06bd0 100644 --- a/src/plugins/axivion/axivionplugin.cpp +++ b/src/plugins/axivion/axivionplugin.cpp @@ -707,12 +707,18 @@ void AxivionPluginPrivate::fetchProjectInfo(const QString &projectName) } const auto onTaskTreeSetup = [this, projectName](TaskTree &taskTree) { - if (!m_dashboardInfo) + if (!m_dashboardInfo) { + MessageManager::writeDisrupting(QString("Axivion: %1") + .arg(Tr::tr("Fetching DashboardInfo error."))); return SetupResult::StopWithError; + } const auto it = m_dashboardInfo->projectUrls.constFind(projectName); - if (it == m_dashboardInfo->projectUrls.constEnd()) + if (it == m_dashboardInfo->projectUrls.constEnd()) { + MessageManager::writeDisrupting(QString("Axivion: %1") + .arg(Tr::tr("The DashboardInfo doesn't contain project \"%1\".").arg(projectName))); return SetupResult::StopWithError; + } const auto handler = [this](const Dto::ProjectInfoDto &data) { m_currentProjectInfo = data; From 862795d69c1e7eca8d0952607c36ec8f860e8b6b Mon Sep 17 00:00:00 2001 From: Jarek Kobus Date: Wed, 21 Feb 2024 16:50:34 +0100 Subject: [PATCH 120/243] Axivion: Ignore the failure on storing the new ApiToken in QtKeyChain Change-Id: Iefd25e07e2f028d32802cf68d69cf46d17ebee22 Reviewed-by: hjk --- src/plugins/axivion/axivionplugin.cpp | 8 +++++++- 1 file changed, 7 insertions(+), 1 deletion(-) diff --git a/src/plugins/axivion/axivionplugin.cpp b/src/plugins/axivion/axivionplugin.cpp index 0f39be06bd0..79a349fed66 100644 --- a/src/plugins/axivion/axivionplugin.cpp +++ b/src/plugins/axivion/axivionplugin.cpp @@ -566,7 +566,13 @@ static Group authorizationRecipe() return SetupResult::Continue; }; const auto onSetCredentialDone = [](const CredentialQuery &credential) { - MessageManager::writeDisrupting(QString("Axivion: %1").arg(credential.errorString())); + const QString keyChainMessage = credential.errorString().isEmpty() ? QString() + : QString(" %1").arg(Tr::tr("Key chain message: \"%1\".").arg(credential.errorString())); + MessageManager::writeDisrupting(QString("Axivion: %1") + .arg(Tr::tr("The ApiToken cannot be stored in a secure way.") + keyChainMessage)); + // TODO: We are multiplying the ApiTokens on Axivion server for each Creator run, + // but at least things should continue to work OK in the current session. + return DoneResult::Success; }; return { From a18522334c2770936cd23d6a66448ceb977a4f35 Mon Sep 17 00:00:00 2001 From: David Schulz Date: Fri, 9 Feb 2024 06:11:27 +0100 Subject: [PATCH 121/243] TextEditor: fix multi text cursor unindent via backspace Change-Id: Iec2e9251b977ccbd7433009ac3e706a9327c704c (cherry picked from commit 971bcb1a5abd396819510644e55ef437978adcd5) Reviewed-by: David Schulz --- 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 e50311b1371..c8ef69c63ef 100644 --- a/src/plugins/texteditor/texteditor.cpp +++ b/src/plugins/texteditor/texteditor.cpp @@ -6845,7 +6845,7 @@ void TextEditorWidgetPrivate::handleBackspaceKey() if (cursorWithinSnippet) m_snippetOverlay->accept(); cursorWithinSnippet = false; - q->unindent(); + c = m_document->unindent(MultiTextCursor({c})).mainCursor(); } handled = true; } From 32cad6d3892abc97ce939cc40beb382897c07c73 Mon Sep 17 00:00:00 2001 From: Christian Stenger Date: Thu, 22 Feb 2024 07:18:19 +0100 Subject: [PATCH 122/243] Tests: Fix build with Qt6.2 Amends d67290860848f4ade033555f591b2881b37fc2dd. Change-Id: Ie80c69ecb1e96a5c86800e8f431f01f6ed611e6d Reviewed-by: Jarek Kobus --- tests/auto/solutions/tasking/tst_tasking.cpp | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/tests/auto/solutions/tasking/tst_tasking.cpp b/tests/auto/solutions/tasking/tst_tasking.cpp index 279400f0218..ee1972c0616 100644 --- a/tests/auto/solutions/tasking/tst_tasking.cpp +++ b/tests/auto/solutions/tasking/tst_tasking.cpp @@ -3145,12 +3145,12 @@ static QString messageInfix(const Message &message) static bool matchesLogPattern(const QString &log, const Message &message) { QStringView logView(log); - const static QLatin1StringView part1("TASK TREE LOG ["); + const static QLatin1String part1("TASK TREE LOG ["); if (!logView.startsWith(part1)) return false; logView = logView.mid(part1.size()); - const static QLatin1StringView part2("HH:mm:ss.zzz"); // check only size + const static QLatin1String part2("HH:mm:ss.zzz"); // check only size logView = logView.mid(part2.size()); const QString part3 = QString("] \"%1\" ").arg(message.name); @@ -3164,13 +3164,13 @@ static bool matchesLogPattern(const QString &log, const Message &message) logView = logView.mid(part4.size()); if (message.handler == Handler::Setup) - return logView == QLatin1StringView("."); + return logView == QLatin1String("."); - const static QLatin1StringView part5(" within "); + const static QLatin1String part5(" within "); if (!logView.startsWith(part5)) return false; - return logView.endsWith(QLatin1StringView("ms.")); + return logView.endsWith(QLatin1String("ms.")); } const QMetaEnum s_handlerEnum = QMetaEnum::fromType(); From a0517bca48104c35b9498a171064c1906cdb5755 Mon Sep 17 00:00:00 2001 From: Eike Ziller Date: Wed, 21 Feb 2024 17:20:17 +0100 Subject: [PATCH 123/243] Fix Axivion tr context Prefix with QtC:: Change-Id: I0cc6b2e4a679c92235ba5c3f471a13f14057418a Reviewed-by: Christian Stenger --- share/qtcreator/translations/qtcreator_fr.ts | 2 +- src/plugins/axivion/axiviontr.h | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/share/qtcreator/translations/qtcreator_fr.ts b/share/qtcreator/translations/qtcreator_fr.ts index adc57cc41ef..6f9ade5c4d3 100644 --- a/share/qtcreator/translations/qtcreator_fr.ts +++ b/share/qtcreator/translations/qtcreator_fr.ts @@ -798,7 +798,7 @@ Une valeur positive augmente la réverbération pour les hautes fréquences et - Axivion + QtC::Axivion Project: Projet : diff --git a/src/plugins/axivion/axiviontr.h b/src/plugins/axivion/axiviontr.h index 1f3475cb456..48798aaa2ad 100644 --- a/src/plugins/axivion/axiviontr.h +++ b/src/plugins/axivion/axiviontr.h @@ -9,7 +9,7 @@ namespace Axivion { struct Tr { - Q_DECLARE_TR_FUNCTIONS(Axivion) + Q_DECLARE_TR_FUNCTIONS(QtC::Axivion) }; } // Axivion From e0c8982b7e89274fa1188bae66b4da59ae2d4009 Mon Sep 17 00:00:00 2001 From: Marcus Tillmanns Date: Thu, 15 Feb 2024 14:43:07 +0100 Subject: [PATCH 124/243] Core: Add Proxy authentication Dialog Change-Id: If48387e9adb9ca9b979dce71e949af1d7e1956cc Reviewed-by: Eike Ziller --- src/plugins/coreplugin/coreplugin.cpp | 29 +++++++++++++++++++++++++++ 1 file changed, 29 insertions(+) diff --git a/src/plugins/coreplugin/coreplugin.cpp b/src/plugins/coreplugin/coreplugin.cpp index 76a808d9a60..4b45c3e6f42 100644 --- a/src/plugins/coreplugin/coreplugin.cpp +++ b/src/plugins/coreplugin/coreplugin.cpp @@ -33,6 +33,8 @@ #include #include #include +#include +#include #include #include #include @@ -41,6 +43,7 @@ #include #include +#include #include #include #include @@ -136,6 +139,30 @@ void CorePlugin::loadMimeFromPlugin(const ExtensionSystem::PluginSpec *plugin) Utils::addMimeTypes(plugin->name() + ".mimetypes", mimetypeString.trimmed().toUtf8()); } +static void initProxyAuthDialog() +{ + QObject::connect(Utils::NetworkAccessManager::instance(), + &QNetworkAccessManager::proxyAuthenticationRequired, + Utils::NetworkAccessManager::instance(), + [](const QNetworkProxy &, QAuthenticator *authenticator) { + static bool doNotAskAgain = false; + + std::optional> answer + = Utils::PasswordDialog::getUserAndPassword( + Tr::tr("Proxy Authentication Required"), + authenticator->realm(), + Tr::tr("Do not ask again."), + {}, + &doNotAskAgain, + Core::ICore::dialogParent()); + + if (answer) { + authenticator->setUser(answer->first); + authenticator->setPassword(answer->second); + } + }); +} + bool CorePlugin::initialize(const QStringList &arguments, QString *errorMessage) { // register all mime types from all plugins @@ -145,6 +172,8 @@ bool CorePlugin::initialize(const QStringList &arguments, QString *errorMessage) loadMimeFromPlugin(plugin); } + initProxyAuthDialog(); + if (ThemeEntry::availableThemes().isEmpty()) { *errorMessage = Tr::tr("No themes found in installation."); return false; From bdbe585e59d8347eec0fb195daed683743f91f32 Mon Sep 17 00:00:00 2001 From: Eike Ziller Date: Thu, 22 Feb 2024 10:48:09 +0100 Subject: [PATCH 125/243] Appmanager: Fix translatable strings Added missing full stops and capitalization. Changed "Appman" and "AppMan" to "Application Manager". It is "Qt Application Manager". "appman" (all lowercase) is the daemon executable, which I think we never actual refer to in the UI. Change-Id: Icb9a192084c13f96d9faef0a3d4617a4d194c624 Reviewed-by: Leena Miettinen Reviewed-by: --- .../appmanagercmakepackagestep.cpp | 2 +- .../appmanagerdeployconfigurationfactory.cpp | 2 +- .../appmanagerdeploypackagestep.cpp | 4 ++-- .../appmanagerrunconfiguration.cpp | 4 ++-- .../qtapplicationmanager/appmanagerruncontrol.cpp | 6 +++--- .../qtapplicationmanager/appmanagerstringaspect.cpp | 12 ++++++------ 6 files changed, 15 insertions(+), 15 deletions(-) diff --git a/src/plugins/qtapplicationmanager/appmanagercmakepackagestep.cpp b/src/plugins/qtapplicationmanager/appmanagercmakepackagestep.cpp index fee8cd49718..94f91a15856 100644 --- a/src/plugins/qtapplicationmanager/appmanagercmakepackagestep.cpp +++ b/src/plugins/qtapplicationmanager/appmanagercmakepackagestep.cpp @@ -42,7 +42,7 @@ public: QObject::connect(step->project(), &Project::displayNameChanged, step, updaterSlot); }); - setDisplayName(Tr::tr("Create Appman package with CMake")); + setDisplayName(Tr::tr("Create Application Manager package with CMake")); setSupportedStepList(ProjectExplorer::Constants::BUILDSTEPS_DEPLOY); } }; diff --git a/src/plugins/qtapplicationmanager/appmanagerdeployconfigurationfactory.cpp b/src/plugins/qtapplicationmanager/appmanagerdeployconfigurationfactory.cpp index 8b2792edba2..ed524cae286 100644 --- a/src/plugins/qtapplicationmanager/appmanagerdeployconfigurationfactory.cpp +++ b/src/plugins/qtapplicationmanager/appmanagerdeployconfigurationfactory.cpp @@ -33,7 +33,7 @@ public: AppManagerDeployConfigurationFactory() { setConfigBaseId(Constants::DEPLOYCONFIGURATION_ID); - setDefaultDisplayName(Tr::tr("Automatic AppMan Deploy Configuration")); + setDefaultDisplayName(Tr::tr("Automatic Application Manager Deploy Configuration")); addSupportedTargetDeviceType(ProjectExplorer::Constants::DESKTOP_DEVICE_TYPE); addSupportedTargetDeviceType(RemoteLinux::Constants::GenericLinuxOsType); addSupportedTargetDeviceType(Qdb::Constants::QdbLinuxOsType); diff --git a/src/plugins/qtapplicationmanager/appmanagerdeploypackagestep.cpp b/src/plugins/qtapplicationmanager/appmanagerdeploypackagestep.cpp index da6c6052008..6263028a6e4 100644 --- a/src/plugins/qtapplicationmanager/appmanagerdeploypackagestep.cpp +++ b/src/plugins/qtapplicationmanager/appmanagerdeploypackagestep.cpp @@ -95,9 +95,9 @@ private: }; const auto onDone = [this](DoneWith result) { if (result == DoneWith::Success) - emit addOutput(Tr::tr("Uploading finished"), OutputFormat::NormalMessage); + emit addOutput(Tr::tr("Uploading finished."), OutputFormat::NormalMessage); else - emit addOutput(Tr::tr("Uploading failed"), OutputFormat::ErrorMessage); + emit addOutput(Tr::tr("Uploading failed."), OutputFormat::ErrorMessage); }; return FileStreamerTask(onSetup, onDone); } diff --git a/src/plugins/qtapplicationmanager/appmanagerrunconfiguration.cpp b/src/plugins/qtapplicationmanager/appmanagerrunconfiguration.cpp index 77bddffb055..bf901128f7b 100644 --- a/src/plugins/qtapplicationmanager/appmanagerrunconfiguration.cpp +++ b/src/plugins/qtapplicationmanager/appmanagerrunconfiguration.cpp @@ -33,7 +33,7 @@ public: AppManagerRunConfiguration(Target *target, Id id) : RunConfiguration(target, id) { - setDefaultDisplayName(Tr::tr("Run an Appman Package")); + setDefaultDisplayName(Tr::tr("Run an Application Manager Package")); setUpdater([this, target] { QList tis = TargetInformation::readFromProject(target, buildKey()); @@ -66,7 +66,7 @@ public: AppManagerRunAndDebugConfiguration(Target *target, Id id) : AppManagerRunConfiguration(target, id) { - setDefaultDisplayName(Tr::tr("Run and Debug an Appman Package")); + setDefaultDisplayName(Tr::tr("Run and Debug an Application Manager Package")); environment.addPreferredBaseEnvironment(Tr::tr("Clean Environment"), {}); } diff --git a/src/plugins/qtapplicationmanager/appmanagerruncontrol.cpp b/src/plugins/qtapplicationmanager/appmanagerruncontrol.cpp index 9c485536a44..5780b6043af 100644 --- a/src/plugins/qtapplicationmanager/appmanagerruncontrol.cpp +++ b/src/plugins/qtapplicationmanager/appmanagerruncontrol.cpp @@ -48,7 +48,7 @@ public: { setId("ApplicationManagerPlugin.Run.TargetRunner"); connect(this, &RunWorker::stopped, this, [this, runControl] { - appendMessage(Tr::tr("%1 exited").arg(runControl->runnable().command.toUserOutput()), + appendMessage(Tr::tr("%1 exited.").arg(runControl->runnable().command.toUserOutput()), OutputFormat::NormalMessageFormat); }); @@ -170,8 +170,8 @@ public: setProcessMode(ProcessMode::Writer); setCommandLine(cmd); - appendMessage(Tr::tr("Starting AppMan Debugging..."), NormalMessageFormat); - appendMessage(Tr::tr("Using: %1").arg(cmd.toUserOutput()), NormalMessageFormat); + appendMessage(Tr::tr("Starting Application Manager debugging..."), NormalMessageFormat); + appendMessage(Tr::tr("Using: %1.").arg(cmd.toUserOutput()), NormalMessageFormat); }); } diff --git a/src/plugins/qtapplicationmanager/appmanagerstringaspect.cpp b/src/plugins/qtapplicationmanager/appmanagerstringaspect.cpp index 23645224c38..6127a7658a9 100644 --- a/src/plugins/qtapplicationmanager/appmanagerstringaspect.cpp +++ b/src/plugins/qtapplicationmanager/appmanagerstringaspect.cpp @@ -24,7 +24,7 @@ AppManagerIdAspect::AppManagerIdAspect(Utils::AspectContainer *container) { setSettingsKey("ApplicationManagerPlugin.ApplicationId"); setDisplayStyle(StringAspect::LineEditDisplay); - setLabelText(Tr::tr("Application id:")); + setLabelText(Tr::tr("Application ID:")); // setReadOnly(true); } @@ -33,9 +33,9 @@ AppManagerInstanceIdAspect::AppManagerInstanceIdAspect(Utils::AspectContainer *c { setSettingsKey("ApplicationManagerPlugin.InstanceId"); setDisplayStyle(StringAspect::LineEditDisplay); - setLabelText(Tr::tr("AppMan instance id:")); + setLabelText(Tr::tr("Application Manager instance ID:")); - makeCheckable(Utils::CheckBoxPlacement::Right, Tr::tr("Default Instance"), + makeCheckable(Utils::CheckBoxPlacement::Right, Tr::tr("Default instance"), "ApplicationManagerPlugin.InstanceIdDefault"); setChecked(true); @@ -52,16 +52,16 @@ AppManagerDocumentUrlAspect::AppManagerDocumentUrlAspect(Utils::AspectContainer { setSettingsKey("ApplicationManagerPlugin.DocumentUrl"); setDisplayStyle(StringAspect::LineEditDisplay); - setLabelText(Tr::tr("Document url:")); + setLabelText(Tr::tr("Document URL:")); } AppManagerCustomizeAspect::AppManagerCustomizeAspect(Utils::AspectContainer *container) : BoolAspect(container) { setSettingsKey("ApplicationManagerPlugin.CustomizeStep"); - setLabelText(Tr::tr("Customize Step")); + setLabelText(Tr::tr("Customize step")); setToolTip(Tr::tr("Disables the automatic updates based on the current run configuration and " - "allows customizing the values")); + "allows customizing the values.")); } AppManagerControllerAspect::AppManagerControllerAspect(Utils::AspectContainer *container) From 455a9986df67ed23eaf67784c30ca763082feb61 Mon Sep 17 00:00:00 2001 From: Eike Ziller Date: Wed, 21 Feb 2024 17:20:58 +0100 Subject: [PATCH 126/243] QmlDesigner: Use qsTr instead of qsTrId The latter is used nowhere else, so stay consistent Change-Id: Iaaf30d8d4c283363a05011a868fc75c773c2ed3c Reviewed-by: Reviewed-by: Alessandro Portale --- share/qtcreator/qmldesigner/welcomepage/TourRestartButton.qml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/share/qtcreator/qmldesigner/welcomepage/TourRestartButton.qml b/share/qtcreator/qmldesigner/welcomepage/TourRestartButton.qml index 55f367ffb9c..d81dafe7bb3 100644 --- a/share/qtcreator/qmldesigner/welcomepage/TourRestartButton.qml +++ b/share/qtcreator/qmldesigner/welcomepage/TourRestartButton.qml @@ -18,7 +18,7 @@ Rectangle { Text { id: text2 color: "#ffffff" - text: qsTrId("Restart") + text: qsTr("Restart") anchors.verticalCenter: parent.verticalCenter font.pixelSize: 12 anchors.horizontalCenter: parent.horizontalCenter From ea26cd13b97e4bc628f75fb115394e1264382a3e Mon Sep 17 00:00:00 2001 From: Assam Boudjelthia Date: Tue, 20 Feb 2024 12:17:28 +0200 Subject: [PATCH 127/243] Android: get essential platforms and build-tools packages from BuiltWith The commit 1180d5b8a270cfe7bd1c501c892d1c38ee7425de added information about the ndk and android api level used at build time, ndk version has already been accounted for in b73d6f3be80461f7e72326d622a07f8d2dfee10e. This now accounts for "platforms;android-xx" and "build-tools;xx.x.x" packages. Fixes: QTCREATORBUG-30404 Change-Id: I78b8885b88294404bc29c41a7b9491a331fcd709 Reviewed-by: Alessandro Portale --- src/plugins/android/androidconfigurations.cpp | 59 ++++++++++++++++++- src/plugins/android/androidconstants.h | 2 + 2 files changed, 58 insertions(+), 3 deletions(-) diff --git a/src/plugins/android/androidconfigurations.cpp b/src/plugins/android/androidconfigurations.cpp index 21a20ff645c..fae6c64bbe3 100644 --- a/src/plugins/android/androidconfigurations.cpp +++ b/src/plugins/android/androidconfigurations.cpp @@ -126,6 +126,15 @@ static QString ndkPackageMarker() return QLatin1String(Constants::ndkPackageName) + ";"; } +static QString platformsPackageMarker() +{ + return QLatin1String(Constants::platformsPackageName) + ";"; +} + +static QString buildToolsPackageMarker() +{ + return QLatin1String(Constants::buildToolsPackageName) + ";"; +} ////////////////////////////////// // AndroidConfig @@ -951,15 +960,59 @@ bool AndroidConfig::sdkToolsOk() const return exists && writable && sdkToolsExist; } +static QStringList packagesExcludingBuiltWithDefaults(const QStringList &packages) +{ + return Utils::filtered(packages, [] (const QString &p) { + return !p.startsWith(ndkPackageMarker()) && !p.startsWith(platformsPackageMarker()) + && !p.startsWith(buildToolsPackageMarker()); }); +} + +static QString essentialBuiltWithBuildToolsPackage(int builtWithApiVersion) +{ + // For build-tools, to avoid the situation of potentially having the essential packages + // 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 apiBuildTools + = Utils::filtered(buildTools, [builtWithApiVersion] (const BuildTools *pkg) { + return pkg->revision().majorVersion() == builtWithApiVersion; }); + const QString installedBuildTool = [apiBuildTools] () -> QString { + for (const BuildTools *pkg : apiBuildTools) { + if (pkg->state() == AndroidSdkPackage::Installed) + return pkg->sdkStylePath(); + } + return {}; + }(); + + if (installedBuildTool.isEmpty()) { + if (!apiBuildTools.isEmpty()) + return apiBuildTools.first()->sdkStylePath(); + else if (!buildTools.isEmpty()) + return buildTools.first()->sdkStylePath(); + // This means there's something wrong with sdkmanager, return a default version anyway + else + return buildToolsPackageMarker() + QString::number(builtWithApiVersion) + ".0.0"; + } + + return installedBuildTool; +} + QStringList AndroidConfig::essentialsFromQtVersion(const QtVersion &version) const { if (auto androidQtVersion = dynamic_cast(&version)) { bool ok; const AndroidQtVersion::BuiltWith bw = androidQtVersion->builtWith(&ok); if (ok) { - const QString ndkPackage = ndkPackageMarker() + bw.ndkVersion.toString(); - return QStringList(ndkPackage) - + packagesWithoutNdks(m_defaultSdkDepends.essentialPackages); + QStringList builtWithPackages; + builtWithPackages.append(ndkPackageMarker() + bw.ndkVersion.toString()); + const QString apiVersion = QString::number(bw.apiVersion); + builtWithPackages.append(platformsPackageMarker() + "android-" + apiVersion); + builtWithPackages.append(essentialBuiltWithBuildToolsPackage(bw.apiVersion)); + + return builtWithPackages + packagesExcludingBuiltWithDefaults( + m_defaultSdkDepends.essentialPackages); } } diff --git a/src/plugins/android/androidconstants.h b/src/plugins/android/androidconstants.h index e2b15e6358d..813b6a924c0 100644 --- a/src/plugins/android/androidconstants.h +++ b/src/plugins/android/androidconstants.h @@ -78,6 +78,8 @@ const Utils::Id AndroidAvdPath = "AndroidAvdPath"; // SDK Tools const char cmdlineToolsName[] = "cmdline-tools"; const char ndkPackageName[] = "ndk"; +const char platformsPackageName[] = "platforms"; +const char buildToolsPackageName[] = "build-tools"; // For AndroidQtVersion const char ArmToolsDisplayName[] = "arm"; From c400664ab277d6012619e25cdbe7ca6083831aad Mon Sep 17 00:00:00 2001 From: Jarek Kobus Date: Thu, 22 Feb 2024 12:28:59 +0100 Subject: [PATCH 128/243] Axivion: Don't report error on semi working setup so intrusively Might be annoying when typing in filter field when storing keychain isn't full functional. Change-Id: I36a1a8e8e8eefcea381a6392e3df032648ed8dc4 Reviewed-by: hjk --- src/plugins/axivion/axivionplugin.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/plugins/axivion/axivionplugin.cpp b/src/plugins/axivion/axivionplugin.cpp index 79a349fed66..3e6a9814bce 100644 --- a/src/plugins/axivion/axivionplugin.cpp +++ b/src/plugins/axivion/axivionplugin.cpp @@ -568,7 +568,7 @@ static Group authorizationRecipe() const auto onSetCredentialDone = [](const CredentialQuery &credential) { const QString keyChainMessage = credential.errorString().isEmpty() ? QString() : QString(" %1").arg(Tr::tr("Key chain message: \"%1\".").arg(credential.errorString())); - MessageManager::writeDisrupting(QString("Axivion: %1") + MessageManager::writeFlashing(QString("Axivion: %1") .arg(Tr::tr("The ApiToken cannot be stored in a secure way.") + keyChainMessage)); // TODO: We are multiplying the ApiTokens on Axivion server for each Creator run, // but at least things should continue to work OK in the current session. From c829bf76436771b5aa793e8c95ea572ec9d7cb20 Mon Sep 17 00:00:00 2001 From: Eike Ziller Date: Thu, 22 Feb 2024 12:38:01 +0100 Subject: [PATCH 129/243] Core: Small tr fix Use "convert to", and the standard is ASCII Change-Id: I0a687f9bcb8f2c97932a03b45e10a80adbd993dc Reviewed-by: Leena Miettinen --- src/plugins/coreplugin/coreplugin.cpp | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/src/plugins/coreplugin/coreplugin.cpp b/src/plugins/coreplugin/coreplugin.cpp index 4b45c3e6f42..c5623134814 100644 --- a/src/plugins/coreplugin/coreplugin.cpp +++ b/src/plugins/coreplugin/coreplugin.cpp @@ -263,9 +263,9 @@ bool CorePlugin::initialize(const QStringList &arguments, QString *errorMessage) [] { return QUuid::createUuid().toString(); }); expander->registerPrefix("#:", Tr::tr("A comment."), [](const QString &) { return QString(); }); - expander->registerPrefix("Asciify:", Tr::tr("Convert string into pure ascii."), - [expander] (const QString &s) { - return asciify(expander->expand(s)); }); + expander->registerPrefix("Asciify:", + Tr::tr("Convert string to pure ASCII."), + [expander](const QString &s) { return asciify(expander->expand(s)); }); Utils::PathChooser::setAboutToShowContextMenuHandler(&CorePlugin::addToPathChooserContextMenu); From ecf1ada3f564bfd9d4125248f3eb81bbae0ccdcd Mon Sep 17 00:00:00 2001 From: Christian Stenger Date: Thu, 22 Feb 2024 10:33:40 +0100 Subject: [PATCH 130/243] Axivion: Fix path filter query If the issue kind has multiple path columns filtering by path failed as it used just the single path filter. Use common approach for all. Fixes: QTCREATORBUG-30420 Change-Id: I60460cebdc4a39b9af57c4f1331cb8cb9eedb67a Reviewed-by: Jarek Kobus --- src/plugins/axivion/axivionplugin.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/plugins/axivion/axivionplugin.cpp b/src/plugins/axivion/axivionplugin.cpp index 3e6a9814bce..5034da51ffb 100644 --- a/src/plugins/axivion/axivionplugin.cpp +++ b/src/plugins/axivion/axivionplugin.cpp @@ -164,7 +164,7 @@ QString IssueListSearch::toQuery() const QString::fromUtf8((QUrl::toPercentEncoding(owner))))); } if (!filter_path.isEmpty()) { - result.append(QString("&filter_path=%1").arg( + result.append(QString("&filter_any path=%1").arg( QString::fromUtf8(QUrl::toPercentEncoding(filter_path)))); } if (!state.isEmpty()) From 1531d2f010c063def258ffff93ffcb78b3bc3aca Mon Sep 17 00:00:00 2001 From: Marcus Tillmanns Date: Thu, 22 Feb 2024 13:33:32 +0100 Subject: [PATCH 131/243] Terminal: Only react to Double click of Left Button Change-Id: I94131389851b2939c2a3e91d9d9a70890928f882 Reviewed-by: David Schulz --- src/libs/solutions/terminal/terminalview.cpp | 3 +++ 1 file changed, 3 insertions(+) diff --git a/src/libs/solutions/terminal/terminalview.cpp b/src/libs/solutions/terminal/terminalview.cpp index 08a85d4f119..0cebe6d9b99 100644 --- a/src/libs/solutions/terminal/terminalview.cpp +++ b/src/libs/solutions/terminal/terminalview.cpp @@ -1199,6 +1199,9 @@ void TerminalView::mouseReleaseEvent(QMouseEvent *event) void TerminalView::mouseDoubleClickEvent(QMouseEvent *event) { + if (event->button() != Qt::LeftButton) + return; + if (d->m_allowMouseTracking) { d->m_surface->mouseMove(toGridPos(event), event->modifiers()); d->m_surface->mouseButton(event->button(), true, event->modifiers()); From 47b5d7eab3824c808ff38c2a483912ec251ad272 Mon Sep 17 00:00:00 2001 From: Jarek Kobus Date: Wed, 21 Feb 2024 18:45:16 +0100 Subject: [PATCH 132/243] Axivion: Handle the error on key read like we do on key storing Change-Id: Icb53d4e005f9bfa2dd1a20c763def1e6ac04e784 Reviewed-by: hjk --- src/plugins/axivion/axivionplugin.cpp | 35 +++++++++++++++++++++------ src/plugins/axivion/credentialquery.h | 1 + 2 files changed, 29 insertions(+), 7 deletions(-) diff --git a/src/plugins/axivion/axivionplugin.cpp b/src/plugins/axivion/axivionplugin.cpp index 5034da51ffb..10364b86f3f 100644 --- a/src/plugins/axivion/axivionplugin.cpp +++ b/src/plugins/axivion/axivionplugin.cpp @@ -476,6 +476,27 @@ static Group dtoRecipe(const Storage> &dtoStorage) }; } +static QString credentialOperationMessage(CredentialOperation operation) +{ + switch (operation) { + case CredentialOperation::Get: + return Tr::tr("The ApiToken cannot be read in a secure way."); + case CredentialOperation::Set: + return Tr::tr("The ApiToken cannot be stored in a secure way."); + case CredentialOperation::Delete: + return Tr::tr("The ApiToken cannot be deleted in a secure way."); + } + return {}; +} + +static void handleCredentialError(const CredentialQuery &credential) +{ + const QString keyChainMessage = credential.errorString().isEmpty() ? QString() + : QString(" %1").arg(Tr::tr("Key chain message: \"%1\".").arg(credential.errorString())); + MessageManager::writeFlashing(QString("Axivion: %1") + .arg(credentialOperationMessage(credential.operation()) + keyChainMessage)); +} + static Group authorizationRecipe() { const Storage> unauthorizedDashboardStorage; @@ -509,7 +530,10 @@ static Group authorizationRecipe() if (result == DoneWith::Success) dd->m_apiToken = credential.data(); else - MessageManager::writeDisrupting(QString("Axivion: %1").arg(credential.errorString())); + handleCredentialError(credential); + // TODO: In case of an error we are multiplying the ApiTokens on Axivion server for each + // Creator run, but at least things should continue to work OK in the current session. + return DoneResult::Success; }; const Storage passwordStorage; @@ -566,12 +590,9 @@ static Group authorizationRecipe() return SetupResult::Continue; }; const auto onSetCredentialDone = [](const CredentialQuery &credential) { - const QString keyChainMessage = credential.errorString().isEmpty() ? QString() - : QString(" %1").arg(Tr::tr("Key chain message: \"%1\".").arg(credential.errorString())); - MessageManager::writeFlashing(QString("Axivion: %1") - .arg(Tr::tr("The ApiToken cannot be stored in a secure way.") + keyChainMessage)); - // TODO: We are multiplying the ApiTokens on Axivion server for each Creator run, - // but at least things should continue to work OK in the current session. + handleCredentialError(credential); + // TODO: In case of an error we are multiplying the ApiTokens on Axivion server for each + // Creator run, but at least things should continue to work OK in the current session. return DoneResult::Success; }; diff --git a/src/plugins/axivion/credentialquery.h b/src/plugins/axivion/credentialquery.h index 6b23c5f4669..b5ea338c3bd 100644 --- a/src/plugins/axivion/credentialquery.h +++ b/src/plugins/axivion/credentialquery.h @@ -17,6 +17,7 @@ public: void setKey(const QString &key) { m_key = key; } void setData(const QByteArray &data) { m_data = data; } + CredentialOperation operation() const { return m_operation; } std::optional data() const { return m_data; } QString errorString() const { return m_errorString; } From 957319fdbc50cfcb132bedffb1ddc247eef7e093 Mon Sep 17 00:00:00 2001 From: hjk Date: Thu, 22 Feb 2024 14:51:01 +0100 Subject: [PATCH 133/243] Axivion: Make the dashboard and issues pane button checkable Change-Id: Idec60b73fa4bfe0057e7d8f9eef3fa403ce6a5cd Reviewed-by: Jarek Kobus --- src/plugins/axivion/axivionoutputpane.cpp | 47 +++++++++++++---------- src/plugins/axivion/axivionoutputpane.h | 5 +++ 2 files changed, 32 insertions(+), 20 deletions(-) diff --git a/src/plugins/axivion/axivionoutputpane.cpp b/src/plugins/axivion/axivionoutputpane.cpp index 42046f78b14..ae4a5057424 100644 --- a/src/plugins/axivion/axivionoutputpane.cpp +++ b/src/plugins/axivion/axivionoutputpane.cpp @@ -623,6 +623,32 @@ AxivionOutputPane::AxivionOutputPane(QObject *parent) m_outputWidget->addWidget(dashboardWidget); IssuesWidget *issuesWidget = new IssuesWidget(m_outputWidget); m_outputWidget->addWidget(issuesWidget); + + m_showDashboard = new QToolButton(m_outputWidget); + m_showDashboard->setIcon(Icons::HOME_TOOLBAR.icon()); + m_showDashboard->setToolTip(Tr::tr("Show dashboard")); + m_showDashboard->setCheckable(true); + m_showDashboard->setChecked(true); + connect(m_showDashboard, &QToolButton::clicked, this, [this] { + QTC_ASSERT(m_outputWidget, return); + m_outputWidget->setCurrentIndex(0); + }); + + m_showIssues = new QToolButton(m_outputWidget); + m_showIssues->setIcon(Icons::ZOOM_TOOLBAR.icon()); + m_showIssues->setToolTip(Tr::tr("Search for issues")); + m_showIssues->setCheckable(true); + connect(m_showIssues, &QToolButton::clicked, this, [this] { + QTC_ASSERT(m_outputWidget, return); + m_outputWidget->setCurrentIndex(1); + if (auto issues = static_cast(m_outputWidget->widget(1))) + issues->updateUi(); + }); + + connect(m_outputWidget, &QStackedWidget::currentChanged, this, [this](int idx) { + m_showDashboard->setChecked(idx == 0); + m_showIssues->setChecked(idx == 1); + }); } AxivionOutputPane::~AxivionOutputPane() @@ -642,26 +668,7 @@ QWidget *AxivionOutputPane::outputWidget(QWidget *parent) QList AxivionOutputPane::toolBarWidgets() const { - QList buttons; - auto showDashboard = new QToolButton(m_outputWidget); - showDashboard->setIcon(Icons::HOME_TOOLBAR.icon()); - showDashboard->setToolTip(Tr::tr("Show dashboard")); - connect(showDashboard, &QToolButton::clicked, this, [this]{ - QTC_ASSERT(m_outputWidget, return); - m_outputWidget->setCurrentIndex(0); - }); - buttons.append(showDashboard); - auto showIssues = new QToolButton(m_outputWidget); - showIssues->setIcon(Icons::ZOOM_TOOLBAR.icon()); - showIssues->setToolTip(Tr::tr("Search for issues")); - connect(showIssues, &QToolButton::clicked, this, [this]{ - QTC_ASSERT(m_outputWidget, return); - m_outputWidget->setCurrentIndex(1); - if (auto issues = static_cast(m_outputWidget->widget(1))) - issues->updateUi(); - }); - buttons.append(showIssues); - return buttons; + return {m_showDashboard, m_showIssues}; } void AxivionOutputPane::clearContents() diff --git a/src/plugins/axivion/axivionoutputpane.h b/src/plugins/axivion/axivionoutputpane.h index 87000e5e187..040a52e193f 100644 --- a/src/plugins/axivion/axivionoutputpane.h +++ b/src/plugins/axivion/axivionoutputpane.h @@ -7,6 +7,7 @@ QT_BEGIN_NAMESPACE class QStackedWidget; +class QToolButton; QT_END_NAMESPACE namespace Axivion::Internal { @@ -14,6 +15,7 @@ namespace Axivion::Internal { class AxivionOutputPane : public Core::IOutputPane { Q_OBJECT + public: explicit AxivionOutputPane(QObject *parent = nullptr); ~AxivionOutputPane(); @@ -32,8 +34,11 @@ public: void goToPrev() override; void updateDashboard(); + private: QStackedWidget *m_outputWidget = nullptr; + QToolButton *m_showDashboard = nullptr; + QToolButton *m_showIssues = nullptr; }; } // Axivion::Internal From df78a36e3e36e6b5307366b55123217ecee00a64 Mon Sep 17 00:00:00 2001 From: hjk Date: Thu, 22 Feb 2024 15:35:03 +0100 Subject: [PATCH 134/243] Axivion: Hide the output pane implementation Change-Id: I4aea1a974cfbbe7aaef370e012b921d5e125e0b8 Reviewed-by: Jarek Kobus --- src/plugins/axivion/axivionoutputpane.cpp | 199 +++++++++++----------- src/plugins/axivion/axivionoutputpane.h | 37 +--- src/plugins/axivion/axivionplugin.cpp | 9 +- 3 files changed, 104 insertions(+), 141 deletions(-) diff --git a/src/plugins/axivion/axivionoutputpane.cpp b/src/plugins/axivion/axivionoutputpane.cpp index ae4a5057424..7ceaf04b8c9 100644 --- a/src/plugins/axivion/axivionoutputpane.cpp +++ b/src/plugins/axivion/axivionoutputpane.cpp @@ -8,6 +8,7 @@ #include "dashboard/dto.h" #include +#include #include #include @@ -611,115 +612,107 @@ void IssuesWidget::fetchMoreIssues() fetchIssues(search); } -AxivionOutputPane::AxivionOutputPane(QObject *parent) - : IOutputPane(parent) +class AxivionOutputPane final : public IOutputPane { - setId("Axivion"); - setDisplayName(Tr::tr("Axivion")); - setPriorityInStatusBar(-50); +public: + explicit AxivionOutputPane(QObject *parent) + : IOutputPane(parent) + { + setId("Axivion"); + setDisplayName(Tr::tr("Axivion")); + setPriorityInStatusBar(-50); - m_outputWidget = new QStackedWidget; - DashboardWidget *dashboardWidget = new DashboardWidget(m_outputWidget); - m_outputWidget->addWidget(dashboardWidget); - IssuesWidget *issuesWidget = new IssuesWidget(m_outputWidget); - m_outputWidget->addWidget(issuesWidget); + m_outputWidget = new QStackedWidget; + DashboardWidget *dashboardWidget = new DashboardWidget(m_outputWidget); + m_outputWidget->addWidget(dashboardWidget); + IssuesWidget *issuesWidget = new IssuesWidget(m_outputWidget); + m_outputWidget->addWidget(issuesWidget); - m_showDashboard = new QToolButton(m_outputWidget); - m_showDashboard->setIcon(Icons::HOME_TOOLBAR.icon()); - m_showDashboard->setToolTip(Tr::tr("Show dashboard")); - m_showDashboard->setCheckable(true); - m_showDashboard->setChecked(true); - connect(m_showDashboard, &QToolButton::clicked, this, [this] { - QTC_ASSERT(m_outputWidget, return); - m_outputWidget->setCurrentIndex(0); - }); + m_showDashboard = new QToolButton(m_outputWidget); + m_showDashboard->setIcon(Icons::HOME_TOOLBAR.icon()); + m_showDashboard->setToolTip(Tr::tr("Show dashboard")); + m_showDashboard->setCheckable(true); + m_showDashboard->setChecked(true); + connect(m_showDashboard, &QToolButton::clicked, this, [this] { + QTC_ASSERT(m_outputWidget, return); + m_outputWidget->setCurrentIndex(0); + }); - m_showIssues = new QToolButton(m_outputWidget); - m_showIssues->setIcon(Icons::ZOOM_TOOLBAR.icon()); - m_showIssues->setToolTip(Tr::tr("Search for issues")); - m_showIssues->setCheckable(true); - connect(m_showIssues, &QToolButton::clicked, this, [this] { - QTC_ASSERT(m_outputWidget, return); - m_outputWidget->setCurrentIndex(1); - if (auto issues = static_cast(m_outputWidget->widget(1))) - issues->updateUi(); - }); + m_showIssues = new QToolButton(m_outputWidget); + m_showIssues->setIcon(Icons::ZOOM_TOOLBAR.icon()); + m_showIssues->setToolTip(Tr::tr("Search for issues")); + m_showIssues->setCheckable(true); + connect(m_showIssues, &QToolButton::clicked, this, [this] { + QTC_ASSERT(m_outputWidget, return); + m_outputWidget->setCurrentIndex(1); + if (auto issues = static_cast(m_outputWidget->widget(1))) + issues->updateUi(); + }); - connect(m_outputWidget, &QStackedWidget::currentChanged, this, [this](int idx) { - m_showDashboard->setChecked(idx == 0); - m_showIssues->setChecked(idx == 1); - }); -} - -AxivionOutputPane::~AxivionOutputPane() -{ - if (!m_outputWidget->parent()) - delete m_outputWidget; -} - -QWidget *AxivionOutputPane::outputWidget(QWidget *parent) -{ - if (m_outputWidget) - m_outputWidget->setParent(parent); - else - QTC_CHECK(false); - return m_outputWidget; -} - -QList AxivionOutputPane::toolBarWidgets() const -{ - return {m_showDashboard, m_showIssues}; -} - -void AxivionOutputPane::clearContents() -{ -} - -void AxivionOutputPane::setFocus() -{ -} - -bool AxivionOutputPane::hasFocus() const -{ - return false; -} - -bool AxivionOutputPane::canFocus() const -{ - return true; -} - -bool AxivionOutputPane::canNavigate() const -{ - return true; -} - -bool AxivionOutputPane::canNext() const -{ - return false; -} - -bool AxivionOutputPane::canPrevious() const -{ - return false; -} - -void AxivionOutputPane::goToNext() -{ -} - -void AxivionOutputPane::goToPrev() -{ -} - -void AxivionOutputPane::updateDashboard() -{ - if (auto dashboard = static_cast(m_outputWidget->widget(0))) { - dashboard->updateUi(); - m_outputWidget->setCurrentIndex(0); - if (dashboard->hasProject()) - flash(); + connect(m_outputWidget, &QStackedWidget::currentChanged, this, [this](int idx) { + m_showDashboard->setChecked(idx == 0); + m_showIssues->setChecked(idx == 1); + }); } + + ~AxivionOutputPane() + { + if (!m_outputWidget->parent()) + delete m_outputWidget; + } + + QWidget *outputWidget(QWidget *parent) final + { + if (m_outputWidget) + m_outputWidget->setParent(parent); + else + QTC_CHECK(false); + return m_outputWidget; + } + + QList toolBarWidgets() const final + { + return {m_showDashboard, m_showIssues}; + } + + void clearContents() final {} + void setFocus() final {} + bool hasFocus() const final { return false; } + bool canFocus() const final { return true; } + bool canNavigate() const final { return true; } + bool canNext() const final { return false; } + bool canPrevious() const final { return false; } + void goToNext() final {} + void goToPrev() final {} + + void updateDashboard() + { + if (auto dashboard = static_cast(m_outputWidget->widget(0))) { + dashboard->updateUi(); + m_outputWidget->setCurrentIndex(0); + if (dashboard->hasProject()) + flash(); + } + } + +private: + QStackedWidget *m_outputWidget = nullptr; + QToolButton *m_showDashboard = nullptr; + QToolButton *m_showIssues = nullptr; +}; + + +static QPointer theAxivionOutputPane; + +void setupAxivionOutputPane(QObject *guard) +{ + theAxivionOutputPane = new AxivionOutputPane(guard); +} + +void updateDashboard() +{ + QTC_ASSERT(theAxivionOutputPane, return); + theAxivionOutputPane->updateDashboard(); } } // Axivion::Internal diff --git a/src/plugins/axivion/axivionoutputpane.h b/src/plugins/axivion/axivionoutputpane.h index 040a52e193f..a13b125c183 100644 --- a/src/plugins/axivion/axivionoutputpane.h +++ b/src/plugins/axivion/axivionoutputpane.h @@ -3,42 +3,11 @@ #pragma once -#include - -QT_BEGIN_NAMESPACE -class QStackedWidget; -class QToolButton; -QT_END_NAMESPACE +#include namespace Axivion::Internal { -class AxivionOutputPane : public Core::IOutputPane -{ - Q_OBJECT - -public: - explicit AxivionOutputPane(QObject *parent = nullptr); - ~AxivionOutputPane(); - - // IOutputPane interface - QWidget *outputWidget(QWidget *parent) override; - QList toolBarWidgets() const override; - void clearContents() override; - void setFocus() override; - bool hasFocus() const override; - bool canFocus() const override; - bool canNavigate() const override; - bool canNext() const override; - bool canPrevious() const override; - void goToNext() override; - void goToPrev() override; - - void updateDashboard(); - -private: - QStackedWidget *m_outputWidget = nullptr; - QToolButton *m_showDashboard = nullptr; - QToolButton *m_showIssues = nullptr; -}; +void setupAxivionOutputPane(QObject *guard); +void updateDashboard(); } // Axivion::Internal diff --git a/src/plugins/axivion/axivionplugin.cpp b/src/plugins/axivion/axivionplugin.cpp index 10364b86f3f..b5c6634c339 100644 --- a/src/plugins/axivion/axivionplugin.cpp +++ b/src/plugins/axivion/axivionplugin.cpp @@ -202,7 +202,6 @@ public: // TODO: Should be cleared on username change in settings. std::optional m_apiToken; NetworkAccessManager m_networkAccessManager; - AxivionOutputPane m_axivionOutputPane; std::optional m_dashboardInfo; std::optional m_currentProjectInfo; Project *m_project = nullptr; @@ -309,7 +308,7 @@ void AxivionPluginPrivate::onStartupProjectChanged(Project *project) m_project = project; clearAllMarks(); m_currentProjectInfo = {}; - m_axivionOutputPane.updateDashboard(); + updateDashboard(); if (!m_project) return; @@ -729,7 +728,7 @@ void AxivionPluginPrivate::fetchProjectInfo(const QString &projectName) clearAllMarks(); if (projectName.isEmpty()) { m_currentProjectInfo = {}; - m_axivionOutputPane.updateDashboard(); + updateDashboard(); return; } @@ -749,7 +748,7 @@ void AxivionPluginPrivate::fetchProjectInfo(const QString &projectName) const auto handler = [this](const Dto::ProjectInfoDto &data) { m_currentProjectInfo = data; - m_axivionOutputPane.updateDashboard(); + updateDashboard(); handleOpenedDocs(); }; @@ -945,6 +944,8 @@ class AxivionPlugin final : public ExtensionSystem::IPlugin void initialize() final { + setupAxivionOutputPane(this); + dd = new AxivionPluginPrivate; AxivionProjectSettings::setupProjectPanel(); From c0dd8f9aa4d7920477302dd6bc393c4e3a859a53 Mon Sep 17 00:00:00 2001 From: hjk Date: Thu, 22 Feb 2024 15:45:07 +0100 Subject: [PATCH 135/243] Axivion: Use normal background for the output pane widgets Change-Id: Iffea125f27eb64bfb9003c3a96fa78dedb6b9ebf Reviewed-by: Jarek Kobus --- src/plugins/axivion/axivionoutputpane.cpp | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/src/plugins/axivion/axivionoutputpane.cpp b/src/plugins/axivion/axivionoutputpane.cpp index 7ceaf04b8c9..104439b9d24 100644 --- a/src/plugins/axivion/axivionoutputpane.cpp +++ b/src/plugins/axivion/axivionoutputpane.cpp @@ -628,6 +628,10 @@ public: IssuesWidget *issuesWidget = new IssuesWidget(m_outputWidget); m_outputWidget->addWidget(issuesWidget); + QPalette pal = m_outputWidget->palette(); + pal.setColor(QPalette::Window, creatorTheme()->color(Theme::Color::BackgroundColorNormal)); + m_outputWidget->setPalette(pal); + m_showDashboard = new QToolButton(m_outputWidget); m_showDashboard->setIcon(Icons::HOME_TOOLBAR.icon()); m_showDashboard->setToolTip(Tr::tr("Show dashboard")); From 82724f60d1e7b8ed66902f5598f271b4eee0d841 Mon Sep 17 00:00:00 2001 From: hjk Date: Thu, 22 Feb 2024 16:09:11 +0100 Subject: [PATCH 136/243] Axivion: Use LayoutBuilder for output pane items Change-Id: I6422a6d30a1b273810f8cf18cf899ee3dcb5bd2e Reviewed-by: Jarek Kobus --- src/plugins/axivion/axivionoutputpane.cpp | 75 +++++++++++------------ 1 file changed, 37 insertions(+), 38 deletions(-) diff --git a/src/plugins/axivion/axivionoutputpane.cpp b/src/plugins/axivion/axivionoutputpane.cpp index 104439b9d24..334df135405 100644 --- a/src/plugins/axivion/axivionoutputpane.cpp +++ b/src/plugins/axivion/axivionoutputpane.cpp @@ -15,6 +15,7 @@ #include +#include #include #include #include @@ -59,22 +60,24 @@ DashboardWidget::DashboardWidget(QWidget *parent) : QScrollArea(parent) { QWidget *widget = new QWidget(this); - QVBoxLayout *layout = new QVBoxLayout(widget); - QFormLayout *projectLayout = new QFormLayout; m_project = new QLabel(this); - projectLayout->addRow(Tr::tr("Project:"), m_project); m_loc = new QLabel(this); - projectLayout->addRow(Tr::tr("Lines of code:"), m_loc); m_timestamp = new QLabel(this); - projectLayout->addRow(Tr::tr("Analysis timestamp:"), m_timestamp); - layout->addLayout(projectLayout); - layout->addSpacing(10); - auto row = new QHBoxLayout; + m_gridLayout = new QGridLayout; - row->addLayout(m_gridLayout); - row->addStretch(1); - layout->addLayout(row); - layout->addStretch(1); + + using namespace Layouting; + Column { + Form { + Tr::tr("Project:"), m_project, br, + Tr::tr("Lines of code:"), m_loc, br, + Tr::tr("Analysis timestamp:"), m_timestamp + }, + Space(10), + Row { m_gridLayout, st }, + st + }.attachTo(widget); + setWidget(widget); setVerticalScrollBarPolicy(Qt::ScrollBarAsNeeded); setWidgetResizable(true); @@ -243,7 +246,6 @@ private: std::optional m_currentTableInfo; QHBoxLayout *m_typesLayout = nullptr; QButtonGroup *m_typesButtonGroup = nullptr; - QHBoxLayout *m_filtersLayout = nullptr; QPushButton *m_addedFilter = nullptr; QPushButton *m_removedFilter = nullptr; QComboBox *m_ownerFilter = nullptr; @@ -264,59 +266,51 @@ IssuesWidget::IssuesWidget(QWidget *parent) : QScrollArea(parent) { QWidget *widget = new QWidget(this); - QVBoxLayout *layout = new QVBoxLayout(widget); // row with issue types (-> depending on choice, tables below change) // and a selectable range (start version, end version) // row with added/removed and some filters (assignee, path glob, (named filter)) // table, columns depend on chosen issue type - QHBoxLayout *top = new QHBoxLayout; - layout->addLayout(top); m_typesButtonGroup = new QButtonGroup(this); m_typesButtonGroup->setExclusive(true); m_typesLayout = new QHBoxLayout; - top->addLayout(m_typesLayout); - top->addStretch(1); + m_versionStart = new QComboBox(this); m_versionStart->setMinimumContentsLength(25); - top->addWidget(m_versionStart); + connect(m_versionStart, &QComboBox::activated, this, &IssuesWidget::onSearchParameterChanged); + m_versionEnd = new QComboBox(this); m_versionEnd->setMinimumContentsLength(25); - connect(m_versionStart, &QComboBox::activated, this, &IssuesWidget::onSearchParameterChanged); connect(m_versionEnd, &QComboBox::activated, this, &IssuesWidget::onSearchParameterChanged); - top->addWidget(m_versionEnd); - top->addStretch(1); - m_filtersLayout = new QHBoxLayout; + m_addedFilter = new QPushButton(this); m_addedFilter->setIcon(trendIcon(1, 0)); m_addedFilter->setText("0"); m_addedFilter->setCheckable(true); - m_filtersLayout->addWidget(m_addedFilter); - m_removedFilter = new QPushButton(this); - m_removedFilter->setIcon(trendIcon(0, 1)); - m_removedFilter->setText("0"); - m_removedFilter->setCheckable(true); - m_filtersLayout->addWidget(m_removedFilter); connect(m_addedFilter, &QPushButton::clicked, this, [this](bool checked) { if (checked && m_removedFilter->isChecked()) m_removedFilter->setChecked(false); onSearchParameterChanged(); }); + + m_removedFilter = new QPushButton(this); + m_removedFilter->setIcon(trendIcon(0, 1)); + m_removedFilter->setText("0"); + m_removedFilter->setCheckable(true); connect(m_removedFilter, &QPushButton::clicked, this, [this](bool checked) { if (checked && m_addedFilter->isChecked()) m_addedFilter->setChecked(false); onSearchParameterChanged(); }); - m_filtersLayout->addSpacing(1); + m_ownerFilter = new QComboBox(this); m_ownerFilter->setToolTip(Tr::tr("Owner")); m_ownerFilter->setMinimumContentsLength(25); connect(m_ownerFilter, &QComboBox::activated, this, &IssuesWidget::onSearchParameterChanged); - m_filtersLayout->addWidget(m_ownerFilter); + m_pathGlobFilter = new QLineEdit(this); m_pathGlobFilter->setPlaceholderText(Tr::tr("Path globbing")); connect(m_pathGlobFilter, &QLineEdit::textEdited, this, &IssuesWidget::onSearchParameterChanged); - m_filtersLayout->addWidget(m_pathGlobFilter); - layout->addLayout(m_filtersLayout); + m_issuesView = new BaseTreeView(this); m_issuesView->setHorizontalScrollBarPolicy(Qt::ScrollBarAsNeeded); m_issuesView->enableColumnHiding(); @@ -331,12 +325,17 @@ IssuesWidget::IssuesWidget(QWidget *parent) } }); } - layout->addWidget(m_issuesView); + m_totalRows = new QLabel(Tr::tr("Total rows:"), this); - QHBoxLayout *bottom = new QHBoxLayout; - layout->addLayout(bottom); - bottom->addStretch(1); - bottom->addWidget(m_totalRows); + + using namespace Layouting; + Column { + Row { m_typesLayout, st, m_versionStart, m_versionEnd, st }, + Row { m_addedFilter, m_removedFilter, Space(1), m_ownerFilter, m_pathGlobFilter }, + m_issuesView, + Row { st, m_totalRows } + }.attachTo(widget); + setWidget(widget); setVerticalScrollBarPolicy(Qt::ScrollBarAsNeeded); setWidgetResizable(true); From 289ac94653eadf73f790f3b2d521863109bfb8d9 Mon Sep 17 00:00:00 2001 From: Christian Stenger Date: Thu, 22 Feb 2024 15:08:35 +0100 Subject: [PATCH 137/243] QtKeychain: Disable gcc compiler warning for the qbs build CMake build disables anything, so we can disable a specific warning as well. Change-Id: Ia350d96708f371323499d645f8cc31e07e4d6c9d Reviewed-by: Christian Kandeler --- src/libs/3rdparty/qtkeychain/qtkeychain.qbs | 1 + 1 file changed, 1 insertion(+) diff --git a/src/libs/3rdparty/qtkeychain/qtkeychain.qbs b/src/libs/3rdparty/qtkeychain/qtkeychain.qbs index 6a1073a953e..b5f8e7dc131 100644 --- a/src/libs/3rdparty/qtkeychain/qtkeychain.qbs +++ b/src/libs/3rdparty/qtkeychain/qtkeychain.qbs @@ -72,6 +72,7 @@ QtcLibrary { Group { name: "qtkeychain dbus support" cpp.defines: outer.concat(["KEYCHAIN_DBUS=1"]) + cpp.cxxFlags: outer.concat("-Wno-cast-function-type") files: [ "gnomekeyring.cpp", "gnomekeyring_p.h", From fdedbdd3d454608a0c94cfaef5665fdea7ccecc1 Mon Sep 17 00:00:00 2001 From: Jarek Kobus Date: Thu, 22 Feb 2024 21:54:00 +0100 Subject: [PATCH 138/243] Axivion: Fix a possible crash when rerunning task tree from its handler Don't call setTableDto() directly from tableInfoRecipe's handler. Store the new table dto in the handler and update the Gui afterwards, on task tree done. Fixes: QTCREATORBUG-30429 Change-Id: Id267c8375bf7c9a107450ac34ecba37d696f45e1 Reviewed-by: hjk --- src/plugins/axivion/axivionoutputpane.cpp | 31 ++++++++++++++--------- 1 file changed, 19 insertions(+), 12 deletions(-) diff --git a/src/plugins/axivion/axivionoutputpane.cpp b/src/plugins/axivion/axivionoutputpane.cpp index 334df135405..3d43df982ce 100644 --- a/src/plugins/axivion/axivionoutputpane.cpp +++ b/src/plugins/axivion/axivionoutputpane.cpp @@ -229,15 +229,15 @@ class IssuesWidget : public QScrollArea public: explicit IssuesWidget(QWidget *parent = nullptr); void updateUi(); - void setTableDto(const Dto::TableInfoDto &dto); + void updateTable(); void addIssues(const Dto::IssueTableDto &dto); private: void onSearchParameterChanged(); void updateBasicProjectInfo(std::optional info); - void updateTableView(); void setFiltersEnabled(bool enabled); IssueListSearch searchFromUi() const; + void fetchTable(); void fetchIssues(const IssueListSearch &search); void fetchMoreIssues(); @@ -360,18 +360,19 @@ void IssuesWidget::updateUi() if (info.issueKinds.size()) m_currentPrefix = info.issueKinds.front().prefix; - updateTableView(); + fetchTable(); } -void IssuesWidget::setTableDto(const Dto::TableInfoDto &dto) +void IssuesWidget::updateTable() { - m_currentTableInfo.emplace(dto); + if (!m_currentTableInfo) + return; // update issues table layout - for now just simple approach TreeModel<> *issuesModel = new TreeModel(this); QStringList columnHeaders; QStringList hiddenColumns; - for (const Dto::ColumnInfoDto &column : dto.columns) { + for (const Dto::ColumnInfoDto &column : m_currentTableInfo->columns) { columnHeaders << column.header.value_or(column.key); if (!column.showByDefault) hiddenColumns << column.key; @@ -511,7 +512,7 @@ void IssuesWidget::updateBasicProjectInfo(std::optional inf button->setCheckable(true); connect(button, &QToolButton::clicked, this, [this, prefix = kind.prefix]{ m_currentPrefix = prefix; - updateTableView(); + fetchTable(); }); m_typesButtonGroup->addButton(button, ++buttonId); m_typesLayout->addWidget(button); @@ -543,20 +544,26 @@ void IssuesWidget::updateBasicProjectInfo(std::optional inf m_versionStart->setCurrentIndex(m_versionDates.count() - 1); } -void IssuesWidget::updateTableView() +void IssuesWidget::fetchTable() { QTC_ASSERT(!m_currentPrefix.isEmpty(), return); // fetch table dto and apply, on done fetch first data for the selected issues - const auto tableHandler = [this](const Dto::TableInfoDto &dto) { setTableDto(dto); }; - const auto setupHandler = [this](TaskTree *) { m_issuesView->showProgressIndicator(); }; + const auto tableHandler = [this](const Dto::TableInfoDto &dto) { + m_currentTableInfo.emplace(dto); + }; + const auto setupHandler = [this](TaskTree *) { + m_totalRowCount = 0; + m_lastRequestedOffset = 0; + m_currentTableInfo.reset(); + m_issuesView->showProgressIndicator(); + }; const auto doneHandler = [this](DoneWith result) { if (result == DoneWith::Error) { m_issuesView->hideProgressIndicator(); return; } // first time lookup... should we cache and maybe represent old data? - m_totalRowCount = 0; - m_lastRequestedOffset = 0; + updateTable(); IssueListSearch search = searchFromUi(); search.computeTotalRowCount = true; fetchIssues(search); From 6ed29d6714114abe4c0c28fa3afebaec62236f39 Mon Sep 17 00:00:00 2001 From: Jarek Kobus Date: Thu, 22 Feb 2024 22:14:38 +0100 Subject: [PATCH 139/243] Axivion: Hide more IssuesWidget functions in private section Move the fetching method closer to the other fetching methods. Change-Id: I2a3b76dd4924a490e58ceab85263ee2ccd96c0e3 Reviewed-by: hjk --- src/plugins/axivion/axivionoutputpane.cpp | 58 +++++++++++------------ 1 file changed, 29 insertions(+), 29 deletions(-) diff --git a/src/plugins/axivion/axivionoutputpane.cpp b/src/plugins/axivion/axivionoutputpane.cpp index 3d43df982ce..b9a0df2229d 100644 --- a/src/plugins/axivion/axivionoutputpane.cpp +++ b/src/plugins/axivion/axivionoutputpane.cpp @@ -229,10 +229,10 @@ class IssuesWidget : public QScrollArea public: explicit IssuesWidget(QWidget *parent = nullptr); void updateUi(); - void updateTable(); - void addIssues(const Dto::IssueTableDto &dto); private: + void updateTable(); + void addIssues(const Dto::IssueTableDto &dto); void onSearchParameterChanged(); void updateBasicProjectInfo(std::optional info); void setFiltersEnabled(bool enabled); @@ -544,33 +544,6 @@ void IssuesWidget::updateBasicProjectInfo(std::optional inf m_versionStart->setCurrentIndex(m_versionDates.count() - 1); } -void IssuesWidget::fetchTable() -{ - QTC_ASSERT(!m_currentPrefix.isEmpty(), return); - // fetch table dto and apply, on done fetch first data for the selected issues - const auto tableHandler = [this](const Dto::TableInfoDto &dto) { - m_currentTableInfo.emplace(dto); - }; - const auto setupHandler = [this](TaskTree *) { - m_totalRowCount = 0; - m_lastRequestedOffset = 0; - m_currentTableInfo.reset(); - m_issuesView->showProgressIndicator(); - }; - const auto doneHandler = [this](DoneWith result) { - if (result == DoneWith::Error) { - m_issuesView->hideProgressIndicator(); - return; - } - // first time lookup... should we cache and maybe represent old data? - updateTable(); - IssueListSearch search = searchFromUi(); - search.computeTotalRowCount = true; - fetchIssues(search); - }; - m_taskTreeRunner.start(tableInfoRecipe(m_currentPrefix, tableHandler), setupHandler, doneHandler); -} - void IssuesWidget::setFiltersEnabled(bool enabled) { m_addedFilter->setEnabled(enabled); @@ -599,6 +572,33 @@ IssueListSearch IssuesWidget::searchFromUi() const return search; } +void IssuesWidget::fetchTable() +{ + QTC_ASSERT(!m_currentPrefix.isEmpty(), return); + // fetch table dto and apply, on done fetch first data for the selected issues + const auto tableHandler = [this](const Dto::TableInfoDto &dto) { + m_currentTableInfo.emplace(dto); + }; + const auto setupHandler = [this](TaskTree *) { + m_totalRowCount = 0; + m_lastRequestedOffset = 0; + m_currentTableInfo.reset(); + m_issuesView->showProgressIndicator(); + }; + const auto doneHandler = [this](DoneWith result) { + if (result == DoneWith::Error) { + m_issuesView->hideProgressIndicator(); + return; + } + // first time lookup... should we cache and maybe represent old data? + updateTable(); + IssueListSearch search = searchFromUi(); + search.computeTotalRowCount = true; + fetchIssues(search); + }; + m_taskTreeRunner.start(tableInfoRecipe(m_currentPrefix, tableHandler), setupHandler, doneHandler); +} + void IssuesWidget::fetchIssues(const IssueListSearch &search) { const auto issuesHandler = [this](const Dto::IssueTableDto &dto) { addIssues(dto); }; From 0a3c0ad1f5a08bd544fe70c204df96566ea23101 Mon Sep 17 00:00:00 2001 From: Christian Stenger Date: Wed, 21 Feb 2024 17:35:18 +0100 Subject: [PATCH 140/243] Axivion: Provide basic sorting for issues table For now this enables just the single column sorting, but this is supposed to be enhanced by multi-column sorting and filtering later on. Change-Id: I7603ae5c412d7a0a669d1ba4ba7e001a059056f4 Reviewed-by: Christian Stenger Reviewed-by: Reviewed-by: Jarek Kobus --- src/plugins/axivion/CMakeLists.txt | 1 + src/plugins/axivion/axivion.qbs | 2 + src/plugins/axivion/axivion.qrc | 4 + src/plugins/axivion/axivionoutputpane.cpp | 17 +++ src/plugins/axivion/axivionplugin.cpp | 3 + src/plugins/axivion/axivionplugin.h | 1 + src/plugins/axivion/images/sortAsc.png | Bin 0 -> 113 bytes src/plugins/axivion/images/sortAsc@2x.png | Bin 0 -> 137 bytes src/plugins/axivion/images/sortDesc.png | Bin 0 -> 118 bytes src/plugins/axivion/images/sortDesc@2x.png | Bin 0 -> 142 bytes src/plugins/axivion/issueheaderview.cpp | 139 +++++++++++++++++++++ src/plugins/axivion/issueheaderview.h | 41 ++++++ 12 files changed, 208 insertions(+) create mode 100644 src/plugins/axivion/images/sortAsc.png create mode 100644 src/plugins/axivion/images/sortAsc@2x.png create mode 100644 src/plugins/axivion/images/sortDesc.png create mode 100644 src/plugins/axivion/images/sortDesc@2x.png create mode 100644 src/plugins/axivion/issueheaderview.cpp create mode 100644 src/plugins/axivion/issueheaderview.h diff --git a/src/plugins/axivion/CMakeLists.txt b/src/plugins/axivion/CMakeLists.txt index a71b984520f..c3e2f5e7eaa 100644 --- a/src/plugins/axivion/CMakeLists.txt +++ b/src/plugins/axivion/CMakeLists.txt @@ -13,4 +13,5 @@ add_qtc_plugin(Axivion dashboard/dto.cpp dashboard/dto.h dashboard/concat.cpp dashboard/concat.h dashboard/error.h dashboard/error.cpp + issueheaderview.cpp issueheaderview.h ) diff --git a/src/plugins/axivion/axivion.qbs b/src/plugins/axivion/axivion.qbs index 7b8034c26c4..70188feb3e4 100644 --- a/src/plugins/axivion/axivion.qbs +++ b/src/plugins/axivion/axivion.qbs @@ -25,6 +25,8 @@ QtcPlugin { "axiviontr.h", "credentialquery.h", "credentialquery.cpp", + "issueheaderview.cpp", + "issueheaderview.h", ] cpp.includePaths: base.concat(["."]) // needed for the generated stuff below diff --git a/src/plugins/axivion/axivion.qrc b/src/plugins/axivion/axivion.qrc index c0d56f8f7b0..fa3ad146d37 100644 --- a/src/plugins/axivion/axivion.qrc +++ b/src/plugins/axivion/axivion.qrc @@ -14,5 +14,9 @@ images/button-mv@2x.png images/button-sv.png images/button-sv@2x.png + images/sortAsc.png + images/sortAsc@2x.png + images/sortDesc.png + images/sortDesc@2x.png diff --git a/src/plugins/axivion/axivionoutputpane.cpp b/src/plugins/axivion/axivionoutputpane.cpp index b9a0df2229d..5be8521b67f 100644 --- a/src/plugins/axivion/axivionoutputpane.cpp +++ b/src/plugins/axivion/axivionoutputpane.cpp @@ -6,6 +6,7 @@ #include "axivionplugin.h" #include "axiviontr.h" #include "dashboard/dto.h" +#include "issueheaderview.h" #include #include @@ -254,6 +255,7 @@ private: QLineEdit *m_pathGlobFilter = nullptr; // FancyLineEdit instead? QLabel *m_totalRows = nullptr; BaseTreeView *m_issuesView = nullptr; + IssueHeaderView *m_headerView = nullptr; TreeModel<> *m_issuesModel = nullptr; int m_totalRowCount = 0; int m_lastRequestedOffset = 0; @@ -312,6 +314,10 @@ IssuesWidget::IssuesWidget(QWidget *parent) connect(m_pathGlobFilter, &QLineEdit::textEdited, this, &IssuesWidget::onSearchParameterChanged); m_issuesView = new BaseTreeView(this); + m_headerView = new IssueHeaderView(this); + connect(m_headerView, &IssueHeaderView::sortTriggered, + this, &IssuesWidget::onSearchParameterChanged); + m_issuesView->setHeader(m_headerView); m_issuesView->setHorizontalScrollBarPolicy(Qt::ScrollBarAsNeeded); m_issuesView->enableColumnHiding(); m_issuesModel = new TreeModel(this); @@ -372,10 +378,12 @@ void IssuesWidget::updateTable() TreeModel<> *issuesModel = new TreeModel(this); QStringList columnHeaders; QStringList hiddenColumns; + QList sortableColumns; for (const Dto::ColumnInfoDto &column : m_currentTableInfo->columns) { columnHeaders << column.header.value_or(column.key); if (!column.showByDefault) hiddenColumns << column.key; + sortableColumns << column.canSort; } m_addedFilter->setText("0"); m_removedFilter->setText("0"); @@ -386,10 +394,12 @@ void IssuesWidget::updateTable() auto oldModel = m_issuesModel; m_issuesModel = issuesModel; m_issuesView->setModel(issuesModel); + m_headerView->setSortableColumns(sortableColumns); delete oldModel; int counter = 0; for (const QString &header : std::as_const(columnHeaders)) m_issuesView->setColumnHidden(counter++, hiddenColumns.contains(header)); + m_issuesView->header()->resizeSections(QHeaderView::ResizeToContents); } static Links linksForIssue(const std::map &issueRow) @@ -569,6 +579,13 @@ IssueListSearch IssuesWidget::searchFromUi() const search.state = "added"; else if (m_removedFilter->isChecked()) search.state = "removed"; + if (int column = m_headerView->currentSortColumn() != -1) { + QTC_ASSERT(m_currentTableInfo, return search); + QTC_ASSERT((ulong)column < m_currentTableInfo->columns.size(), return search); + search.sort = m_currentTableInfo->columns.at(m_headerView->currentSortColumn()).key + + (m_headerView->currentSortOrder() == SortOrder::Ascending ? " asc" : " desc"); + } + return search; } diff --git a/src/plugins/axivion/axivionplugin.cpp b/src/plugins/axivion/axivionplugin.cpp index b5c6634c339..558f7909744 100644 --- a/src/plugins/axivion/axivionplugin.cpp +++ b/src/plugins/axivion/axivionplugin.cpp @@ -171,6 +171,9 @@ QString IssueListSearch::toQuery() const result.append(QString("&state=%1").arg(state)); if (computeTotalRowCount) result.append("&computeTotalRowCount=true"); + if (!sort.isEmpty()) + result.append(QString("&sort=%1").arg( + QString::fromUtf8(QUrl::toPercentEncoding(sort)))); return result; } diff --git a/src/plugins/axivion/axivionplugin.h b/src/plugins/axivion/axivionplugin.h index 1d2ebe12129..c60aad6e9e9 100644 --- a/src/plugins/axivion/axivionplugin.h +++ b/src/plugins/axivion/axivionplugin.h @@ -31,6 +31,7 @@ struct IssueListSearch QString versionEnd; QString owner; QString filter_path; + QString sort; int offset = 0; int limit = 150; bool computeTotalRowCount = false; diff --git a/src/plugins/axivion/images/sortAsc.png b/src/plugins/axivion/images/sortAsc.png new file mode 100644 index 0000000000000000000000000000000000000000..c907297279033bd84a2e985e9121832fc4eb74cb GIT binary patch literal 113 zcmeAS@N?(olHy`uVBq!ia0y~yU=RRdCT0c(hNQXTpBNYzcmjMvTp1V`%FD~^>+Apj z|34>nV+jKTgMz1vV+elq|_4WV% z|DTh(v4nwv!NSwUF+?If`3FBM&xxM;uK~ySD>WW7T2HxnfFtowa>5FB<2nO_6U~zR o5)wBK_OP+BxtTDx>o7CSNPaJPSyV=xfq{X+)78&qol`;+0EOfymjD0& literal 0 HcmV?d00001 diff --git a/src/plugins/axivion/images/sortDesc.png b/src/plugins/axivion/images/sortDesc.png new file mode 100644 index 0000000000000000000000000000000000000000..a92d018d4e191790d5fc6a4bd950a64ae379509d GIT binary patch literal 118 zcmeAS@N?(olHy`uVBq!ia0y~yU=RRd7G?$phPQVgfdu#id_r6q7#Qm7>l+#xIyyT3 z|NlQ#%sQWefkDaB#W92AM?zx80iJX=HqnkLjKU$ki#awWG5Gh%e|+_` S^AiID1B0ilpUXO@geCyWry=qH literal 0 HcmV?d00001 diff --git a/src/plugins/axivion/images/sortDesc@2x.png b/src/plugins/axivion/images/sortDesc@2x.png new file mode 100644 index 0000000000000000000000000000000000000000..9991ff2955a1a2b8f4c5592039c5b611d0713ef2 GIT binary patch literal 142 zcmeAS@N?(olHy`uVBq!ia0y~yU{C;I7G?$phQ^Te;|vT8`~f~8t_%ze_4V})4GkR~ z9smFTpDJdZ&%nT7<>}%WqA@YKz>%3}F;j_`D_+KvWe7YEjbM;X>JXg%NwXE46P tu#7?N0Z%Z)_G=BCXJz}8Ty~2vw3*azKKJ$L69xtb22WQ%mvv4FO#lj + +#include +#include + +namespace Axivion::Internal { + +constexpr int ICON_SIZE = 16; + +static QIcon iconForSorted(SortOrder order) +{ + const Utils::Icon UNSORTED( + {{":/axivion/images/sortAsc.png", Utils::Theme::PaletteButtonTextDisabled}, + {":/axivion/images/sortDesc.png", Utils::Theme::PaletteButtonTextDisabled}}); + const Utils::Icon SORT_ASC( + {{":/axivion/images/sortAsc.png", Utils::Theme::PaletteButtonText}, + {":/axivion/images/sortDesc.png", Utils::Theme::PaletteButtonTextDisabled}}); + const Utils::Icon SORT_DESC( + {{":/axivion/images/sortAsc.png", Utils::Theme::PaletteButtonTextDisabled}, + {":/axivion/images/sortDesc.png", Utils::Theme::PaletteButtonText}}); + static const QIcon unsorted = UNSORTED.icon(); + static const QIcon sortedAsc = SORT_ASC.icon(); + static const QIcon sortedDesc = SORT_DESC.icon(); + + switch (order) { + case SortOrder::None: + return unsorted; + case SortOrder::Ascending: + return sortedAsc; + case SortOrder::Descending: + return sortedDesc; + } + return {}; +} + +void IssueHeaderView::setSortableColumns(const QList &sortable) +{ + m_sortableColumns = sortable; + int oldIndex = m_currentSortIndex; + m_currentSortIndex = -1; + m_currentSortOrder = SortOrder::None; + if (oldIndex != -1) + headerDataChanged(Qt::Horizontal, oldIndex, oldIndex); +} + +int IssueHeaderView::currentSortColumn() const +{ + return m_currentSortOrder == SortOrder::None ? -1 : m_currentSortIndex; +} + +void IssueHeaderView::mousePressEvent(QMouseEvent *event) +{ + if (event->button() == Qt::LeftButton) { + const QPoint position = event->position().toPoint(); + const int y = position.y(); + if (y > 1 && y < height() - 2) { // TODO improve + const int pos = position.x(); + const int logical = logicalIndexAt(pos); + const int end = sectionPosition(logical) + sectionSize(logical); + const int start = end - ICON_SIZE - 2; + m_maybeToggleSort = start < pos && end > pos; + } + } + QHeaderView::mousePressEvent(event); +} + +void IssueHeaderView::mouseReleaseEvent(QMouseEvent *event) +{ + bool dontSkip = !m_dragging && m_maybeToggleSort; + m_dragging = false; + m_maybeToggleSort = false; + + if (dontSkip) { + const QPoint position = event->position().toPoint(); + const int y = position.y(); + const int logical = logicalIndexAt(position.x()); + if (logical > -1 && logical < m_sortableColumns.size()) { + if (m_sortableColumns.at(logical)) { // ignore non-sortable + if (y < height() / 2) // TODO improve + onToggleSort(logical, SortOrder::Ascending); + else + onToggleSort(logical, SortOrder::Descending); + } + } + } + QHeaderView::mouseReleaseEvent(event); +} + +void IssueHeaderView::mouseMoveEvent(QMouseEvent *event) +{ + if (event->button() == Qt::LeftButton) + m_dragging = true; + QHeaderView::mouseMoveEvent(event); +} + +void IssueHeaderView::onToggleSort(int index, SortOrder order) +{ + if (m_currentSortIndex == index) + m_currentSortOrder = (order == m_currentSortOrder) ? SortOrder::None : order; + else + m_currentSortOrder = order; + + int oldIndex = m_currentSortIndex; + m_currentSortIndex = index; + if (oldIndex != -1) + headerDataChanged(Qt::Horizontal, oldIndex, oldIndex); + headerDataChanged(Qt::Horizontal, index, index); + emit sortTriggered(); +} + +QSize IssueHeaderView::sectionSizeFromContents(int logicalIndex) const +{ + QSize size = QHeaderView::sectionSizeFromContents(logicalIndex); + // add icon size and margin (2) + return QSize{size.width() + ICON_SIZE + 2, qMax(size.height(), ICON_SIZE)}; +} + +void IssueHeaderView::paintSection(QPainter *painter, const QRect &rect, int logicalIndex) const +{ + painter->save(); + QHeaderView::paintSection(painter, rect, logicalIndex); + painter->restore(); + if (logicalIndex < 0 || logicalIndex >= m_sortableColumns.size()) + return; + if (!m_sortableColumns.at(logicalIndex)) + return; + + const QIcon icon = iconForSorted(logicalIndex == m_currentSortIndex ? m_currentSortOrder : SortOrder::None); + const int offset = qMax((rect.height() - ICON_SIZE), 0) / 2; + const QRect iconRect(rect.left() + rect.width() - ICON_SIZE - 2, offset, ICON_SIZE, ICON_SIZE); + icon.paint(painter, iconRect); +} + +} // namespace Axivion::Internal diff --git a/src/plugins/axivion/issueheaderview.h b/src/plugins/axivion/issueheaderview.h new file mode 100644 index 00000000000..3d6f271a762 --- /dev/null +++ b/src/plugins/axivion/issueheaderview.h @@ -0,0 +1,41 @@ +// Copyright (C) 2023 The Qt Company Ltd. +// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only WITH Qt-GPL-exception-1.0 + +#pragma once + +#include +#include + +namespace Axivion::Internal { + +enum class SortOrder { None, Ascending, Descending }; + +class IssueHeaderView : public QHeaderView +{ + Q_OBJECT +public: + explicit IssueHeaderView(QWidget *parent = nullptr) : QHeaderView(Qt::Horizontal, parent) {} + void setSortableColumns(const QList &sortable); + + SortOrder currentSortOrder() const { return m_currentSortOrder; } + int currentSortColumn() const; +signals: + void sortTriggered(); + +protected: + void paintSection(QPainter *painter, const QRect &rect, int logicalIndex) const override; + QSize sectionSizeFromContents(int logicalIndex) const override; + void mousePressEvent(QMouseEvent *event) override; + void mouseReleaseEvent(QMouseEvent *event) override; + void mouseMoveEvent(QMouseEvent *event) override; + +private: + void onToggleSort(int index, SortOrder order); + bool m_dragging = false; + bool m_maybeToggleSort = false; + int m_currentSortIndex = -1; + SortOrder m_currentSortOrder = SortOrder::None; + QList m_sortableColumns; +}; + +} // namespace Axivion::Internal From 97ebd272538c23672c1f925ec4484cdbdb4235d3 Mon Sep 17 00:00:00 2001 From: Jarek Kobus Date: Thu, 22 Feb 2024 18:22:10 +0100 Subject: [PATCH 141/243] QmlJsPluginDumper: Ensure we don't take results from the canceled futures Amends 91c1c244a1256b2dc9979edb1a3ce83c28ef5636 Fixes: QTCREATORBUG-30424 Change-Id: Ie0bddb79362945a040c6cb95edf37fbec3ed064d Reviewed-by: hjk Reviewed-by: --- src/libs/qmljs/qmljsplugindumper.cpp | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/src/libs/qmljs/qmljsplugindumper.cpp b/src/libs/qmljs/qmljsplugindumper.cpp index b2591fbf0ab..36f2cd802db 100644 --- a/src/libs/qmljs/qmljsplugindumper.cpp +++ b/src/libs/qmljs/qmljsplugindumper.cpp @@ -569,6 +569,9 @@ void PluginDumper::loadQmltypesFile(const FilePaths &qmltypesFilePaths, Utils::onFinished(loadQmlTypeDescription(qmltypesFilePaths), this, [this, qmltypesFilePaths, libraryPath, libraryInfo] (const QFuture &typesFuture) { + if (typesFuture.isCanceled() || typesFuture.resultCount() == 0) + return; + PluginDumper::QmlTypeDescription typesResult = typesFuture.result(); if (!typesResult.dependencies.isEmpty()) { @@ -576,6 +579,9 @@ void PluginDumper::loadQmltypesFile(const FilePaths &qmltypesFilePaths, QSharedPointer>()), this, [typesResult, libraryInfo, libraryPath, this] (const QFuture &loadFuture) { + if (loadFuture.isCanceled() || loadFuture.resultCount() == 0) + return; + PluginDumper::DependencyInfo loadResult = loadFuture.result(); QStringList errors = typesResult.errors; QStringList warnings = typesResult.errors; From 55c12d022c9388a635f2a955746156eec1d5d7e2 Mon Sep 17 00:00:00 2001 From: Jarek Kobus Date: Thu, 22 Feb 2024 23:39:56 +0100 Subject: [PATCH 142/243] Expected: Add a test ensuring the default c'tor has value When docs aren't easily available, let's have a test for it. Change-Id: Ic9cec669cc93a38e79b68ddec7cfcc5bccae5de5 Reviewed-by: Reviewed-by: Marcus Tillmanns --- tests/auto/utils/expected/tst_expected.cpp | 11 +++++++++++ 1 file changed, 11 insertions(+) diff --git a/tests/auto/utils/expected/tst_expected.cpp b/tests/auto/utils/expected/tst_expected.cpp index ae084036bdc..073f6b7ce7e 100644 --- a/tests/auto/utils/expected/tst_expected.cpp +++ b/tests/auto/utils/expected/tst_expected.cpp @@ -51,6 +51,17 @@ private slots: QVERIFY(e1 == e2); QVERIFY(!(e1 != e2)); } + + void defaultConstructorHasValue() + { + expected_str e1; + QVERIFY(e1.has_value()); + QVERIFY(e1->isEmpty()); + + expected_str e2{}; + QVERIFY(e2.has_value()); + QVERIFY(e2->isEmpty()); + } }; QTEST_GUILESS_MAIN(tst_expected) From b7a8ee92beeddf765d5e6000b9f8188ca8541038 Mon Sep 17 00:00:00 2001 From: Cristian Adam Date: Wed, 21 Feb 2024 16:31:46 +0100 Subject: [PATCH 143/243] Core: Mention Ctrl+Shift+K into the hide menubar messagebox This way the user can trigger the "Show Menu Bar" action when the Ctrl+Alt+M doesn't work. Task-number: QTCREATORBUG-30114 Change-Id: I4e1d14b7bf7554ce1a262c4b1d2671f8d0b81b85 Reviewed-by: Leena Miettinen Reviewed-by: --- src/plugins/coreplugin/icore.cpp | 34 ++++++++++++++++++++++++-------- 1 file changed, 26 insertions(+), 8 deletions(-) diff --git a/src/plugins/coreplugin/icore.cpp b/src/plugins/coreplugin/icore.cpp index ef11fd6d161..54462f30512 100644 --- a/src/plugins/coreplugin/icore.cpp +++ b/src/plugins/coreplugin/icore.cpp @@ -1971,14 +1971,32 @@ void ICorePrivate::registerDefaultActions() toggleMenubarAction.addToContainer(Constants::M_VIEW, Constants::G_VIEW_VIEWS); toggleMenubarAction.addOnToggled(this, [](bool visible) { if (!visible) { - const QString keys = ActionManager::command(Constants::TOGGLE_MENUBAR) - ->keySequence().toString(QKeySequence::NativeText); - 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.") - .arg(keys), - Key("ToogleMenuBarHint")); + auto keySequenceAndText = [](const Utils::Id &actionName) { + const auto command = ActionManager::command(actionName); + + const QString keySequence = command->keySequence().toString( + QKeySequence::NativeText); + const QString text = command->action()->text(); + + return QPair(keySequence, text); + }; + + auto [menuBarKeys, menuBarText] = keySequenceAndText(Constants::TOGGLE_MENUBAR); + auto [actionsFromMenuKeys, actionsFromMenuText] = keySequenceAndText( + "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." + "

" + "Or, trigger the \"%2\" action from the \"%3\" locator filter (%4).") + .arg(menuBarKeys) + .arg(menuBarText) + .arg(actionsFromMenuText) + .arg(actionsFromMenuKeys), + Key("ToogleMenuBarHint")); } globalMenuBar()->setVisible(visible); }); From 787c2ccee9b003c580877b150be07e7f6b5db414 Mon Sep 17 00:00:00 2001 From: David Schulz Date: Fri, 9 Feb 2024 06:33:25 +0100 Subject: [PATCH 144/243] Debugger: ensure final new line after debug messages collected by cdb Since recently cdb seems to report messages without a final new line. Change-Id: I6b15d6c5668b7a4bec207d56d86da5a0afa77cb4 Reviewed-by: Christian Stenger --- src/plugins/debugger/cdb/cdbengine.cpp | 8 +++++--- 1 file changed, 5 insertions(+), 3 deletions(-) diff --git a/src/plugins/debugger/cdb/cdbengine.cpp b/src/plugins/debugger/cdb/cdbengine.cpp index d292028050a..c7e20aae980 100644 --- a/src/plugins/debugger/cdb/cdbengine.cpp +++ b/src/plugins/debugger/cdb/cdbengine.cpp @@ -2096,9 +2096,11 @@ void CdbEngine::handleExtensionMessage(char t, int token, const QString &what, c } if (what == "debuggee_output") { - const QByteArray decoded = QByteArray::fromHex(message.toUtf8()); - showMessage(QString::fromUtf16(reinterpret_cast(decoded.data()), decoded.size() / 2), - AppOutput); + const QByteArray encoded = QByteArray::fromHex(message.toUtf8()); + const QString message = QString::fromUtf16(reinterpret_cast( + encoded.data()), + encoded.size() / 2); + showMessage(message.endsWith('\n') ? message : message + '\n', AppOutput); return; } From 9f7d8b06b26fc87e5f588519e53d39a0ed790142 Mon Sep 17 00:00:00 2001 From: Leena Miettinen Date: Fri, 23 Feb 2024 11:42:10 +0100 Subject: [PATCH 145/243] Doc: Mention using CMake presets in "Share project settings" You cannot use a .shared file to share CMake project settings. Change-Id: I605ead2f42ed012da789c1eef3a4e6a51de62243 Reviewed-by: Cristian Adam --- .../creator-only/creator-projects-settings-sharing.qdoc | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/doc/qtcreator/src/projects/creator-only/creator-projects-settings-sharing.qdoc b/doc/qtcreator/src/projects/creator-only/creator-projects-settings-sharing.qdoc index 161874f4b59..3e48923ad36 100644 --- a/doc/qtcreator/src/projects/creator-only/creator-projects-settings-sharing.qdoc +++ b/doc/qtcreator/src/projects/creator-only/creator-projects-settings-sharing.qdoc @@ -1,4 +1,4 @@ -// Copyright (C) 2023 The Qt Company Ltd. +// Copyright (C) 2024 The Qt Company Ltd. // SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GFDL-1.3-no-invariants-only // ********************************************************************** @@ -20,6 +20,8 @@ has the same XML structure as a \e {.user} file, but only has the settings to share. + \note Use \l{CMake Presets} to share CMake project settings. + \section1 Create a shared settings file The easiest way to create a \e {.shared} file is to copy settings from the @@ -70,5 +72,5 @@ a permanent sticky setting that was created just because you wanted to try something out. - \sa {Configuring Projects} + \sa {Configuring Projects}, {CMake Presets} */ From 8feb31b2ac194af3b5da09e6c1636a7953b40ffb Mon Sep 17 00:00:00 2001 From: David Schulz Date: Fri, 23 Feb 2024 12:36:11 +0100 Subject: [PATCH 146/243] TextEditor: bound increase and decreaseFontZoom to a 10% grid This allows to get back to a 100% font zoom with the keyboard shortcuts by zooming to an odd zoom factor by other means. Change-Id: Ie90853367b17c207e9c47fc108b8d6f451e0f838 Reviewed-by: Marcus Tillmanns --- src/plugins/texteditor/texteditor.cpp | 12 +++++++ src/plugins/texteditor/texteditor.h | 2 ++ .../texteditor/texteditoractionhandler.cpp | 4 +-- src/plugins/texteditor/texteditorsettings.cpp | 31 +++++++++++++------ src/plugins/texteditor/texteditorsettings.h | 2 ++ 5 files changed, 40 insertions(+), 11 deletions(-) diff --git a/src/plugins/texteditor/texteditor.cpp b/src/plugins/texteditor/texteditor.cpp index c8ef69c63ef..70239b286e0 100644 --- a/src/plugins/texteditor/texteditor.cpp +++ b/src/plugins/texteditor/texteditor.cpp @@ -6891,6 +6891,18 @@ static void showZoomIndicator(QWidget *editor, const int newZoom) Utils::FadingIndicator::SmallText); } +void TextEditorWidget::increaseFontZoom() +{ + d->clearVisibleFoldedBlock(); + showZoomIndicator(this, TextEditorSettings::increaseFontZoom()); +} + +void TextEditorWidget::decreaseFontZoom() +{ + d->clearVisibleFoldedBlock(); + showZoomIndicator(this, TextEditorSettings::decreaseFontZoom()); +} + void TextEditorWidget::zoomF(float delta) { d->clearVisibleFoldedBlock(); diff --git a/src/plugins/texteditor/texteditor.h b/src/plugins/texteditor/texteditor.h index a2a1aafb2b8..33b8cb84f09 100644 --- a/src/plugins/texteditor/texteditor.h +++ b/src/plugins/texteditor/texteditor.h @@ -349,6 +349,8 @@ public: void pasteWithoutFormat(); void switchUtf8bom(); + void increaseFontZoom(); + void decreaseFontZoom(); void zoomF(float delta); void zoomReset(); diff --git a/src/plugins/texteditor/texteditoractionhandler.cpp b/src/plugins/texteditor/texteditoractionhandler.cpp index 2e48670bf4d..240e8498ed1 100644 --- a/src/plugins/texteditor/texteditoractionhandler.cpp +++ b/src/plugins/texteditor/texteditoractionhandler.cpp @@ -394,11 +394,11 @@ void TextEditorActionHandlerPrivate::createActions() QKeySequence(), G_EDIT_COLLAPSING, advancedEditMenu); registerAction(INCREASE_FONT_SIZE, - [] (TextEditorWidget *w) { w->zoomF(1.f); }, false, Tr::tr("Increase Font Size"), + [] (TextEditorWidget *w) { w->increaseFontZoom(); }, false, Tr::tr("Increase Font Size"), QKeySequence(Tr::tr("Ctrl++")), G_EDIT_FONT, advancedEditMenu); registerAction(DECREASE_FONT_SIZE, - [] (TextEditorWidget *w) { w->zoomF(-1.f); }, false, Tr::tr("Decrease Font Size"), + [] (TextEditorWidget *w) { w->decreaseFontZoom(); }, false, Tr::tr("Decrease Font Size"), QKeySequence(Tr::tr("Ctrl+-")), G_EDIT_FONT, advancedEditMenu); registerAction(RESET_FONT_SIZE, diff --git a/src/plugins/texteditor/texteditorsettings.cpp b/src/plugins/texteditor/texteditorsettings.cpp index 1d7dd89386a..811852b8a84 100644 --- a/src/plugins/texteditor/texteditorsettings.cpp +++ b/src/plugins/texteditor/texteditorsettings.cpp @@ -560,20 +560,33 @@ Utils::Id TextEditorSettings::languageId(const QString &mimeType) return d->m_mimeTypeToLanguage.value(mimeType); } -static void setFontZoom(int zoom) +static int setFontZoom(int zoom) { - d->m_fontSettings.setFontZoom(zoom); - d->m_fontSettings.toSettings(Core::ICore::settings()); - emit textEditorSettings().fontSettingsChanged(d->m_fontSettings); + zoom = qMax(10, zoom); + if (d->m_fontSettings.fontZoom() != zoom) { + d->m_fontSettings.setFontZoom(zoom); + d->m_fontSettings.toSettings(Core::ICore::settings()); + emit textEditorSettings().fontSettingsChanged(d->m_fontSettings); + } + return zoom; +} + +int TextEditorSettings::increaseFontZoom() +{ + const int previousZoom = d->m_fontSettings.fontZoom(); + return setFontZoom(previousZoom + 10 - previousZoom % 10); +} + +int TextEditorSettings::decreaseFontZoom() +{ + const int previousZoom = d->m_fontSettings.fontZoom(); + const int delta = previousZoom % 10; + return setFontZoom(previousZoom - (delta == 0 ? 10 : delta)); } int TextEditorSettings::increaseFontZoom(int step) { - const int previousZoom = d->m_fontSettings.fontZoom(); - const int newZoom = qMax(10, previousZoom + step); - if (newZoom != previousZoom) - setFontZoom(newZoom); - return newZoom; + return setFontZoom(d->m_fontSettings.fontZoom() + step); } void TextEditorSettings::resetFontZoom() diff --git a/src/plugins/texteditor/texteditorsettings.h b/src/plugins/texteditor/texteditorsettings.h index 88dd057608f..1599fcbba5a 100644 --- a/src/plugins/texteditor/texteditorsettings.h +++ b/src/plugins/texteditor/texteditorsettings.h @@ -76,6 +76,8 @@ public: static void registerMimeTypeForLanguageId(const char *mimeType, Utils::Id languageId); static Utils::Id languageId(const QString &mimeType); + static int increaseFontZoom(); + static int decreaseFontZoom(); static int increaseFontZoom(int step); static void resetFontZoom(); From a9c2be10713fc4cba647c91d50cc6d9e4d1d8136 Mon Sep 17 00:00:00 2001 From: Eike Ziller Date: Fri, 23 Feb 2024 11:49:23 +0100 Subject: [PATCH 147/243] Projects: Fix misc settings widgets if vanished targets are shown When vanished targets where shown in Projects, clicking on the project specific settings showed a blank page. There were hardcoded indices for the target and the misc settings. Get the right child for the index directly instead. Change-Id: I725d470ad04f8a227c91938efada76a757a7442c Reviewed-by: Christian Kandeler --- src/plugins/projectexplorer/projectwindow.cpp | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/src/plugins/projectexplorer/projectwindow.cpp b/src/plugins/projectexplorer/projectwindow.cpp index c0577c5c52b..66dca5ecd56 100644 --- a/src/plugins/projectexplorer/projectwindow.cpp +++ b/src/plugins/projectexplorer/projectwindow.cpp @@ -527,11 +527,11 @@ public: } case PanelWidgetRole: - case ActiveItemRole: - if (m_currentChildIndex == 0) - return m_targetsItem->data(column, role); - if (m_currentChildIndex == 1) - return m_miscItem->data(column, role); + case ActiveItemRole: { + TreeItem *child = childAt(m_currentChildIndex); + if (child) + return child->data(column, role); + } } return {}; } From 11c1e071d7ceee7e2bd3457a05814d7c82ca2584 Mon Sep 17 00:00:00 2001 From: Leena Miettinen Date: Wed, 21 Feb 2024 16:59:07 +0100 Subject: [PATCH 148/243] Doc: Update the docs about Python development Task-number: QTCREATORBUG-30209 Change-Id: I3023fb6b9005092ecd76f62774942f366e1bd7d9 Reviewed-by: David Schulz --- dist/changelog/changes-13.0.0.md | 5 +- ...w-project-qt-for-python-kit-selection.webp | Bin 0 -> 5796 bytes ...new-qt-for-python-app-project-details.webp | Bin 0 -> 4374 bytes ...on-app-qt-quick-empty-project-details.webp | Bin 7176 -> 0 bytes ...or-python-app-widgets-project-details.webp | Bin 7464 -> 0 bytes .../images/qtcreator-python-interpreters.webp | Bin 7062 -> 5362 bytes .../images/qtcreator-python-run-settings.png | Bin 8396 -> 0 bytes .../images/qtcreator-python-run-settings.webp | Bin 0 -> 5836 bytes .../python/creator-python-development.qdoc | 62 +++++++----------- .../python/creator-python-run-settings.qdoc | 4 +- ...utorial-python-application-qt-widgets.qdoc | 27 ++++---- ...r-tutorial-python-application-qtquick.qdoc | 32 ++++----- 12 files changed, 57 insertions(+), 73 deletions(-) create mode 100644 doc/qtcreator/images/qtcreator-new-project-qt-for-python-kit-selection.webp create mode 100644 doc/qtcreator/images/qtcreator-new-qt-for-python-app-project-details.webp delete mode 100644 doc/qtcreator/images/qtcreator-new-qt-for-python-app-qt-quick-empty-project-details.webp delete mode 100644 doc/qtcreator/images/qtcreator-new-qt-for-python-app-widgets-project-details.webp delete mode 100644 doc/qtcreator/images/qtcreator-python-run-settings.png create mode 100644 doc/qtcreator/images/qtcreator-python-run-settings.webp diff --git a/dist/changelog/changes-13.0.0.md b/dist/changelog/changes-13.0.0.md index f1199018f8b..b8aa6aa1160 100644 --- a/dist/changelog/changes-13.0.0.md +++ b/dist/changelog/changes-13.0.0.md @@ -169,12 +169,13 @@ Projects * Added `Generate Kit` to the Python interpreter preferences for generating a Python kit with this interpreter - ([Documentation](https://doc-snapshots.qt.io/qtcreator-13.0/creator-python-development.html#create-kits-for-python-interpreters)) -* Added the target setup page when loading unconfigured Python projects +* Added the `Kit Selection` page for creating and opening Python projects * Added a `requirements.txt` file to the application wizard * Fixed that the same Python interpreter could be auto-detected multiple times under different names + ([Documentation](https://doc-snapshots.qt.io/qtcreator-13.0/creator-python-development.html)) + Debugging --------- diff --git a/doc/qtcreator/images/qtcreator-new-project-qt-for-python-kit-selection.webp b/doc/qtcreator/images/qtcreator-new-project-qt-for-python-kit-selection.webp new file mode 100644 index 0000000000000000000000000000000000000000..f7c3be17d5b7658dc6ca0d7490ff45a10eb40a0a GIT binary patch literal 5796 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 literal 0 HcmV?d00001 diff --git a/doc/qtcreator/images/qtcreator-new-qt-for-python-app-project-details.webp b/doc/qtcreator/images/qtcreator-new-qt-for-python-app-project-details.webp new file mode 100644 index 0000000000000000000000000000000000000000..14494a04d374d609a6341b4a83fc49e101488a35 GIT binary patch literal 4374 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 I1{3%g0XACU`2YX_ diff --git a/doc/qtcreator/images/qtcreator-new-qt-for-python-app-widgets-project-details.webp b/doc/qtcreator/images/qtcreator-new-qt-for-python-app-widgets-project-details.webp deleted file mode 100644 index 3890e8e75bad09b22ea44c443c7fa9aca68dc92f..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 7464 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 diff --git a/doc/qtcreator/images/qtcreator-python-interpreters.webp b/doc/qtcreator/images/qtcreator-python-interpreters.webp index 597b99e720d2d39f85eb77cc21912a95391a76bb..b5027b0a0d481060fc0c7a6205d727071e066192 100644 GIT binary patch literal 5362 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 U?Q|`dyp;HuEhTw;ce)`j0P~z@9{>OV literal 7062 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 A;{X5v diff --git a/doc/qtcreator/images/qtcreator-python-run-settings.webp b/doc/qtcreator/images/qtcreator-python-run-settings.webp new file mode 100644 index 0000000000000000000000000000000000000000..69f2d7676d6295e9dfe7807000afdbd4936d9a91 GIT binary patch literal 5836 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 F1OU + \uicontrol {Build & Run} set the Python version to use. - \image qtcreator-new-qt-for-python-app-widgets-project-details.webp {Define Project Details dialog} + The \l {Edit Mode}{Edit mode} toolbar shows the current Python version. - You can see the current Python interpreter on the \uicontrol Edit mode - toolbar. + \image qtcreator-python-interpreter-edit-mode.webp {Python version on the Edit mode toolbar} - \image qtcreator-python-interpreter-edit-mode.webp {Python interpreter on the Edit mode toolbar} + To use another Python version, activate another kit for the project. - You can change the interpreter to use for a particular project in - \uicontrol Projects > \uicontrol Run > \uicontrol Interpreter. + \section1 Create kits for Python - \image qtcreator-python-run-settings.png {Python run settings} - - To see the available interpreters and choose another interpreter, select the - current interpreter, and then select \uicontrol {Manage Python Interpreters}. - Or, select \preferences > \uicontrol Python > \uicontrol Interpreters. + \QC automatically adds all Python versions it can find to the list of + Python versions in \preferences > \uicontrol Python > \uicontrol Interpreters. + It generates kits for the global Python versions that are not inside a + virtual environment. \image qtcreator-python-interpreters.webp {Python Interpreters in Preferences} - You can add and remove interpreters and clean up references to interpreters - that you uninstalled, but that still appear in the list. + You can add and remove Python versions and clean up references to Python + versions that you uninstalled, but that still appear in the list. - To use the selected Python interpreter by default, select - \uicontrol {Make Default}. - - \section1 Create a virtual environment - - To use a clean \l{https://docs.python.org/3/library/venv.html}{Python} - virtual environment (\c venv) that is independent of your global Python - installation for a Qt for Python project, select the - \uicontrol {Create new virtual environment} check box in the project wizard. - Set the directory where to create the environment in - \uicontrol {Path to virtual environment}. - - \section1 Create kits for Python interpreters - - \QC automatically adds all Python interpreters it can find to the list of - interpreters in \preferences > \uicontrol Python > \uicontrol Interpreters. - It generates \l{kits-tab}{kits} for the global Python interpreters that are - not inside a virtual environment. + To use the selected Python version when opening \c {.py} files that don't + belong to a project, select \uicontrol {Make Default}. To use a virtual environment as a kit, select it in \uicontrol Interpreters, and then select \uicontrol {Generate Kit}. @@ -133,5 +114,6 @@ the file, select \uicontrol {REPL Import *}. \sa {Creating a Qt for Python Application with Qt Widgets}, - {Creating a Qt for Python Application with Qt Quick} + {Creating a Qt for Python Application with Qt Quick}, + {Activate kits for a project} */ diff --git a/doc/qtcreator/src/python/creator-python-run-settings.qdoc b/doc/qtcreator/src/python/creator-python-run-settings.qdoc index 3d5d5eab27b..6c6c3b4fe2b 100644 --- a/doc/qtcreator/src/python/creator-python-run-settings.qdoc +++ b/doc/qtcreator/src/python/creator-python-run-settings.qdoc @@ -35,7 +35,7 @@ you select for a kit in \uicontrol Projects > \uicontrol {Build & Run} > \uicontrol Run > \uicontrol {Run Settings}. - \image qtcreator-python-run-settings.png {Python run settings} + \image qtcreator-python-run-settings.webp {Python run settings} The following table summarizes the settings for running Qt for Python applications. @@ -45,7 +45,7 @@ \li Setting \li Value \row - \li \uicontrol Interpreter + \li \uicontrol Python \li Path to the Python executable. \row \li \uicontrol {Buffered output} diff --git a/doc/qtcreator/src/python/creator-tutorial-python-application-qt-widgets.qdoc b/doc/qtcreator/src/python/creator-tutorial-python-application-qt-widgets.qdoc index ae3ef8b93ec..51275cfea4d 100644 --- a/doc/qtcreator/src/python/creator-tutorial-python-application-qt-widgets.qdoc +++ b/doc/qtcreator/src/python/creator-tutorial-python-application-qt-widgets.qdoc @@ -1,4 +1,4 @@ -// Copyright (C) 2023 The Qt Company Ltd. +// Copyright (C) 2024 The Qt Company Ltd. // SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GFDL-1.3-no-invariants-only /*! @@ -28,11 +28,10 @@ class: \list 1 - \li Select \uicontrol File > \uicontrol {New Project} > - \uicontrol {Application (Qt for Python)} > \uicontrol {Empty Window} - > \uicontrol Choose. - - The \uicontrol {Project Location} dialog opens. + \li Go to \uicontrol File > \uicontrol {New Project}. + \li Select \uicontrol {Application (Qt for Python)} > + \uicontrol {Empty Window} > \uicontrol Choose to open the + \uicontrol {Project Location} dialog. \image qtcreator-new-qt-for-python-app-widgets-project-location.webp {Project Location dialog} \li In \uicontrol {Name}, enter the project name. For example, \e {hello_world}. @@ -49,16 +48,14 @@ \li In \uicontrol {Project file}, enter a name for the project file. \li Select \uicontrol{Next} or \uicontrol Continue to open the \uicontrol {Define Project Details} dialog. - \image qtcreator-new-qt-for-python-app-widgets-project-details.webp {Define Project Details dialog} + \image qtcreator-new-qt-for-python-app-project-details.webp {Define Project Details dialog} \li In \uicontrol {PySide version}, select the PySide version of the generated code. - \li In \uicontrol {Interpreter}, select the Python interpreter to use for - the project. - \li Select the \uicontrol {Create new virtual environment} check box to - use a clean \l{https://docs.python.org/3/library/venv.html}{Python} - environment that is independent of your global Python installation. - \li In \uicontrol {Path to virtual environment}, specify the directory - where to create the environment. + \li Select \uicontrol{Next} or \uicontrol Continue to open the + \uicontrol {Kit Selection} dialog. + \image qtcreator-new-project-qt-for-python-kit-selection.webp {Selecting a kit for a Python project} + \li Select Qt for Python kits for building, deploying, and running the + project. \li Select \uicontrol{Next} or \uicontrol Continue. \li Review the project settings, and select \uicontrol {Finish} (on Windows and Linux) or \uicontrol Done (on \macos) to create the @@ -71,6 +68,8 @@ \li \c {hellow_world.pyproject}, which lists the files in the Python project. \li \c {mywidget.py}, which has some boilerplate code for a class. + \li \c {reguirements.txt}, which stores the PySide version of the + generated code. \endlist \section1 Adding Qt Widgets Imports diff --git a/doc/qtcreator/src/python/creator-tutorial-python-application-qtquick.qdoc b/doc/qtcreator/src/python/creator-tutorial-python-application-qtquick.qdoc index 868d500ae6c..9357ad2ea70 100644 --- a/doc/qtcreator/src/python/creator-tutorial-python-application-qtquick.qdoc +++ b/doc/qtcreator/src/python/creator-tutorial-python-application-qtquick.qdoc @@ -1,4 +1,4 @@ -// Copyright (C) 2023 The Qt Company Ltd. +// Copyright (C) 2024 The Qt Company Ltd. // SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GFDL-1.3-no-invariants-only /*! @@ -18,16 +18,19 @@ \image qtcreator-new-qt-for-python-app-qt-quick-empty-project-ready.webp {A small Qt Quick application} + For more examples of creating Qt for Python applications, see + \l {https://doc.qt.io/qtforpython/tutorials/index.html} + {Qt for Python Examples and Tutorials}. + \section1 Creating an Empty Project To create a Qt for Python application that has a main QML file: \list 1 - \li Select \uicontrol File > \uicontrol {New Project} > - \uicontrol {Application (Qt for Python)} > - \uicontrol {Qt Quick Application - Empty} > \uicontrol Choose. - - The \uicontrol {Project Location} dialog opens. + \li Go to \uicontrol File > \uicontrol {New Project}. + \li Select \uicontrol {Application (Qt for Python)} > + \uicontrol {Qt Quick Application - Empty} > \uicontrol Choose to + open the \uicontrol {Project Location} dialog. \image qtcreator-new-qt-for-python-app-qt-quick-empty-project-location.webp {Project Location dialog} \li In \uicontrol {Name}, enter the project name. For example, \e {hello_world_quick}. @@ -35,17 +38,14 @@ For example, \c {C:\Qt\examples}. \li Select \uicontrol{Next} (on Windows and Linux) or \uicontrol Continue (on \macos) to open the \uicontrol {Define Project Details} dialog. - \image qtcreator-new-qt-for-python-app-qt-quick-empty-project-details.webp {Define Project Details dialog} + \image qtcreator-new-qt-for-python-app-project-details.webp {Define Project Details dialog} \li In \uicontrol {PySide version}, select the PySide version of the generated code. - \li In \uicontrol {Interpreter}, select the Python interpreter to use for - the project. - \li Select the \uicontrol {Create new virtual environment} check box to - use a clean \l{https://docs.python.org/3/library/venv.html}{Python} - environment that is independent of your global Python installation. - \li In \uicontrol {Path to virtual environment}, specify the directory - where to create the environment. - \li Select \uicontrol{Next} or \uicontrol Continue. + \li Select \uicontrol{Next} or \uicontrol Continue to open the + \uicontrol {Kit Selection} dialog. + \image qtcreator-new-project-qt-for-python-kit-selection.webp {Selecting a kit for a Python project} + \li Select Qt for Python kits for building, deploying, and running the + project. \li Review the project settings, and select \uicontrol {Finish} (on Windows and Linux) or \uicontrol Done (on \macos) to create the project. @@ -58,6 +58,8 @@ project. \li \c {main.py}, which has some boilerplate code. \li \c {main.qml}, which imports Qt Quick controls. + \li \c {reguirements.txt}, which stores the PySide version of the + generated code. \endlist \section1 Adding Qt Quick Imports From d167b16ac2561982a1b304ae523f701662bafd6a Mon Sep 17 00:00:00 2001 From: Christian Stenger Date: Wed, 14 Feb 2024 16:10:03 +0100 Subject: [PATCH 149/243] Axivion: Redo lazy fetching of issues Change-Id: I8c29c6494c651602fa443c76a6c9e3848f352a66 Reviewed-by: Marcus Tillmanns Reviewed-by: hjk Reviewed-by: Jarek Kobus --- src/plugins/axivion/CMakeLists.txt | 4 +- src/plugins/axivion/axivion.qbs | 4 +- src/plugins/axivion/axivionoutputpane.cpp | 87 +++++----- src/plugins/axivion/axivionplugin.cpp | 1 - src/plugins/axivion/dynamiclistmodel.cpp | 184 ++++++++++++++++++++++ src/plugins/axivion/dynamiclistmodel.h | 67 ++++++++ 6 files changed, 303 insertions(+), 44 deletions(-) create mode 100644 src/plugins/axivion/dynamiclistmodel.cpp create mode 100644 src/plugins/axivion/dynamiclistmodel.h diff --git a/src/plugins/axivion/CMakeLists.txt b/src/plugins/axivion/CMakeLists.txt index c3e2f5e7eaa..561ad680e61 100644 --- a/src/plugins/axivion/CMakeLists.txt +++ b/src/plugins/axivion/CMakeLists.txt @@ -6,12 +6,14 @@ add_qtc_plugin(Axivion axivion.qrc axivionoutputpane.cpp axivionoutputpane.h axivionplugin.cpp axivionplugin.h - axivionprojectsettings.h axivionprojectsettings.cpp + axivionprojectsettings.cpp axivionprojectsettings.h axivionsettings.cpp axivionsettings.h axiviontr.h credentialquery.h credentialquery.cpp dashboard/dto.cpp dashboard/dto.h dashboard/concat.cpp dashboard/concat.h dashboard/error.h dashboard/error.cpp + dashboard/error.cpp dashboard/error.h + dynamiclistmodel.cpp dynamiclistmodel.h issueheaderview.cpp issueheaderview.h ) diff --git a/src/plugins/axivion/axivion.qbs b/src/plugins/axivion/axivion.qbs index 70188feb3e4..0e808f65806 100644 --- a/src/plugins/axivion/axivion.qbs +++ b/src/plugins/axivion/axivion.qbs @@ -23,8 +23,10 @@ QtcPlugin { "axivionsettings.cpp", "axivionsettings.h", "axiviontr.h", - "credentialquery.h", "credentialquery.cpp", + "credentialquery.h", + "dynamiclistmodel.cpp", + "dynamiclistmodel.h", "issueheaderview.cpp", "issueheaderview.h", ] diff --git a/src/plugins/axivion/axivionoutputpane.cpp b/src/plugins/axivion/axivionoutputpane.cpp index 5be8521b67f..7a45584bace 100644 --- a/src/plugins/axivion/axivionoutputpane.cpp +++ b/src/plugins/axivion/axivionoutputpane.cpp @@ -7,6 +7,7 @@ #include "axiviontr.h" #include "dashboard/dto.h" #include "issueheaderview.h" +#include "dynamiclistmodel.h" #include #include @@ -19,7 +20,6 @@ #include #include #include -#include #include #include @@ -31,7 +31,6 @@ #include #include #include -#include #include #include @@ -191,16 +190,27 @@ void DashboardWidget::updateUi() addValuesWidgets(Tr::tr("Total:"), allTotal, allAdded, allRemoved, row); } -class IssueTreeItem final : public StaticTreeItem +class IssueListItem final : public ListItem { public: - IssueTreeItem(const QString &id, const QStringList &data, const QStringList &toolTips) - : StaticTreeItem(data, toolTips) + IssueListItem(int row, const QString &id, const QStringList &data, const QStringList &toolTips) + : ListItem(row) , m_id(id) + , m_data(data) + , m_toolTips(toolTips) {} void setLinks(const Links &links) { m_links = links; } + QVariant data(int column, int role) const + { + if (role == Qt::DisplayRole && column >= 0 && column < m_data.size()) + return m_data.at(column); + if (role == Qt::ToolTipRole && column >= 0 && column < m_toolTips.size()) + return m_toolTips.at(column); + return {}; + } + bool setData(int column, const QVariant &value, int role) final { if (role == BaseTreeView::ItemActivatedRole) { @@ -217,11 +227,13 @@ public: fetchIssueInfo(m_id); return true; } - return StaticTreeItem::setData(column, value, role); + return ListItem::setData(column, value, role); } private: const QString m_id; + QStringList m_data; + QStringList m_toolTips; Links m_links; }; @@ -233,14 +245,14 @@ public: private: void updateTable(); - void addIssues(const Dto::IssueTableDto &dto); + void addIssues(const Dto::IssueTableDto &dto, int startRow); void onSearchParameterChanged(); void updateBasicProjectInfo(std::optional info); void setFiltersEnabled(bool enabled); IssueListSearch searchFromUi() const; void fetchTable(); void fetchIssues(const IssueListSearch &search); - void fetchMoreIssues(); + void onFetchRequested(int startRow, int limit); QString m_currentPrefix; QString m_currentProject; @@ -256,9 +268,9 @@ private: QLabel *m_totalRows = nullptr; BaseTreeView *m_issuesView = nullptr; IssueHeaderView *m_headerView = nullptr; - TreeModel<> *m_issuesModel = nullptr; + DynamicListModel *m_issuesModel = nullptr; int m_totalRowCount = 0; - int m_lastRequestedOffset = 0; + bool m_fetchingMore = false; QStringList m_userNames; QStringList m_versionDates; TaskTreeRunner m_taskTreeRunner; @@ -320,18 +332,9 @@ IssuesWidget::IssuesWidget(QWidget *parent) m_issuesView->setHeader(m_headerView); m_issuesView->setHorizontalScrollBarPolicy(Qt::ScrollBarAsNeeded); m_issuesView->enableColumnHiding(); - m_issuesModel = new TreeModel(this); + m_issuesModel = new DynamicListModel(this); m_issuesView->setModel(m_issuesModel); - auto sb = m_issuesView->verticalScrollBar(); - if (QTC_GUARD(sb)) { - connect(sb, &QAbstractSlider::valueChanged, sb, [this, sb](int value) { - if (value >= sb->maximum() - 50) { - if (m_issuesModel->rowCount() < m_totalRowCount) - fetchMoreIssues(); - } - }); - } - + connect(m_issuesModel, &DynamicListModel::fetchRequested, this, &IssuesWidget::onFetchRequested); m_totalRows = new QLabel(Tr::tr("Total rows:"), this); using namespace Layouting; @@ -374,8 +377,6 @@ void IssuesWidget::updateTable() if (!m_currentTableInfo) return; - // update issues table layout - for now just simple approach - TreeModel<> *issuesModel = new TreeModel(this); QStringList columnHeaders; QStringList hiddenColumns; QList sortableColumns; @@ -389,17 +390,14 @@ void IssuesWidget::updateTable() m_removedFilter->setText("0"); m_totalRows->setText(Tr::tr("Total rows:")); - issuesModel->setHeader(columnHeaders); - - auto oldModel = m_issuesModel; - m_issuesModel = issuesModel; - m_issuesView->setModel(issuesModel); + m_issuesModel->clear(); + m_issuesModel->setHeader(columnHeaders); m_headerView->setSortableColumns(sortableColumns); - delete oldModel; + int counter = 0; for (const QString &header : std::as_const(columnHeaders)) m_issuesView->setColumnHidden(counter++, hiddenColumns.contains(header)); - m_issuesView->header()->resizeSections(QHeaderView::ResizeToContents); + m_headerView->resizeSections(QHeaderView::ResizeToContents); } static Links linksForIssue(const std::map &issueRow) @@ -427,11 +425,13 @@ static Links linksForIssue(const std::map &issueRow) return links; } -void IssuesWidget::addIssues(const Dto::IssueTableDto &dto) +void IssuesWidget::addIssues(const Dto::IssueTableDto &dto, int startRow) { + m_fetchingMore = false; QTC_ASSERT(m_currentTableInfo.has_value(), return); if (dto.totalRowCount.has_value()) { m_totalRowCount = dto.totalRowCount.value(); + m_issuesModel->setExpectedRowCount(m_totalRowCount); m_totalRows->setText(Tr::tr("Total rows:") + ' ' + QString::number(m_totalRowCount)); } if (dto.totalAddedCount.has_value()) @@ -441,6 +441,7 @@ void IssuesWidget::addIssues(const Dto::IssueTableDto &dto) const std::vector &tableColumns = m_currentTableInfo->columns; const std::vector> &rows = dto.rows; + QList items; for (const auto &row : rows) { QString id; QStringList data; @@ -455,10 +456,11 @@ void IssuesWidget::addIssues(const Dto::IssueTableDto &dto) data << value; } } - IssueTreeItem *it = new IssueTreeItem(id, data, data); + IssueListItem *it = new IssueListItem(startRow++, id, data, data); it->setLinks(linksForIssue(row)); - m_issuesModel->rootItem()->appendChild(it); + items.append(it); } + m_issuesModel->setItems(items); } void IssuesWidget::onSearchParameterChanged() @@ -467,10 +469,10 @@ void IssuesWidget::onSearchParameterChanged() m_removedFilter->setText("0"); m_totalRows->setText(Tr::tr("Total rows:")); - m_issuesModel->rootItem()->removeChildren(); + m_issuesModel->clear(); // new "first" time lookup m_totalRowCount = 0; - m_lastRequestedOffset = 0; + m_fetchingMore = false; IssueListSearch search = searchFromUi(); search.computeTotalRowCount = true; fetchIssues(search); @@ -598,7 +600,7 @@ void IssuesWidget::fetchTable() }; const auto setupHandler = [this](TaskTree *) { m_totalRowCount = 0; - m_lastRequestedOffset = 0; + m_fetchingMore = false; m_currentTableInfo.reset(); m_issuesView->showProgressIndicator(); }; @@ -618,20 +620,23 @@ void IssuesWidget::fetchTable() void IssuesWidget::fetchIssues(const IssueListSearch &search) { - const auto issuesHandler = [this](const Dto::IssueTableDto &dto) { addIssues(dto); }; + const auto issuesHandler = [this, startRow = search.offset](const Dto::IssueTableDto &dto) { + addIssues(dto, startRow); + }; const auto setupHandler = [this](TaskTree *) { m_issuesView->showProgressIndicator(); }; const auto doneHandler = [this](DoneWith) { m_issuesView->hideProgressIndicator(); }; m_taskTreeRunner.start(issueTableRecipe(search, issuesHandler), setupHandler, doneHandler); } -void IssuesWidget::fetchMoreIssues() +void IssuesWidget::onFetchRequested(int startRow, int limit) { - if (m_lastRequestedOffset == m_issuesModel->rowCount()) + if (m_fetchingMore) return; + m_fetchingMore = true; IssueListSearch search = searchFromUi(); - m_lastRequestedOffset = m_issuesModel->rowCount(); - search.offset = m_lastRequestedOffset; + search.offset = startRow; + search.limit = limit; fetchIssues(search); } diff --git a/src/plugins/axivion/axivionplugin.cpp b/src/plugins/axivion/axivionplugin.cpp index 558f7909744..3fb567e22cd 100644 --- a/src/plugins/axivion/axivionplugin.cpp +++ b/src/plugins/axivion/axivionplugin.cpp @@ -696,7 +696,6 @@ Group issueTableRecipe(const IssueListSearch &search, const IssueTableHandler &h const QUrl url = urlForProject(dd->m_currentProjectInfo.value().name + '/') .resolved(QString("issues" + query)); - return fetchDataRecipe(url, handler); } diff --git a/src/plugins/axivion/dynamiclistmodel.cpp b/src/plugins/axivion/dynamiclistmodel.cpp new file mode 100644 index 00000000000..45819995963 --- /dev/null +++ b/src/plugins/axivion/dynamiclistmodel.cpp @@ -0,0 +1,184 @@ +// 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 "dynamiclistmodel.h" + +#include "axiviontr.h" + +#include +#include + +namespace Axivion::Internal { + +constexpr int pageSize = 150; + +DynamicListModel::DynamicListModel(QObject *parent) + : QAbstractItemModel(parent) +{ + m_fetchMoreTimer.setSingleShot(true); + m_fetchMoreTimer.setInterval(50); + connect(&m_fetchMoreTimer, &QTimer::timeout, this, &DynamicListModel::fetchNow); +} + +DynamicListModel::~DynamicListModel() +{ + clear(); +} + +QModelIndex DynamicListModel::index(int row, int column, const QModelIndex &parent) const +{ + if (parent.isValid()) + return {}; + if (row < m_expectedRowCount.value_or(m_children.size())) { + auto it = m_children.constFind(row); + return createIndex(row, column, it != m_children.constEnd() ? it.value() : nullptr); + } + return {}; +} + +QModelIndex DynamicListModel::parent(const QModelIndex &/*child*/) const +{ + return {}; +} + +int DynamicListModel::rowCount(const QModelIndex &parent) const +{ + if (parent.isValid()) // for simplicity only single level + return 0; + + return m_expectedRowCount.value_or(m_children.size()); +} + +int DynamicListModel::columnCount(const QModelIndex &/*parent*/) const +{ + return m_columnCount; +} + +QVariant DynamicListModel::data(const QModelIndex &index, int role) const +{ + const int row = index.row(); + if (!index.isValid() || row < 0 || row > m_expectedRowCount.value_or(m_children.size())) + return {}; + + auto item = m_children.constFind(row); + if (item != m_children.cend()) + return item.value()->data(index.column(), role); + + if ((row < m_lastFetch || row > m_lastFetchEnd) && (row < m_fetchStart || row > m_fetchEnd)) + const_cast(this)->onNeedFetch(row); + if (role == Qt::DisplayRole && index.column() == 0) + return Tr::tr("Fetching..."); // TODO improve/customize? + if (role == Qt::ForegroundRole && index.column() == 0) + return Utils::creatorTheme()->color(Utils::Theme::TextColorDisabled); + return {}; +} + +bool DynamicListModel::setData(const QModelIndex &index, const QVariant &value, int role) +{ + auto found = m_children.constFind(index.row()); + if (found == m_children.constEnd()) + return false; + return found.value()->setData(index.column(), value, role); +} + +QVariant DynamicListModel::headerData(int section, Qt::Orientation orientation, int role) const +{ + if (orientation == Qt::Horizontal && role == Qt::DisplayRole && section < m_header.size()) + return m_header.at(section); + return {}; +} + +void DynamicListModel::setItems(const QList &items) +{ + m_lastFetchEnd = -1; // FIXME wrong.. better a callback? - should happen for failed requests too + // for simplicity we assume an ordered list and no non-existing items between first and last + if (items.isEmpty()) + return; + // to keep it simple here, we expect the expectedRowCount to be set *before* adding items + QTC_ASSERT(m_expectedRowCount, setExpectedRowCount(items.size())); + if (int lastRow = items.last()->row; lastRow > *m_expectedRowCount) + m_expectedRowCount.emplace(lastRow); + + emit layoutAboutToBeChanged(); + auto end = m_children.end(); + for (ListItem *it : items) { + auto found = m_children.find(it->row); // check for old data to be removed + ListItem *old = nullptr; + if (found != end) + old = found.value(); + m_children.insert(it->row, it); + delete old; + } + emit dataChanged(indexForItem(items.first()), indexForItem(items.last())); + emit layoutChanged(); +} + +void DynamicListModel::clear() +{ + beginResetModel(); + qDeleteAll(m_children); + m_children.clear(); + m_expectedRowCount.reset(); + endResetModel(); +} + +void DynamicListModel::setExpectedRowCount(int expected) +{ + QTC_ASSERT(expected >= m_children.size(), return); + if (expected == m_children.size()) + return; + beginInsertRows({}, m_children.size(), expected); + m_expectedRowCount.emplace(expected); + endInsertRows(); +} + +void DynamicListModel::setHeader(const QStringList &header) +{ + m_header = header; + m_columnCount = m_header.size(); +} + +QModelIndex DynamicListModel::indexForItem(const ListItem *item) const +{ + QTC_ASSERT(item, return {}); + auto found = m_children.constFind(item->row); + if (found == m_children.cend()) + return {}; + QTC_ASSERT(found.value() == item, return {}); + return createIndex(item->row, 0, item); +} + +void DynamicListModel::onNeedFetch(int row) +{ + m_fetchStart = row; + m_fetchEnd = row + pageSize; + if (m_fetchStart < 0) + return; + m_fetchMoreTimer.start(); +} + +void DynamicListModel::fetchNow() +{ + const int old = m_lastFetch; + m_lastFetch = m_fetchStart; // we need the "original" fetch request to avoid endless loop + m_lastFetchEnd = m_fetchStart + pageSize; + + if (old != -1) { + const int diff = old - m_fetchStart; + if (0 < diff && diff < pageSize) { + m_fetchStart = qMax(old - pageSize, 0); + } else if (0 > diff && diff > -pageSize) { + m_fetchStart = old + pageSize; + if (m_expectedRowCount && m_fetchStart > *m_expectedRowCount) + m_fetchStart = *m_expectedRowCount; + } + } + + QTC_CHECK(m_expectedRowCount ? m_fetchStart <= *m_expectedRowCount + : m_fetchStart >= m_children.size()); + emit fetchRequested(m_fetchStart, pageSize); + m_fetchStart = -1; + m_fetchEnd = -1; +} + +} // namespace Axivion::Internal diff --git a/src/plugins/axivion/dynamiclistmodel.h b/src/plugins/axivion/dynamiclistmodel.h new file mode 100644 index 00000000000..1e83a572c35 --- /dev/null +++ b/src/plugins/axivion/dynamiclistmodel.h @@ -0,0 +1,67 @@ +// 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 + +namespace Axivion::Internal { + +class ListItem +{ +public: + explicit ListItem(int row) : row(row) {} + virtual ~ListItem() = default; + virtual bool setData(int /*column*/, const QVariant &/*value*/, int /*role*/) { return false; } + virtual QVariant data(int /*column*/, int /*role*/) const { return {}; } + + const int row; +}; + +class DynamicListModel : public QAbstractItemModel +{ + Q_OBJECT +public: + explicit DynamicListModel(QObject *parent = nullptr); + ~DynamicListModel(); + + QModelIndex index(int row, int column, const QModelIndex &parent) const override; + QModelIndex parent(const QModelIndex &child) const override; + int rowCount(const QModelIndex &parent = QModelIndex()) const override; + int columnCount(const QModelIndex &parent) const override; + QVariant data(const QModelIndex &index, int role) const override; + bool setData(const QModelIndex&, const QVariant &value, int role) override; + QVariant headerData(int section, Qt::Orientation orientation, int role) const override; + + void setItems(const QList &items); + void clear(); + + void setExpectedRowCount(int expected); + void setHeader(const QStringList &header); + + QModelIndex indexForItem(const ListItem *item) const; + +signals: + void fetchRequested(int startRow, int limit); + +private: + void onNeedFetch(int row); + void fetchNow(); + + QHash m_children; + QStringList m_header; + QTimer m_fetchMoreTimer; + std::optional m_expectedRowCount = {}; + int m_fetchStart = -1; + int m_fetchEnd = -1; + int m_lastFetch = -1; + int m_lastFetchEnd = -1; + int m_columnCount = 0; +}; + +} // namespace Axivion::Internal From 09c8bd841b5fe9280d18227a714c011426b18ac3 Mon Sep 17 00:00:00 2001 From: Christian Stenger Date: Fri, 23 Feb 2024 10:37:54 +0100 Subject: [PATCH 150/243] Axivion: Improve sort icons Palette colors may not be correctly populated depending on the platform, so use some common available one. Change-Id: I5f660aaefbd5882a255da4a25c3e15edc3fe3643 Reviewed-by: hjk --- src/plugins/axivion/issueheaderview.cpp | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/src/plugins/axivion/issueheaderview.cpp b/src/plugins/axivion/issueheaderview.cpp index 460dd711489..dfb4c11eec3 100644 --- a/src/plugins/axivion/issueheaderview.cpp +++ b/src/plugins/axivion/issueheaderview.cpp @@ -15,14 +15,14 @@ constexpr int ICON_SIZE = 16; static QIcon iconForSorted(SortOrder order) { const Utils::Icon UNSORTED( - {{":/axivion/images/sortAsc.png", Utils::Theme::PaletteButtonTextDisabled}, - {":/axivion/images/sortDesc.png", Utils::Theme::PaletteButtonTextDisabled}}); + {{":/axivion/images/sortAsc.png", Utils::Theme::IconsDisabledColor}, + {":/axivion/images/sortDesc.png", Utils::Theme::IconsDisabledColor}}); const Utils::Icon SORT_ASC( - {{":/axivion/images/sortAsc.png", Utils::Theme::PaletteButtonText}, - {":/axivion/images/sortDesc.png", Utils::Theme::PaletteButtonTextDisabled}}); + {{":/axivion/images/sortAsc.png", Utils::Theme::PaletteText}, + {":/axivion/images/sortDesc.png", Utils::Theme::IconsDisabledColor}}); const Utils::Icon SORT_DESC( - {{":/axivion/images/sortAsc.png", Utils::Theme::PaletteButtonTextDisabled}, - {":/axivion/images/sortDesc.png", Utils::Theme::PaletteButtonText}}); + {{":/axivion/images/sortAsc.png", Utils::Theme::IconsDisabledColor}, + {":/axivion/images/sortDesc.png", Utils::Theme::PaletteText}}); static const QIcon unsorted = UNSORTED.icon(); static const QIcon sortedAsc = SORT_ASC.icon(); static const QIcon sortedDesc = SORT_DESC.icon(); From feb70c1d7b78a622586642223d93296ad63a8171 Mon Sep 17 00:00:00 2001 From: Christian Kandeler Date: Fri, 23 Feb 2024 12:11:13 +0100 Subject: [PATCH 151/243] Update qbs submodule to HEAD of 2.3 branch Change-Id: I62099a9605b2d9deeb6d36be3c43e088b9cd2578 Reviewed-by: Reviewed-by: Christian Stenger Reviewed-by: Qt CI Bot --- src/shared/qbs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/shared/qbs b/src/shared/qbs index bd0c59e572f..60a18f09fa5 160000 --- a/src/shared/qbs +++ b/src/shared/qbs @@ -1 +1 @@ -Subproject commit bd0c59e572f95953337177e68fa32cb0c4aa1e29 +Subproject commit 60a18f09fa547af064fb851e72b816ee25bf71a3 From c0bbf285a7eecfbc461290042015e0b23db2909e Mon Sep 17 00:00:00 2001 From: Christian Kandeler Date: Fri, 23 Feb 2024 11:30:55 +0100 Subject: [PATCH 152/243] CppEditor: Fix indentation with inline namespaces After encountering the namespace keyword, we have to backtrack the state change introduced by the inline keyword. Fixes: QTCREATORBUG-22071 Change-Id: I543976622d1a56b2c61d68da6ec3eee8b6d0d5b3 Reviewed-by: Qt CI Bot Reviewed-by: Christian Stenger Reviewed-by: --- src/plugins/cppeditor/cppcodeformatter.cpp | 1 + tests/auto/cplusplus/codeformatter/tst_codeformatter.cpp | 8 ++++---- 2 files changed, 5 insertions(+), 4 deletions(-) diff --git a/src/plugins/cppeditor/cppcodeformatter.cpp b/src/plugins/cppeditor/cppcodeformatter.cpp index 6b30e78fa6c..e0e22fc6fe1 100644 --- a/src/plugins/cppeditor/cppcodeformatter.cpp +++ b/src/plugins/cppeditor/cppcodeformatter.cpp @@ -151,6 +151,7 @@ void CodeFormatter::recalculateStateAfter(const QTextBlock &block) case T_OPERATOR: enter(operator_declaration); break; case T_GREATER_GREATER: break; case T_LBRACKET: break; + case T_NAMESPACE: leave(); enter(namespace_start); break; default: tryExpression(true); break; } break; diff --git a/tests/auto/cplusplus/codeformatter/tst_codeformatter.cpp b/tests/auto/cplusplus/codeformatter/tst_codeformatter.cpp index ce57e939ee5..82b5cba5b19 100644 --- a/tests/auto/cplusplus/codeformatter/tst_codeformatter.cpp +++ b/tests/auto/cplusplus/codeformatter/tst_codeformatter.cpp @@ -1544,8 +1544,8 @@ void tst_CodeFormatter::indentNamespace() << Line("};") << Line("}") << Line("int j;") - << Line("namespace {") - << Line("namespace Foo {") + << Line("inline namespace {") + << Line("inline namespace Foo {") << Line("int j;") << Line("}") << Line("int j;") @@ -1585,9 +1585,9 @@ void tst_CodeFormatter::indentNamespace2() << Line(" };") << Line("}") << Line("int j;") - << Line("namespace {") + << Line("inline namespace {") << Line(" int j;") - << Line(" namespace Foo {") + << Line(" inline namespace Foo {") << Line(" int j;") << Line(" }") << Line(" int j;") From 026de59be9d7fdc07cc4f96eebab3d9a448d9845 Mon Sep 17 00:00:00 2001 From: hjk Date: Fri, 23 Feb 2024 11:07:27 +0100 Subject: [PATCH 153/243] Meson: Fix reading of tool settings We were accumulating copies of the auto-detected system ninja setting since the QVariantMap retrieved with toMap() was empty as it is a Store nowadays. Change-Id: Id983b5f1bf5ff18d6f43a71ebb406520e7655705 Reviewed-by: Reviewed-by: Christian Stenger --- .../toolssettingsaccessor.cpp | 16 ++++++++-------- 1 file changed, 8 insertions(+), 8 deletions(-) diff --git a/src/plugins/mesonprojectmanager/toolssettingsaccessor.cpp b/src/plugins/mesonprojectmanager/toolssettingsaccessor.cpp index 1fe381d0255..8e941ae21b3 100644 --- a/src/plugins/mesonprojectmanager/toolssettingsaccessor.cpp +++ b/src/plugins/mesonprojectmanager/toolssettingsaccessor.cpp @@ -77,14 +77,14 @@ std::vector ToolsSettingsAccessor::loadMesonTools() std::vector result; for (auto toolIndex = 0; toolIndex < entry_count; toolIndex++) { Key name = entryName(toolIndex); - if (data.contains(name)) { - const auto map = data[name].toMap(); - auto type = map.value(ToolsSettings::TOOL_TYPE_KEY, ToolsSettings::TOOL_TYPE_MESON); - if (type == ToolsSettings::TOOL_TYPE_NINJA) - result.emplace_back(fromVariantMap(storeFromVariant(data[name]))); - else - result.emplace_back(fromVariantMap(storeFromVariant(data[name]))); - } + Store store = storeFromVariant(data[name]); + QString type = store.value(ToolsSettings::TOOL_TYPE_KEY).toString(); + if (type == ToolsSettings::TOOL_TYPE_NINJA) + result.emplace_back(fromVariantMap(storeFromVariant(data[name]))); + else if (type == ToolsSettings::TOOL_TYPE_MESON) + result.emplace_back(fromVariantMap(storeFromVariant(data[name]))); + else + QTC_CHECK(false); } return result; } From 0acc91a6e89e1d6c7ccea4c718a283b6b3813291 Mon Sep 17 00:00:00 2001 From: Cristian Adam Date: Fri, 23 Feb 2024 11:46:19 +0100 Subject: [PATCH 154/243] LLVM: Use lldb-dap.exe on Windows for qtcreatorcdbext LLVM 18 has renamed lldb-vscode.exe to lldb-dap.exe. Change-Id: I4b0b108ebebc552a4c843f4c8a2fa563132176cd Reviewed-by: Reviewed-by: David Schulz --- src/libs/qtcreatorcdbext/CMakeLists.txt | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/libs/qtcreatorcdbext/CMakeLists.txt b/src/libs/qtcreatorcdbext/CMakeLists.txt index 97307164f65..4359d79d546 100644 --- a/src/libs/qtcreatorcdbext/CMakeLists.txt +++ b/src/libs/qtcreatorcdbext/CMakeLists.txt @@ -205,7 +205,7 @@ if (_library_enabled) # Deploy lldb.exe and its Python dependency find_package(Clang QUIET) if (LLVM_TOOLS_BINARY_DIR AND LLVM_LIBRARY_DIRS) - foreach(lldb_file lldb.exe lldb-vscode.exe liblldb.dll python311.zip python311.dll) + foreach(lldb_file lldb.exe lldb-dap.exe liblldb.dll python311.zip python311.dll) if (EXISTS ${LLVM_TOOLS_BINARY_DIR}/${lldb_file}) install(FILES ${LLVM_TOOLS_BINARY_DIR}/${lldb_file} DESTINATION bin/clang/bin From 5ff64ed95cf781d92e995d208d1d7a4229757208 Mon Sep 17 00:00:00 2001 From: Jarek Kobus Date: Fri, 23 Feb 2024 14:42:20 +0100 Subject: [PATCH 155/243] Axivion: Remove unneeded m_fetchingMore field Use m_taskTreeRunner.isRunning() instead. Change-Id: I2feed612cf8eabfc5ec160a4586b3158aa4d90b8 Reviewed-by: hjk --- src/plugins/axivion/axivionoutputpane.cpp | 7 +------ 1 file changed, 1 insertion(+), 6 deletions(-) diff --git a/src/plugins/axivion/axivionoutputpane.cpp b/src/plugins/axivion/axivionoutputpane.cpp index 7a45584bace..5164cd743b6 100644 --- a/src/plugins/axivion/axivionoutputpane.cpp +++ b/src/plugins/axivion/axivionoutputpane.cpp @@ -270,7 +270,6 @@ private: IssueHeaderView *m_headerView = nullptr; DynamicListModel *m_issuesModel = nullptr; int m_totalRowCount = 0; - bool m_fetchingMore = false; QStringList m_userNames; QStringList m_versionDates; TaskTreeRunner m_taskTreeRunner; @@ -427,7 +426,6 @@ static Links linksForIssue(const std::map &issueRow) void IssuesWidget::addIssues(const Dto::IssueTableDto &dto, int startRow) { - m_fetchingMore = false; QTC_ASSERT(m_currentTableInfo.has_value(), return); if (dto.totalRowCount.has_value()) { m_totalRowCount = dto.totalRowCount.value(); @@ -472,7 +470,6 @@ void IssuesWidget::onSearchParameterChanged() m_issuesModel->clear(); // new "first" time lookup m_totalRowCount = 0; - m_fetchingMore = false; IssueListSearch search = searchFromUi(); search.computeTotalRowCount = true; fetchIssues(search); @@ -600,7 +597,6 @@ void IssuesWidget::fetchTable() }; const auto setupHandler = [this](TaskTree *) { m_totalRowCount = 0; - m_fetchingMore = false; m_currentTableInfo.reset(); m_issuesView->showProgressIndicator(); }; @@ -630,10 +626,9 @@ void IssuesWidget::fetchIssues(const IssueListSearch &search) void IssuesWidget::onFetchRequested(int startRow, int limit) { - if (m_fetchingMore) + if (m_taskTreeRunner.isRunning()) return; - m_fetchingMore = true; IssueListSearch search = searchFromUi(); search.offset = startRow; search.limit = limit; From e3e8b624179e572c96f7599c7a1c725fc3aabe00 Mon Sep 17 00:00:00 2001 From: Christian Kandeler Date: Fri, 23 Feb 2024 12:52:48 +0100 Subject: [PATCH 156/243] RemoteLinux: Make deployment method downgrade transparent Fixes: QTCREATORBUG-29710 Change-Id: I27f3252f8a3d9bc03f2abd096aae6f0df4a6448c Reviewed-by: Qt CI Bot Reviewed-by: hjk Reviewed-by: --- src/plugins/remotelinux/genericdeploystep.cpp | 9 +++++++++ 1 file changed, 9 insertions(+) diff --git a/src/plugins/remotelinux/genericdeploystep.cpp b/src/plugins/remotelinux/genericdeploystep.cpp index 23e8a1b8c75..bddc7bfcd3d 100644 --- a/src/plugins/remotelinux/genericdeploystep.cpp +++ b/src/plugins/remotelinux/genericdeploystep.cpp @@ -72,6 +72,7 @@ private: StringAspect flags{this}; BoolAspect ignoreMissingFiles{this}; SelectionAspect method{this}; + bool m_emittedDowngradeWarning = false; }; GroupItem GenericDeployStep::mkdirTask(const Storage &storage) @@ -153,6 +154,14 @@ GroupItem GenericDeployStep::transferTask(const Storage &storag break; } } + if (!m_emittedDowngradeWarning && transferMethod != preferredTransferMethod) { + addWarningMessage(Tr::tr("Transfer method was downgraded from \"%1\" to \"%2\". If " + "this is unexpected, please re-test device \"%3\".") + .arg(FileTransfer::transferMethodName(preferredTransferMethod), + FileTransfer::transferMethodName(transferMethod), + deviceConfiguration()->displayName())); + m_emittedDowngradeWarning = true; + } transfer.setTransferMethod(transferMethod); transfer.setRsyncFlags(flags()); From 09cc4507973165154e88622ded59d6b5ec8ca29f Mon Sep 17 00:00:00 2001 From: Christian Stenger Date: Fri, 23 Feb 2024 13:45:15 +0100 Subject: [PATCH 157/243] Axivion: Handle links more appropriate If the user clicks on a row's column holding a location information then use this explicitly instead of always using the first available link. Change-Id: Ifecbecac632a4bfd4d31614a8c43ab6c80de4819 Reviewed-by: hjk --- src/plugins/axivion/axivionoutputpane.cpp | 44 +++++++++++++++++------ 1 file changed, 34 insertions(+), 10 deletions(-) diff --git a/src/plugins/axivion/axivionoutputpane.cpp b/src/plugins/axivion/axivionoutputpane.cpp index 5164cd743b6..063fafdc988 100644 --- a/src/plugins/axivion/axivionoutputpane.cpp +++ b/src/plugins/axivion/axivionoutputpane.cpp @@ -17,6 +17,7 @@ #include +#include #include #include #include @@ -190,6 +191,12 @@ void DashboardWidget::updateUi() addValuesWidgets(Tr::tr("Total:"), allTotal, allAdded, allRemoved, row); } +struct LinkWithColumns +{ + Link link; + QList columns; +}; + class IssueListItem final : public ListItem { public: @@ -200,7 +207,7 @@ public: , m_toolTips(toolTips) {} - void setLinks(const Links &links) { m_links = links; } + void setLinks(const QList &links) { m_links = links; } QVariant data(int column, int role) const { @@ -215,8 +222,10 @@ public: { if (role == BaseTreeView::ItemActivatedRole) { if (!m_links.isEmpty()) { - // TODO for now only simple - just the first.. - Link link = m_links.first(); + Link link + = Utils::findOr(m_links, m_links.first(), [column](const LinkWithColumns &link) { + return link.columns.contains(column); + }).link; Project *project = ProjectManager::startupProject(); FilePath baseDir = project ? project->projectDirectory() : FilePath{}; link.targetFilePath = baseDir.resolvePath(link.targetFilePath); @@ -234,7 +243,7 @@ private: const QString m_id; QStringList m_data; QStringList m_toolTips; - Links m_links; + QList m_links; }; class IssuesWidget : public QScrollArea @@ -399,19 +408,34 @@ void IssuesWidget::updateTable() m_headerView->resizeSections(QHeaderView::ResizeToContents); } -static Links linksForIssue(const std::map &issueRow) +static QList linksForIssue(const std::map &issueRow, + const std::vector &columnInfos) { - Links links; + QList links; auto end = issueRow.end(); - auto findAndAppend = [&links, &issueRow, &end](const QString &path, const QString &line) { + auto findColumn = [columnInfos](const QString &columnKey) { + int col = 0; + for (auto it = columnInfos.cbegin(), end = columnInfos.cend(); it != end; ++it) { + if (it->key == columnKey) + return col; + ++col; + } + return -1; + }; + auto findAndAppend = [&links, &issueRow, &columnInfos, &findColumn, &end](const QString &path, + const QString &line) { + QList columns; auto it = issueRow.find(path); if (it != end) { Link link{ FilePath::fromUserInput(it->second.getString()) }; + columns.append(findColumn(it->first)); it = issueRow.find(line); - if (it != end) + if (it != end) { link.targetLine = it->second.getDouble(); - links.append(link); + columns.append(findColumn(it->first)); + } + links.append({link, columns}); } }; // do these always? or just for their "expected" kind @@ -455,7 +479,7 @@ void IssuesWidget::addIssues(const Dto::IssueTableDto &dto, int startRow) } } IssueListItem *it = new IssueListItem(startRow++, id, data, data); - it->setLinks(linksForIssue(row)); + it->setLinks(linksForIssue(row, tableColumns)); items.append(it); } m_issuesModel->setItems(items); From 51998c52392df63d2ca354b06077df00ee52e13d Mon Sep 17 00:00:00 2001 From: Jarek Kobus Date: Thu, 22 Feb 2024 20:34:28 +0100 Subject: [PATCH 158/243] Axivion: Make use of the column widths coming from the server Change-Id: Idcce80ed987ed02cb0197cfca93d32deb715f95c Reviewed-by: hjk --- src/plugins/axivion/axivionoutputpane.cpp | 3 ++- src/plugins/axivion/issueheaderview.cpp | 6 ++++-- src/plugins/axivion/issueheaderview.h | 3 +++ 3 files changed, 9 insertions(+), 3 deletions(-) diff --git a/src/plugins/axivion/axivionoutputpane.cpp b/src/plugins/axivion/axivionoutputpane.cpp index 063fafdc988..d4462f06133 100644 --- a/src/plugins/axivion/axivionoutputpane.cpp +++ b/src/plugins/axivion/axivionoutputpane.cpp @@ -388,11 +388,13 @@ void IssuesWidget::updateTable() QStringList columnHeaders; QStringList hiddenColumns; QList sortableColumns; + QList columnWidths; for (const Dto::ColumnInfoDto &column : m_currentTableInfo->columns) { columnHeaders << column.header.value_or(column.key); if (!column.showByDefault) hiddenColumns << column.key; sortableColumns << column.canSort; + columnWidths << column.width; } m_addedFilter->setText("0"); m_removedFilter->setText("0"); @@ -401,7 +403,6 @@ void IssuesWidget::updateTable() m_issuesModel->clear(); m_issuesModel->setHeader(columnHeaders); m_headerView->setSortableColumns(sortableColumns); - int counter = 0; for (const QString &header : std::as_const(columnHeaders)) m_issuesView->setColumnHidden(counter++, hiddenColumns.contains(header)); diff --git a/src/plugins/axivion/issueheaderview.cpp b/src/plugins/axivion/issueheaderview.cpp index dfb4c11eec3..ceb2d520afa 100644 --- a/src/plugins/axivion/issueheaderview.cpp +++ b/src/plugins/axivion/issueheaderview.cpp @@ -115,9 +115,11 @@ void IssueHeaderView::onToggleSort(int index, SortOrder order) QSize IssueHeaderView::sectionSizeFromContents(int logicalIndex) const { - QSize size = QHeaderView::sectionSizeFromContents(logicalIndex); + const QSize oldSize = QHeaderView::sectionSizeFromContents(logicalIndex); + const QSize newSize = logicalIndex < m_columnWidths.size() + ? QSize(qMax(m_columnWidths.at(logicalIndex), oldSize.width()), oldSize.height()) : oldSize; // add icon size and margin (2) - return QSize{size.width() + ICON_SIZE + 2, qMax(size.height(), ICON_SIZE)}; + return QSize{newSize.width() + ICON_SIZE + 2, qMax(newSize.height(), ICON_SIZE)}; } void IssueHeaderView::paintSection(QPainter *painter, const QRect &rect, int logicalIndex) const diff --git a/src/plugins/axivion/issueheaderview.h b/src/plugins/axivion/issueheaderview.h index 3d6f271a762..1fbbd9b76fd 100644 --- a/src/plugins/axivion/issueheaderview.h +++ b/src/plugins/axivion/issueheaderview.h @@ -16,9 +16,11 @@ class IssueHeaderView : public QHeaderView public: explicit IssueHeaderView(QWidget *parent = nullptr) : QHeaderView(Qt::Horizontal, parent) {} void setSortableColumns(const QList &sortable); + void setColumnWidths(const QList &widths) { m_columnWidths = widths; } SortOrder currentSortOrder() const { return m_currentSortOrder; } int currentSortColumn() const; + signals: void sortTriggered(); @@ -36,6 +38,7 @@ private: int m_currentSortIndex = -1; SortOrder m_currentSortOrder = SortOrder::None; QList m_sortableColumns; + QList m_columnWidths; }; } // namespace Axivion::Internal From d5f50a3fa44bdf9230561290c66cfe890d1994c1 Mon Sep 17 00:00:00 2001 From: Jarek Kobus Date: Fri, 23 Feb 2024 15:54:00 +0100 Subject: [PATCH 159/243] Axivion: Remove warning about unused lambda capture Amends 09cc4507973165154e88622ded59d6b5ec8ca29f Change-Id: I44a5ba2a0f83f9f75ba84b1b6470e875027c290b Reviewed-by: hjk --- src/plugins/axivion/axivionoutputpane.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/plugins/axivion/axivionoutputpane.cpp b/src/plugins/axivion/axivionoutputpane.cpp index d4462f06133..1b69fce8b55 100644 --- a/src/plugins/axivion/axivionoutputpane.cpp +++ b/src/plugins/axivion/axivionoutputpane.cpp @@ -424,7 +424,7 @@ static QList linksForIssue(const std::map &i } return -1; }; - auto findAndAppend = [&links, &issueRow, &columnInfos, &findColumn, &end](const QString &path, + auto findAndAppend = [&links, &issueRow, &findColumn, &end](const QString &path, const QString &line) { QList columns; auto it = issueRow.find(path); From 8b4578f0c4a0096c70fcc275b27c27f96b6e00ce Mon Sep 17 00:00:00 2001 From: Jarek Kobus Date: Fri, 23 Feb 2024 16:06:43 +0100 Subject: [PATCH 160/243] Axivion: Amends the commit regarding column sizes When resolving a conflit the key line got removed by mistake. Amends 51998c52392df63d2ca354b06077df00ee52e13d Change-Id: I74af26d23e7ac0180d1b351d7ecf6d6876499d89 Reviewed-by: hjk --- src/plugins/axivion/axivionoutputpane.cpp | 1 + 1 file changed, 1 insertion(+) diff --git a/src/plugins/axivion/axivionoutputpane.cpp b/src/plugins/axivion/axivionoutputpane.cpp index 1b69fce8b55..e6272d46ccf 100644 --- a/src/plugins/axivion/axivionoutputpane.cpp +++ b/src/plugins/axivion/axivionoutputpane.cpp @@ -403,6 +403,7 @@ void IssuesWidget::updateTable() m_issuesModel->clear(); m_issuesModel->setHeader(columnHeaders); m_headerView->setSortableColumns(sortableColumns); + m_headerView->setColumnWidths(columnWidths); int counter = 0; for (const QString &header : std::as_const(columnHeaders)) m_issuesView->setColumnHidden(counter++, hiddenColumns.contains(header)); From d061e29dd307c42a7fd79091be14f745752c27c5 Mon Sep 17 00:00:00 2001 From: Marcus Tillmanns Date: Fri, 23 Feb 2024 16:27:58 +0100 Subject: [PATCH 161/243] Utils: Allow different codec for Process stdout and stderr Change-Id: Ie6a3fb74a447a599c492e38ec83a2330f3cb4cd8 Reviewed-by: hjk --- src/libs/utils/process.cpp | 27 +++++++++++++++++++++------ src/libs/utils/process.h | 6 ++++-- 2 files changed, 25 insertions(+), 8 deletions(-) diff --git a/src/libs/utils/process.cpp b/src/libs/utils/process.cpp index 4eacb28986f..651dd5b49b1 100644 --- a/src/libs/utils/process.cpp +++ b/src/libs/utils/process.cpp @@ -847,7 +847,9 @@ public: qint64 m_applicationMainThreadId = 0; ProcessResultData m_resultData; - QTextCodec *m_codec = QTextCodec::codecForLocale(); + QTextCodec *m_stdOutCodec = QTextCodec::codecForLocale(); + QTextCodec *m_stdErrCodec = QTextCodec::codecForLocale(); + ProcessResult m_result = ProcessResult::StartFailed; ChannelBuffer m_stdOut; ChannelBuffer m_stdErr; @@ -1102,9 +1104,9 @@ void ProcessPrivate::sendControlSignal(ControlSignal controlSignal) void ProcessPrivate::clearForRun() { m_stdOut.clearForRun(); - m_stdOut.codec = m_codec; + m_stdOut.codec = m_stdOutCodec; m_stdErr.clearForRun(); - m_stdErr.codec = m_codec; + m_stdErr.codec = m_stdErrCodec; m_result = ProcessResult::StartFailed; m_startTimestamp = {}; m_doneTimestamp = {}; @@ -1729,13 +1731,13 @@ QByteArray Process::rawStdErr() const QString Process::stdOut() const { QTC_CHECK(d->m_stdOut.keepRawData); - return d->m_codec->toUnicode(d->m_stdOut.rawData); + return d->m_stdOutCodec->toUnicode(d->m_stdOut.rawData); } QString Process::stdErr() const { QTC_CHECK(d->m_stdErr.keepRawData); - return d->m_codec->toUnicode(d->m_stdErr.rawData); + return d->m_stdErrCodec->toUnicode(d->m_stdErr.rawData); } QString Process::cleanedStdOut() const @@ -1850,7 +1852,20 @@ void ChannelBuffer::handleRest() void Process::setCodec(QTextCodec *c) { QTC_ASSERT(c, return); - d->m_codec = c; + d->m_stdOutCodec = c; + d->m_stdErrCodec = c; +} + +void Process::setStdOutCodec(QTextCodec *c) +{ + QTC_ASSERT(c, return); + d->m_stdOutCodec = c; +} + +void Process::setStdErrCodec(QTextCodec *c) +{ + QTC_ASSERT(c, return); + d->m_stdErrCodec = c; } void Process::setTimeOutMessageBoxEnabled(bool v) diff --git a/src/libs/utils/process.h b/src/libs/utils/process.h index d425f76eed3..694c1a12a86 100644 --- a/src/libs/utils/process.h +++ b/src/libs/utils/process.h @@ -148,8 +148,10 @@ public: void runBlocking(std::chrono::seconds timeout = std::chrono::seconds(10), EventLoopMode eventLoopMode = EventLoopMode::Off); - // TODO: We should specify the purpose of the codec, e.g. setCodecForStandardChannel() - void setCodec(QTextCodec *c); + void setCodec(QTextCodec *c); // for stdOut and stdErr + void setStdOutCodec(QTextCodec *c); + void setStdErrCodec(QTextCodec *c); + void setTimeOutMessageBoxEnabled(bool); void setStdOutCallback(const TextChannelCallback &callback); From 5590efa30bc28bff6c530b280258dfc6945f061d Mon Sep 17 00:00:00 2001 From: Jarek Kobus Date: Fri, 23 Feb 2024 16:54:14 +0100 Subject: [PATCH 162/243] FunctionDeclDefLinkFinder: Don't delete the watcher from its signal handler Use std::unique_ptr instead, as QScopedPointer doesn't offer release(). Change-Id: Ifbe42dca5b266930e1000a50441995023b89b802 Reviewed-by: Christian Kandeler --- src/plugins/cppeditor/cppfunctiondecldeflink.cpp | 11 +++++------ src/plugins/cppeditor/cppfunctiondecldeflink.h | 2 +- 2 files changed, 6 insertions(+), 7 deletions(-) diff --git a/src/plugins/cppeditor/cppfunctiondecldeflink.cpp b/src/plugins/cppeditor/cppfunctiondecldeflink.cpp index 9552ba21984..710397e3a81 100644 --- a/src/plugins/cppeditor/cppfunctiondecldeflink.cpp +++ b/src/plugins/cppeditor/cppfunctiondecldeflink.cpp @@ -41,21 +41,20 @@ namespace Internal { FunctionDeclDefLinkFinder::FunctionDeclDefLinkFinder(QObject *parent) : QObject(parent) -{ -} +{} void FunctionDeclDefLinkFinder::onFutureDone() { std::shared_ptr link = m_watcher->result(); - m_watcher.reset(); + m_watcher.release()->deleteLater(); if (link) { link->linkSelection = m_scannedSelection; link->nameSelection = m_nameSelection; if (m_nameSelection.selectedText() != link->nameInitial) link.reset(); } - m_scannedSelection = QTextCursor(); - m_nameSelection = QTextCursor(); + m_scannedSelection = {}; + m_nameSelection = {}; if (link) emit foundLink(link); } @@ -234,7 +233,7 @@ void FunctionDeclDefLinkFinder::startFindLinkAt( // handle the rest in a thread m_watcher.reset(new QFutureWatcher >()); - connect(m_watcher.data(), &QFutureWatcherBase::finished, this, &FunctionDeclDefLinkFinder::onFutureDone); + connect(m_watcher.get(), &QFutureWatcherBase::finished, this, &FunctionDeclDefLinkFinder::onFutureDone); m_watcher->setFuture(Utils::asyncRun(findLinkHelper, result, refactoringChanges)); } diff --git a/src/plugins/cppeditor/cppfunctiondecldeflink.h b/src/plugins/cppeditor/cppfunctiondecldeflink.h index 4ffce9bf915..8fe6219e339 100644 --- a/src/plugins/cppeditor/cppfunctiondecldeflink.h +++ b/src/plugins/cppeditor/cppfunctiondecldeflink.h @@ -36,7 +36,7 @@ private: QTextCursor m_scannedSelection; QTextCursor m_nameSelection; - QScopedPointer>> m_watcher; + std::unique_ptr>> m_watcher; }; class FunctionDeclDefLink From 53f8956fb8a4fd606a140e804a9d67a20c55f380 Mon Sep 17 00:00:00 2001 From: Jarek Kobus Date: Fri, 23 Feb 2024 17:01:03 +0100 Subject: [PATCH 163/243] FunctionDeclDefLinkFinder: Ensure the old futures are synchronized Change-Id: I68b271f85d2bb319230529d4b0b074c05c12ba4c Reviewed-by: Christian Kandeler --- src/plugins/cppeditor/cppfunctiondecldeflink.cpp | 9 +++++++-- 1 file changed, 7 insertions(+), 2 deletions(-) diff --git a/src/plugins/cppeditor/cppfunctiondecldeflink.cpp b/src/plugins/cppeditor/cppfunctiondecldeflink.cpp index 710397e3a81..e489045f351 100644 --- a/src/plugins/cppeditor/cppfunctiondecldeflink.cpp +++ b/src/plugins/cppeditor/cppfunctiondecldeflink.cpp @@ -14,8 +14,6 @@ #include #include -#include -#include #include #include @@ -23,7 +21,13 @@ #include #include +#include + +#include +#include + #include +#include #include #include #include @@ -235,6 +239,7 @@ void FunctionDeclDefLinkFinder::startFindLinkAt( m_watcher.reset(new QFutureWatcher >()); connect(m_watcher.get(), &QFutureWatcherBase::finished, this, &FunctionDeclDefLinkFinder::onFutureDone); m_watcher->setFuture(Utils::asyncRun(findLinkHelper, result, refactoringChanges)); + ExtensionSystem::PluginManager::futureSynchronizer()->addFuture(m_watcher->future()); } bool FunctionDeclDefLink::isValid() const From b0592abbf04280dc26f1c8f5936b69ff10fb7b5d Mon Sep 17 00:00:00 2001 From: Jarek Kobus Date: Fri, 23 Feb 2024 17:24:44 +0100 Subject: [PATCH 164/243] DebuggerItemConfigWidget: Ensure the futures are synchronized Don't leave possibly running futures on Creator shutdown. Change-Id: I6f4253d657b2b61112c15c9c144be10fcc8ed0cf Reviewed-by: hjk --- src/plugins/debugger/debuggeritemmanager.cpp | 9 ++++++--- 1 file changed, 6 insertions(+), 3 deletions(-) diff --git a/src/plugins/debugger/debuggeritemmanager.cpp b/src/plugins/debugger/debuggeritemmanager.cpp index 2644e3fa125..b4fb2af2dea 100644 --- a/src/plugins/debugger/debuggeritemmanager.cpp +++ b/src/plugins/debugger/debuggeritemmanager.cpp @@ -9,6 +9,8 @@ #include #include +#include + #include #include #include @@ -19,6 +21,7 @@ #include #include #include +#include #include #include #include @@ -480,14 +483,14 @@ void DebuggerItemConfigWidget::binaryPathHasChanged() if (!m_generic) { m_updateWatcher.cancel(); - DebuggerItem tmp; if (m_binaryChooser->filePath().isExecutableFile()) { - tmp = item(); - m_updateWatcher.setFuture(Utils::asyncRun([tmp]() mutable { + m_updateWatcher.setFuture(Utils::asyncRun([tmp = item()]() mutable { tmp.reinitializeFromFile(); return tmp; })); + ExtensionSystem::PluginManager::futureSynchronizer()->addFuture(m_updateWatcher.future()); } else { + const DebuggerItem tmp; setAbis(tmp.abiNames()); m_version->setText(tmp.version()); m_engineType = tmp.engineType(); From 5406f11a2b77b1088f8d9b9a525f25b204cfbad7 Mon Sep 17 00:00:00 2001 From: hjk Date: Thu, 22 Feb 2024 17:30:39 +0100 Subject: [PATCH 165/243] Debugger: Robustify lldb line parser The original version might have missed to recognize a @\r\n combination or multi-byte UTF-8 code units when they were split across to readyRead() handlers. Change-Id: Ib543fa0070b63d25b44be429a3759964d65e878e Reviewed-by: Marcus Tillmanns Reviewed-by: Alessandro Portale Reviewed-by: --- src/plugins/debugger/lldb/lldbengine.cpp | 25 ++++++++++++++---------- src/plugins/debugger/lldb/lldbengine.h | 2 +- 2 files changed, 16 insertions(+), 11 deletions(-) diff --git a/src/plugins/debugger/lldb/lldbengine.cpp b/src/plugins/debugger/lldb/lldbengine.cpp index deb42544a87..1bb409bf948 100644 --- a/src/plugins/debugger/lldb/lldbengine.cpp +++ b/src/plugins/debugger/lldb/lldbengine.cpp @@ -841,18 +841,23 @@ void LldbEngine::readLldbStandardError() void LldbEngine::readLldbStandardOutput() { - QByteArray outba = m_lldbProc.readAllRawStandardOutput(); - outba.replace("\r\n", "\n"); - QString out = QString::fromUtf8(outba); - showMessage(out, LogOutput); + const QByteArray out = m_lldbProc.readAllRawStandardOutput(); + showMessage(QString::fromUtf8(out), LogOutput); m_inbuffer.append(out); while (true) { - int pos = m_inbuffer.indexOf("@\n"); - if (pos == -1) - break; - QString response = m_inbuffer.left(pos).trimmed(); - m_inbuffer = m_inbuffer.mid(pos + 2); - emit outputReady(response); + if (int pos = m_inbuffer.indexOf("@\n"); pos >= 0) { + const QByteArray response = m_inbuffer.left(pos).trimmed(); + m_inbuffer = m_inbuffer.mid(pos + 2); + emit outputReady(QString::fromUtf8(response)); + continue; + } + if (int pos = m_inbuffer.indexOf("@\r\n"); pos >= 0) { + const QByteArray response = m_inbuffer.left(pos).trimmed(); + m_inbuffer = m_inbuffer.mid(pos + 3); + emit outputReady(QString::fromUtf8(response)); + continue; + } + break; } } diff --git a/src/plugins/debugger/lldb/lldbengine.h b/src/plugins/debugger/lldb/lldbengine.h index db11af9c104..57cbd1e7c75 100644 --- a/src/plugins/debugger/lldb/lldbengine.h +++ b/src/plugins/debugger/lldb/lldbengine.h @@ -111,7 +111,7 @@ private: private: DebuggerCommand m_lastDebuggableCommand; - QString m_inbuffer; + QByteArray m_inbuffer; QString m_scriptFileName; Utils::Process m_lldbProc; From 462caec2789a52656ca31f8d52a87d35729b67eb Mon Sep 17 00:00:00 2001 From: Eike Ziller Date: Mon, 26 Feb 2024 09:37:00 +0100 Subject: [PATCH 166/243] Utils: Small string fixes Change-Id: I2fd6bf14b1cb35f61ced841e3deea011fd54ff03 Reviewed-by: Leena Miettinen Reviewed-by: Jarek Kobus --- src/libs/utils/devicefileaccess.cpp | 4 ++-- src/libs/utils/process.cpp | 3 +-- 2 files changed, 3 insertions(+), 4 deletions(-) diff --git a/src/libs/utils/devicefileaccess.cpp b/src/libs/utils/devicefileaccess.cpp index 39bdc736e09..a38a098d380 100644 --- a/src/libs/utils/devicefileaccess.cpp +++ b/src/libs/utils/devicefileaccess.cpp @@ -568,8 +568,8 @@ static bool checkToRefuseRemoveStandardLocationDirectory(const QString &dirPath, { if (QStandardPaths::standardLocations(location).contains(dirPath)) { if (error) { - *error = Tr::tr("Refusing to remove your %1 directory.").arg( - QStandardPaths::displayName(location)); + *error = Tr::tr("Refusing to remove the standard directory \"%1\".") + .arg(QStandardPaths::displayName(location)); } return false; } diff --git a/src/libs/utils/process.cpp b/src/libs/utils/process.cpp index 651dd5b49b1..5bf44513654 100644 --- a/src/libs/utils/process.cpp +++ b/src/libs/utils/process.cpp @@ -1665,8 +1665,7 @@ QString Process::exitMessage(const CommandLine &command, ProcessResult result, case ProcessResult::Canceled: // TODO: We might want to format it nicely when bigger than 1 second, e.g. 1,324 s. // Also when it's bigger than 1 minute, 1 hour, etc... - return Tr::tr("The command \"%1\" was canceled after (%2 ms).") - .arg(cmd).arg(duration.count()); + return Tr::tr("The command \"%1\" was canceled after %2 ms.").arg(cmd).arg(duration.count()); } return {}; } From 2d7af40007eae8088aabfd75bbe0dc4bfc47cf2e Mon Sep 17 00:00:00 2001 From: Cristian Adam Date: Thu, 22 Feb 2024 16:22:46 +0100 Subject: [PATCH 167/243] CMakePM: Consider envvar QTC_CMAKE_USE_JUNCTIONS This envrionment variable can be set globally or locally for a project via '.shared' configuration. See https://doc.qt.io/qtcreator/creator-sharing-project-settings.html for details. Task-number: QTCREATORBUG-30385 Change-Id: Ie28caac8f4232678c5761b54ce370d1aeb139389 Reviewed-by: Thomas Hartmann Reviewed-by: hjk --- .../cmakeprojectmanager/cmaketoolmanager.cpp | 34 ++++++++++++++----- 1 file changed, 25 insertions(+), 9 deletions(-) diff --git a/src/plugins/cmakeprojectmanager/cmaketoolmanager.cpp b/src/plugins/cmakeprojectmanager/cmaketoolmanager.cpp index 16473a6e79a..e20c3c58eba 100644 --- a/src/plugins/cmakeprojectmanager/cmaketoolmanager.cpp +++ b/src/plugins/cmakeprojectmanager/cmaketoolmanager.cpp @@ -16,6 +16,7 @@ #include #include +#include #include #include @@ -69,6 +70,7 @@ typedef struct _REPARSE_DATA_BUFFER { #endif using namespace Core; +using namespace ProjectExplorer; using namespace Utils; namespace CMakeProjectManager { @@ -451,8 +453,19 @@ FilePath CMakeToolManager::mappedFilePath(const FilePath &path) if (path.needsDevice()) return path; - Internal::settings(); - if (!Internal::settings().useJunctionsForSourceAndBuildDirectories()) + auto project = ProjectManager::startupProject(); + auto environment = Environment::systemEnvironment(); + if (project) + environment.modify(project->additionalEnvironment()); + const bool enableJunctions + = QVariant( + environment.value_or("QTC_CMAKE_USE_JUNCTIONS", + Internal::settings().useJunctionsForSourceAndBuildDirectories() + ? "1" + : "0")) + .toBool(); + + if (!enableJunctions) return path; if (!d->m_junctionsDir.isDir()) @@ -583,14 +596,17 @@ CMakeToolManagerPrivate::CMakeToolManagerPrivate() m_junctionsDir = FilePath::fromString(*std::min_element(locations.begin(), locations.end())) .pathAppended("QtCreator/Links"); - if (Utils::qtcEnvironmentVariableIsSet("QTC_CMAKE_JUNCTIONS_DIR")) { - m_junctionsDir = FilePath::fromUserInput( - Utils::qtcEnvironmentVariable("QTC_CMAKE_JUNCTIONS_DIR")); - } - if (Utils::qtcEnvironmentVariableIsSet("QTC_CMAKE_JUNCTIONS_HASH_LENGTH")) { + auto project = ProjectManager::startupProject(); + auto environment = Environment::systemEnvironment(); + if (project) + environment.modify(project->additionalEnvironment()); + + if (environment.hasKey("QTC_CMAKE_JUNCTIONS_DIR")) + m_junctionsDir = FilePath::fromUserInput(environment.value("QTC_CMAKE_JUNCTIONS_DIR")); + + if (environment.hasKey("QTC_CMAKE_JUNCTIONS_HASH_LENGTH")) { bool ok = false; - const int hashLength - = Utils::qtcEnvironmentVariableIntValue("QTC_CMAKE_JUNCTIONS_HASH_LENGTH", &ok); + const int hashLength = environment.value("QTC_CMAKE_JUNCTIONS_HASH_LENGTH").toInt(&ok); if (ok && hashLength >= 4 && hashLength < 32) m_junctionsHashLength = hashLength; } From 44f6bbf2607cdc8bdac204e3ee9d987fb75d9243 Mon Sep 17 00:00:00 2001 From: Eike Ziller Date: Mon, 26 Feb 2024 09:00:08 +0100 Subject: [PATCH 168/243] Python: Wrap some file paths and kit name with quotes Change-Id: If147eae864013d410239d69184cdb9a4bc4479eb Reviewed-by: Leena Miettinen --- src/plugins/python/pythonkitaspect.cpp | 15 +++++++++------ src/plugins/python/pythonproject.cpp | 5 +++-- 2 files changed, 12 insertions(+), 8 deletions(-) diff --git a/src/plugins/python/pythonkitaspect.cpp b/src/plugins/python/pythonkitaspect.cpp index 2c700f58ae5..26ad44bad48 100644 --- a/src/plugins/python/pythonkitaspect.cpp +++ b/src/plugins/python/pythonkitaspect.cpp @@ -108,15 +108,17 @@ public: result << BuildSystemTask(Task::Error, Tr::tr("No Python setup.")); } else if (!path.exists()) { result << BuildSystemTask(Task::Error, - Tr::tr("Python %1 not found.").arg(path.toUserOutput())); + Tr::tr("Python \"%1\" not found.").arg(path.toUserOutput())); } else if (!path.isExecutableFile()) { result << BuildSystemTask(Task::Error, - Tr::tr("Python %1 not executable.").arg(path.toUserOutput())); + Tr::tr("Python \"%1\" is not executable.") + .arg(path.toUserOutput())); } else { if (!pipIsUsable(path)) { result << BuildSystemTask( Task::Warning, - Tr::tr("Python %1 does not contain a usable pip. Pip is used to install python " + Tr::tr("Python \"%1\" does not contain a usable pip. Pip is used to install " + "python " "packages from the Python Package Index, like PySide and the python " "language server. If you want to use any of that functionality " "ensure pip is installed for that python.") @@ -125,9 +127,10 @@ public: if (!venvIsUsable(path)) { result << BuildSystemTask( Task::Warning, - Tr::tr("Python %1 does not contain a usable venv. venv is the recommended way " - "to isolate a development environment for a project from the globally " - "installed python.") + Tr::tr( + "Python \"%1\" does not contain a usable venv. venv is the recommended way " + "to isolate a development environment for a project from the globally " + "installed python.") .arg(path.toUserOutput())); } } diff --git a/src/plugins/python/pythonproject.cpp b/src/plugins/python/pythonproject.cpp index 49216b2d6a3..129782773d3 100644 --- a/src/plugins/python/pythonproject.cpp +++ b/src/plugins/python/pythonproject.cpp @@ -33,8 +33,9 @@ Tasks PythonProject::projectIssues(const Kit *k) const { if (PythonKitAspect::python(k)) return {}; - return {BuildSystemTask{Task::Error, - Tr::tr("No python interpreter set for kit %1").arg(k->displayName())}}; + return { + BuildSystemTask{Task::Error, + Tr::tr("No python interpreter set for kit \"%1\"").arg(k->displayName())}}; } PythonProjectNode::PythonProjectNode(const FilePath &path) From 902a42a0f2d7f6e1e627fb72aae0286320995fdb Mon Sep 17 00:00:00 2001 From: Eike Ziller Date: Mon, 26 Feb 2024 08:52:10 +0100 Subject: [PATCH 169/243] Perforce: Add missing full stop Change-Id: Ic8e78fd3465ad3a0301f4bce65ced5f9948753f3 Reviewed-by: Leena Miettinen Reviewed-by: Jarek Kobus --- src/plugins/perforce/perforceplugin.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/plugins/perforce/perforceplugin.cpp b/src/plugins/perforce/perforceplugin.cpp index 42e2bbfcb18..7e8dca82656 100644 --- a/src/plugins/perforce/perforceplugin.cpp +++ b/src/plugins/perforce/perforceplugin.cpp @@ -1499,7 +1499,7 @@ QString fileNameFromPerforceName(const QString &perforceName, bool quiet) //: Failed to run p4 "where" to resolve a Perforce file name to a local //: file system name. VcsOutputWindow::appendError( - Tr::tr("Error running \"where\" on %1: The file is not mapped") + Tr::tr("Error running \"where\" on %1: The file is not mapped.") .arg(QDir::toNativeSeparators(perforceName))); } return {}; From d2cec31f0872199defcb7c9bd6dd3eada27f490e Mon Sep 17 00:00:00 2001 From: Eike Ziller Date: Fri, 23 Feb 2024 15:16:06 +0100 Subject: [PATCH 170/243] Git: Fix a label Settings labels are lower case and end with ":" Change-Id: I729d25569790899a8d26966914ee8b872a48bcb0 Reviewed-by: Leena Miettinen --- src/plugins/git/gitsettings.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/plugins/git/gitsettings.cpp b/src/plugins/git/gitsettings.cpp index 95938a41d88..2e7f8bf2de4 100644 --- a/src/plugins/git/gitsettings.cpp +++ b/src/plugins/git/gitsettings.cpp @@ -33,7 +33,7 @@ GitSettings::GitSettings() path.setLabelText(Tr::tr("Prepend to PATH:")); path.setDisplayStyle(StringAspect::LineEditDisplay); - binaryPath.setLabelText(Tr::tr("Git Command")); + binaryPath.setLabelText(Tr::tr("Git command:")); binaryPath.setDefaultValue("git"); binaryPath.setExpectedKind(PathChooser::ExistingCommand); binaryPath.setHistoryCompleter("Git.Command.History"); From 76cd84b7cd631fcb4331e9558ca9b89a695bc942 Mon Sep 17 00:00:00 2001 From: Eike Ziller Date: Fri, 23 Feb 2024 15:21:41 +0100 Subject: [PATCH 171/243] iOS: Fix some missing full stops Change-Id: Ie6c1b9dafc3e3fe349adcbe6011244136002cc01 Reviewed-by: Leena Miettinen --- share/qtcreator/translations/qtcreator_da.ts | 4 ++-- share/qtcreator/translations/qtcreator_de.ts | 2 +- share/qtcreator/translations/qtcreator_fr.ts | 4 ++-- share/qtcreator/translations/qtcreator_hr.ts | 4 ++-- share/qtcreator/translations/qtcreator_pl.ts | 4 ++-- share/qtcreator/translations/qtcreator_ru.ts | 4 ++-- share/qtcreator/translations/qtcreator_zh_CN.ts | 2 +- src/plugins/ios/devicectlutils.cpp | 2 +- src/plugins/ios/iosrunner.cpp | 2 +- src/plugins/ios/iossettingspage.cpp | 8 +++++--- 10 files changed, 19 insertions(+), 17 deletions(-) diff --git a/share/qtcreator/translations/qtcreator_da.ts b/share/qtcreator/translations/qtcreator_da.ts index 8421c0a6242..6e004586ba2 100644 --- a/share/qtcreator/translations/qtcreator_da.ts +++ b/share/qtcreator/translations/qtcreator_da.ts @@ -18346,8 +18346,8 @@ Id'er skal begynde med et lille bogstav. Simulator start - Cannot start simulator (%1, %2) in current state: %3 - Kan ikke starte simulator (%1, %2) i aktuelle tilstand: %3 + Cannot start simulator (%1, %2) in current state: %3. + Kan ikke starte simulator (%1, %2) i aktuelle tilstand: %3. simulator start diff --git a/share/qtcreator/translations/qtcreator_de.ts b/share/qtcreator/translations/qtcreator_de.ts index 89ac1623b2d..3e349e87747 100644 --- a/share/qtcreator/translations/qtcreator_de.ts +++ b/share/qtcreator/translations/qtcreator_de.ts @@ -33897,7 +33897,7 @@ Möchten Sie sie überschreiben? Simulator starten - Cannot start simulator (%1, %2) in current state: %3 + Cannot start simulator (%1, %2) in current state: %3. Der Simulator (%1, %2) kann im momentanen Zustand (%3) nicht gestartet werden. diff --git a/share/qtcreator/translations/qtcreator_fr.ts b/share/qtcreator/translations/qtcreator_fr.ts index 6f9ade5c4d3..5a5c4dd6dd7 100644 --- a/share/qtcreator/translations/qtcreator_fr.ts +++ b/share/qtcreator/translations/qtcreator_fr.ts @@ -33467,8 +33467,8 @@ Souhaitez-vous les écraser ? - Cannot start simulator (%1, %2) in current state: %3 - Impossible de démarrer le simulateur (%1, %2) dans l'état actuel : %3 + Cannot start simulator (%1, %2) in current state: %3. + Impossible de démarrer le simulateur (%1, %2) dans l'état actuel : %3. simulator start diff --git a/share/qtcreator/translations/qtcreator_hr.ts b/share/qtcreator/translations/qtcreator_hr.ts index 5cb6489b7ed..08d49c74894 100644 --- a/share/qtcreator/translations/qtcreator_hr.ts +++ b/share/qtcreator/translations/qtcreator_hr.ts @@ -4546,8 +4546,8 @@ Dodaj, izmijeni i ukloni filtre dokumenata koji određuju skup dokumentacije pri - Cannot start simulator (%1, %2) in current state: %3 - Nije moguće pokrenuti simulatora (%1, %2) u trenutačnom stanju: %3 + Cannot start simulator (%1, %2) in current state: %3. + Nije moguće pokrenuti simulatora (%1, %2) u trenutačnom stanju: %3. simulator start diff --git a/share/qtcreator/translations/qtcreator_pl.ts b/share/qtcreator/translations/qtcreator_pl.ts index 91aba3691e2..15ae93c1b15 100644 --- a/share/qtcreator/translations/qtcreator_pl.ts +++ b/share/qtcreator/translations/qtcreator_pl.ts @@ -33930,8 +33930,8 @@ Czy nadpisać je? Uruchomienie symulatora - Cannot start simulator (%1, %2) in current state: %3 - Nie można uruchomić symulatora (%1, %2) w bieżącym stanie: %3 + Cannot start simulator (%1, %2) in current state: %3. + Nie można uruchomić symulatora (%1, %2) w bieżącym stanie: %3. simulator start diff --git a/share/qtcreator/translations/qtcreator_ru.ts b/share/qtcreator/translations/qtcreator_ru.ts index ed5d78ba7a2..047034c9052 100644 --- a/share/qtcreator/translations/qtcreator_ru.ts +++ b/share/qtcreator/translations/qtcreator_ru.ts @@ -22984,8 +22984,8 @@ Ids must begin with a lowercase letter. Запустить эмулятор - Cannot start simulator (%1, %2) in current state: %3 - Невозможно запустить эмулятор (%1, %2) в текущем состоянии: %3 + Cannot start simulator (%1, %2) in current state: %3. + Невозможно запустить эмулятор (%1, %2) в текущем состоянии: %3. simulator start diff --git a/share/qtcreator/translations/qtcreator_zh_CN.ts b/share/qtcreator/translations/qtcreator_zh_CN.ts index 4e361b52d34..43021c4804e 100644 --- a/share/qtcreator/translations/qtcreator_zh_CN.ts +++ b/share/qtcreator/translations/qtcreator_zh_CN.ts @@ -23217,7 +23217,7 @@ Id必须以小写字母开头。 - Cannot start simulator (%1, %2) in current state: %3 + Cannot start simulator (%1, %2) in current state: %3. diff --git a/src/plugins/ios/devicectlutils.cpp b/src/plugins/ios/devicectlutils.cpp index f8d47caf0be..7bbed859b27 100644 --- a/src/plugins/ios/devicectlutils.cpp +++ b/src/plugins/ios/devicectlutils.cpp @@ -46,7 +46,7 @@ expected_str parseDevicectlResult(const QByteArray &rawOutput) } const QJsonValue resultValue = jsonOutput["result"]; if (resultValue.isUndefined()) { - return make_unexpected(Tr::tr("Failed to parse devicectl output: 'result' is missing")); + return make_unexpected(Tr::tr("Failed to parse devicectl output: \"result\" is missing.")); } return resultValue; } diff --git a/src/plugins/ios/iosrunner.cpp b/src/plugins/ios/iosrunner.cpp index e2ed4191292..02d47e914fc 100644 --- a/src/plugins/ios/iosrunner.cpp +++ b/src/plugins/ios/iosrunner.cpp @@ -264,7 +264,7 @@ GroupItem DeviceCtlRunner::launchTask(const QString &bundleIdentifier) void DeviceCtlRunner::reportStoppedImpl() { - appendMessage(Tr::tr("\"%1\" exited").arg(m_bundlePath.toUserOutput()), + appendMessage(Tr::tr("\"%1\" exited.").arg(m_bundlePath.toUserOutput()), Utils::NormalMessageFormat); reportStopped(); } diff --git a/src/plugins/ios/iossettingspage.cpp b/src/plugins/ios/iossettingspage.cpp index ad81b81b19d..042dfca9af6 100644 --- a/src/plugins/ios/iossettingspage.cpp +++ b/src/plugins/ios/iossettingspage.cpp @@ -204,9 +204,11 @@ void IosSettingsWidget::onStart() QList> futureList; for (const SimulatorInfo &info : simulatorInfoList) { if (!info.isShutdown()) { - statusDialog->addMessage(Tr::tr("Cannot start simulator (%1, %2) in current state: %3") - .arg(info.name).arg(info.runtimeName).arg(info.state), - Utils::StdErrFormat); + statusDialog->addMessage(Tr::tr("Cannot start simulator (%1, %2) in current state: %3.") + .arg(info.name) + .arg(info.runtimeName) + .arg(info.state), + Utils::StdErrFormat); } else { futureList << QFuture(Utils::onResultReady( SimulatorControl::startSimulator(info.identifier), this, From fdc84e84580f7640d2dcc6e2d8065abf57596da3 Mon Sep 17 00:00:00 2001 From: Christian Stenger Date: Mon, 26 Feb 2024 08:20:08 +0100 Subject: [PATCH 172/243] Axivion: Tweak path display Change-Id: I9148530eff5dbc4757c2f4b46c1b55a895043f1f Reviewed-by: hjk --- src/plugins/axivion/axivionoutputpane.cpp | 8 +++++++- 1 file changed, 7 insertions(+), 1 deletion(-) diff --git a/src/plugins/axivion/axivionoutputpane.cpp b/src/plugins/axivion/axivionoutputpane.cpp index e6272d46ccf..132ebebf65d 100644 --- a/src/plugins/axivion/axivionoutputpane.cpp +++ b/src/plugins/axivion/axivionoutputpane.cpp @@ -469,6 +469,7 @@ void IssuesWidget::addIssues(const Dto::IssueTableDto &dto, int startRow) for (const auto &row : rows) { QString id; QStringList data; + QStringList toolTips; for (const auto &column : tableColumns) { const auto it = row.find(column.key); if (it != row.end()) { @@ -477,10 +478,15 @@ void IssuesWidget::addIssues(const Dto::IssueTableDto &dto, int startRow) value.prepend(m_currentPrefix); id = value; } + toolTips << value; + if (column.key.toLower().endsWith("path")) { + const FilePath fp = FilePath::fromUserInput(value); + value = QString("%1 [%2]").arg(fp.fileName(), fp.path()); + } data << value; } } - IssueListItem *it = new IssueListItem(startRow++, id, data, data); + IssueListItem *it = new IssueListItem(startRow++, id, data, toolTips); it->setLinks(linksForIssue(row, tableColumns)); items.append(it); } From 6dda17a2b3547a21f27893c7ff94952a719ffe21 Mon Sep 17 00:00:00 2001 From: Christian Stenger Date: Mon, 26 Feb 2024 08:46:37 +0100 Subject: [PATCH 173/243] Axivion: Take alignments into account Change-Id: I3d14b88562dbd9eca79ba954e6d01206aaec450e Reviewed-by: hjk --- src/plugins/axivion/axivionoutputpane.cpp | 14 ++++++++++++++ src/plugins/axivion/dynamiclistmodel.cpp | 12 +++++++++++- src/plugins/axivion/dynamiclistmodel.h | 2 ++ 3 files changed, 27 insertions(+), 1 deletion(-) diff --git a/src/plugins/axivion/axivionoutputpane.cpp b/src/plugins/axivion/axivionoutputpane.cpp index 132ebebf65d..a13b63dd3a2 100644 --- a/src/plugins/axivion/axivionoutputpane.cpp +++ b/src/plugins/axivion/axivionoutputpane.cpp @@ -380,6 +380,17 @@ void IssuesWidget::updateUi() fetchTable(); } +static Qt::Alignment alignmentFromString(const QString &str) +{ + if (str == "left") + return Qt::AlignLeft; + if (str == "right") + return Qt::AlignRight; + if (str == "center") + return Qt::AlignHCenter; + return Qt::AlignLeft; +} + void IssuesWidget::updateTable() { if (!m_currentTableInfo) @@ -389,12 +400,14 @@ void IssuesWidget::updateTable() QStringList hiddenColumns; QList sortableColumns; QList columnWidths; + QList alignments; for (const Dto::ColumnInfoDto &column : m_currentTableInfo->columns) { columnHeaders << column.header.value_or(column.key); if (!column.showByDefault) hiddenColumns << column.key; sortableColumns << column.canSort; columnWidths << column.width; + alignments << alignmentFromString(column.alignment); } m_addedFilter->setText("0"); m_removedFilter->setText("0"); @@ -402,6 +415,7 @@ void IssuesWidget::updateTable() m_issuesModel->clear(); m_issuesModel->setHeader(columnHeaders); + m_issuesModel->setAlignments(alignments); m_headerView->setSortableColumns(sortableColumns); m_headerView->setColumnWidths(columnWidths); int counter = 0; diff --git a/src/plugins/axivion/dynamiclistmodel.cpp b/src/plugins/axivion/dynamiclistmodel.cpp index 45819995963..70abe087bdb 100644 --- a/src/plugins/axivion/dynamiclistmodel.cpp +++ b/src/plugins/axivion/dynamiclistmodel.cpp @@ -61,8 +61,13 @@ QVariant DynamicListModel::data(const QModelIndex &index, int role) const return {}; auto item = m_children.constFind(row); - if (item != m_children.cend()) + if (item != m_children.cend()) { + if (role == Qt::TextAlignmentRole) { + if (!m_alignments.isEmpty() && index.column() < m_alignments.size()) + return QVariant::fromValue(m_alignments.at(index.column())); + } return item.value()->data(index.column(), role); + } if ((row < m_lastFetch || row > m_lastFetchEnd) && (row < m_fetchStart || row > m_fetchEnd)) const_cast(this)->onNeedFetch(row); @@ -138,6 +143,11 @@ void DynamicListModel::setHeader(const QStringList &header) m_columnCount = m_header.size(); } +void DynamicListModel::setAlignments(const QList &alignments) +{ + m_alignments = alignments; +} + QModelIndex DynamicListModel::indexForItem(const ListItem *item) const { QTC_ASSERT(item, return {}); diff --git a/src/plugins/axivion/dynamiclistmodel.h b/src/plugins/axivion/dynamiclistmodel.h index 1e83a572c35..d60f9f16159 100644 --- a/src/plugins/axivion/dynamiclistmodel.h +++ b/src/plugins/axivion/dynamiclistmodel.h @@ -43,6 +43,7 @@ public: void setExpectedRowCount(int expected); void setHeader(const QStringList &header); + void setAlignments(const QList &alignments); QModelIndex indexForItem(const ListItem *item) const; @@ -55,6 +56,7 @@ private: QHash m_children; QStringList m_header; + QList m_alignments; QTimer m_fetchMoreTimer; std::optional m_expectedRowCount = {}; int m_fetchStart = -1; From 2bee865f807605e56aae8e5b0bd642b28d72357c Mon Sep 17 00:00:00 2001 From: Jarek Kobus Date: Fri, 23 Feb 2024 18:55:02 +0100 Subject: [PATCH 174/243] CompilationDbParser: Ensure the futures are synchronized Don't leave possibly running futures on Creator shutdown. Change-Id: I8b0f800518edde638376013f993f5846df4d1753 Reviewed-by: Reviewed-by: Christian Kandeler --- .../compilationdatabaseprojectmanager/compilationdbparser.cpp | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/src/plugins/compilationdatabaseprojectmanager/compilationdbparser.cpp b/src/plugins/compilationdatabaseprojectmanager/compilationdbparser.cpp index 5f860956026..4ab893a9e6c 100644 --- a/src/plugins/compilationdatabaseprojectmanager/compilationdbparser.cpp +++ b/src/plugins/compilationdatabaseprojectmanager/compilationdbparser.cpp @@ -8,9 +8,12 @@ #include +#include + #include #include +#include #include #include @@ -187,6 +190,7 @@ void CompilationDbParser::start() "CompilationDatabase.Parse"); ++m_runningParserJobs; m_parserWatcher.setFuture(future); + ExtensionSystem::PluginManager::futureSynchronizer()->addFuture(future); } void CompilationDbParser::stop() From ff6e231170c992a184829bd9c94fbffcca15df7a Mon Sep 17 00:00:00 2001 From: Jarek Kobus Date: Fri, 23 Feb 2024 18:38:42 +0100 Subject: [PATCH 175/243] CompilationDatabaseBuildSystem: Remove unused QFutureWatcher Change-Id: I6dd6769cb5aa71149735a7920701c8f6ad98ee03 Reviewed-by: Christian Kandeler Reviewed-by: Qt CI Bot Reviewed-by: --- .../compilationdatabaseproject.cpp | 6 +----- .../compilationdatabaseproject.h | 3 --- 2 files changed, 1 insertion(+), 8 deletions(-) diff --git a/src/plugins/compilationdatabaseprojectmanager/compilationdatabaseproject.cpp b/src/plugins/compilationdatabaseprojectmanager/compilationdatabaseproject.cpp index 914c6f705f0..ebe7ff44753 100644 --- a/src/plugins/compilationdatabaseprojectmanager/compilationdatabaseproject.cpp +++ b/src/plugins/compilationdatabaseprojectmanager/compilationdatabaseproject.cpp @@ -332,11 +332,7 @@ CompilationDatabaseBuildSystem::CompilationDatabaseBuildSystem(Target *target) this, &CompilationDatabaseBuildSystem::updateDeploymentData); } -CompilationDatabaseBuildSystem::~CompilationDatabaseBuildSystem() -{ - m_parserWatcher.cancel(); - m_parserWatcher.waitForFinished(); -} +CompilationDatabaseBuildSystem::~CompilationDatabaseBuildSystem() = default; void CompilationDatabaseBuildSystem::triggerParsing() { diff --git a/src/plugins/compilationdatabaseprojectmanager/compilationdatabaseproject.h b/src/plugins/compilationdatabaseprojectmanager/compilationdatabaseproject.h index 25561f5aac1..2b8faec0208 100644 --- a/src/plugins/compilationdatabaseprojectmanager/compilationdatabaseproject.h +++ b/src/plugins/compilationdatabaseprojectmanager/compilationdatabaseproject.h @@ -13,8 +13,6 @@ #include -#include - namespace ProjectExplorer { class Kit; class ProjectUpdater; @@ -51,7 +49,6 @@ public: void updateDeploymentData(); void buildTreeAndProjectParts(); - QFutureWatcher m_parserWatcher; std::unique_ptr m_cppCodeModelUpdater; MimeBinaryCache m_mimeBinaryCache; QByteArray m_projectFileHash; From 51ddffefd87770c6d13a75fdaa8687e0587cd525 Mon Sep 17 00:00:00 2001 From: Jarek Kobus Date: Mon, 26 Feb 2024 10:57:08 +0100 Subject: [PATCH 176/243] QLiteHtml: Update submodule sha to include the crash fix Task-number: QTCREATORBUG-30427 Change-Id: Icc166c8bb895e5ce37887b12af97a5b785df2b29 Reviewed-by: Eike Ziller --- src/libs/qlitehtml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/libs/qlitehtml b/src/libs/qlitehtml index 9248bd827b3..7e8eb0f5eae 160000 --- a/src/libs/qlitehtml +++ b/src/libs/qlitehtml @@ -1 +1 @@ -Subproject commit 9248bd827b3859e6898860c15a63c6cd57ca5434 +Subproject commit 7e8eb0f5eaee53b0aeb04208bdaba74fcffc3a3f From 17a9cce898e19587d229e5f9b9f88aea6e1fa729 Mon Sep 17 00:00:00 2001 From: Jarek Kobus Date: Mon, 26 Feb 2024 11:30:42 +0100 Subject: [PATCH 177/243] Async: Avoid potential leak of QFutureWatcher Make QFutureWatcher a child of the receiver / guard inside the onResultReady() / onFinished() handlers. This prevents the leak of QFutureWatcher when the receiver / guard got deleted and the future never finishes. Change-Id: I5653593777ee394dff8cc3c4b7506d8c1907232f Reviewed-by: Eike Ziller --- src/libs/utils/async.h | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/src/libs/utils/async.h b/src/libs/utils/async.h index e1aacb126ef..af6fb3fd85d 100644 --- a/src/libs/utils/async.h +++ b/src/libs/utils/async.h @@ -54,7 +54,7 @@ auto asyncRun(Function &&function, Args &&...args) template const QFuture &onResultReady(const QFuture &future, R *receiver, void(R::*member)(const T &)) { - auto watcher = new QFutureWatcher(); + auto watcher = new QFutureWatcher(receiver); QObject::connect(watcher, &QFutureWatcherBase::finished, watcher, &QObject::deleteLater); QObject::connect(watcher, &QFutureWatcherBase::resultReadyAt, receiver, [=](int index) { (receiver->*member)(watcher->future().resultAt(index)); @@ -72,7 +72,7 @@ const QFuture &onResultReady(const QFuture &future, R *receiver, void(R::* template const QFuture &onResultReady(const QFuture &future, QObject *guard, Function f) { - auto watcher = new QFutureWatcher(); + auto watcher = new QFutureWatcher(guard); QObject::connect(watcher, &QFutureWatcherBase::finished, watcher, &QObject::deleteLater); QObject::connect(watcher, &QFutureWatcherBase::resultReadyAt, guard, [f, watcher](int index) { f(watcher->future().resultAt(index)); @@ -90,7 +90,7 @@ template const QFuture &onFinished(const QFuture &future, R *receiver, void (R::*member)(const QFuture &)) { - auto watcher = new QFutureWatcher(); + auto watcher = new QFutureWatcher(receiver); QObject::connect(watcher, &QFutureWatcherBase::finished, watcher, &QObject::deleteLater); QObject::connect(watcher, &QFutureWatcherBase::finished, receiver, [=] { (receiver->*member)(watcher->future()); }); @@ -107,7 +107,7 @@ const QFuture &onFinished(const QFuture &future, template const QFuture &onFinished(const QFuture &future, QObject *guard, Function f) { - auto watcher = new QFutureWatcher(); + auto watcher = new QFutureWatcher(guard); QObject::connect(watcher, &QFutureWatcherBase::finished, watcher, &QObject::deleteLater); QObject::connect(watcher, &QFutureWatcherBase::finished, guard, [f, watcher] { f(watcher->future()); From 98ffe3d9d05cbcb3b7f12d9912e108a8e19b203d Mon Sep 17 00:00:00 2001 From: Eike Ziller Date: Thu, 22 Feb 2024 12:08:37 +0100 Subject: [PATCH 178/243] AutoTest: Small fixes in translatable strings Make the tool tip for useXMLOutput, quickCheckForDerivedTests, and parseMessages consistent, use rich text instead of manual line breaks. We use plural for the things that a locator filter locates (for filters that don't trigger an action). Beautify tool tip. Change-Id: I6276e9a0894d59670a45937e1c4227405c346f38 Reviewed-by: Leena Miettinen Reviewed-by: Reviewed-by: Christian Stenger --- share/qtcreator/translations/qtcreator_da.ts | 8 ++---- share/qtcreator/translations/qtcreator_de.ts | 14 +++-------- share/qtcreator/translations/qtcreator_fr.ts | 14 +++-------- share/qtcreator/translations/qtcreator_hr.ts | 8 ++---- share/qtcreator/translations/qtcreator_pl.ts | 7 ++---- share/qtcreator/translations/qtcreator_ru.ts | 8 ++---- .../qtcreator/translations/qtcreator_zh_CN.ts | 8 ++---- .../autotest/qtest/datataglocatorfilter.cpp | 2 +- .../autotest/qtest/qttestframework.cpp | 25 +++++++++++-------- 9 files changed, 34 insertions(+), 60 deletions(-) diff --git a/share/qtcreator/translations/qtcreator_da.ts b/share/qtcreator/translations/qtcreator_da.ts index 6e004586ba2..43f21468465 100644 --- a/share/qtcreator/translations/qtcreator_da.ts +++ b/share/qtcreator/translations/qtcreator_da.ts @@ -1717,12 +1717,8 @@ Se Google Test-dokumentation for yderligere information om GTest-filtre.Perf - XML output is recommended, because it avoids parsing issues, while plain text is more human readable. - -Warning: Plain text misses some information, such as duration. - XML-output anbefales, fordi det forhindre parsing-problemer, mens ren tekst er lettere at læse for mennesker. - -Advarsel: Ren tekst mangle nogle informationer, såsom varighed. + XML output is recommended, because it avoids parsing issues, while plain text is more human readable.<p>Warning: Plain text misses some information, such as duration. + XML-output anbefales, fordi det forhindre parsing-problemer, mens ren tekst er lettere at læse for mennesker.<p>Advarsel: Ren tekst mangle nogle informationer, såsom varighed. Select Run Configuration diff --git a/share/qtcreator/translations/qtcreator_de.ts b/share/qtcreator/translations/qtcreator_de.ts index 3e349e87747..b15b6a1af2e 100644 --- a/share/qtcreator/translations/qtcreator_de.ts +++ b/share/qtcreator/translations/qtcreator_de.ts @@ -12413,10 +12413,8 @@ Weitere Informationen über GTest-Filter finden Sie in der Dokumenation von Goog Auf abgeleitete Qt Quick-Tests überprüfen - Search for Qt Quick tests that are derived from TestCase. -Warning: Enabling this feature significantly increases scan time. - Sucht nach Qt Quick-Tests, die von TestCase abgeleitet sind. -Achtung: Dies erhöht die zum Durchsuchen benötigte Zeit erheblich. + Search for Qt Quick tests that are derived from TestCase.<p>Warning: Enabling this feature significantly increases scan time. + Sucht nach Qt Quick-Tests, die von TestCase abgeleitet sind.<p>Achtung: Dies erhöht die zum Durchsuchen benötigte Zeit erheblich. Benchmark Metrics @@ -12463,12 +12461,8 @@ Achtung: Dies erhöht die zum Durchsuchen benötigte Zeit erheblich.Perf - XML output is recommended, because it avoids parsing issues, while plain text is more human readable. - -Warning: Plain text misses some information, such as duration. - Die XML-Ausgabe ist empfehlenswert, weil sie Probleme beim Einlesen vermeidet. Reiner Text ist hingegen besser lesbar für Menschen. - -Warnung: Reinem Text fehlen manche Informationen, etwa die Dauer. + XML output is recommended, because it avoids parsing issues, while plain text is more human readable.<p>Warning: Plain text misses some information, such as duration. + Die XML-Ausgabe ist empfehlenswert, weil sie Probleme beim Einlesen vermeidet. Reiner Text ist hingegen besser lesbar für Menschen.<p>Warnung: Reinem Text fehlen manche Informationen, etwa die Dauer. Select Run Configuration diff --git a/share/qtcreator/translations/qtcreator_fr.ts b/share/qtcreator/translations/qtcreator_fr.ts index 5a5c4dd6dd7..fe4d87c0326 100644 --- a/share/qtcreator/translations/qtcreator_fr.ts +++ b/share/qtcreator/translations/qtcreator_fr.ts @@ -12063,12 +12063,8 @@ Voir la documentation de Google Test pour plus d'informations sur les filtr Utilise la sortie XML - XML output is recommended, because it avoids parsing issues, while plain text is more human readable. - -Warning: Plain text misses some information, such as duration. - La sortie XML est recommandée : elle évite des problèmes d'analyse, alors que le texte brut est plus lisible pour un humain. - -Avertissement : le texte brut ne contient pas toutes les informations, telle que la durée. + XML output is recommended, because it avoids parsing issues, while plain text is more human readable.<p>Warning: Plain text misses some information, such as duration. + La sortie XML est recommandée : elle évite des problèmes d'analyse, alors que le texte brut est plus lisible pour un humain.<p>Avertissement : le texte brut ne contient pas toutes les informations, telle que la durée. Verbose benchmarks @@ -12099,10 +12095,8 @@ Avertissement : le texte brut ne contient pas toutes les informations, tell Vérifier la présence de tests dérivés de Qt Quick - Search for Qt Quick tests that are derived from TestCase. -Warning: Enabling this feature significantly increases scan time. - Recherche des tests Qt Quick dérivé de TestCase. -Avertissement : l'activation de cette fonctionnalité augmente significativement le temps de recherche. + Search for Qt Quick tests that are derived from TestCase.<p>Warning: Enabling this feature significantly increases scan time. + Recherche des tests Qt Quick dérivé de TestCase.<p>Avertissement : l'activation de cette fonctionnalité augmente significativement le temps de recherche. Benchmark Metrics diff --git a/share/qtcreator/translations/qtcreator_hr.ts b/share/qtcreator/translations/qtcreator_hr.ts index 08d49c74894..6d69f112adb 100644 --- a/share/qtcreator/translations/qtcreator_hr.ts +++ b/share/qtcreator/translations/qtcreator_hr.ts @@ -1135,12 +1135,8 @@ Dodatne dokumente o GTest filtrima potraži u Google Test dokumentaciji.Deaktiviraj rukovatelja urušivanja tijekom uklanjanja grešaka - XML output is recommended, because it avoids parsing issues, while plain text is more human readable. - -Warning: Plain text misses some information, such as duration. - Preporuča se XML izlaz, jer izbjegava probleme s raščlanjivanjem, dok je običan tekst čitljiviji za čitanje. - -Upozorenje: Običan tekst propušta neke informacije, kao što je trajanje. + XML output is recommended, because it avoids parsing issues, while plain text is more human readable.<p>Warning: Plain text misses some information, such as duration. + Preporuča se XML izlaz, jer izbjegava probleme s raščlanjivanjem, dok je običan tekst čitljiviji za čitanje.<p>Upozorenje: Običan tekst propušta neke informacije, kao što je trajanje. Use XML output diff --git a/share/qtcreator/translations/qtcreator_pl.ts b/share/qtcreator/translations/qtcreator_pl.ts index 15ae93c1b15..a59ebcb424c 100644 --- a/share/qtcreator/translations/qtcreator_pl.ts +++ b/share/qtcreator/translations/qtcreator_pl.ts @@ -12692,8 +12692,7 @@ See also Google Test settings. - Search for Qt Quick tests that are derived from TestCase. -Warning: Enabling this feature significantly increases scan time. + Search for Qt Quick tests that are derived from TestCase.<p>Warning: Enabling this feature significantly increases scan time. @@ -12713,9 +12712,7 @@ Warning: Enabling this feature significantly increases scan time. Używaj XML na wyjściu - XML output is recommended, because it avoids parsing issues, while plain text is more human readable. - -Warning: Plain text misses some information, such as duration. + XML output is recommended, because it avoids parsing issues, while plain text is more human readable.<p>Warning: Plain text misses some information, such as duration. diff --git a/share/qtcreator/translations/qtcreator_ru.ts b/share/qtcreator/translations/qtcreator_ru.ts index 047034c9052..ac9a564f8b3 100644 --- a/share/qtcreator/translations/qtcreator_ru.ts +++ b/share/qtcreator/translations/qtcreator_ru.ts @@ -2745,12 +2745,8 @@ See Google Test documentation for further information on GTest filters. Логировать сигналы и слоты - XML output is recommended, because it avoids parsing issues, while plain text is more human readable. - -Warning: Plain text misses some information, such as duration. - Рекомендуется вывод в формате XML, так как исключает проблемы при разборе. Простой же текст более удобен для чтения человеком. - -Предупреждение: простой текст не содержит некоторую информацию, например, длительность. + XML output is recommended, because it avoids parsing issues, while plain text is more human readable.<p>Warning: Plain text misses some information, such as duration. + Рекомендуется вывод в формате XML, так как исключает проблемы при разборе. Простой же текст более удобен для чтения человеком.<p>Предупреждение: простой текст не содержит некоторую информацию, например, длительность. Select Run Configuration diff --git a/share/qtcreator/translations/qtcreator_zh_CN.ts b/share/qtcreator/translations/qtcreator_zh_CN.ts index 43021c4804e..7526f78c968 100644 --- a/share/qtcreator/translations/qtcreator_zh_CN.ts +++ b/share/qtcreator/translations/qtcreator_zh_CN.ts @@ -2950,12 +2950,8 @@ See Google Test documentation for further information on GTest filters. 使用 XML 输出 - XML output is recommended, because it avoids parsing issues, while plain text is more human readable. - -Warning: Plain text misses some information, such as duration. - 建议使用 XML 输出,它避免了一些解析问题,虽然纯文本可读性更好。 - -警告:纯文本丢失了一些信息,比如持续时间。 + XML output is recommended, because it avoids parsing issues, while plain text is more human readable.<p>Warning: Plain text misses some information, such as duration. + 建议使用 XML 输出,它避免了一些解析问题,虽然纯文本可读性更好。<p>警告:纯文本丢失了一些信息,比如持续时间。 Verbose benchmarks diff --git a/src/plugins/autotest/qtest/datataglocatorfilter.cpp b/src/plugins/autotest/qtest/datataglocatorfilter.cpp index bb0745d189e..e6a436666ce 100644 --- a/src/plugins/autotest/qtest/datataglocatorfilter.cpp +++ b/src/plugins/autotest/qtest/datataglocatorfilter.cpp @@ -70,7 +70,7 @@ DataTagLocatorFilter::DataTagLocatorFilter() { setId("Locate Qt Test data tags"); setDisplayName(Tr::tr("Locate Qt Test data tags")); - setDescription(Tr::tr("Locates a Qt Test data tag found inside the active project.")); + setDescription(Tr::tr("Locates Qt Test data tags found inside the active project.")); setDefaultShortcutString("qdt"); setPriority(Medium); using namespace ProjectExplorer; diff --git a/src/plugins/autotest/qtest/qttestframework.cpp b/src/plugins/autotest/qtest/qttestframework.cpp index 009acc81ab1..17970e19d70 100644 --- a/src/plugins/autotest/qtest/qttestframework.cpp +++ b/src/plugins/autotest/qtest/qttestframework.cpp @@ -73,9 +73,10 @@ QtTestFramework::QtTestFramework() useXMLOutput.setSettingsKey("UseXMLOutput"); useXMLOutput.setDefaultValue(true); useXMLOutput.setLabelText(Tr::tr("Use XML output")); - useXMLOutput.setToolTip(Tr::tr("XML output is recommended, because it avoids parsing issues, " - "while plain text is more human readable.\n\nWarning: " - "Plain text misses some information, such as duration.")); + useXMLOutput.setToolTip("" + + Tr::tr("XML output is recommended, because it avoids parsing issues, " + "while plain text is more human readable.

Warning: " + "Plain text misses some information, such as duration.")); verboseBench.setSettingsKey("VerboseBench"); verboseBench.setLabelText(Tr::tr("Verbose benchmarks")); @@ -98,18 +99,22 @@ QtTestFramework::QtTestFramework() quickCheckForDerivedTests.setDefaultValue(false); quickCheckForDerivedTests.setLabelText(Tr::tr("Check for derived Qt Quick tests")); quickCheckForDerivedTests.setToolTip( - Tr::tr("Search for Qt Quick tests that are derived from TestCase.\nWarning: Enabling this " - "feature significantly increases scan time.")); + "" + + Tr::tr( + "Search for Qt Quick tests that are derived from TestCase.

Warning: Enabling this " + "feature significantly increases scan time.")); parseMessages.setSettingsKey("ParseMessages"); parseMessages.setDefaultValue(false); parseMessages.setLabelText(Tr::tr("Find user-defined locations")); parseMessages.setToolTip( - Tr::tr("Parse messages for the pattern \"file://filepath:line\", where \":line\" is " - "optional, and use this as location information.\n" - "Warning: If the patterns are used in code, the location information for debug " - "messages and other messages might improve,\n" - "at the risk of some incorrect locations and lower performance.")); + "" + + Tr::tr("Parse messages for the following pattern and use it as location information:" + "

file://filepath:line
" + "where \":line\" is optional." + "

Warning: If the patterns are used in code, the location information for debug " + "messages and other messages might improve," + "at the risk of some incorrect locations and lower performance.")); readSettings(); maxWarnings.setEnabler(&limitWarnings); From 1b53c931c5bd544811cbdb51441c76b17c482b2a Mon Sep 17 00:00:00 2001 From: Semih Yavuz Date: Fri, 23 Feb 2024 11:44:17 +0100 Subject: [PATCH 179/243] qmllssettings: Fix incorrect detecting of latest version Update the latestVersion in the loop. Otherwise we always compare to initial value and consequently the last installed version incorrecyly becomes the latest version. Fixes: QTCREATORBUG-30423 Change-Id: I7083928c5e371f0337677eacf1b3b4da50358a7c Reviewed-by: Reviewed-by: Fabian Kosmale Reviewed-by: Ulf Hermann --- src/plugins/qmljseditor/qmllssettings.cpp | 1 + 1 file changed, 1 insertion(+) diff --git a/src/plugins/qmljseditor/qmllssettings.cpp b/src/plugins/qmljseditor/qmllssettings.cpp index 76ce535fa79..15cb8908afb 100644 --- a/src/plugins/qmljseditor/qmllssettings.cpp +++ b/src/plugins/qmljseditor/qmllssettings.cpp @@ -49,6 +49,7 @@ static FilePath evaluateLatestQmlls() if (latestQmakeFilePath == qmakeNow && latestUniqueId >= v->uniqueId()) continue; } + latestVersion = vNow; latestQmlls = qmllsNow; latestQmakeFilePath = qmakeNow; latestUniqueId = uniqueIdNow; From b890b35e116ef9349afc78920b9e460e628eaa2f Mon Sep 17 00:00:00 2001 From: Orgad Shaneh Date: Sun, 25 Feb 2024 12:22:41 +0200 Subject: [PATCH 180/243] SyntaxHighlighting: Fix MSVC warning Implicit size_t -> int conversion. Upstream MR: https://invent.kde.org/frameworks/syntax-highlighting/-/merge_requests/601 Change-Id: I4208f0240c8a223fccf40add828499597e137c26 Reviewed-by: David Schulz --- src/libs/3rdparty/syntax-highlighting/src/lib/state_p.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/libs/3rdparty/syntax-highlighting/src/lib/state_p.h b/src/libs/3rdparty/syntax-highlighting/src/lib/state_p.h index 4aee1416818..9971f7f6602 100644 --- a/src/libs/3rdparty/syntax-highlighting/src/lib/state_p.h +++ b/src/libs/3rdparty/syntax-highlighting/src/lib/state_p.h @@ -36,7 +36,7 @@ public: return state.d.data(); } - int size() const + std::size_t size() const { return m_contextStack.size(); } From 6df43e8b61c9bc257c851d490cc43f5832ce2578 Mon Sep 17 00:00:00 2001 From: Leena Miettinen Date: Mon, 26 Feb 2024 11:53:09 +0100 Subject: [PATCH 181/243] Axivion: Improve tooltip Remove wordiness and just explain what enabling the checkbox does. Change-Id: Id4c03c1aa7fe7b87919036ffe39717e1a184d5f2 Reviewed-by: Eike Ziller Reviewed-by: Christian Stenger --- src/plugins/axivion/axivionsettings.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/plugins/axivion/axivionsettings.cpp b/src/plugins/axivion/axivionsettings.cpp index 8597fac9150..9b24fa51f02 100644 --- a/src/plugins/axivion/axivionsettings.cpp +++ b/src/plugins/axivion/axivionsettings.cpp @@ -108,7 +108,7 @@ AxivionSettings::AxivionSettings() highlightMarks.setSettingsKey("HighlightMarks"); highlightMarks.setLabelText(Tr::tr("Highlight marks")); - highlightMarks.setToolTip(Tr::tr("Check to enable issue marks on the scroll bar.")); + highlightMarks.setToolTip(Tr::tr("Marks issues on the scroll bar.")); highlightMarks.setDefaultValue(false); AspectContainer::readSettings(); From b10df4c1b3cdb0d2d9c36a0655af95085abe615e Mon Sep 17 00:00:00 2001 From: Marcus Tillmanns Date: Fri, 23 Feb 2024 17:01:58 +0100 Subject: [PATCH 182/243] ProjectExplorer: Show full lines during compilation Especially on Windows with VC2022 & Ninja, the output would often display lines that ended in the middle until the next batch of output was added. This patch uses the Process facilities to only show full lines. Change-Id: I38fcb2e8cb115637d15181b39374c533db150c1a Reviewed-by: Reviewed-by: David Schulz --- .../projectexplorer/abstractprocessstep.cpp | 21 +++++++++---------- 1 file changed, 10 insertions(+), 11 deletions(-) diff --git a/src/plugins/projectexplorer/abstractprocessstep.cpp b/src/plugins/projectexplorer/abstractprocessstep.cpp index 84a31135790..547599bc9d6 100644 --- a/src/plugins/projectexplorer/abstractprocessstep.cpp +++ b/src/plugins/projectexplorer/abstractprocessstep.cpp @@ -79,8 +79,6 @@ public: std::function m_environmentModifier; bool m_ignoreReturnValue = false; bool m_lowPriority = false; - std::unique_ptr stdOutDecoder; - std::unique_ptr stdErrDecoder; OutputFormatter *outputFormatter = nullptr; }; @@ -146,9 +144,6 @@ bool AbstractProcessStep::init() if (!setupProcessParameters(processParameters())) return false; - d->stdOutDecoder = std::make_unique(buildEnvironment().hasKey("VSLANG") - ? QTextCodec::codecForName("UTF-8") : QTextCodec::codecForLocale()); - d->stdErrDecoder = std::make_unique(QTextCodec::codecForLocale()); return true; } @@ -197,14 +192,18 @@ bool AbstractProcessStep::setupProcess(Process &process) if (d->m_lowPriority && ProjectExplorerPlugin::projectExplorerSettings().lowBuildPriority) process.setLowPriority(); - connect(&process, &Process::readyReadStandardOutput, this, [this, &process] { - emit addOutput(d->stdOutDecoder->toUnicode(process.readAllRawStandardOutput()), - OutputFormat::Stdout, DontAppendNewline); + process.setStdOutCodec(buildEnvironment().hasKey("VSLANG") + ? QTextCodec::codecForName("UTF-8") : QTextCodec::codecForLocale()); + process.setStdErrCodec(QTextCodec::codecForLocale()); + + process.setStdOutLineCallback([this](const QString &s){ + emit addOutput(s, OutputFormat::Stdout, DontAppendNewline); }); - connect(&process, &Process::readyReadStandardError, this, [this, &process] { - emit addOutput(d->stdErrDecoder->toUnicode(process.readAllRawStandardError()), - OutputFormat::Stderr, DontAppendNewline); + + process.setStdErrLineCallback([this](const QString &s){ + emit addOutput(s, OutputFormat::Stderr, DontAppendNewline); }); + connect(&process, &Process::started, this, [this] { ProcessParameters *params = d->m_displayedParams; emit addOutput(Tr::tr("Starting: \"%1\" %2") From b5e03b8fe2ce7bfe3ef782591bf19a6e452ef32d Mon Sep 17 00:00:00 2001 From: hjk Date: Mon, 26 Feb 2024 10:28:28 +0100 Subject: [PATCH 183/243] QtSupport: Reduce ExtraCompiler life time to plugin life time again Amends 6467797af2. The created extra compilers were parented to their factories, who gained a life time extension from 'end of plugin live' to static destruction when the factories were made static. However, this that time the likewise static QObjectCache in GeneratedCodeModelSupport::update might be destroyed already, leading to a potential crash in m_cache.remove(dead). This change here re-establishes the original timing by using the plugin itself as parent for the extra compilers. Change-Id: Id868b7b87f00440c67af551b71359c47a5c29cba Reviewed-by: Christian Kandeler Reviewed-by: --- src/plugins/qtsupport/qscxmlcgenerator.cpp | 11 +++++++---- src/plugins/qtsupport/qscxmlcgenerator.h | 4 +++- src/plugins/qtsupport/qtsupportplugin.cpp | 4 ++-- src/plugins/qtsupport/uicgenerator.cpp | 11 +++++++---- src/plugins/qtsupport/uicgenerator.h | 4 +++- 5 files changed, 22 insertions(+), 12 deletions(-) diff --git a/src/plugins/qtsupport/qscxmlcgenerator.cpp b/src/plugins/qtsupport/qscxmlcgenerator.cpp index 8aa1c0198fd..3bfd201a04e 100644 --- a/src/plugins/qtsupport/qscxmlcgenerator.cpp +++ b/src/plugins/qtsupport/qscxmlcgenerator.cpp @@ -129,8 +129,9 @@ FileNameToContentsHash QScxmlcGenerator::handleProcessFinished(Process *process) class QScxmlcGeneratorFactory final : public ExtraCompilerFactory { public: - QScxmlcGeneratorFactory() = default; + explicit QScxmlcGeneratorFactory(QObject *guard) : m_guard(guard) {} +private: FileType sourceType() const final { return FileType::StateChart; } QString sourceTag() const final { return QStringLiteral("scxml"); } @@ -139,13 +140,15 @@ public: const FilePath &source, const FilePaths &targets) final { - return new QScxmlcGenerator(project, source, targets, this); + return new QScxmlcGenerator(project, source, targets, m_guard); } + + QObject *m_guard; }; -void setupQScxmlcGenerator() +void setupQScxmlcGenerator(QObject *guard) { - static QScxmlcGeneratorFactory theQScxmlcGeneratorFactory; + static QScxmlcGeneratorFactory theQScxmlcGeneratorFactory(guard); } } // QtSupport::Internal diff --git a/src/plugins/qtsupport/qscxmlcgenerator.h b/src/plugins/qtsupport/qscxmlcgenerator.h index 811f485689d..c7c8cf8265b 100644 --- a/src/plugins/qtsupport/qscxmlcgenerator.h +++ b/src/plugins/qtsupport/qscxmlcgenerator.h @@ -3,8 +3,10 @@ #pragma once +#include + namespace QtSupport::Internal { -void setupQScxmlcGenerator(); +void setupQScxmlcGenerator(QObject *guard); } // QtSupport::Internal diff --git a/src/plugins/qtsupport/qtsupportplugin.cpp b/src/plugins/qtsupport/qtsupportplugin.cpp index 6a34e466d14..db0f8888af4 100644 --- a/src/plugins/qtsupport/qtsupportplugin.cpp +++ b/src/plugins/qtsupport/qtsupportplugin.cpp @@ -88,8 +88,8 @@ void QtSupportPlugin::initialize() setupGettingStartedWelcomePage(); setupQtSettingsPage(); setupQtOutputFormatter(); - setupUicGenerator(); - setupQScxmlcGenerator(); + setupUicGenerator(this); + setupQScxmlcGenerator(this); setupExternalDesigner(this); setupExternalLinguist(); diff --git a/src/plugins/qtsupport/uicgenerator.cpp b/src/plugins/qtsupport/uicgenerator.cpp index dee12b9f9c9..74b8355af9a 100644 --- a/src/plugins/qtsupport/uicgenerator.cpp +++ b/src/plugins/qtsupport/uicgenerator.cpp @@ -72,8 +72,9 @@ FileNameToContentsHash UicGenerator::handleProcessFinished(Process *process) class UicGeneratorFactory final : public ExtraCompilerFactory { public: - UicGeneratorFactory() = default; + explicit UicGeneratorFactory(QObject *guard) : m_guard(guard) {} +private: FileType sourceType() const final { return FileType::Form; } QString sourceTag() const final { return QLatin1String("ui"); } @@ -82,13 +83,15 @@ public: const FilePath &source, const FilePaths &targets) final { - return new UicGenerator(project, source, targets, this); + return new UicGenerator(project, source, targets, m_guard); } + + QObject *m_guard; }; -void setupUicGenerator() +void setupUicGenerator(QObject *guard) { - static UicGeneratorFactory theUicGeneratorFactory; + static UicGeneratorFactory theUicGeneratorFactory(guard); } } // QtSupport::Internal diff --git a/src/plugins/qtsupport/uicgenerator.h b/src/plugins/qtsupport/uicgenerator.h index f8fdeb5ca05..3f3d4c20b51 100644 --- a/src/plugins/qtsupport/uicgenerator.h +++ b/src/plugins/qtsupport/uicgenerator.h @@ -3,8 +3,10 @@ #pragma once +#include + namespace QtSupport::Internal { -void setupUicGenerator(); +void setupUicGenerator(QObject *guard); } // QtSupport::Internal From 97ec97ff27c72ed6feb41a1d3d9264d3f36f36ad Mon Sep 17 00:00:00 2001 From: Jarek Kobus Date: Mon, 26 Feb 2024 13:12:45 +0100 Subject: [PATCH 184/243] ClangModelManagerSupport: Skip explicit call to waitForFinished() This is done by the FutureSynchronizer d'tor, so no need to call it explicitly. Move the FutureSynchronizer as the last field of ClangModelManagerSupport so that its d'tor is executed first. Change-Id: Id38b8ec08579be8e4ade99ecadb511850ff37f8c Reviewed-by: Christian Kandeler --- src/plugins/clangcodemodel/clangmodelmanagersupport.cpp | 5 +---- src/plugins/clangcodemodel/clangmodelmanagersupport.h | 2 +- 2 files changed, 2 insertions(+), 5 deletions(-) diff --git a/src/plugins/clangcodemodel/clangmodelmanagersupport.cpp b/src/plugins/clangcodemodel/clangmodelmanagersupport.cpp index 53d0e6f3784..477ab9104b9 100644 --- a/src/plugins/clangcodemodel/clangmodelmanagersupport.cpp +++ b/src/plugins/clangcodemodel/clangmodelmanagersupport.cpp @@ -293,10 +293,7 @@ ClangModelManagerSupport::ClangModelManagerSupport() new ClangdQuickFixFactory(); // memory managed by CppEditor::g_cppQuickFixFactories } -ClangModelManagerSupport::~ClangModelManagerSupport() -{ - m_generatorSynchronizer.waitForFinished(); -} +ClangModelManagerSupport::~ClangModelManagerSupport() = default; void ClangModelManagerSupport::followSymbol(const CursorInEditor &data, const LinkHandler &processLinkCallback, diff --git a/src/plugins/clangcodemodel/clangmodelmanagersupport.h b/src/plugins/clangcodemodel/clangmodelmanagersupport.h index a598bea8bbd..67fc12868cb 100644 --- a/src/plugins/clangcodemodel/clangmodelmanagersupport.h +++ b/src/plugins/clangcodemodel/clangmodelmanagersupport.h @@ -94,10 +94,10 @@ private: void scheduleClientRestart(ClangdClient *client); static ClangdClient *clientWithProject(const ProjectExplorer::Project *project); - Utils::FutureSynchronizer m_generatorSynchronizer; QList> m_clientsToRestart; QTimer * const m_clientRestartTimer; QHash m_potentialShadowDocuments; + Utils::FutureSynchronizer m_generatorSynchronizer; // Keep me last }; } // namespace Internal From 0bcc5378e5e9a829f1a4d658e4720e1c26dea83f Mon Sep 17 00:00:00 2001 From: Leena Miettinen Date: Mon, 26 Feb 2024 13:35:24 +0100 Subject: [PATCH 185/243] CMake: Fix setting label and tooltip Change-Id: Ia5ca9472054ec366110086bf79f630c5716b83fb Reviewed-by: Cristian Adam --- .../cmakeprojectmanager/cmakespecificsettings.cpp | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/src/plugins/cmakeprojectmanager/cmakespecificsettings.cpp b/src/plugins/cmakeprojectmanager/cmakespecificsettings.cpp index d814ee81350..28668b3567d 100644 --- a/src/plugins/cmakeprojectmanager/cmakespecificsettings.cpp +++ b/src/plugins/cmakeprojectmanager/cmakespecificsettings.cpp @@ -93,16 +93,16 @@ CMakeSpecificSettings::CMakeSpecificSettings() "UseJunctionsForSourceAndBuildDirectories"); useJunctionsForSourceAndBuildDirectories.setDefaultValue(false); useJunctionsForSourceAndBuildDirectories.setLabelText(::CMakeProjectManager::Tr::tr( - "Use Junctions for CMake configuration and build operations")); + "Use junctions for CMake configuration and build operations")); useJunctionsForSourceAndBuildDirectories.setVisible(Utils::HostOsInfo().isWindowsHost()); useJunctionsForSourceAndBuildDirectories.setToolTip(::CMakeProjectManager::Tr::tr( - "Create and use junctions for the source and build directories. This helps to overcome " + "Create and use junctions for the source and build directories to overcome " "issues with long paths on Windows.

" - "They are stored under C:\\ProgramData\\QtCreator\\Links (overridable via " - "QTC_CMAKE_JUNCTIONS_DIR environment variable).

" - "With QTC_CMAKE_JUNCTIONS_HASH_LENGTH the MD5 hash key length can be shortened " + "Junctions are stored under C:\\ProgramData\\QtCreator\\Links (overridable via " + "the QTC_CMAKE_JUNCTIONS_DIR environment variable).

" + "With QTC_CMAKE_JUNCTIONS_HASH_LENGTH, you can shorten the MD5 hash key length " "to a value smaller than the default length value of 32.

" - "They are used for CMake configure, build and install operations.")); + "Junctions are used for CMake configure, build and install operations.")); readSettings(); } From e8bc1fa78e7d4eef23ed8912d3a7b72a244f7186 Mon Sep 17 00:00:00 2001 From: Eike Ziller Date: Mon, 26 Feb 2024 09:12:22 +0100 Subject: [PATCH 186/243] Squish: Avoid yes/no questions, actions are clearer Change-Id: Ia0e23a08f074d61db8ead4566753fb27e4a97a71 Reviewed-by: Christian Stenger Reviewed-by: Leena Miettinen --- src/plugins/squish/squishnavigationwidget.cpp | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) diff --git a/src/plugins/squish/squishnavigationwidget.cpp b/src/plugins/squish/squishnavigationwidget.cpp index 7921938c37a..d3fb523196e 100644 --- a/src/plugins/squish/squishnavigationwidget.cpp +++ b/src/plugins/squish/squishnavigationwidget.cpp @@ -340,7 +340,12 @@ void SquishNavigationWidget::onRemoveSharedFileTriggered(const QModelIndex &idx) = CheckableMessageBox::question(Core::ICore::dialogParent(), Tr::tr("Remove Shared File"), detail, - Key("RemoveSharedSquishScript")); + Key("RemoveSharedSquishScript"), + QMessageBox::Yes | QMessageBox::No, + /*defaultButton=*/QMessageBox::No, + /*acceptButton=*/QMessageBox::Yes, + {{QMessageBox::Yes, Tr::tr("Delete")}, + {QMessageBox::No, Tr::tr("Cancel")}}); if (pressed != QMessageBox::Yes) return; From dafb8f2231694abae6cb573e5448462c2273acc0 Mon Sep 17 00:00:00 2001 From: Christian Stenger Date: Mon, 26 Feb 2024 10:20:18 +0100 Subject: [PATCH 187/243] Axivion: Fix toggling sort If the horizontal scroll bar is not at position 0 we got the wrong offset for the position of the column. Change-Id: Id333584f9d509b67eeef39bc7966f095b577e0fe Reviewed-by: Jarek Kobus --- src/plugins/axivion/issueheaderview.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/plugins/axivion/issueheaderview.cpp b/src/plugins/axivion/issueheaderview.cpp index ceb2d520afa..3f8efd86c6e 100644 --- a/src/plugins/axivion/issueheaderview.cpp +++ b/src/plugins/axivion/issueheaderview.cpp @@ -61,7 +61,7 @@ void IssueHeaderView::mousePressEvent(QMouseEvent *event) if (y > 1 && y < height() - 2) { // TODO improve const int pos = position.x(); const int logical = logicalIndexAt(pos); - const int end = sectionPosition(logical) + sectionSize(logical); + const int end = sectionViewportPosition(logical) + sectionSize(logical); const int start = end - ICON_SIZE - 2; m_maybeToggleSort = start < pos && end > pos; } From 5df9dee69a2f63a09f64ee4829f4322868bff916 Mon Sep 17 00:00:00 2001 From: Jarek Kobus Date: Mon, 26 Feb 2024 14:54:41 +0100 Subject: [PATCH 188/243] Axivion: Remove assert for empty relative doc path Change-Id: I4364e691c78eb52a2c880e416521458b66931f47 Reviewed-by: Christian Stenger --- src/plugins/axivion/axivionplugin.cpp | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/src/plugins/axivion/axivionplugin.cpp b/src/plugins/axivion/axivionplugin.cpp index 3fb567e22cd..c559e2b7d3a 100644 --- a/src/plugins/axivion/axivionplugin.cpp +++ b/src/plugins/axivion/axivionplugin.cpp @@ -816,7 +816,8 @@ void AxivionPluginPrivate::onDocumentOpened(IDocument *doc) return; const FilePath filePath = doc->filePath().relativeChildPath(m_project->projectDirectory()); - QTC_ASSERT(!filePath.isEmpty(), return); + if (filePath.isEmpty()) + return; // Empty is fine const auto handler = [this](const Dto::FileViewDto &data) { if (data.lineMarkers.empty()) From 290232bfd3d378f434161adc5452732a183c1454 Mon Sep 17 00:00:00 2001 From: Marcus Tillmanns Date: Tue, 27 Feb 2024 06:52:33 +0100 Subject: [PATCH 189/243] Android: Warn if parsing packages failed Change-Id: I61f249e1b45f1b9322b189b2781dc2375e9d13ca Reviewed-by: hjk --- src/plugins/android/androidsdkmanager.cpp | 3 +++ 1 file changed, 3 insertions(+) diff --git a/src/plugins/android/androidsdkmanager.cpp b/src/plugins/android/androidsdkmanager.cpp index c952ff90978..029cfd83524 100644 --- a/src/plugins/android/androidsdkmanager.cpp +++ b/src/plugins/android/androidsdkmanager.cpp @@ -405,7 +405,10 @@ void AndroidSdkManagerPrivate::reloadSdkPackages() if (m_packageListingSuccessful) { SdkManagerOutputParser parser(m_allPackages); parser.parsePackageListing(packageListing); + } else { + qCWarning(sdkManagerLog) << "Failed parsing packages:" << packageListing; } + emit m_sdkManager.packageReloadFinished(); } From 795d144227eaf20356376e3f160ded5cac53f7a3 Mon Sep 17 00:00:00 2001 From: Leena Miettinen Date: Mon, 26 Feb 2024 17:16:02 +0100 Subject: [PATCH 190/243] Translation Wizard: Be less polite Do not use "please" in UI text. Change-Id: I5332579ab297ae35a18fed88097313c8a50a1f6d Reviewed-by: Reviewed-by: Christian Stenger --- src/plugins/qtsupport/translationwizardpage.cpp | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/plugins/qtsupport/translationwizardpage.cpp b/src/plugins/qtsupport/translationwizardpage.cpp index be35a90dec0..bde480edd09 100644 --- a/src/plugins/qtsupport/translationwizardpage.cpp +++ b/src/plugins/qtsupport/translationwizardpage.cpp @@ -58,10 +58,10 @@ TranslationWizardPage::TranslationWizardPage(const QString &enabledExpr, bool si { const auto mainLayout = new QVBoxLayout(this); const auto descriptionLabel = new QLabel( - singleFile ? Tr::tr("Please select a language for which a corresponding " + singleFile ? Tr::tr("Select a language for which a corresponding " "translation (.ts) file will be generated for you.") : Tr::tr("If you plan to provide translations for your project's " - "user interface via the Qt Linguist tool, please select a " + "user interface via the Qt Linguist tool, select a " "language here. A corresponding translation (.ts) file will be " "generated for you.")); descriptionLabel->setWordWrap(true); From 3d8592edd1bb3f211a3f53584fb2c5d394c9941a Mon Sep 17 00:00:00 2001 From: Leena Miettinen Date: Mon, 26 Feb 2024 16:54:52 +0100 Subject: [PATCH 191/243] Project Explorer: Fix quotes Use double quotes for emphasis in UI text. Change-Id: Idb34140816c8dfffaa87837055a1b76ceda09ef0 Reviewed-by: Christian Kandeler Reviewed-by: --- src/plugins/projectexplorer/buildaspects.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/plugins/projectexplorer/buildaspects.cpp b/src/plugins/projectexplorer/buildaspects.cpp index 18f7fe2b851..0f9c025fce2 100644 --- a/src/plugins/projectexplorer/buildaspects.cpp +++ b/src/plugins/projectexplorer/buildaspects.cpp @@ -194,7 +194,7 @@ QString BuildDirectoryAspect::updateProblemLabelsHelper(const QString &value) const auto isInvalid = [](QChar c) { return c.isSpace() || !isascii(c.toLatin1()); }; if (const auto invalidChar = Utils::findOr(value, std::nullopt, isInvalid)) { genericProblem = Tr::tr( - "Build directory contains potentially problematic character '%1'.") + "Build directory contains potentially problematic character \"%1\".") .arg(*invalidChar); genericProblemLabelString = genericProblem From fdabbfcbcfe35bce731a2eff3fe13e2d6df238b9 Mon Sep 17 00:00:00 2001 From: Eike Ziller Date: Fri, 23 Feb 2024 12:17:37 +0100 Subject: [PATCH 192/243] Diff: Fix that dialog for "Revert Chunk" closes right away MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit On macOS. Change-Id: Ifbe402c44779e4062a5dfb5d7c09da7ac845acce Reviewed-by: Jarek Kobus Reviewed-by: Reviewed-by: Orgad Shaneh Reviewed-by: André Hartmann --- .../diffeditor/diffeditorwidgetcontroller.cpp | 9 ++++++--- src/plugins/vcsbase/vcsbaseeditor.cpp | 18 ++++++++++++------ 2 files changed, 18 insertions(+), 9 deletions(-) diff --git a/src/plugins/diffeditor/diffeditorwidgetcontroller.cpp b/src/plugins/diffeditor/diffeditorwidgetcontroller.cpp index 0f3a57ee086..9decc5f1a60 100644 --- a/src/plugins/diffeditor/diffeditorwidgetcontroller.cpp +++ b/src/plugins/diffeditor/diffeditorwidgetcontroller.cpp @@ -267,9 +267,12 @@ void DiffEditorWidgetController::addPatchAction(QMenu *menu, int fileIndex, int const QString actionName = patchAction == PatchAction::Apply ? Tr::tr("Apply Chunk...") : Tr::tr("Revert Chunk..."); QAction *action = menu->addAction(actionName); - connect(action, &QAction::triggered, this, [this, fileIndex, chunkIndex, patchAction] { - patch(patchAction, fileIndex, chunkIndex); - }); + connect( + action, + &QAction::triggered, + this, + [this, fileIndex, chunkIndex, patchAction] { patch(patchAction, fileIndex, chunkIndex); }, + Qt::QueuedConnection); const bool enabled = chunkExists(fileIndex, chunkIndex) && (patchAction == PatchAction::Revert || fileNamesAreDifferent(fileIndex)); action->setEnabled(enabled); diff --git a/src/plugins/vcsbase/vcsbaseeditor.cpp b/src/plugins/vcsbase/vcsbaseeditor.cpp index b10758233a0..38bb004a2d6 100644 --- a/src/plugins/vcsbase/vcsbaseeditor.cpp +++ b/src/plugins/vcsbase/vcsbaseeditor.cpp @@ -995,14 +995,20 @@ void VcsBaseEditorWidget::contextMenuEvent(QContextMenuEvent *e) // the user has "Open With" and choose the right diff editor so that // fileNameFromDiffSpecification() works. QAction *applyAction = menu->addAction(Tr::tr("Apply Chunk...")); - connect(applyAction, &QAction::triggered, this, [this, chunk] { - slotApplyDiffChunk(chunk, PatchAction::Apply); - }); + connect( + applyAction, + &QAction::triggered, + this, + [this, chunk] { slotApplyDiffChunk(chunk, PatchAction::Apply); }, + Qt::QueuedConnection); // Revert a chunk from a VCS diff, which might be linked to reloading the diff. QAction *revertAction = menu->addAction(Tr::tr("Revert Chunk...")); - connect(revertAction, &QAction::triggered, this, [this, chunk] { - slotApplyDiffChunk(chunk, PatchAction::Revert); - }); + connect( + revertAction, + &QAction::triggered, + this, + [this, chunk] { slotApplyDiffChunk(chunk, PatchAction::Revert); }, + Qt::QueuedConnection); // Custom diff actions addDiffActions(menu, chunk); break; From 536bb51c5abf69104b4e49dbf068b594ca195435 Mon Sep 17 00:00:00 2001 From: Marcus Tillmanns Date: Tue, 27 Feb 2024 08:43:26 +0100 Subject: [PATCH 193/243] Android: Validate selected Java version Change-Id: If77e5b524fdfea7d87ff4f221ef81d2f723f2f82 Reviewed-by: hjk --- src/plugins/android/androidsettingswidget.cpp | 60 +++++++++++++++++-- 1 file changed, 55 insertions(+), 5 deletions(-) diff --git a/src/plugins/android/androidsettingswidget.cpp b/src/plugins/android/androidsettingswidget.cpp index ca0ff057dfb..0001c37de5f 100644 --- a/src/plugins/android/androidsettingswidget.cpp +++ b/src/plugins/android/androidsettingswidget.cpp @@ -13,13 +13,14 @@ #include +#include #include #include #include #include #include -#include #include +#include #include #include @@ -203,6 +204,47 @@ enum OpenSslValidation { OpenSslCmakeListsPathExists }; +static expected_str testJavaC(const FilePath &jdkPath) +{ + if (!jdkPath.isReadableDir()) + return make_unexpected(Tr::tr("The selected path does not exist or is not readable.")); + + const FilePath bin = jdkPath.pathAppended("bin/javac" QTC_HOST_EXE_SUFFIX); + + if (!bin.isExecutableFile()) + return make_unexpected( + Tr::tr("The selected path does not contain an executable bin/javac.")); + + QVersionNumber jdkVersion; + + Process javacProcess; + CommandLine cmd(bin, {"-version"}); + javacProcess.setProcessChannelMode(QProcess::ProcessChannelMode::MergedChannels); + javacProcess.setCommand(cmd); + javacProcess.runBlocking(); + + const QString stdOut = javacProcess.stdOut().trimmed(); + + if (javacProcess.exitCode() != 0) + return make_unexpected( + Tr::tr("The selected path does not contain a valid JDK. (javac -version failed: %1)") + .arg(stdOut)); + + // We expect "javac " where is "major.minor.patch" + if (!stdOut.startsWith("javac ")) + return make_unexpected(Tr::tr("Unexpected output from \"javac -version\": %1").arg(stdOut)); + + jdkVersion = QVersionNumber::fromString(stdOut.mid(6).split('\n').first()); + + if (jdkVersion.isNull() || jdkVersion.majorVersion() != 17) { + return make_unexpected(Tr::tr("Unsupported JDK version (needs to be 17): %1 (parsed: %2)") + .arg(stdOut) + .arg(jdkVersion.toString())); + } + + return {}; +} + AndroidSettingsWidget::AndroidSettingsWidget() { setWindowTitle(Tr::tr("Android Configuration")); @@ -307,6 +349,15 @@ AndroidSettingsWidget::AndroidSettingsWidget() Tr::tr("OpenSSL settings have errors."), openSslDetailsWidget); + m_openJdkLocationPathChooser->setValidationFunction([](const QString &s) { + return Utils::asyncRun([s]() -> expected_str { + expected_str test = testJavaC(FilePath::fromUserInput(s)); + if (!test) + return make_unexpected(test.error()); + return s; + }); + }); + connect(m_openJdkLocationPathChooser, &PathChooser::rawPathChanged, this, &AndroidSettingsWidget::validateJdk); if (androidConfig().openJDKLocation().isEmpty()) @@ -533,10 +584,9 @@ bool AndroidSettingsWidget::isDefaultNdkSelected() const void AndroidSettingsWidget::validateJdk() { androidConfig().setOpenJDKLocation(m_openJdkLocationPathChooser->filePath()); - bool jdkPathExists = androidConfig().openJDKLocation().exists(); - const FilePath bin = androidConfig().openJDKLocation() - .pathAppended("bin/javac" QTC_HOST_EXE_SUFFIX); - m_androidSummary->setPointValid(JavaPathExistsAndWritableRow, jdkPathExists && bin.exists()); + expected_str test = testJavaC(androidConfig().openJDKLocation()); + + m_androidSummary->setPointValid(JavaPathExistsAndWritableRow, test.has_value()); updateUI(); From 7c98f2aa9ea3c1464c490e3dfc9636e7e1f51510 Mon Sep 17 00:00:00 2001 From: Jarek Kobus Date: Mon, 26 Feb 2024 17:44:14 +0100 Subject: [PATCH 194/243] Axivion: Unuglify issues view frame BaseTreeView's c'tor calls setFrameStyle(QFrame::NoFrame), that's why the frame was lacking. Bring back the Qt defaults explicitly. Change-Id: If48c97cc0b0afa3fdb71b5ba30284371da35192f Reviewed-by: hjk --- src/plugins/axivion/axivionoutputpane.cpp | 2 ++ 1 file changed, 2 insertions(+) diff --git a/src/plugins/axivion/axivionoutputpane.cpp b/src/plugins/axivion/axivionoutputpane.cpp index a13b63dd3a2..31a03f0d569 100644 --- a/src/plugins/axivion/axivionoutputpane.cpp +++ b/src/plugins/axivion/axivionoutputpane.cpp @@ -334,6 +334,8 @@ IssuesWidget::IssuesWidget(QWidget *parent) connect(m_pathGlobFilter, &QLineEdit::textEdited, this, &IssuesWidget::onSearchParameterChanged); m_issuesView = new BaseTreeView(this); + m_issuesView->setFrameShape(QFrame::StyledPanel); // Bring back Qt default + m_issuesView->setFrameShadow(QFrame::Sunken); // Bring back Qt default m_headerView = new IssueHeaderView(this); connect(m_headerView, &IssueHeaderView::sortTriggered, this, &IssuesWidget::onSearchParameterChanged); From 0114933deba8d0f75a9e76f0699358748e8be33d Mon Sep 17 00:00:00 2001 From: Jarek Kobus Date: Mon, 26 Feb 2024 20:59:11 +0100 Subject: [PATCH 195/243] AndroidRunWorker: Remove redundant variables Change-Id: I6677ce5d4640fdd68d3571d833f9c3651068facc Reviewed-by: hjk Reviewed-by: --- src/plugins/android/androidrunnerworker.cpp | 10 ++++------ 1 file changed, 4 insertions(+), 6 deletions(-) diff --git a/src/plugins/android/androidrunnerworker.cpp b/src/plugins/android/androidrunnerworker.cpp index 6cba25a0179..7452e975811 100644 --- a/src/plugins/android/androidrunnerworker.cpp +++ b/src/plugins/android/androidrunnerworker.cpp @@ -819,15 +819,13 @@ void AndroidRunnerWorker::removeForwardPort(const QString &port) void AndroidRunnerWorker::onProcessIdChanged(PidUserPair pidUser) { - qint64 pid = pidUser.first; - qint64 user = pidUser.second; // Don't write to m_psProc from a different thread QTC_ASSERT(QThread::currentThread() == thread(), return); qCDebug(androidRunWorkerLog) << "Process ID changed from:" << m_processPID - << "to:" << pid; - m_processPID = pid; - m_processUser = user; - if (pid == -1) { + << "to:" << pidUser.first; + m_processPID = pidUser.first; + m_processUser = pidUser.second; + if (m_processPID == -1) { emit remoteProcessFinished(QLatin1String("\n\n") + Tr::tr("\"%1\" died.") .arg(m_packageName)); // App died/killed. Reset log, monitor, jdb & gdbserver/lldb-server processes. From e95ad3778fef7bf198bc8296e3c5ba1894ae0e1a Mon Sep 17 00:00:00 2001 From: Jarek Kobus Date: Mon, 26 Feb 2024 21:02:42 +0100 Subject: [PATCH 196/243] AndroidRunnerWorker: Avoid deleting process directly from its handler Task-number: QTCREATORBUG-29928 Change-Id: If25c742e57ddaa90ed3342d09dafe626288f0783 Reviewed-by: hjk --- src/plugins/android/androidrunnerworker.cpp | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/src/plugins/android/androidrunnerworker.cpp b/src/plugins/android/androidrunnerworker.cpp index 7452e975811..d18f645165f 100644 --- a/src/plugins/android/androidrunnerworker.cpp +++ b/src/plugins/android/androidrunnerworker.cpp @@ -850,7 +850,10 @@ void AndroidRunnerWorker::onProcessIdChanged(PidUserPair pidUser) QTC_ASSERT(m_psIsAlive, return); m_psIsAlive->setObjectName("IsAliveProcess"); m_psIsAlive->setProcessChannelMode(QProcess::MergedChannels); - connect(m_psIsAlive.get(), &Process::done, this, [this] { onProcessIdChanged({-1, -1}); }); + connect(m_psIsAlive.get(), &Process::done, this, [this] { + m_psIsAlive.release()->deleteLater(); + onProcessIdChanged({-1, -1}); + }); } } From 4dcba2ad259514fe21cda500120c05e0f7d1f094 Mon Sep 17 00:00:00 2001 From: Christian Stenger Date: Tue, 27 Feb 2024 08:27:06 +0100 Subject: [PATCH 197/243] Core: Correct log view thread handling Fixes a crash when log messages are received from multiple threads. Fixes: QTCREATORBUG-30444 Change-Id: I51c78656da1dd30bcb51a801083d1714e474d8e5 Reviewed-by: Marcus Tillmanns --- src/plugins/coreplugin/loggingviewer.cpp | 12 +++++++++--- 1 file changed, 9 insertions(+), 3 deletions(-) diff --git a/src/plugins/coreplugin/loggingviewer.cpp b/src/plugins/coreplugin/loggingviewer.cpp index 5e83c76df3e..d6aad897148 100644 --- a/src/plugins/coreplugin/loggingviewer.cpp +++ b/src/plugins/coreplugin/loggingviewer.cpp @@ -559,10 +559,16 @@ private: const QString timestamp = QDateTime::currentDateTime().toString("HH:mm:ss.zzz"); - if (rowCount() >= 1000000) // limit log to 1000000 items - destroyItem(itemForIndex(index(0, 0))); + auto append = [this, timestamp, type, category, msg] { + if (rowCount() >= 1000000) // limit log to 1000000 items + destroyItem(itemForIndex(index(0, 0))); + appendItem(LogEntry{timestamp, messageTypeToString(type), category, msg}); + }; - appendItem(LogEntry{timestamp, messageTypeToString(type), category, msg}); + if (QThread::currentThread() != thread()) + QMetaObject::invokeMethod(this, append, Qt::QueuedConnection); + else + append(); } private: From 82399ac9c54dcdbe03e4240c5b2ffe6850a95afd Mon Sep 17 00:00:00 2001 From: David Schulz Date: Tue, 27 Feb 2024 08:34:28 +0100 Subject: [PATCH 198/243] ClangFormat: Fix compile against latest llvm main branch Change-Id: I6fe414721103d00eb3212040c1aafa2ef123b9d1 Reviewed-by: Artem Sokolovskii Reviewed-by: --- src/plugins/clangformat/clangformatutils.cpp | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) diff --git a/src/plugins/clangformat/clangformatutils.cpp b/src/plugins/clangformat/clangformatutils.cpp index 4036d34f6dc..747c30c2a57 100644 --- a/src/plugins/clangformat/clangformatutils.cpp +++ b/src/plugins/clangformat/clangformatutils.cpp @@ -59,9 +59,14 @@ clang::format::FormatStyle calculateQtcStyle() style.AllowShortFunctionsOnASingleLine = FormatStyle::SFS_Inline; style.AllowShortIfStatementsOnASingleLine = FormatStyle::SIS_Never; style.AllowShortLoopsOnASingleLine = false; - style.AlwaysBreakAfterReturnType = FormatStyle::RTBS_None; style.AlwaysBreakBeforeMultilineStrings = false; +#if LLVM_VERSION_MAJOR >= 19 + style.BreakAfterReturnType = FormatStyle::RTBS_None; + style.BreakTemplateDeclarations = FormatStyle::BTDS_Yes; +#else + style.AlwaysBreakAfterReturnType = FormatStyle::RTBS_None; style.AlwaysBreakTemplateDeclarations = FormatStyle::BTDS_Yes; +#endif style.BinPackArguments = false; style.BinPackParameters = false; style.BraceWrapping.AfterClass = true; From 5152a35048b7800ff8b10e1f254357a046a9543e Mon Sep 17 00:00:00 2001 From: Jarek Kobus Date: Tue, 27 Feb 2024 12:00:51 +0100 Subject: [PATCH 199/243] Axivion: Change the credential key Make it user @ server. Change-Id: I62e2c88ade5cc984ba11f718c3db292e4075e5e4 Reviewed-by: Andreas Loth Reviewed-by: hjk --- src/plugins/axivion/axivionplugin.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/plugins/axivion/axivionplugin.cpp b/src/plugins/axivion/axivionplugin.cpp index c559e2b7d3a..20e7871b14e 100644 --- a/src/plugins/axivion/axivionplugin.cpp +++ b/src/plugins/axivion/axivionplugin.cpp @@ -122,7 +122,7 @@ static QString credentialKey() QString escaped = string; return escaped.replace('\\', "\\\\").replace('@', "\\@"); }; - return escape(settings().server.dashboard) + '@' + escape(settings().server.username); + return escape(settings().server.username) + '@' + escape(settings().server.dashboard); } static DashboardInfo toDashboardInfo(const QUrl &source, const Dto::DashboardInfoDto &infoDto) From a57a925b76785c1269ca5bcbacd553f01c0f238d Mon Sep 17 00:00:00 2001 From: David Schulz Date: Mon, 12 Feb 2024 14:03:00 +0100 Subject: [PATCH 200/243] Debugger: defer type look up Change-Id: I425c2bfc3c88ebf46af161c5434c0c05a3bb9c97 Reviewed-by: Christian Stenger --- share/qtcreator/debugger/cdbbridge.py | 493 +++++++++++++++++++++++-- share/qtcreator/debugger/dumper.py | 68 ++-- share/qtcreator/debugger/lldbbridge.py | 2 +- src/libs/qtcreatorcdbext/pytype.cpp | 46 +-- src/libs/qtcreatorcdbext/pytype.h | 1 + 5 files changed, 533 insertions(+), 77 deletions(-) diff --git a/share/qtcreator/debugger/cdbbridge.py b/share/qtcreator/debugger/cdbbridge.py index d323714ba44..b5fc683cbae 100644 --- a/share/qtcreator/debugger/cdbbridge.py +++ b/share/qtcreator/debugger/cdbbridge.py @@ -11,7 +11,7 @@ from utils import TypeCode sys.path.insert(1, os.path.dirname(os.path.abspath(inspect.getfile(inspect.currentframe())))) -from dumper import DumperBase, SubItem +from dumper import DumperBase, SubItem, Children, DisplayFormat, UnnamedSubItem class FakeVoidType(cdbext.Type): @@ -84,10 +84,9 @@ class Dumper(DumperBase): self.check(isinstance(nativeValue, cdbext.Value)) val = self.Value(self) val.name = nativeValue.name() - val._type = self.fromNativeType(nativeValue.type()) # There is no cdb api for the size of bitfields. # Workaround this issue by parsing the native debugger text for integral types. - if val._type.code == TypeCode.Integral: + if nativeValue.type().code() == TypeCode.Integral: try: integerString = nativeValue.nativeDebuggerValue() except UnicodeDecodeError: @@ -106,16 +105,18 @@ class Dumper(DumperBase): base = 16 else: base = 10 - signed = not val._type.name.startswith('unsigned') + signed = not nativeValue.type().name().startswith('unsigned') try: - val.ldata = int(integerString, base).to_bytes(val._type.size(), + val.ldata = int(integerString, base).to_bytes((nativeValue.type().bitsize() +7) // 8, byteorder='little', signed=signed) except: # read raw memory in case the integerString can not be interpreted pass - if val._type.code == TypeCode.Enum: + if nativeValue.type().code() == TypeCode.Enum: val.ldisplay = self.enumValue(nativeValue) - val.isBaseClass = val.name == val._type.name + elif not nativeValue.type().resolved and nativeValue.type().code() == TypeCode.Struct and not nativeValue.hasChildren(): + val.ldisplay = self.enumValue(nativeValue) + val.isBaseClass = val.name == nativeValue.type().name() val.nativeValue = nativeValue val.laddress = nativeValue.address() val.lbitsize = nativeValue.bitsize() @@ -136,6 +137,9 @@ class Dumper(DumperBase): for f in nativeType.fields()]) return typeId + def nativeValueType(self, nativeValue): + return self.fromNativeType(nativeValue.type()) + def fromNativeType(self, nativeType): self.check(isinstance(nativeType, cdbext.Type)) typeId = self.nativeTypeId(nativeType) @@ -150,51 +154,66 @@ class Dumper(DumperBase): if nativeType.name().startswith(''): code = TypeCode.Function elif nativeType.targetName() != nativeType.name(): - targetType = self.lookupType(nativeType.targetName(), nativeType.moduleId()) - if targetType is not None and targetType is not nativeType: - return self.createPointerType(targetType) + return self.createPointerType(nativeType.targetName()) if code == TypeCode.Array: # cdb reports virtual function tables as arrays those ar handled separetly by # the DumperBase. Declare those types as structs prevents a lookup to a # none existing type if not nativeType.name().startswith('__fptr()') and not nativeType.name().startswith(' 0: namespace = name[:namespaceIndex + 2] + self.qtNamespace = lambda: namespace self.qtCustomEventFunc = self.parseAndEvaluate( '%s!%sQObject::customEvent' % (self.qtCoreModuleName(), namespace)).address() @@ -498,7 +518,7 @@ class Dumper(DumperBase): else: val = self.Value(self) val.laddress = value.pointer() - val._type = value.type.dereference() + val._type = DumperBase.Type(self, value.type.targetName) val.nativeValue = value.nativeValue return val @@ -519,3 +539,424 @@ class Dumper(DumperBase): def symbolAddress(self, symbolName): res = self.nativeParseAndEvaluate(symbolName) return None if res is None else res.address() + + def putItemX(self, value): + #DumperBase.warn('PUT ITEM: %s' % value.stringify()) + + typeobj = value.type # unqualified() + typeName = typeobj.name + + self.addToCache(typeobj) # Fill type cache + + if not value.lIsInScope: + self.putSpecialValue('optimizedout') + #self.putType(typeobj) + #self.putSpecialValue('outofscope') + self.putNumChild(0) + return + + if not isinstance(value, self.Value): + raise RuntimeError('WRONG TYPE IN putItem: %s' % type(self.Value)) + + # Try on possibly typedefed type first. + if self.tryPutPrettyItem(typeName, value): + if typeobj.code == TypeCode.Pointer: + self.putOriginalAddress(value.address()) + else: + self.putAddress(value.address()) + return + + if typeobj.code == TypeCode.Pointer: + self.putFormattedPointer(value) + return + + self.putAddress(value.address()) + if value.lbitsize is not None: + self.putField('size', value.lbitsize // 8) + + if typeobj.code == TypeCode.Function: + #DumperBase.warn('FUNCTION VALUE: %s' % value) + self.putType(typeobj) + self.putSymbolValue(value.pointer()) + self.putNumChild(0) + return + + if typeobj.code == TypeCode.Enum: + #DumperBase.warn('ENUM VALUE: %s' % value.stringify()) + self.putType(typeobj.name) + self.putValue(value.display()) + self.putNumChild(0) + return + + if typeobj.code == TypeCode.Array: + #DumperBase.warn('ARRAY VALUE: %s' % value) + self.putCStyleArray(value) + return + + if typeobj.code == TypeCode.Integral: + #DumperBase.warn('INTEGER: %s %s' % (value.name, value)) + val = value.value() + self.putNumChild(0) + self.putValue(val) + self.putType(typeName) + return + + if typeobj.code == TypeCode.Float: + #DumperBase.warn('FLOAT VALUE: %s' % value) + self.putValue(value.value()) + self.putNumChild(0) + self.putType(typeobj.name) + return + + if typeobj.code in (TypeCode.Reference, TypeCode.RValueReference): + #DumperBase.warn('REFERENCE VALUE: %s' % value) + val = value.dereference() + if val.laddress != 0: + self.putItem(val) + else: + self.putSpecialValue('nullreference') + self.putBetterType(typeName) + return + + if typeobj.code == TypeCode.Complex: + self.putType(typeobj) + self.putValue(value.display()) + self.putNumChild(0) + return + + self.putType(typeName) + + if value.summary is not None and self.useFancy: + self.putValue(self.hexencode(value.summary), 'utf8:1:0') + self.putNumChild(0) + return + + self.putExpandable() + self.putEmptyValue() + #DumperBase.warn('STRUCT GUTS: %s ADDRESS: 0x%x ' % (value.name, value.address())) + if self.showQObjectNames: + #with self.timer(self.currentIName): + self.putQObjectNameValue(value) + if self.isExpanded(): + self.putField('sortable', 1) + with Children(self): + baseIndex = 0 + for item in self.listValueChildren(value): + if item.name.startswith('__vfptr'): + with SubItem(self, '[vptr]'): + # int (**)(void) + self.putType(' ') + self.putSortGroup(20) + self.putValue(item.name) + n = 100 + if self.isExpanded(): + with Children(self): + n = self.putVTableChildren(item, n) + self.putNumChild(n) + continue + + if item.isBaseClass: + baseIndex += 1 + # We cannot use nativeField.name as part of the iname as + # it might contain spaces and other strange characters. + with UnnamedSubItem(self, "@%d" % baseIndex): + self.putField('iname', self.currentIName) + self.putField('name', '[%s]' % item.name) + self.putSortGroup(1000 - baseIndex) + self.putAddress(item.address()) + self.putItem(item) + continue + + + with SubItem(self, item.name): + self.putItem(item) + if self.showQObjectNames: + self.tryPutQObjectGuts(value) + + + def putFormattedPointerX(self, value: DumperBase.Value): + self.putOriginalAddress(value.address()) + pointer = value.pointer() + self.putAddress(pointer) + if pointer == 0: + self.putType(value.type) + self.putValue('0x0') + return + + typeName = value.type.name + + try: + self.readRawMemory(pointer, 1) + except: + # Failure to dereference a pointer should at least + # show the value of a pointer. + #DumperBase.warn('BAD POINTER: %s' % value) + self.putValue('0x%x' % pointer) + self.putType(typeName) + return + + if self.currentIName.endswith('.this'): + self.putDerefedPointer(value) + return + + displayFormat = self.currentItemFormat(value.type.name) + + if value.type.targetName == 'void': + #DumperBase.warn('VOID POINTER: %s' % displayFormat) + self.putType(typeName) + self.putSymbolValue(pointer) + return + + if displayFormat == DisplayFormat.Raw: + # Explicitly requested bald pointer. + #DumperBase.warn('RAW') + self.putType(typeName) + self.putValue('0x%x' % pointer) + self.putExpandable() + if self.currentIName in self.expandedINames: + with Children(self): + with SubItem(self, '*'): + self.putItem(value.dereference()) + return + + limit = self.displayStringLimit + if displayFormat in (DisplayFormat.SeparateLatin1String, DisplayFormat.SeparateUtf8String): + limit = 1000000 + if self.tryPutSimpleFormattedPointer(pointer, typeName, + value.type.targetName, displayFormat, limit): + self.putExpandable() + return + + if DisplayFormat.Array10 <= displayFormat and displayFormat <= DisplayFormat.Array10000: + n = (10, 100, 1000, 10000)[displayFormat - DisplayFormat.Array10] + self.putType(typeName) + self.putItemCount(n) + self.putArrayData(value.pointer(), n, value.type.targetName) + return + + #DumperBase.warn('AUTODEREF: %s' % self.autoDerefPointers) + #DumperBase.warn('INAME: %s' % self.currentIName) + if self.autoDerefPointers: + # Generic pointer type with AutomaticFormat, but never dereference char types: + if value.type.targetName not in ( + 'char', + 'signed char', + 'int8_t', + 'qint8', + 'unsigned char', + 'uint8_t', + 'quint8', + 'wchar_t', + 'CHAR', + 'WCHAR', + 'char8_t', + 'char16_t', + 'char32_t' + ): + self.putDerefedPointer(value) + return + + #DumperBase.warn('GENERIC PLAIN POINTER: %s' % value.type) + #DumperBase.warn('ADDR PLAIN POINTER: 0x%x' % value.laddress) + self.putType(typeName) + self.putSymbolValue(pointer) + self.putExpandable() + if self.currentIName in self.expandedINames: + with Children(self): + with SubItem(self, '*'): + self.putItem(value.dereference()) + + + def putCStyleArray(self, value): + arrayType = value.type + innerType = arrayType.ltarget + address = value.address() + if address: + self.putValue('@0x%x' % address, priority=-1) + else: + self.putEmptyValue() + self.putType(arrayType) + + displayFormat = self.currentItemFormat() + arrayByteSize = arrayType.size() + n = self.arrayItemCountFromTypeName(value.type.name, 100) + + p = value.address() + if displayFormat != DisplayFormat.Raw and p: + if innerType.name in ( + 'char', + 'int8_t', + 'qint8', + 'wchar_t', + 'unsigned char', + 'uint8_t', + 'quint8', + 'signed char', + 'CHAR', + 'WCHAR', + 'char8_t', + 'char16_t', + 'char32_t' + ): + self.putCharArrayHelper(p, n, innerType, self.currentItemFormat(), + makeExpandable=False) + else: + self.tryPutSimpleFormattedPointer(p, arrayType, innerType, + displayFormat, arrayByteSize) + self.putNumChild(n) + + if self.isExpanded(): + if n > 100: + addrStep = innerType.size() + with Children(self, n, innerType, addrBase=address, addrStep=addrStep): + for i in self.childRange(): + self.putSubItem(i, self.createValue(address + i * addrStep, innerType)) + else: + with Children(self): + n = 0 + for item in self.listValueChildren(value): + with SubItem(self, n): + n += 1 + self.putItem(item) + + + def putArrayData(self, base, n, innerType, childNumChild=None): + self.checkIntType(base) + self.checkIntType(n) + addrBase = base + innerType = self.createType(innerType) + innerSize = innerType.size() + self.putNumChild(n) + #DumperBase.warn('ADDRESS: 0x%x INNERSIZE: %s INNERTYPE: %s' % (addrBase, innerSize, innerType)) + enc = innerType.simpleEncoding() + maxNumChild = self.maxArrayCount() + if enc: + self.put('childtype="%s",' % innerType.name) + self.put('addrbase="0x%x",' % addrBase) + self.put('addrstep="0x%x",' % innerSize) + self.put('arrayencoding="%s",' % enc) + self.put('endian="%s",' % self.packCode) + if n > maxNumChild: + self.put('childrenelided="%s",' % n) + n = maxNumChild + self.put('arraydata="') + self.put(self.readMemory(addrBase, n * innerSize)) + self.put('",') + else: + with Children(self, n, innerType, childNumChild, maxNumChild, + addrBase=addrBase, addrStep=innerSize): + for i in self.childRange(): + self.putSubItem(i, self.createValue(addrBase + i * innerSize, innerType)) + + def tryPutSimpleFormattedPointer(self, ptr, typeName, innerType, displayFormat, limit): + if isinstance(innerType, self.Type): + innerType = innerType.name + if displayFormat == DisplayFormat.Automatic: + if innerType in ('char', 'signed char', 'unsigned char', 'uint8_t', 'CHAR'): + # Use UTF-8 as default for char *. + self.putType(typeName) + (length, shown, data) = self.readToFirstZero(ptr, 1, limit) + self.putValue(data, 'utf8', length=length) + if self.isExpanded(): + self.putArrayData(ptr, shown, innerType) + return True + + if innerType in ('wchar_t', 'WCHAR'): + self.putType(typeName) + charSize = self.lookupType('wchar_t').size() + (length, data) = self.encodeCArray(ptr, charSize, limit) + if charSize == 2: + self.putValue(data, 'utf16', length=length) + else: + self.putValue(data, 'ucs4', length=length) + return True + + if displayFormat == DisplayFormat.Latin1String: + self.putType(typeName) + (length, data) = self.encodeCArray(ptr, 1, limit) + self.putValue(data, 'latin1', length=length) + return True + + if displayFormat == DisplayFormat.SeparateLatin1String: + self.putType(typeName) + (length, data) = self.encodeCArray(ptr, 1, limit) + self.putValue(data, 'latin1', length=length) + self.putDisplay('latin1:separate', data) + return True + + if displayFormat == DisplayFormat.Utf8String: + self.putType(typeName) + (length, data) = self.encodeCArray(ptr, 1, limit) + self.putValue(data, 'utf8', length=length) + return True + + if displayFormat == DisplayFormat.SeparateUtf8String: + self.putType(typeName) + (length, data) = self.encodeCArray(ptr, 1, limit) + self.putValue(data, 'utf8', length=length) + self.putDisplay('utf8:separate', data) + return True + + if displayFormat == DisplayFormat.Local8BitString: + self.putType(typeName) + (length, data) = self.encodeCArray(ptr, 1, limit) + self.putValue(data, 'local8bit', length=length) + return True + + if displayFormat == DisplayFormat.Utf16String: + self.putType(typeName) + (length, data) = self.encodeCArray(ptr, 2, limit) + self.putValue(data, 'utf16', length=length) + return True + + if displayFormat == DisplayFormat.Ucs4String: + self.putType(typeName) + (length, data) = self.encodeCArray(ptr, 4, limit) + self.putValue(data, 'ucs4', length=length) + return True + + return False + + def putDerefedPointer(self, value): + derefValue = value.dereference() + savedCurrentChildType = self.currentChildType + self.currentChildType = value.type.targetName + self.putType(value.type.targetName) + derefValue.name = '*' + derefValue.autoDerefCount = value.autoDerefCount + 1 + + if derefValue.type.code == TypeCode.Pointer: + self.putField('autoderefcount', '{}'.format(derefValue.autoDerefCount)) + + self.putItem(derefValue) + self.currentChildType = savedCurrentChildType + + def extractPointer(self, value): + code = 'I' if self.ptrSize() == 4 else 'Q' + return self.extractSomething(value, code, 8 * self.ptrSize()) + + def createValue(self, datish, typish): + if self.isInt(datish): # Used as address. + return self.createValueFromAddressAndType(datish, typish) + if isinstance(datish, bytes): + val = self.Value(self) + if isinstance(typish, self.Type): + val._type = typish + else: + val._type = self.Type(self, typish) + #DumperBase.warn('CREATING %s WITH DATA %s' % (val.type.name, self.hexencode(datish))) + val.ldata = datish + val.check() + return val + raise RuntimeError('EXPECTING ADDRESS OR BYTES, GOT %s' % type(datish)) + + def createValueFromAddressAndType(self, address, typish): + val = self.Value(self) + if isinstance(typish, self.Type): + val._type = typish + else: + val._type = self.Type(self, typish) + val.laddress = address + if self.useDynamicType: + val._type = val.type.dynamicType(address) + return val diff --git a/share/qtcreator/debugger/dumper.py b/share/qtcreator/debugger/dumper.py index 2fa7d31da50..836b1860cb2 100644 --- a/share/qtcreator/debugger/dumper.py +++ b/share/qtcreator/debugger/dumper.py @@ -3041,7 +3041,7 @@ class DumperBase(): or self.type.name.startswith('unsigned ') \ or self.type.name.find(' unsigned ') != -1 if bitsize is None: - bitsize = self.type.bitsize() + bitsize = self.type.lbitsize return self.extractInteger(bitsize, unsigned) def floatingPoint(self): @@ -3512,26 +3512,40 @@ class DumperBase(): tdata.moduleName = self.moduleName return tdata + @property + def bitsize(self): + if callable(self.lbitsize): + self.lbitsize = self.lbitsize() + return self.lbitsize + class Type(): def __init__(self, dumper, typeId): - self.typeId = typeId + self.typeId = typeId.replace('@', dumper.qtNamespace()) self.dumper = dumper - self.tdata = dumper.typeData.get(typeId, None) - if self.tdata is None: - #DumperBase.warn('USING : %s' % self.typeId) - self.dumper.lookupType(self.typeId) - self.tdata = self.dumper.typeData.get(self.typeId) + self.initialized = False def __str__(self): #return self.typeId return self.stringify() + @property + def tdata(self): + if not self.initialized: + self.initialized = True + self.data = self.dumper.typeData.get(self.typeId, None) + if self.data is None: + #DumperBase.warn('USING : %s' % self.typeId) + self.dumper.lookupType(self.typeId) + self.data = self.dumper.typeData.get(self.typeId) + return self.data + + def setTdata(self, tdata): + self.initialized = True + self.data = tdata + @property def name(self): - tdata = self.dumper.typeData.get(self.typeId) - if tdata is None: - return self.typeId - return tdata.name + return self.typeId if self.tdata is None else self.tdata.name @property def code(self): @@ -3539,7 +3553,7 @@ class DumperBase(): @property def lbitsize(self): - return self.tdata.lbitsize + return self.tdata.bitsize @property def lbitpos(self): @@ -3547,15 +3561,25 @@ class DumperBase(): @property def ltarget(self): + if isinstance(self.tdata.ltarget, str): + self.tdata.ltarget = self.dumper.createType(self.tdata.ltarget) return self.tdata.ltarget + @property + def targetName(self): + if self.tdata.ltarget is None: + return '' + return self.tdata.ltarget if isinstance(self.tdata.ltarget, str) else self.tdata.ltarget.name + @property def moduleName(self): + if callable(self.tdata.moduleName): + self.tdata.moduleName = self.tdata.moduleName() return self.tdata.moduleName def stringify(self): return 'Type(name="%s",bsize=%s,code=%s)' \ - % (self.tdata.name, self.tdata.lbitsize, self.tdata.code) + % (self.tdata.name, self.lbitsize, self.tdata.code) def __getitem__(self, index): if self.dumper.isInt(index): @@ -3659,7 +3683,7 @@ class DumperBase(): def alignment(self): if self.tdata.code == TypeCode.Typedef: - return self.tdata.ltarget.alignment() + return self.ltarget.alignment() if self.tdata.code in (TypeCode.Integral, TypeCode.Float, TypeCode.Enum): if self.tdata.name in ('double', 'long long', 'unsigned long long'): # Crude approximation. @@ -3678,7 +3702,7 @@ class DumperBase(): return self.dumper.createPointerType(self) def target(self): - return self.tdata.ltarget + return self.ltarget def stripTypedefs(self): if isinstance(self, self.dumper.Type) and self.code != TypeCode.Typedef: @@ -3687,7 +3711,7 @@ class DumperBase(): return self.ltarget def size(self): - bs = self.bitsize() + bs = self.lbitsize if bs % 8 != 0: DumperBase.warn('ODD SIZE: %s' % self) return (7 + bs) >> 3 @@ -3797,12 +3821,12 @@ class DumperBase(): return val def createPointerType(self, targetType): - if not isinstance(targetType, self.Type): - raise RuntimeError('Expected type in createPointerType(), got %s' + if not isinstance(targetType, (str, self.Type)): + raise RuntimeError('Expected type or str in createPointerType(), got %s' % type(targetType)) - typeId = targetType.typeId + ' *' + typeId = (targetType if isinstance(targetType, str) else targetType.typeId) + ' *' tdata = self.TypeData(self, typeId) - tdata.name = targetType.name + '*' + tdata.name = (targetType if isinstance(targetType, str) else targetType.name) + '*' tdata.lbitsize = 8 * self.ptrSize() tdata.code = TypeCode.Pointer tdata.ltarget = targetType @@ -3927,7 +3951,7 @@ class DumperBase(): tdata = self.typeData.get(typish, None) if tdata is not None: if tdata.lbitsize is not None: - if tdata.lbitsize > 0: + if callable(tdata.lbitsize) or tdata.lbitsize > 0: return self.Type(self, typish) knownType = self.lookupType(typish) @@ -3944,7 +3968,7 @@ class DumperBase(): if typish.endswith('*'): tdata.code = TypeCode.Pointer tdata.lbitsize = 8 * self.ptrSize() - tdata.ltarget = self.createType(typish[:-1].strip()) + tdata.ltarget = typish[:-1].strip() typeobj = self.Type(self, tdata.typeId) #DumperBase.warn('CREATE TYPE: %s' % typeobj.stringify()) diff --git a/share/qtcreator/debugger/lldbbridge.py b/share/qtcreator/debugger/lldbbridge.py index 7558bcdfa47..c6aae0c2e48 100644 --- a/share/qtcreator/debugger/lldbbridge.py +++ b/share/qtcreator/debugger/lldbbridge.py @@ -419,7 +419,7 @@ class Dumper(DumperBase): targetTypeName = typeName[0:pos1].strip() #DumperBase.warn("TARGET TYPENAME: %s" % targetTypeName) targetType = self.fromNativeType(nativeTargetType) - targetType.tdata = targetType.tdata.copy() + targetType.setTdata(targetType.tdata.copy()) targetType.tdata.name = targetTypeName return self.createArrayType(targetType, count) if hasattr(nativeType, 'GetVectorElementType'): # New in 3.8(?) / 350.x diff --git a/src/libs/qtcreatorcdbext/pytype.cpp b/src/libs/qtcreatorcdbext/pytype.cpp index 0621793b7e0..9345c1d91af 100644 --- a/src/libs/qtcreatorcdbext/pytype.cpp +++ b/src/libs/qtcreatorcdbext/pytype.cpp @@ -121,6 +121,9 @@ static std::string stripPointerType(const std::string &typeNameIn) std::string typeName = typeNameIn; if (typeName.back() == '*') { typeName.pop_back(); + trimBack(typeName); + if (endsWith(typeName, "const")) + typeName = typeName.erase(typeName.size() - 5, 5); } else { const auto arrayPosition = typeName.find_first_of('['); if (arrayPosition != std::string::npos @@ -296,35 +299,19 @@ int PyType::code() const return std::nullopt; }; - if (!resolve()) - return parseTypeName(name()).value_or(TypeCodeUnresolvable); - - if (m_tag < 0) { - if (const std::optional typeCode = parseTypeName(name())) - return *typeCode; - - IDebugSymbolGroup2 *sg = 0; - if (FAILED(ExtensionCommandContext::instance()->symbols()->CreateSymbolGroup2(&sg))) - return TypeCodeStruct; - - const std::string helperValueName = SymbolGroupValue::pointedToSymbolName(0, name(true)); - ULONG index = DEBUG_ANY_ID; - if (SUCCEEDED(sg->AddSymbol(helperValueName.c_str(), &index))) - m_tag = PyValue(index, sg).tag(); - sg->Release(); + if (m_tag >= 0) { + switch (m_tag) { + case SymTagUDT: return TypeCodeStruct; + case SymTagEnum: return TypeCodeEnum; + case SymTagTypedef: return TypeCodeTypedef; + case SymTagFunctionType: return TypeCodeFunction; + case SymTagPointerType: return TypeCodePointer; + case SymTagArrayType: return TypeCodeArray; + case SymTagBaseType: return isIntegralType(name()) ? TypeCodeIntegral : TypeCodeFloat; + default: break; + } } - switch (m_tag) { - case SymTagUDT: return TypeCodeStruct; - case SymTagEnum: return TypeCodeEnum; - case SymTagTypedef: return TypeCodeTypedef; - case SymTagFunctionType: return TypeCodeFunction; - case SymTagPointerType: return TypeCodePointer; - case SymTagArrayType: return TypeCodeArray; - case SymTagBaseType: return isIntegralType(name()) ? TypeCodeIntegral : TypeCodeFloat; - default: break; - } - - return TypeCodeStruct; + return parseTypeName(name()).value_or(TypeCodeStruct); } PyType PyType::target() const @@ -533,6 +520,7 @@ PY_FUNC_RET_OBJECT_LIST(fields, PY_OBJ_NAME) PY_FUNC_RET_STD_STRING(module, PY_OBJ_NAME) PY_FUNC(moduleId, PY_OBJ_NAME, "K") PY_FUNC(arrayElements, PY_OBJ_NAME, "k") +PY_FUNC_RET_BOOL(resolved, PY_OBJ_NAME) PY_FUNC_DECL(templateArguments, PY_OBJ_NAME) { PY_IMPL_GUARD; @@ -568,6 +556,8 @@ static PyMethodDef typeMethods[] = { "Returns the number of elements in an array or 0 for non array types"}, {"templateArguments", PyCFunction(templateArguments), METH_NOARGS, "Returns all template arguments."}, + {"resolved", PyCFunction(resolved), METH_NOARGS, + "Returns whether the type is resolved"}, {NULL} /* Sentinel */ }; diff --git a/src/libs/qtcreatorcdbext/pytype.h b/src/libs/qtcreatorcdbext/pytype.h index 8b05fffe0ad..b71eae1ab02 100644 --- a/src/libs/qtcreatorcdbext/pytype.h +++ b/src/libs/qtcreatorcdbext/pytype.h @@ -29,6 +29,7 @@ public: std::string module() const; ULONG64 moduleId() const; int arrayElements() const; + bool resolved() const { return m_resolved.value_or(false); } struct TemplateArgument { From 226806e0fbbd01d9967b34567dfdb10b1a170d87 Mon Sep 17 00:00:00 2001 From: Christian Kandeler Date: Tue, 27 Feb 2024 12:53:59 +0100 Subject: [PATCH 201/243] RemoteLinux: Make deployment downgrade warning less spammy Keep the message, but make it a warning only for the "generic copy" case, which almost no one ever wants. Otherwise, it will annoy Windows users, who typically have no rsync installed. Change-Id: I2044b9ea2b199e03dc4e9421d05a2698d92ad76a Reviewed-by: hjk --- src/plugins/remotelinux/genericdeploystep.cpp | 15 ++++++++++----- 1 file changed, 10 insertions(+), 5 deletions(-) diff --git a/src/plugins/remotelinux/genericdeploystep.cpp b/src/plugins/remotelinux/genericdeploystep.cpp index bddc7bfcd3d..6071c4c8cae 100644 --- a/src/plugins/remotelinux/genericdeploystep.cpp +++ b/src/plugins/remotelinux/genericdeploystep.cpp @@ -155,11 +155,16 @@ GroupItem GenericDeployStep::transferTask(const Storage &storag } } if (!m_emittedDowngradeWarning && transferMethod != preferredTransferMethod) { - addWarningMessage(Tr::tr("Transfer method was downgraded from \"%1\" to \"%2\". If " - "this is unexpected, please re-test device \"%3\".") - .arg(FileTransfer::transferMethodName(preferredTransferMethod), - FileTransfer::transferMethodName(transferMethod), - deviceConfiguration()->displayName())); + const QString message + = Tr::tr("Transfer method was downgraded from \"%1\" to \"%2\". If " + "this is unexpected, please re-test device \"%3\".") + .arg(FileTransfer::transferMethodName(preferredTransferMethod), + FileTransfer::transferMethodName(transferMethod), + deviceConfiguration()->displayName()); + if (transferMethod == FileTransferMethod::GenericCopy) + addWarningMessage(message); + else + addProgressMessage(message); m_emittedDowngradeWarning = true; } transfer.setTransferMethod(transferMethod); From c536712707d5ba42eeebddcf78702fc7e06dc984 Mon Sep 17 00:00:00 2001 From: Alessandro Portale Date: Tue, 27 Feb 2024 11:07:28 +0100 Subject: [PATCH 202/243] Android: Remove command line and version numbers from translations Change-Id: Ib4fcd6cbf0a023e074aaad4b265c0ab60edac01a Reviewed-by: Marcus Tillmanns --- src/plugins/android/androidsettingswidget.cpp | 27 ++++++++++++------- 1 file changed, 18 insertions(+), 9 deletions(-) diff --git a/src/plugins/android/androidsettingswidget.cpp b/src/plugins/android/androidsettingswidget.cpp index 0001c37de5f..c75ba299c5b 100644 --- a/src/plugins/android/androidsettingswidget.cpp +++ b/src/plugins/android/androidsettingswidget.cpp @@ -209,16 +209,20 @@ static expected_str testJavaC(const FilePath &jdkPath) if (!jdkPath.isReadableDir()) return make_unexpected(Tr::tr("The selected path does not exist or is not readable.")); - const FilePath bin = jdkPath.pathAppended("bin/javac" QTC_HOST_EXE_SUFFIX); + const QString javacCommand("javac"); + const QString versionParameter("-version"); + constexpr int requiredMajorVersion = 17; + const FilePath bin = jdkPath / "bin" / (javacCommand + QTC_HOST_EXE_SUFFIX); if (!bin.isExecutableFile()) return make_unexpected( - Tr::tr("The selected path does not contain an executable bin/javac.")); + Tr::tr("Could not find \"%1\" in the selected path.") + .arg(bin.toUserOutput())); QVersionNumber jdkVersion; Process javacProcess; - CommandLine cmd(bin, {"-version"}); + const CommandLine cmd(bin, {versionParameter}); javacProcess.setProcessChannelMode(QProcess::ProcessChannelMode::MergedChannels); javacProcess.setCommand(cmd); javacProcess.runBlocking(); @@ -227,17 +231,22 @@ static expected_str testJavaC(const FilePath &jdkPath) if (javacProcess.exitCode() != 0) return make_unexpected( - Tr::tr("The selected path does not contain a valid JDK. (javac -version failed: %1)") + Tr::tr("The selected path does not contain a valid JDK. (%1 failed: %2)") + .arg(cmd.toUserOutput()) .arg(stdOut)); // We expect "javac " where is "major.minor.patch" - if (!stdOut.startsWith("javac ")) - return make_unexpected(Tr::tr("Unexpected output from \"javac -version\": %1").arg(stdOut)); + const QString outputPrefix = javacCommand + " "; + if (!stdOut.startsWith(outputPrefix)) + return make_unexpected(Tr::tr("Unexpected output from \"%1\": %2") + .arg(cmd.toUserOutput()) + .arg(stdOut)); - jdkVersion = QVersionNumber::fromString(stdOut.mid(6).split('\n').first()); + jdkVersion = QVersionNumber::fromString(stdOut.mid(outputPrefix.length()).split('\n').first()); - if (jdkVersion.isNull() || jdkVersion.majorVersion() != 17) { - return make_unexpected(Tr::tr("Unsupported JDK version (needs to be 17): %1 (parsed: %2)") + if (jdkVersion.isNull() || jdkVersion.majorVersion() != requiredMajorVersion) { + return make_unexpected(Tr::tr("Unsupported JDK version (needs to be %1): %2 (parsed: %3)") + .arg(requiredMajorVersion) .arg(stdOut) .arg(jdkVersion.toString())); } From b60e0cfee7e346adc934d910216bbc0e47ccffb6 Mon Sep 17 00:00:00 2001 From: Eike Ziller Date: Tue, 27 Feb 2024 12:45:36 +0100 Subject: [PATCH 203/243] Update change log for 13.0.0 Change-Id: I7760acdfeb1b0a309e8d939bf37494aa3a0a7a36 Reviewed-by: Leena Miettinen --- dist/changelog/changes-13.0.0.md | 11 +++++++++++ 1 file changed, 11 insertions(+) diff --git a/dist/changelog/changes-13.0.0.md b/dist/changelog/changes-13.0.0.md index b8aa6aa1160..6ca281668ff 100644 --- a/dist/changelog/changes-13.0.0.md +++ b/dist/changelog/changes-13.0.0.md @@ -39,6 +39,8 @@ General for searching in `Files in File System` * Added `Copy to Clipboard` to the `About Qt Creator` dialog ([QTCREATORBUG-29886](https://bugreports.qt.io/browse/QTCREATORBUG-29886)) +* Fixed issues with the window actions + ([QTCREATORBUG-30381](https://bugreports.qt.io/browse/QTCREATORBUG-30381)) Editing ------- @@ -78,6 +80,8 @@ Editing * Clangd * Fixed that `Follow Symbol Under Cursor` only worked for exact matches ([QTCREATORBUG-29814](https://bugreports.qt.io/browse/QTCREATORBUG-29814)) + * Fixed the version check for remote `clangd` executables + ([QTCREATORBUG-30374](https://bugreports.qt.io/browse/QTCREATORBUG-30374)) ### QML @@ -133,6 +137,8 @@ Projects ([QTCREATORBUG-29530](https://bugreports.qt.io/browse/QTCREATORBUG-29530)) * Added a file wizard for Qt translation (`.ts`) files ([QTCREATORBUG-29775](https://bugreports.qt.io/browse/QTCREATORBUG-29775)) +* Added an optional warning for special characters in build directories + ([QTCREATORBUG-20834](https://bugreports.qt.io/browse/QTCREATORBUG-20834)) * Improved the environment settings by making the changes explicit in a separate, text-based editor * Increased the maximum width of the target selector @@ -184,6 +190,9 @@ Debugging ### C++ * Added a pretty printer for `std::tuple` +* Improved the display of size information for the pretty printer of + `QByteArray` + ([QTCREATORBUG-30065](https://bugreports.qt.io/browse/QTCREATORBUG-30065)) * Fixed that breakpoints were not hit while the message dialog about missing debug information was shown ([QTCREATORBUG-30168](https://bugreports.qt.io/browse/QTCREATORBUG-30168)) @@ -270,6 +279,7 @@ Andre Hartmann André Pönitz Andreas Loth Artem Sokolovskii +Assam Boudjelthia Brook Cronin Burak Hancerli Christian Kandeler @@ -306,6 +316,7 @@ Robert Löhning Sami Shalayel Samuel Jose Raposo Vieira Mira Samuel Mira +Semih Yavuz Serg Kryvonos Shrief Gabr Sivert Krøvel From e8b3887dbf584460973ed0212a66f9b400bcc464 Mon Sep 17 00:00:00 2001 From: Jarek Kobus Date: Tue, 27 Feb 2024 13:51:54 +0100 Subject: [PATCH 204/243] Axivion: Make use of Dto::IssueKind enum Use Dto::IssueKindMeta::enumToStr() to convert it to string. Rename icons accordingly. Change-Id: I8a955f2f0075793eea761cd4a41374a65d2aaea2 Reviewed-by: hjk --- src/plugins/axivion/axivion.qrc | 24 +++++++++--------- src/plugins/axivion/axivionoutputpane.cpp | 2 +- src/plugins/axivion/axivionplugin.cpp | 20 ++++++++------- src/plugins/axivion/axivionplugin.h | 2 +- .../images/{button-av.png => button-AV.png} | Bin .../{button-av@2x.png => button-AV@2x.png} | Bin .../images/{button-cl.png => button-CL.png} | Bin .../{button-cl@2x.png => button-CL@2x.png} | Bin .../images/{button-cy.png => button-CY.png} | Bin .../{button-cy@2x.png => button-CY@2x.png} | Bin .../images/{button-de.png => button-DE.png} | Bin .../{button-de@2x.png => button-DE@2x.png} | Bin .../images/{button-mv.png => button-MV.png} | Bin .../{button-mv@2x.png => button-MV@2x.png} | Bin .../images/{button-sv.png => button-SV.png} | Bin .../{button-sv@2x.png => button-SV@2x.png} | Bin src/tools/icons/qtcreatoricons.svg | 12 ++++----- 17 files changed, 31 insertions(+), 29 deletions(-) rename src/plugins/axivion/images/{button-av.png => button-AV.png} (100%) rename src/plugins/axivion/images/{button-av@2x.png => button-AV@2x.png} (100%) rename src/plugins/axivion/images/{button-cl.png => button-CL.png} (100%) rename src/plugins/axivion/images/{button-cl@2x.png => button-CL@2x.png} (100%) rename src/plugins/axivion/images/{button-cy.png => button-CY.png} (100%) rename src/plugins/axivion/images/{button-cy@2x.png => button-CY@2x.png} (100%) rename src/plugins/axivion/images/{button-de.png => button-DE.png} (100%) rename src/plugins/axivion/images/{button-de@2x.png => button-DE@2x.png} (100%) rename src/plugins/axivion/images/{button-mv.png => button-MV.png} (100%) rename src/plugins/axivion/images/{button-mv@2x.png => button-MV@2x.png} (100%) rename src/plugins/axivion/images/{button-sv.png => button-SV.png} (100%) rename src/plugins/axivion/images/{button-sv@2x.png => button-SV@2x.png} (100%) diff --git a/src/plugins/axivion/axivion.qrc b/src/plugins/axivion/axivion.qrc index fa3ad146d37..d1e41e3cdb3 100644 --- a/src/plugins/axivion/axivion.qrc +++ b/src/plugins/axivion/axivion.qrc @@ -2,18 +2,18 @@ images/axivion.png images/axivion@2x.png - images/button-av.png - images/button-av@2x.png - images/button-cl.png - images/button-cl@2x.png - images/button-cy.png - images/button-cy@2x.png - images/button-de.png - images/button-de@2x.png - images/button-mv.png - images/button-mv@2x.png - images/button-sv.png - images/button-sv@2x.png + images/button-AV.png + images/button-AV@2x.png + images/button-CL.png + images/button-CL@2x.png + images/button-CY.png + images/button-CY@2x.png + images/button-DE.png + images/button-DE@2x.png + images/button-MV.png + images/button-MV@2x.png + images/button-SV.png + images/button-SV@2x.png images/sortAsc.png images/sortAsc@2x.png images/sortDesc.png diff --git a/src/plugins/axivion/axivionoutputpane.cpp b/src/plugins/axivion/axivionoutputpane.cpp index 31a03f0d569..70e44057e9f 100644 --- a/src/plugins/axivion/axivionoutputpane.cpp +++ b/src/plugins/axivion/axivionoutputpane.cpp @@ -564,7 +564,7 @@ void IssuesWidget::updateBasicProjectInfo(std::optional inf int buttonId = 0; for (const Dto::IssueKindInfoDto &kind : issueKinds) { auto button = new QToolButton(this); - button->setIcon(iconForIssue(kind.prefix)); + button->setIcon(iconForIssue(kind.getOptionalPrefixEnum())); button->setToolTip(kind.nicePluralName); button->setCheckable(true); connect(button, &QToolButton::clicked, this, [this, prefix = kind.prefix]{ diff --git a/src/plugins/axivion/axivionplugin.cpp b/src/plugins/axivion/axivionplugin.cpp index 20e7871b14e..6e04af7e30d 100644 --- a/src/plugins/axivion/axivionplugin.cpp +++ b/src/plugins/axivion/axivionplugin.cpp @@ -63,16 +63,18 @@ using namespace Utils; namespace Axivion::Internal { -QIcon iconForIssue(const QString &prefix) +QIcon iconForIssue(const std::optional &issueKind) { - static QHash prefixToIcon; - auto it = prefixToIcon.find(prefix); + if (!issueKind) + return {}; - if (it == prefixToIcon.end()) { - Icon icon({{FilePath::fromString(":/axivion/images/button-" + prefix.toLower() + ".png"), - Theme::PaletteButtonText}}, - Icon::Tint); - it = prefixToIcon.insert(prefix, icon.icon()); + static QHash prefixToIcon; + auto it = prefixToIcon.constFind(*issueKind); + if (it == prefixToIcon.constEnd()) { + const auto prefix = Dto::IssueKindMeta::enumToStr(*issueKind); + const Icon icon({{FilePath::fromString(":/axivion/images/button-" + prefix + ".png"), + Theme::PaletteButtonText}}, Icon::Tint); + it = prefixToIcon.insert(*issueKind, icon.icon()); } return it.value(); } @@ -226,7 +228,7 @@ public: const QString markText = issue.description; const QString id = issue.kind + QString::number(issue.id.value_or(-1)); setToolTip(id + '\n' + markText); - setIcon(iconForIssue(issue.kind)); + setIcon(iconForIssue(issue.getOptionalKindEnum())); if (color) setColor(*color); setPriority(TextMark::NormalPriority); diff --git a/src/plugins/axivion/axivionplugin.h b/src/plugins/axivion/axivionplugin.h index c60aad6e9e9..18cdae6dded 100644 --- a/src/plugins/axivion/axivionplugin.h +++ b/src/plugins/axivion/axivionplugin.h @@ -71,7 +71,7 @@ void fetchProjectInfo(const QString &projectName); std::optional projectInfo(); bool handleCertificateIssue(); -QIcon iconForIssue(const QString &prefix); +QIcon iconForIssue(const std::optional &issueKind); QString anyToSimpleString(const Dto::Any &any); void fetchIssueInfo(const QString &id); diff --git a/src/plugins/axivion/images/button-av.png b/src/plugins/axivion/images/button-AV.png similarity index 100% rename from src/plugins/axivion/images/button-av.png rename to src/plugins/axivion/images/button-AV.png diff --git a/src/plugins/axivion/images/button-av@2x.png b/src/plugins/axivion/images/button-AV@2x.png similarity index 100% rename from src/plugins/axivion/images/button-av@2x.png rename to src/plugins/axivion/images/button-AV@2x.png diff --git a/src/plugins/axivion/images/button-cl.png b/src/plugins/axivion/images/button-CL.png similarity index 100% rename from src/plugins/axivion/images/button-cl.png rename to src/plugins/axivion/images/button-CL.png diff --git a/src/plugins/axivion/images/button-cl@2x.png b/src/plugins/axivion/images/button-CL@2x.png similarity index 100% rename from src/plugins/axivion/images/button-cl@2x.png rename to src/plugins/axivion/images/button-CL@2x.png diff --git a/src/plugins/axivion/images/button-cy.png b/src/plugins/axivion/images/button-CY.png similarity index 100% rename from src/plugins/axivion/images/button-cy.png rename to src/plugins/axivion/images/button-CY.png diff --git a/src/plugins/axivion/images/button-cy@2x.png b/src/plugins/axivion/images/button-CY@2x.png similarity index 100% rename from src/plugins/axivion/images/button-cy@2x.png rename to src/plugins/axivion/images/button-CY@2x.png diff --git a/src/plugins/axivion/images/button-de.png b/src/plugins/axivion/images/button-DE.png similarity index 100% rename from src/plugins/axivion/images/button-de.png rename to src/plugins/axivion/images/button-DE.png diff --git a/src/plugins/axivion/images/button-de@2x.png b/src/plugins/axivion/images/button-DE@2x.png similarity index 100% rename from src/plugins/axivion/images/button-de@2x.png rename to src/plugins/axivion/images/button-DE@2x.png diff --git a/src/plugins/axivion/images/button-mv.png b/src/plugins/axivion/images/button-MV.png similarity index 100% rename from src/plugins/axivion/images/button-mv.png rename to src/plugins/axivion/images/button-MV.png diff --git a/src/plugins/axivion/images/button-mv@2x.png b/src/plugins/axivion/images/button-MV@2x.png similarity index 100% rename from src/plugins/axivion/images/button-mv@2x.png rename to src/plugins/axivion/images/button-MV@2x.png diff --git a/src/plugins/axivion/images/button-sv.png b/src/plugins/axivion/images/button-SV.png similarity index 100% rename from src/plugins/axivion/images/button-sv.png rename to src/plugins/axivion/images/button-SV.png diff --git a/src/plugins/axivion/images/button-sv@2x.png b/src/plugins/axivion/images/button-SV@2x.png similarity index 100% rename from src/plugins/axivion/images/button-sv@2x.png rename to src/plugins/axivion/images/button-SV@2x.png diff --git a/src/tools/icons/qtcreatoricons.svg b/src/tools/icons/qtcreatoricons.svg index ddec488f3cb..07452dc8c1e 100644 --- a/src/tools/icons/qtcreatoricons.svg +++ b/src/tools/icons/qtcreatoricons.svg @@ -3813,7 +3813,7 @@ r="1.5" /> Date: Tue, 27 Feb 2024 15:34:32 +0100 Subject: [PATCH 205/243] Axivion: Fix clazy warning about mixing const and mutable iterators Change-Id: Ief898ff2febb958f3f68a64ddcb614479854600f Reviewed-by: Christian Stenger Reviewed-by: Jarek Kobus Reviewed-by: Andreas Loth --- src/plugins/axivion/axivionplugin.cpp | 15 ++++++++------- 1 file changed, 8 insertions(+), 7 deletions(-) diff --git a/src/plugins/axivion/axivionplugin.cpp b/src/plugins/axivion/axivionplugin.cpp index 6e04af7e30d..43316c4f8b7 100644 --- a/src/plugins/axivion/axivionplugin.cpp +++ b/src/plugins/axivion/axivionplugin.cpp @@ -69,14 +69,15 @@ QIcon iconForIssue(const std::optional &issueKind) return {}; static QHash prefixToIcon; + auto it = prefixToIcon.constFind(*issueKind); - if (it == prefixToIcon.constEnd()) { - const auto prefix = Dto::IssueKindMeta::enumToStr(*issueKind); - const Icon icon({{FilePath::fromString(":/axivion/images/button-" + prefix + ".png"), - Theme::PaletteButtonText}}, Icon::Tint); - it = prefixToIcon.insert(*issueKind, icon.icon()); - } - return it.value(); + if (it != prefixToIcon.constEnd()) + return *it; + + const QLatin1String prefix = Dto::IssueKindMeta::enumToStr(*issueKind); + const Icon icon({{FilePath::fromString(":/axivion/images/button-" + prefix + ".png"), + Theme::PaletteButtonText}}, Icon::Tint); + return prefixToIcon.insert(*issueKind, icon.icon()).value(); } QString anyToSimpleString(const Dto::Any &any) From fdb1fa2a3b868ced9075b6e40527364f209edbed Mon Sep 17 00:00:00 2001 From: Leena Miettinen Date: Mon, 26 Feb 2024 17:13:01 +0100 Subject: [PATCH 206/243] Python: Fix capitalization of Python in UI text Change-Id: I55beeb658eb583a74c4d79f3dc2f121010080101 Reviewed-by: Reviewed-by: David Schulz Reviewed-by: Eike Ziller --- src/plugins/python/pythonkitaspect.cpp | 12 ++++++------ src/plugins/python/pythonproject.cpp | 2 +- 2 files changed, 7 insertions(+), 7 deletions(-) diff --git a/src/plugins/python/pythonkitaspect.cpp b/src/plugins/python/pythonkitaspect.cpp index 26ad44bad48..254a720d7cc 100644 --- a/src/plugins/python/pythonkitaspect.cpp +++ b/src/plugins/python/pythonkitaspect.cpp @@ -117,11 +117,11 @@ public: if (!pipIsUsable(path)) { result << BuildSystemTask( Task::Warning, - Tr::tr("Python \"%1\" does not contain a usable pip. Pip is used to install " - "python " - "packages from the Python Package Index, like PySide and the python " - "language server. If you want to use any of that functionality " - "ensure pip is installed for that python.") + Tr::tr("Python \"%1\" does not contain a usable pip. pip is needed to install " + "Python " + "packages from the Python Package Index, like PySide and the Python " + "language server. To use any of that functionality " + "ensure that pip is installed for that Python.") .arg(path.toUserOutput())); } if (!venvIsUsable(path)) { @@ -130,7 +130,7 @@ public: Tr::tr( "Python \"%1\" does not contain a usable venv. venv is the recommended way " "to isolate a development environment for a project from the globally " - "installed python.") + "installed Python.") .arg(path.toUserOutput())); } } diff --git a/src/plugins/python/pythonproject.cpp b/src/plugins/python/pythonproject.cpp index 129782773d3..db0831005f1 100644 --- a/src/plugins/python/pythonproject.cpp +++ b/src/plugins/python/pythonproject.cpp @@ -35,7 +35,7 @@ Tasks PythonProject::projectIssues(const Kit *k) const return {}; return { BuildSystemTask{Task::Error, - Tr::tr("No python interpreter set for kit \"%1\"").arg(k->displayName())}}; + Tr::tr("No Python interpreter set for kit \"%1\"").arg(k->displayName())}}; } PythonProjectNode::PythonProjectNode(const FilePath &path) From 97077f4d263c3da34d360e2509daf273d1cecefd Mon Sep 17 00:00:00 2001 From: Jarek Kobus Date: Tue, 27 Feb 2024 13:56:47 +0100 Subject: [PATCH 207/243] Axivion: Raise the size of issues packet Change-Id: I4a60649982b1ffa50c2c85f4db3d57f88186a211 Reviewed-by: hjk Reviewed-by: Andreas Loth --- src/plugins/axivion/axivionplugin.h | 4 +++- src/plugins/axivion/dynamiclistmodel.cpp | 17 ++++++++--------- 2 files changed, 11 insertions(+), 10 deletions(-) diff --git a/src/plugins/axivion/axivionplugin.h b/src/plugins/axivion/axivionplugin.h index 18cdae6dded..39783a956da 100644 --- a/src/plugins/axivion/axivionplugin.h +++ b/src/plugins/axivion/axivionplugin.h @@ -23,6 +23,8 @@ namespace Utils { class FilePath; } namespace Axivion::Internal { +constexpr int DefaultSearchLimit = 2048; + struct IssueListSearch { QString kind; @@ -33,7 +35,7 @@ struct IssueListSearch QString filter_path; QString sort; int offset = 0; - int limit = 150; + int limit = DefaultSearchLimit; bool computeTotalRowCount = false; QString toQuery() const; diff --git a/src/plugins/axivion/dynamiclistmodel.cpp b/src/plugins/axivion/dynamiclistmodel.cpp index 70abe087bdb..7c5262132b8 100644 --- a/src/plugins/axivion/dynamiclistmodel.cpp +++ b/src/plugins/axivion/dynamiclistmodel.cpp @@ -3,6 +3,7 @@ #include "dynamiclistmodel.h" +#include "axivionplugin.h" #include "axiviontr.h" #include @@ -10,8 +11,6 @@ namespace Axivion::Internal { -constexpr int pageSize = 150; - DynamicListModel::DynamicListModel(QObject *parent) : QAbstractItemModel(parent) { @@ -161,7 +160,7 @@ QModelIndex DynamicListModel::indexForItem(const ListItem *item) const void DynamicListModel::onNeedFetch(int row) { m_fetchStart = row; - m_fetchEnd = row + pageSize; + m_fetchEnd = row + DefaultSearchLimit; if (m_fetchStart < 0) return; m_fetchMoreTimer.start(); @@ -171,14 +170,14 @@ void DynamicListModel::fetchNow() { const int old = m_lastFetch; m_lastFetch = m_fetchStart; // we need the "original" fetch request to avoid endless loop - m_lastFetchEnd = m_fetchStart + pageSize; + m_lastFetchEnd = m_fetchStart + DefaultSearchLimit; if (old != -1) { const int diff = old - m_fetchStart; - if (0 < diff && diff < pageSize) { - m_fetchStart = qMax(old - pageSize, 0); - } else if (0 > diff && diff > -pageSize) { - m_fetchStart = old + pageSize; + if (0 < diff && diff < DefaultSearchLimit) { + m_fetchStart = qMax(old - DefaultSearchLimit, 0); + } else if (0 > diff && diff > - DefaultSearchLimit) { + m_fetchStart = old + DefaultSearchLimit; if (m_expectedRowCount && m_fetchStart > *m_expectedRowCount) m_fetchStart = *m_expectedRowCount; } @@ -186,7 +185,7 @@ void DynamicListModel::fetchNow() QTC_CHECK(m_expectedRowCount ? m_fetchStart <= *m_expectedRowCount : m_fetchStart >= m_children.size()); - emit fetchRequested(m_fetchStart, pageSize); + emit fetchRequested(m_fetchStart, DefaultSearchLimit); m_fetchStart = -1; m_fetchEnd = -1; } From e2a0dd2cefe5265a9d3ba59de766f73302cf0082 Mon Sep 17 00:00:00 2001 From: Jarek Kobus Date: Tue, 27 Feb 2024 15:51:46 +0100 Subject: [PATCH 208/243] Axivion: Fix the condition inside onUnauthorizedGroupSetup We should execute this branch just once, when the server access is unknown. Introduce isServerAccessEstablished() helper. Change-Id: I28953f468be39ca49f088032aebb3fa81b814f3f Reviewed-by: hjk --- src/plugins/axivion/axivionplugin.cpp | 15 +++++++++++---- 1 file changed, 11 insertions(+), 4 deletions(-) diff --git a/src/plugins/axivion/axivionplugin.cpp b/src/plugins/axivion/axivionplugin.cpp index 43316c4f8b7..2152755fd14 100644 --- a/src/plugins/axivion/axivionplugin.cpp +++ b/src/plugins/axivion/axivionplugin.cpp @@ -333,11 +333,17 @@ static constexpr int httpStatusCodeOk = 200; constexpr char s_htmlContentType[] = "text/html"; constexpr char s_jsonContentType[] = "application/json"; +static bool isServerAccessEstablished() +{ + return dd->m_serverAccess == ServerAccess::NoAuthorization + || (dd->m_serverAccess == ServerAccess::WithAuthorization && dd->m_apiToken); +} + static Group fetchHtmlRecipe(const QUrl &url, const std::function &handler) { // TODO: Refactor so that it's a common code with fetchDataRecipe(). const auto onQuerySetup = [url](NetworkQuery &query) { - if (dd->m_serverAccess == ServerAccess::Unknown) + if (!isServerAccessEstablished()) return SetupResult::StopWithError; // TODO: start authorizationRecipe()? QNetworkRequest request(url); @@ -506,7 +512,7 @@ static Group authorizationRecipe() { const Storage> unauthorizedDashboardStorage; const auto onUnauthorizedGroupSetup = [unauthorizedDashboardStorage] { - if (dd->m_serverAccess != ServerAccess::NoAuthorization) + if (isServerAccessEstablished()) return SetupResult::StopWithSuccess; unauthorizedDashboardStorage->url = QUrl(settings().server.dashboard); @@ -636,10 +642,11 @@ static Group fetchDataRecipe(const QUrl &url, const std::function> dtoStorage; const auto onDtoSetup = [dtoStorage, url] { - if (!dd->m_apiToken) + if (!isServerAccessEstablished()) return SetupResult::StopWithError; - dtoStorage->credential = "AxToken " + *dd->m_apiToken; + if (dd->m_serverAccess == ServerAccess::WithAuthorization && dd->m_apiToken) + dtoStorage->credential = "AxToken " + *dd->m_apiToken; dtoStorage->url = url; return SetupResult::Continue; }; From 903d01b93459d0f1ee70e6ca74a8c01af5e0981b Mon Sep 17 00:00:00 2001 From: Alessandro Portale Date: Mon, 12 Feb 2024 17:19:41 +0100 Subject: [PATCH 209/243] Welcome: Implement new design 2024 redesign Change-Id: I6629849921272d856f201693973a8e29c6465e94 Reviewed-by: hjk Reviewed-by: Alessandro Portale --- share/qtcreator/themes/dark.creatortheme | 34 +- share/qtcreator/themes/dark.figmatokens | 31 + share/qtcreator/themes/default.creatortheme | 34 +- .../themes/design-light.creatortheme | 34 +- share/qtcreator/themes/design.creatortheme | 34 +- share/qtcreator/themes/flat-dark.creatortheme | 34 +- .../qtcreator/themes/flat-light.creatortheme | 34 +- share/qtcreator/themes/flat.creatortheme | 34 +- share/qtcreator/themes/light.figmatokens | 31 + src/libs/utils/stylehelper.cpp | 24 +- src/libs/utils/stylehelper.h | 31 +- src/libs/utils/theme/theme.h | 12 - src/plugins/coreplugin/core.qrc | 4 + src/plugins/coreplugin/images/expandarrow.png | Bin 0 -> 169 bytes .../coreplugin/images/expandarrow@2x.png | Bin 0 -> 209 bytes src/plugins/coreplugin/images/search.png | Bin 0 -> 179 bytes src/plugins/coreplugin/images/search@2x.png | Bin 0 -> 361 bytes src/plugins/coreplugin/iwelcomepage.cpp | 184 ----- src/plugins/coreplugin/iwelcomepage.h | 44 +- src/plugins/coreplugin/session.cpp | 5 + src/plugins/coreplugin/session.h | 1 + src/plugins/coreplugin/welcomepagehelper.cpp | 717 ++++++++++++++---- src/plugins/coreplugin/welcomepagehelper.h | 126 ++- .../extensionmanagerwidget.cpp | 20 +- .../extensionmanager/extensionsbrowser.cpp | 26 +- .../extensionmanager/extensionsbrowser.h | 12 +- src/plugins/marketplace/productlistmodel.cpp | 2 +- .../marketplace/qtmarketplacewelcomepage.cpp | 39 +- .../projectexplorer/projectwelcomepage.cpp | 660 ++++++++++------ src/plugins/qtsupport/exampleslistmodel.cpp | 2 +- .../qtsupport/gettingstartedwelcomepage.cpp | 53 +- src/plugins/welcome/images/expandarrow.png | Bin 106 -> 0 bytes src/plugins/welcome/images/expandarrow@2x.png | Bin 148 -> 0 bytes src/plugins/welcome/images/link.png | Bin 0 -> 186 bytes src/plugins/welcome/images/link@2x.png | Bin 0 -> 236 bytes src/plugins/welcome/images/project.png | Bin 106 -> 175 bytes src/plugins/welcome/images/project@2x.png | Bin 112 -> 225 bytes src/plugins/welcome/images/session.png | Bin 118 -> 192 bytes src/plugins/welcome/images/session@2x.png | Bin 161 -> 255 bytes src/plugins/welcome/welcome.qrc | 4 +- src/plugins/welcome/welcomeplugin.cpp | 324 ++++---- src/tools/icons/qtcreatoricons.svg | 115 ++- .../uifonts/tst_manual_widgets_uifonts.cpp | 8 +- 43 files changed, 1517 insertions(+), 1196 deletions(-) create mode 100644 share/qtcreator/themes/dark.figmatokens create mode 100644 share/qtcreator/themes/light.figmatokens create mode 100644 src/plugins/coreplugin/images/expandarrow.png create mode 100644 src/plugins/coreplugin/images/expandarrow@2x.png create mode 100644 src/plugins/coreplugin/images/search.png create mode 100644 src/plugins/coreplugin/images/search@2x.png delete mode 100644 src/plugins/welcome/images/expandarrow.png delete mode 100644 src/plugins/welcome/images/expandarrow@2x.png create mode 100644 src/plugins/welcome/images/link.png create mode 100644 src/plugins/welcome/images/link@2x.png diff --git a/share/qtcreator/themes/dark.creatortheme b/share/qtcreator/themes/dark.creatortheme index a7dcedd104a..c2846fa0940 100644 --- a/share/qtcreator/themes/dark.creatortheme +++ b/share/qtcreator/themes/dark.creatortheme @@ -1,4 +1,5 @@ [General] +Includes=dark.figmatokens ThemeName=Dark PreferredStyles= DefaultTextEditorColorScheme=dark.xml @@ -406,39 +407,6 @@ Debugger_WatchItem_ValueChanged=ffff6666 Debugger_Breakpoint_TextMarkColor=ffff4040 -; Qt Creator Color Tokens - dark mode -Token_Basic_Black=ff131313 -Token_Basic_White=fff8f8f8 -Token_Accent_Default=ff23b26a -Token_Accent_Muted=ff1f9b5d -Token_Accent_Subtle=ff1a8550 -Token_Background_Default=ff1f1f1f -Token_Background_Muted=ff262626 -Token_Background_Subtle=ff2e2e2e -Token_Foreground_Default=ff5a5a5a -Token_Foreground_Muted=ff3e3e3e -Token_Foreground_Subtle=ff303030 -Token_Text_Default=fff8f8f8 -Token_Text_Muted=ffaeaeae -Token_Text_Subtle=ff595959 -Token_Stroke_Strong=ffeeeeee -Token_Stroke_Muted=ff727272 -Token_Stroke_Subtle=ff3a3a3a -Token_Notification_Alert=ffc98014 -Token_Notification_Success=ff1f9b5d -Token_Notification_Neutral=ff016876 -Token_Notification_Danger=ffb22245 - -Welcome_TextColor=text -Welcome_ForegroundPrimaryColor=ffa3a3a3 -Welcome_ForegroundSecondaryColor=ff808080 -Welcome_BackgroundPrimaryColor=normalBackground -Welcome_BackgroundSecondaryColor=shadowBackground -Welcome_HoverColor=ff404040 -Welcome_AccentColor=ff57d658 -Welcome_LinkColor=ff67e668 -Welcome_DisabledLinkColor=textDisabled - Timeline_TextColor=text Timeline_BackgroundColor1=normalBackground Timeline_BackgroundColor2=ff444444 diff --git a/share/qtcreator/themes/dark.figmatokens b/share/qtcreator/themes/dark.figmatokens new file mode 100644 index 00000000000..fdd98e80c10 --- /dev/null +++ b/share/qtcreator/themes/dark.figmatokens @@ -0,0 +1,31 @@ +; Qt Creator Color Tokens - dark mode + +[Colors] + +Token_Basic_Black=ff131313 +Token_Basic_White=fff8f8f8 + +Token_Accent_Default=ff23b26a +Token_Accent_Muted=ff1f9b5d +Token_Accent_Subtle=ff1a8550 + +Token_Background_Default=ff1f1f1f +Token_Background_Muted=ff262626 +Token_Background_Subtle=ff2e2e2e + +Token_Foreground_Default=ff5a5a5a +Token_Foreground_Muted=ff3e3e3e +Token_Foreground_Subtle=ff303030 + +Token_Text_Default=fff8f8f8 +Token_Text_Muted=ffaeaeae +Token_Text_Subtle=ff595959 + +Token_Stroke_Strong=ffeeeeee +Token_Stroke_Muted=ff727272 +Token_Stroke_Subtle=ff3a3a3a + +Token_Notification_Alert=ffc98014 +Token_Notification_Success=ff1f9b5d +Token_Notification_Neutral=ff016876 +Token_Notification_Danger=ffb22245 diff --git a/share/qtcreator/themes/default.creatortheme b/share/qtcreator/themes/default.creatortheme index 2dee7ab2469..f2c4c7f7a43 100644 --- a/share/qtcreator/themes/default.creatortheme +++ b/share/qtcreator/themes/default.creatortheme @@ -1,4 +1,5 @@ [General] +Includes=light.figmatokens ThemeName=Classic PreferredStyles= @@ -398,39 +399,6 @@ Debugger_WatchItem_ValueChanged=ffc80000 Debugger_Breakpoint_TextMarkColor=ffff4040 -; Qt Creator Color Tokens - light mode -Token_Basic_Black=ff131313 -Token_Basic_White=fff2f2f2 -Token_Accent_Default=ff23b26a -Token_Accent_Muted=ff1f9b5d -Token_Accent_Subtle=ff1a8550 -Token_Background_Default=ffe3e3e3 -Token_Background_Muted=ffeeeeee -Token_Background_Subtle=fffbfbfb -Token_Foreground_Default=ffcdcdcd -Token_Foreground_Muted=ffd5d5d5 -Token_Foreground_Subtle=ffdddddd -Token_Text_Default=ff393939 -Token_Text_Muted=ff7c7c7c -Token_Text_Subtle=ffbebebe -Token_Stroke_Strong=ff464646 -Token_Stroke_Muted=ff727272 -Token_Stroke_Subtle=ffcdcdcd -Token_Notification_Alert=ffeb991f -Token_Notification_Success=ff23b26a -Token_Notification_Neutral=ff0e7887 -Token_Notification_Danger=ffdc1343 - -Welcome_TextColor=ff000000 -Welcome_ForegroundPrimaryColor=shadowBackground -Welcome_ForegroundSecondaryColor=ff939393 -Welcome_BackgroundPrimaryColor=fffafafa -Welcome_BackgroundSecondaryColor=ffffffff -Welcome_HoverColor=ffefefef -Welcome_AccentColor=ff45ce55 -Welcome_LinkColor=ff20a020 -Welcome_DisabledLinkColor=textDisabled - Timeline_TextColor=darkText Timeline_BackgroundColor1=ffffffff Timeline_BackgroundColor2=fff6f6f6 diff --git a/share/qtcreator/themes/design-light.creatortheme b/share/qtcreator/themes/design-light.creatortheme index 8931b620424..41a9f07ba84 100644 --- a/share/qtcreator/themes/design-light.creatortheme +++ b/share/qtcreator/themes/design-light.creatortheme @@ -1,4 +1,5 @@ [General] +Includes=light.figmatokens ThemeName=Design Light PreferredStyles= @@ -410,39 +411,6 @@ Debugger_WatchItem_ValueChanged=ffbf0303 Debugger_Breakpoint_TextMarkColor=ffff4040 -; Qt Creator Color Tokens - light mode -Token_Basic_Black=ff131313 -Token_Basic_White=fff2f2f2 -Token_Accent_Default=ff23b26a -Token_Accent_Muted=ff1f9b5d -Token_Accent_Subtle=ff1a8550 -Token_Background_Default=ffe3e3e3 -Token_Background_Muted=ffeeeeee -Token_Background_Subtle=fffbfbfb -Token_Foreground_Default=ffcdcdcd -Token_Foreground_Muted=ffd5d5d5 -Token_Foreground_Subtle=ffdddddd -Token_Text_Default=ff393939 -Token_Text_Muted=ff7c7c7c -Token_Text_Subtle=ffbebebe -Token_Stroke_Strong=ff464646 -Token_Stroke_Muted=ff727272 -Token_Stroke_Subtle=ffcdcdcd -Token_Notification_Alert=ffeb991f -Token_Notification_Success=ff23b26a -Token_Notification_Neutral=ff0e7887 -Token_Notification_Danger=ffdc1343 - -Welcome_TextColor=ff000000 -Welcome_ForegroundPrimaryColor=ff404040 -Welcome_ForegroundSecondaryColor=ff727272 -Welcome_BackgroundPrimaryColor=ffeaeaea -Welcome_BackgroundSecondaryColor=ffefefef -Welcome_HoverColor=ffe1e1e1 -Welcome_AccentColor=ff25709a -Welcome_LinkColor=ff104090 -Welcome_DisabledLinkColor=textDisabled - Timeline_TextColor=text Timeline_BackgroundColor1=normalBackground Timeline_BackgroundColor2=fff6f6f6 diff --git a/share/qtcreator/themes/design.creatortheme b/share/qtcreator/themes/design.creatortheme index e29240a3cf6..11022bd7e5d 100644 --- a/share/qtcreator/themes/design.creatortheme +++ b/share/qtcreator/themes/design.creatortheme @@ -1,4 +1,5 @@ [General] +Includes=dark.figmatokens ThemeName=Design Dark PreferredStyles= DefaultTextEditorColorScheme=creator-dark.xml @@ -414,39 +415,6 @@ Debugger_WatchItem_ValueChanged=ffff6666 Debugger_Breakpoint_TextMarkColor=ffff4040 -; Qt Creator Color Tokens - dark mode -Token_Basic_Black=ff131313 -Token_Basic_White=fff8f8f8 -Token_Accent_Default=ff23b26a -Token_Accent_Muted=ff1f9b5d -Token_Accent_Subtle=ff1a8550 -Token_Background_Default=ff1f1f1f -Token_Background_Muted=ff262626 -Token_Background_Subtle=ff2e2e2e -Token_Foreground_Default=ff5a5a5a -Token_Foreground_Muted=ff3e3e3e -Token_Foreground_Subtle=ff303030 -Token_Text_Default=fff8f8f8 -Token_Text_Muted=ffaeaeae -Token_Text_Subtle=ff595959 -Token_Stroke_Strong=ffeeeeee -Token_Stroke_Muted=ff727272 -Token_Stroke_Subtle=ff3a3a3a -Token_Notification_Alert=ffc98014 -Token_Notification_Success=ff1f9b5d -Token_Notification_Neutral=ff016876 -Token_Notification_Danger=ffb22245 - -Welcome_TextColor=text -Welcome_ForegroundPrimaryColor=ffa3a3a3 -Welcome_ForegroundSecondaryColor=ff808080 -Welcome_BackgroundPrimaryColor=ff242424 -Welcome_BackgroundSecondaryColor=ff1c1c1c -Welcome_HoverColor=ff2b2a2a -Welcome_AccentColor=ff3f8ccc -Welcome_LinkColor=ff5fafef -Welcome_DisabledLinkColor=textDisabled - Timeline_TextColor=text Timeline_BackgroundColor1=normalBackground Timeline_BackgroundColor2=ff444444 diff --git a/share/qtcreator/themes/flat-dark.creatortheme b/share/qtcreator/themes/flat-dark.creatortheme index 7e94645b743..9737e9cd53e 100644 --- a/share/qtcreator/themes/flat-dark.creatortheme +++ b/share/qtcreator/themes/flat-dark.creatortheme @@ -1,4 +1,5 @@ [General] +Includes=dark.figmatokens ThemeName=Flat Dark PreferredStyles= DefaultTextEditorColorScheme=creator-dark.xml @@ -410,39 +411,6 @@ Debugger_WatchItem_ValueChanged=ffff6666 Debugger_Breakpoint_TextMarkColor=ffff4040 -; Qt Creator Color Tokens - dark mode -Token_Basic_Black=ff131313 -Token_Basic_White=fff8f8f8 -Token_Accent_Default=ff23b26a -Token_Accent_Muted=ff1f9b5d -Token_Accent_Subtle=ff1a8550 -Token_Background_Default=ff1f1f1f -Token_Background_Muted=ff262626 -Token_Background_Subtle=ff2e2e2e -Token_Foreground_Default=ff5a5a5a -Token_Foreground_Muted=ff3e3e3e -Token_Foreground_Subtle=ff303030 -Token_Text_Default=fff8f8f8 -Token_Text_Muted=ffaeaeae -Token_Text_Subtle=ff595959 -Token_Stroke_Strong=ffeeeeee -Token_Stroke_Muted=ff727272 -Token_Stroke_Subtle=ff3a3a3a -Token_Notification_Alert=ffc98014 -Token_Notification_Success=ff1f9b5d -Token_Notification_Neutral=ff016876 -Token_Notification_Danger=ffb22245 - -Welcome_TextColor=text -Welcome_ForegroundPrimaryColor=ff999999 -Welcome_ForegroundSecondaryColor=ff808080 -Welcome_BackgroundPrimaryColor=normalBackground -Welcome_BackgroundSecondaryColor=ff242628 -Welcome_HoverColor=ff404243 -Welcome_AccentColor=ff36c148 -Welcome_LinkColor=ff5fcf4f -Welcome_DisabledLinkColor=textDisabled - Timeline_TextColor=text Timeline_BackgroundColor1=normalBackground Timeline_BackgroundColor2=ff444444 diff --git a/share/qtcreator/themes/flat-light.creatortheme b/share/qtcreator/themes/flat-light.creatortheme index eddf38971d2..1ff8a7a3ff4 100644 --- a/share/qtcreator/themes/flat-light.creatortheme +++ b/share/qtcreator/themes/flat-light.creatortheme @@ -1,4 +1,5 @@ [General] +Includes=light.figmatokens ThemeName=Flat Light PreferredStyles= @@ -407,39 +408,6 @@ Debugger_WatchItem_ValueChanged=ffbf0303 Debugger_Breakpoint_TextMarkColor=ffff4040 -; Qt Creator Color Tokens - light mode -Token_Basic_Black=ff131313 -Token_Basic_White=fff2f2f2 -Token_Accent_Default=ff23b26a -Token_Accent_Muted=ff1f9b5d -Token_Accent_Subtle=ff1a8550 -Token_Background_Default=ffe3e3e3 -Token_Background_Muted=ffeeeeee -Token_Background_Subtle=fffbfbfb -Token_Foreground_Default=ffcdcdcd -Token_Foreground_Muted=ffd5d5d5 -Token_Foreground_Subtle=ffdddddd -Token_Text_Default=ff393939 -Token_Text_Muted=ff7c7c7c -Token_Text_Subtle=ffbebebe -Token_Stroke_Strong=ff464646 -Token_Stroke_Muted=ff727272 -Token_Stroke_Subtle=ffcdcdcd -Token_Notification_Alert=ffeb991f -Token_Notification_Success=ff23b26a -Token_Notification_Neutral=ff0e7887 -Token_Notification_Danger=ffdc1343 - -Welcome_TextColor=ff000000 -Welcome_ForegroundPrimaryColor=ff232323 -Welcome_ForegroundSecondaryColor=ff939393 -Welcome_BackgroundPrimaryColor=fffafafa -Welcome_BackgroundSecondaryColor=ffffffff -Welcome_HoverColor=ffefefef -Welcome_AccentColor=ff45ce55 -Welcome_LinkColor=ff20a020 -Welcome_DisabledLinkColor=textDisabled - Timeline_TextColor=text Timeline_BackgroundColor1=normalBackground Timeline_BackgroundColor2=fff6f6f6 diff --git a/share/qtcreator/themes/flat.creatortheme b/share/qtcreator/themes/flat.creatortheme index 08697334f40..f479077889e 100644 --- a/share/qtcreator/themes/flat.creatortheme +++ b/share/qtcreator/themes/flat.creatortheme @@ -1,4 +1,5 @@ [General] +Includes=light.figmatokens ThemeName=Flat PreferredStyles= @@ -405,39 +406,6 @@ Debugger_WatchItem_ValueChanged=ffbf0303 Debugger_Breakpoint_TextMarkColor=ffff4040 -; Qt Creator Color Tokens - light mode -Token_Basic_Black=ff131313 -Token_Basic_White=fff2f2f2 -Token_Accent_Default=ff23b26a -Token_Accent_Muted=ff1f9b5d -Token_Accent_Subtle=ff1a8550 -Token_Background_Default=ffe3e3e3 -Token_Background_Muted=ffeeeeee -Token_Background_Subtle=fffbfbfb -Token_Foreground_Default=ffcdcdcd -Token_Foreground_Muted=ffd5d5d5 -Token_Foreground_Subtle=ffdddddd -Token_Text_Default=ff393939 -Token_Text_Muted=ff7c7c7c -Token_Text_Subtle=ffbebebe -Token_Stroke_Strong=ff464646 -Token_Stroke_Muted=ff727272 -Token_Stroke_Subtle=ffcdcdcd -Token_Notification_Alert=ffeb991f -Token_Notification_Success=ff23b26a -Token_Notification_Neutral=ff0e7887 -Token_Notification_Danger=ffdc1343 - -Welcome_TextColor=ff000000 -Welcome_ForegroundPrimaryColor=shadowBackground -Welcome_ForegroundSecondaryColor=ff939393 -Welcome_BackgroundPrimaryColor=fffafafa -Welcome_BackgroundSecondaryColor=ffffffff -Welcome_HoverColor=ffefefef -Welcome_AccentColor=ff45ce55 -Welcome_LinkColor=ff20a020 -Welcome_DisabledLinkColor=textDisabled - Timeline_TextColor=text Timeline_BackgroundColor1=normalBackground Timeline_BackgroundColor2=fff6f6f6 diff --git a/share/qtcreator/themes/light.figmatokens b/share/qtcreator/themes/light.figmatokens new file mode 100644 index 00000000000..a4d1bfcaa8d --- /dev/null +++ b/share/qtcreator/themes/light.figmatokens @@ -0,0 +1,31 @@ +; Qt Creator Color Tokens - light mode + +[Colors] + +Token_Basic_Black=ff131313 +Token_Basic_White=fff2f2f2 + +Token_Accent_Default=ff23b26a +Token_Accent_Muted=ff1f9b5d +Token_Accent_Subtle=ff1a8550 + +Token_Background_Default=fffcfcfc +Token_Background_Muted=ffefefef +Token_Background_Subtle=ffe7e7e7 + +Token_Foreground_Default=ffcdcdcd +Token_Foreground_Muted=ffd5d5d5 +Token_Foreground_Subtle=ffdddddd + +Token_Text_Default=ff393939 +Token_Text_Muted=ff6a6a6a +Token_Text_Subtle=ffbebebe + +Token_Stroke_Strong=ff464646 +Token_Stroke_Muted=ff727272 +Token_Stroke_Subtle=ffcdcdcd + +Token_Notification_Alert=ffeb991f +Token_Notification_Success=ff23b26a +Token_Notification_Neutral=ff0e7887 +Token_Notification_Danger=ffdc1343 diff --git a/src/libs/utils/stylehelper.cpp b/src/libs/utils/stylehelper.cpp index ffb7efc417c..991b43df528 100644 --- a/src/libs/utils/stylehelper.cpp +++ b/src/libs/utils/stylehelper.cpp @@ -933,7 +933,17 @@ QColor StyleHelper::ensureReadableOn(const QColor &background, const QColor &des return foreground; } -static QStringList brandFontFamilies() +static const QStringList &applicationFontFamilies() +{ + const static QStringList families = [] { + constexpr QLatin1String familyName("Inter"); + // Font is either installed in the system, or was loaded from share/qtcreator/fonts/ + return QFontDatabase::hasFamily(familyName) ? QStringList(familyName) : QStringList(); + }(); + return families; +} + +static const QStringList &brandFontFamilies() { const static QStringList families = []{ const int id = QFontDatabase::addApplicationFont(":/studiofonts/TitilliumWeb-Regular.ttf"); @@ -959,10 +969,14 @@ static const UiFontMetrics& uiFontMetrics(StyleHelper::UiElement element) {StyleHelper::UiElementH5, {14, 16, QFont::DemiBold}}, {StyleHelper::UiElementH6, {12, 14, QFont::DemiBold}}, {StyleHelper::UiElementH6Capital, {12, 14, QFont::DemiBold}}, + {StyleHelper::UiElementBody1, {14, 20, QFont::Light}}, + {StyleHelper::UiElementBody2, {12, 20, QFont::Light}}, + {StyleHelper::UiElementButtonMedium, {12, 16, QFont::Bold}}, + {StyleHelper::UiElementButtonSmall, {10, 12, QFont::Bold}}, {StyleHelper::UiElementCaptionStrong, {10, 12, QFont::DemiBold}}, {StyleHelper::UiElementCaption, {10, 12, QFont::Normal}}, - {StyleHelper::UIElementIconStandard, {12, 16, QFont::Normal}}, - {StyleHelper::UIElementIconActive, {12, 16, QFont::DemiBold}}, + {StyleHelper::UiElementIconStandard, {12, 16, QFont::Medium}}, + {StyleHelper::UiElementIconActive, {12, 16, QFont::DemiBold}}, }; QTC_ASSERT(metrics.count(element) > 0, return metrics.at(StyleHelper::UiElementCaptionStrong)); return metrics.at(element); @@ -983,8 +997,10 @@ QFont StyleHelper::uiFont(UiElement element) case UiElementH3: case UiElementH6Capital: font.setCapitalization(QFont::AllUppercase); - break; + [[fallthrough]]; default: + if (!applicationFontFamilies().isEmpty()) + font.setFamilies(applicationFontFamilies()); break; } diff --git a/src/libs/utils/stylehelper.h b/src/libs/utils/stylehelper.h index 4b986c68313..7d434925e66 100644 --- a/src/libs/utils/stylehelper.h +++ b/src/libs/utils/stylehelper.h @@ -42,15 +42,15 @@ constexpr char C_TOOLBAR_ACTIONWIDGET[] = "toolbar_actionWidget"; constexpr char C_QT_SCALE_FACTOR_ROUNDING_POLICY[] = "QT_SCALE_FACTOR_ROUNDING_POLICY"; namespace SpacingTokens { - constexpr int VPaddingXXS = 4; // Top and bottom padding within the component - constexpr int HPaddingXXS = 4; // Left and right padding within the component - constexpr int VGapXXS = 4; // Vertical Space between TEXT LINE within the Component - constexpr int HGapXXS = 4; // Horizontal Space between elements within the Component + constexpr int VPaddingXxs = 4; // Top and bottom padding within the component + constexpr int HPaddingXxs = 4; // Left and right padding within the component + constexpr int VGapXxs = 4; // Vertical Space between TEXT LINE within the Component + constexpr int HGapXxs = 4; // Horizontal Space between elements within the Component - constexpr int VPaddingXS = 8; - constexpr int HPaddingXS = 8; - constexpr int VGapXS = 4; - constexpr int HGapXS = 8; + constexpr int VPaddingXs = 8; + constexpr int HPaddingXs = 8; + constexpr int VGapXs = 4; + constexpr int HGapXs = 8; constexpr int VPaddingS = 8; constexpr int HPaddingS = 16; @@ -62,10 +62,15 @@ namespace SpacingTokens { constexpr int VGapM = 4; constexpr int HGapM = 16; - constexpr int VPaddingL = 12; + constexpr int VPaddingL = 16; constexpr int HPaddingL = 24; constexpr int VGapL = 8; constexpr int HGapL = 16; + + constexpr int ExPaddingGapS = 2; + constexpr int ExPaddingGapM = 6; + constexpr int ExPaddingGapL = 12; + constexpr int ExVPaddingGapXl = 24; } enum ToolbarStyle { @@ -82,10 +87,14 @@ enum UiElement { UiElementH5, UiElementH6, UiElementH6Capital, + UiElementBody1, + UiElementBody2, + UiElementButtonMedium, + UiElementButtonSmall, UiElementCaptionStrong, UiElementCaption, - UIElementIconStandard, - UIElementIconActive, + UiElementIconStandard, + UiElementIconActive, }; // Height of the project explorer navigation bar diff --git a/src/libs/utils/theme/theme.h b/src/libs/utils/theme/theme.h index 2e4d61d943b..65d0ee91eaf 100644 --- a/src/libs/utils/theme/theme.h +++ b/src/libs/utils/theme/theme.h @@ -247,18 +247,6 @@ public: Token_Notification_Neutral, Token_Notification_Danger, - /* Welcome Plugin */ - - Welcome_TextColor, - Welcome_ForegroundPrimaryColor, - Welcome_ForegroundSecondaryColor, - Welcome_BackgroundPrimaryColor, - Welcome_BackgroundSecondaryColor, - Welcome_HoverColor, - Welcome_AccentColor, - Welcome_LinkColor, - Welcome_DisabledLinkColor, - /* Timeline Library */ Timeline_TextColor, Timeline_BackgroundColor1, diff --git a/src/plugins/coreplugin/core.qrc b/src/plugins/coreplugin/core.qrc index ff855e3f4b8..239bd946121 100644 --- a/src/plugins/coreplugin/core.qrc +++ b/src/plugins/coreplugin/core.qrc @@ -1,5 +1,9 @@ + images/expandarrow.png + images/expandarrow@2x.png + images/search.png + images/search@2x.png images/settingscategory_core.png images/settingscategory_core@2x.png images/settingscategory_design.png diff --git a/src/plugins/coreplugin/images/expandarrow.png b/src/plugins/coreplugin/images/expandarrow.png new file mode 100644 index 0000000000000000000000000000000000000000..c463d0236d17b03893fb92d06cc9fc0acbe33b08 GIT binary patch literal 169 zcmeAS@N?(olHy`uVBq!ia0y~yU=RRd7G?$phPQVgfdo_nd_r8s#KgqK#U&&pq@<*R zgM+VJxpMvb^&2;C+`M`7<;$0^UcLJN|9?rr!*5!0~3bQg8t(#I469)(ed5RMWOdMXT-C^q>OIG709&FDH_Xt>^sA z+Eu+uT3GmxHpi{$H(ivXbJ(LDBg!ILf;r6(9%ofLckf@*cb*5PZI@pzc*i(%BJZK% zfc{_KHL^4{&gcZNecg5Lc5uK{g@Om3)9$gD3oPJW9@V75FU#0J*B*!%VGX~sKJ zoN259XI-bgaCH22n<;Gyo?BlH)QWk*PoXECQjxp^ZDOq-oFhGoY{T1@=xAB2Cd7w?BzDI QB|%~6>FVdQ&MBb@0NoOr5dZ)H literal 0 HcmV?d00001 diff --git a/src/plugins/coreplugin/iwelcomepage.cpp b/src/plugins/coreplugin/iwelcomepage.cpp index 3eb63d80312..beef33f40d6 100644 --- a/src/plugins/coreplugin/iwelcomepage.cpp +++ b/src/plugins/coreplugin/iwelcomepage.cpp @@ -3,25 +3,8 @@ #include "iwelcomepage.h" -#include -#include -#include - -#include -#include -#include -#include -#include -#include - -#include - -using namespace Utils; - namespace Core { -const char WITHACCENTCOLOR_PROPERTY_NAME[] = "_withAccentColor"; - static QList g_welcomePages; const QList IWelcomePage::allWelcomePages() @@ -39,171 +22,4 @@ IWelcomePage::~IWelcomePage() g_welcomePages.removeOne(this); } -QPalette WelcomePageFrame::buttonPalette(bool isActive, bool isCursorInside, bool forText) -{ - QPalette pal; - pal.setBrush(QPalette::Window, {}); - pal.setBrush(QPalette::WindowText, {}); - - Theme *theme = Utils::creatorTheme(); - if (isActive) { - if (forText) { - pal.setColor(QPalette::Window, theme->color(Theme::Welcome_ForegroundPrimaryColor)); - pal.setColor(QPalette::WindowText, theme->color(Theme::Welcome_BackgroundPrimaryColor)); - } else { - pal.setColor(QPalette::Window, theme->color(Theme::Welcome_AccentColor)); - pal.setColor(QPalette::WindowText, theme->color(Theme::Welcome_AccentColor)); - } - } else { - if (isCursorInside) { - if (forText) { - pal.setColor(QPalette::Window, theme->color(Theme::Welcome_HoverColor)); - pal.setColor(QPalette::WindowText, theme->color(Theme::Welcome_TextColor)); - } else { - pal.setColor(QPalette::Window, theme->color(Theme::Welcome_HoverColor)); - pal.setColor(QPalette::WindowText, theme->color(Theme::Welcome_ForegroundSecondaryColor)); - } - } else { - if (forText) { - pal.setColor(QPalette::Window, theme->color(Theme::Welcome_ForegroundPrimaryColor)); - pal.setColor(QPalette::WindowText, theme->color(Theme::Welcome_TextColor)); - } else { - pal.setColor(QPalette::Window, theme->color(Theme::Welcome_BackgroundPrimaryColor)); - pal.setColor(QPalette::WindowText, theme->color(Theme::Welcome_ForegroundSecondaryColor)); - } - } - } - return pal; -} - -WelcomePageFrame::WelcomePageFrame(QWidget *parent) - : QWidget(parent) -{ - setContentsMargins(1, 1, 1, 1); -} - -void WelcomePageFrame::paintEvent(QPaintEvent *event) -{ - QWidget::paintEvent(event); - QPainter p(this); - - qDrawPlainRect(&p, rect(), palette().color(QPalette::WindowText), 1); - - if (property(WITHACCENTCOLOR_PROPERTY_NAME).toBool()) { - const int accentRectWidth = 10; - const QRect accentRect = rect().adjusted(width() - accentRectWidth, 0, 0, 0); - p.fillRect(accentRect, creatorTheme()->color(Theme::Welcome_AccentColor)); - } -} - -class WelcomePageButtonPrivate -{ -public: - explicit WelcomePageButtonPrivate(WelcomePageButton *parent) - : q(parent) {} - bool isActive() const; - void doUpdate(bool cursorInside); - - WelcomePageButton *q; - QHBoxLayout *m_layout = nullptr; - QLabel *m_label = nullptr; - - std::function onClicked; - std::function activeChecker; -}; - -WelcomePageButton::WelcomePageButton(QWidget *parent) - : WelcomePageFrame(parent), d(new WelcomePageButtonPrivate(this)) -{ - setAutoFillBackground(true); - setPalette(buttonPalette(false, false, false)); - setContentsMargins(0, 1, 0, 1); - - d->m_label = new QLabel(this); - d->m_label->setPalette(buttonPalette(false, false, true)); - d->m_label->setAlignment(Qt::AlignCenter); - - d->m_layout = new QHBoxLayout; - d->m_layout->setSpacing(0); - d->m_layout->addWidget(d->m_label); - setSize(SizeLarge); - setLayout(d->m_layout); -} - -WelcomePageButton::~WelcomePageButton() -{ - delete d; -} - -void WelcomePageButton::mousePressEvent(QMouseEvent *) -{ - if (d->onClicked) - d->onClicked(); -} - -void WelcomePageButton::enterEvent(QEnterEvent *) -{ - d->doUpdate(true); -} - -void WelcomePageButton::leaveEvent(QEvent *) -{ - d->doUpdate(false); -} - -bool WelcomePageButtonPrivate::isActive() const -{ - return activeChecker && activeChecker(); -} - -void WelcomePageButtonPrivate::doUpdate(bool cursorInside) -{ - const bool active = isActive(); - q->setPalette(WelcomePageFrame::buttonPalette(active, cursorInside, false)); - const QPalette lpal = WelcomePageFrame::buttonPalette(active, cursorInside, true); - m_label->setPalette(lpal); - q->update(); -} - -void WelcomePageButton::setText(const QString &text) -{ - d->m_label->setText(text); -} - -void WelcomePageButton::setSize(Size size) -{ - const int hMargin = size == SizeSmall ? 12 : 26; - const int vMargin = size == SizeSmall ? 2 : 4; - d->m_layout->setContentsMargins(hMargin, vMargin, hMargin, vMargin); -} - -void WelcomePageButton::setWithAccentColor(bool withAccent) -{ - setProperty(WITHACCENTCOLOR_PROPERTY_NAME, withAccent); -} - -void WelcomePageButton::setActiveChecker(const std::function &value) -{ - d->activeChecker = value; -} - -void WelcomePageButton::recheckActive() -{ - bool isActive = d->isActive(); - d->doUpdate(isActive); -} - -void WelcomePageButton::click() -{ - if (d->onClicked) - d->onClicked(); -} - -void WelcomePageButton::setOnClicked(const std::function &value) -{ - d->onClicked = value; - if (d->isActive()) - click(); -} - } // namespace Core diff --git a/src/plugins/coreplugin/iwelcomepage.h b/src/plugins/coreplugin/iwelcomepage.h index 9a64dd3a701..1f59a791195 100644 --- a/src/plugins/coreplugin/iwelcomepage.h +++ b/src/plugins/coreplugin/iwelcomepage.h @@ -7,13 +7,10 @@ #include -#include #include -#include - QT_BEGIN_NAMESPACE -class QPixmap; +class QWidget; QT_END_NAMESPACE namespace Core { @@ -37,43 +34,4 @@ public: static const QList allWelcomePages(); }; -class WelcomePageButtonPrivate; - -class CORE_EXPORT WelcomePageFrame : public QWidget -{ -public: - WelcomePageFrame(QWidget *parent); - - void paintEvent(QPaintEvent *event) override; - - static QPalette buttonPalette(bool isActive, bool isCursorInside, bool forText); -}; - -class CORE_EXPORT WelcomePageButton : public WelcomePageFrame -{ -public: - enum Size { - SizeSmall, - SizeLarge, - }; - - explicit WelcomePageButton(QWidget *parent = nullptr); - ~WelcomePageButton() override; - - void mousePressEvent(QMouseEvent *) override; - void enterEvent(QEnterEvent *) override; - void leaveEvent(QEvent *) override; - - void setText(const QString &text); - void setSize(enum Size); - void setWithAccentColor(bool withAccent); - void setOnClicked(const std::function &value); - void setActiveChecker(const std::function &value); - void recheckActive(); - void click(); - -private: - WelcomePageButtonPrivate *d; -}; - } // Core diff --git a/src/plugins/coreplugin/session.cpp b/src/plugins/coreplugin/session.cpp index c188f6812c3..921046ffed4 100644 --- a/src/plugins/coreplugin/session.cpp +++ b/src/plugins/coreplugin/session.cpp @@ -267,6 +267,11 @@ QDateTime SessionManager::lastActiveTime(const QString &session) return d->m_lastActiveTimes.value(session); } +int SessionManager::sessionsCount() +{ + return d->m_sessions.count(); +} + FilePath SessionManager::sessionNameToFileName(const QString &session) { return ICore::userResourcePath(session + ".qws"); diff --git a/src/plugins/coreplugin/session.h b/src/plugins/coreplugin/session.h index 962db5172b5..ef51228b018 100644 --- a/src/plugins/coreplugin/session.h +++ b/src/plugins/coreplugin/session.h @@ -34,6 +34,7 @@ public: static QStringList sessions(); static QDateTime sessionDateTime(const QString &session); static QDateTime lastActiveTime(const QString &session); + static int sessionsCount(); static bool createSession(const QString &session); diff --git a/src/plugins/coreplugin/welcomepagehelper.cpp b/src/plugins/coreplugin/welcomepagehelper.cpp index 44fc75270dd..636888d6b47 100644 --- a/src/plugins/coreplugin/welcomepagehelper.cpp +++ b/src/plugins/coreplugin/welcomepagehelper.cpp @@ -7,6 +7,7 @@ #include #include +#include #include #include #include @@ -26,36 +27,34 @@ #include + +QT_BEGIN_NAMESPACE +void qt_blurImage(QImage &blurImage, qreal radius, bool quality, int transposed = 0); +QT_END_NAMESPACE + using namespace Utils; namespace Core { using namespace WelcomePageHelpers; +using namespace StyleHelper::SpacingTokens; static QColor themeColor(Theme::Color role) { return creatorTheme()->color(role); } -static QFont sizedFont(int size, const QWidget *widget) -{ - QFont f = widget->font(); - f.setPixelSize(size); - return f; -} - namespace WelcomePageHelpers { -QWidget *panelBar(QWidget *parent) +void setBackgroundColor(QWidget *widget, Theme::Color colorRole) { - auto frame = new QWidget(parent); - frame->setAutoFillBackground(true); - frame->setMinimumWidth(WelcomePageHelpers::HSpacing); - QPalette pal; - pal.setBrush(QPalette::Window, {}); - pal.setColor(QPalette::Window, themeColor(Theme::Welcome_BackgroundPrimaryColor)); - frame->setPalette(pal); - return frame; + QPalette palette = creatorTheme()->palette(); + const QPalette::ColorRole role = QPalette::Window; + palette.setBrush(role, {}); + palette.setColor(role, creatorTheme()->color(colorRole)); + widget->setPalette(palette); + widget->setBackgroundRole(role); + widget->setAutoFillBackground(true); } void drawCardBackground(QPainter *painter, const QRectF &rect, @@ -77,30 +76,351 @@ void drawCardBackground(QPainter *painter, const QRectF &rect, painter->restore(); } +QWidget *createRule(Qt::Orientation orientation, QWidget *parent) +{ + auto rule = new QWidget(parent); + if (orientation == Qt::Horizontal) + rule->setFixedHeight(1); + else + rule->setFixedWidth(1); + setBackgroundColor(rule, Theme::Token_Stroke_Subtle); + return rule; +} + } // namespace WelcomePageHelpers -SearchBox::SearchBox(QWidget *parent) - : WelcomePageFrame(parent) +enum WidgetState { + WidgetStateDefault, + WidgetStateChecked, + WidgetStateHovered, +}; + +static const TextFormat &buttonTF(Button::Role role, WidgetState state) { - setAutoFillBackground(true); + using namespace WelcomePageHelpers; + static const TextFormat mediumPrimaryTF + {Theme::Token_Basic_White, StyleHelper::UiElement::UiElementButtonMedium, + Qt::AlignCenter | Qt::TextDontClip}; + static const TextFormat mediumSecondaryTF + {Theme::Token_Text_Default, mediumPrimaryTF.uiElement, mediumPrimaryTF.drawTextFlags}; + static const TextFormat smallPrimaryTF + {mediumPrimaryTF.themeColor, StyleHelper::UiElement::UiElementButtonSmall, + mediumPrimaryTF.drawTextFlags}; + static const TextFormat smallSecondaryTF + {mediumSecondaryTF.themeColor, smallPrimaryTF.uiElement, smallPrimaryTF.drawTextFlags}; + static const TextFormat smallListDefaultTF + {Theme::Token_Text_Default, StyleHelper::UiElement::UiElementIconStandard, + Qt::AlignLeft | Qt::AlignVCenter | Qt::TextDontClip}; + static const TextFormat smallListCheckedTF + {smallListDefaultTF.themeColor, StyleHelper::UiElement::UiElementIconActive, + smallListDefaultTF.drawTextFlags}; + static const TextFormat smallLinkDefaultTF + {Theme::Token_Text_Default, smallListDefaultTF.uiElement, smallListDefaultTF.drawTextFlags}; + static const TextFormat smallLinkHoveredTF + {Theme::Token_Accent_Default, smallListCheckedTF.uiElement, + smallLinkDefaultTF.drawTextFlags}; - m_lineEdit = new FancyLineEdit; - m_lineEdit->setFiltering(true); - m_lineEdit->setFrame(false); - m_lineEdit->setMinimumHeight(33); - m_lineEdit->setAttribute(Qt::WA_MacShowFocusRect, false); + switch (role) { + case Button::MediumPrimary: return mediumPrimaryTF; + case Button::MediumSecondary: return mediumSecondaryTF; + case Button::SmallPrimary: return smallPrimaryTF; + case Button::SmallSecondary: return smallSecondaryTF; + case Button::SmallList: return (state == WidgetStateDefault) ? smallListDefaultTF + : smallListCheckedTF; + case Button::SmallLink: return (state == WidgetStateDefault) ? smallLinkDefaultTF + : smallLinkHoveredTF; + } + return mediumPrimaryTF; +} - QPalette pal = buttonPalette(false, false, true); - // for the margins - pal.setColor(QPalette::Window, m_lineEdit->palette().color(QPalette::Base)); - // for macOS dark mode - pal.setColor(QPalette::WindowText, themeColor(Theme::Welcome_ForegroundPrimaryColor)); - pal.setColor(QPalette::Text, themeColor(Theme::Welcome_TextColor)); +Button::Button(const QString &text, Role role, QWidget *parent) + : QPushButton(text, parent) + , m_role(role) +{ + // Prevent QMacStyle::subElementRect(SE_PushButtonLayoutItem) from changing our geometry + setFlat(true); + + updateMargins(); + if (m_role == SmallList) + setCheckable(true); + else if (m_role == SmallLink) + setCursor(Qt::PointingHandCursor); +} + +QSize Button::minimumSizeHint() const +{ + const TextFormat &tf = buttonTF(m_role, WidgetStateHovered); + const QFontMetrics fm(tf.font()); + const QSize textS = fm.size(Qt::TextShowMnemonic, text()); + const QMargins margins = contentsMargins(); + return {margins.left() + textS.width() + margins.right(), + margins.top() + tf.lineHeight() + margins.bottom()}; +} + +void Button::paintEvent(QPaintEvent *event) +{ + // Without pixmap + // +----------------+----------------+----------------+ + // | |(VPadding[S|XS])| | + // | +----------------+----------------+ + // |(HPadding[S|XS])|