diff --git a/dist/changelog/changes-11.0.0.md b/dist/changelog/changes-11.0.0.md
new file mode 100644
index 00000000000..5600390c091
--- /dev/null
+++ b/dist/changelog/changes-11.0.0.md
@@ -0,0 +1,223 @@
+Qt Creator 11
+=============
+
+Qt Creator version 11 contains bug fixes and new features.
+
+The most important changes are listed in this document. For a complete list of
+changes, see the Git log for the Qt Creator sources that you can check out from
+the public Git repository. For example:
+
+ git clone git://code.qt.io/qt-creator/qt-creator.git
+ git log --cherry-pick --pretty=oneline origin/10.0..v11.0.0
+
+General
+-------
+
+* Added a `Terminal` view (QTCREATORBUG-8511)
+ * Opt-out via `Preferences` > `Terminal` preferences
+ * Added support for
+ * different shells, colors, fonts, and multiple tabs
+ * opening file paths in Qt Creator with `Ctrl+click` (`Cmd+click` on
+ macOS)
+* Added a more spacious "relaxed" toolbar style `Environment > Interface`
+* Added a pin button to progress details instead of automatically resetting
+ their position (QTCREATORBUG-28829)
+* Improved the selection and navigation in the `Issues` view
+ (QTCREATORBUG-26128, QTCREATORBUG-27006, QTCREATORBUG-27506)
+* Locator
+ * Improved performance
+ * Added the creation of directories to the `Files in File System` filter
+ * Added device roots and browsing remote file systems to the
+ `Files in File System` filter
+
+Editing
+-------
+
+* Improved the performance of the multi-cursor support
+* Fixed the saving of hardlinked files (QTCREATORBUG-19651)
+* Fixed an issue of copy and paste with multiple cursors (QTCREATORBUG-29117)
+
+### C++
+
+* Improved the style of forward declarations in the outline (QTCREATORBUG-312)
+* Added highlighting for typed string literals and user-defined literals
+ (QTCREATORBUG-28869)
+* Added the option to create class members from assignments (QTCREATORBUG-1918)
+* Fixed that locator showed both the declaration and the definition of symbols
+ (QTCREATORBUG-13894)
+* Fixed the handling of C++20 keywords and concepts
+* Built-in
+ * Fixed support for `if`-statements with initializer (QTCREATORBUG-29182)
+
+### Language Server Protocol
+
+* Added experimental support for GitHub Copilot
+ ([GitHub documentation](https://github.com/features/copilot))
+* Added missing actions for opening the `Call Hierarchy` (QTCREATORBUG-28839,
+ QTCREATORBUG-28842)
+
+### QML
+
+* Fixed the reformatting in the presence of JavaScript directives and function
+ return type annotations (QTCREATORBUG-29001, QTCREATORBUG-29046)
+* Fixed that reformatting changed `of` to `in` (QTCREATORBUG-29123)
+* Fixed the completion for Qt Quick Controls (QTCREATORBUG-28648)
+
+### Python
+
+* Added the option to create a virtual environment (`venv`) to the Python
+ interpreter selector and the wizard (PYSIDE-2152)
+
+### Markdown
+
+* Added a Markdown editor with preview (QTCREATORBUG-27883)
+* Added a wizard for Markdown files (QTCREATORBUG-29056)
+
+Projects
+--------
+
+* Made it possible to add devices without going through the wizard
+* Added support for moving files to a different directory when renaming
+ (QTCREATORBUG-15981)
+
+### CMake
+
+* Implemented adding files to the project (QTCREATORBUG-25922,
+ QTCREATORBUG-26006, QTCREATORBUG-27213, QTCREATORBUG-27538,
+ QTCREATORBUG-28493, QTCREATORBUG-28904, QTCREATORBUG-28985,
+ QTCREATORBUG-29006)
+* Fixed issues with detecting a configured Qt version when importing a build
+ (QTCREATORBUG-29075)
+
+### Python
+
+* Added an option for the interpreter to the wizards
+
+### vcpkg
+
+* Added experimental support for `vcpkg`
+ ([vcpgk documentation](https://vcpkg.io/en/))
+* Added an option for the `vcpkg` installation location
+* Added a search dialog for packages
+* Added a wizard and an editor for `vcpkg.json` files
+
+Debugging
+---------
+
+* Improved the UI for enabling and disabling debuggers (QTCREATORBUG-28627)
+
+### C++
+
+* Added an option for the default number of array elements to show
+ (`Preferences > Debugger > Locals & Expressions > Default array size`)
+* CDB
+ * Added automatic source file mapping for Qt packages
+ * Fixed the variables view on remote Windows devices (QTCREATORBUG-29000)
+* LLDB
+ * Fixed that long lines in the application output were broken into multiple
+ lines (QTCREATORBUG-29098)
+
+### Qt Quick
+
+* Improved the auto-detection if QML debugging is required (QTCREATORBUG-28627)
+* Added an option for disabling static analyzer messages to
+ `Qt Quick > QML/JS Editing` (QTCREATORBUG-29095)
+
+Analyzer
+--------
+
+### Clang
+
+* Fixed that a `.clang-tidy` file in the project directory was not used by
+ default (QTCREATORBUG-28852)
+
+### Axivion
+
+* Added experimental support
+
+Version Control Systems
+-----------------------
+
+### Git
+
+* Instant Blame
+ * Improved the performance (QTCREATORBUG-29151)
+ * Fixed that it did not show at the end of the document
+
+Platforms
+---------
+
+### Android
+
+* Fixed an issue with building library targets (QTCREATORBUG-26980)
+
+### Remote Linux
+
+* Removed the automatic sourcing of target-side shell profiles
+
+### Docker
+
+* Added support for `qmake` based projects (QTCREATORBUG-29140)
+* Fixed issues after deleting the Docker image for a registered Docker device
+ (QTCREATORBUG-28880)
+
+### QNX
+
+* Added `slog2info` as a requirement for devices
+* Fixed the support for remote working directories (QTCREATORBUG-28900)
+
+Credits for these changes go to:
+--------------------------------
+Aleksei German
+Alessandro Portale
+Alexander Drozdov
+Alexander Pershin
+Ali Kianian
+Alibek Omarov
+Amr Essam
+Andre Hartmann
+André Pönitz
+Artem Mukhin
+Artem Sokolovskii
+Assam Boudjelthia
+Björn Schäpers
+Brook Cronin
+Burak Hancerli
+Christian Kandeler
+Christian Stenger
+Cristian Adam
+David Schulz
+Eike Ziller
+Esa Törmänen
+Fabian Kosmale
+Filippo Gentile
+Friedemann Kleint
+Henning Gruendl
+Jaroslaw Kobus
+Jussi Witick
+Kai Köhne
+Knud Dollereder
+Knut Petter Svendsen
+Leena Miettinen
+Mahmoud Badri
+Marco Bubke
+Marcus Tillmanns
+Martin Delille
+Mats Honkamaa
+Miikka Heikkinen
+Mitch Curtis
+Niels Weber
+Orgad Shaneh
+Pranta Dastider
+Robert Löhning
+Samuel Ghinet
+Semih Yavuz
+Tasuku Suzuki
+Thiago Macieira
+Thomas Hartmann
+Tim Jenssen
+Tim Jenßen
+Ulf Hermann
+Vikas Pachdha
+Yasser Grimes
+Yixue Wang
diff --git a/doc/qtcreator/src/editors/creator-quick-fixes.qdoc b/doc/qtcreator/src/editors/creator-quick-fixes.qdoc
index 57bb973bb28..0f6e7fd58af 100644
--- a/doc/qtcreator/src/editors/creator-quick-fixes.qdoc
+++ b/doc/qtcreator/src/editors/creator-quick-fixes.qdoc
@@ -482,8 +482,9 @@
\row
\li Add Class Member
\li Adds a member declaration for the class member being
- initialized if it is not yet declared. You must enter
- the data type of the member.
+ initialized if it is not yet declared. If \QC cannot
+ automatically detect the data type of the member, you
+ must add it.
\li Identifier
\row
\li Create Implementations for Member Functions
diff --git a/doc/qtcreator/src/projects/creator-only/creator-projects-opening.qdoc b/doc/qtcreator/src/projects/creator-only/creator-projects-opening.qdoc
index d06989e66fc..85d04903921 100644
--- a/doc/qtcreator/src/projects/creator-only/creator-projects-opening.qdoc
+++ b/doc/qtcreator/src/projects/creator-only/creator-projects-opening.qdoc
@@ -99,4 +99,7 @@
\image qtcreator-toggle-progress-bar.webp {Toggle Progress Details button}
+ You can drag the progress bar to another position. The position is saved for
+ later. Select the \inlineimage icons/pin.png
+ (\uicontrol Pin) button to pin the progress bar back to the toggle button.
*/
diff --git a/share/qtcreator/translations/qtcreator_de.ts b/share/qtcreator/translations/qtcreator_de.ts
index 4b2e4bc008f..f4886dc760d 100644
--- a/share/qtcreator/translations/qtcreator_de.ts
+++ b/share/qtcreator/translations/qtcreator_de.ts
@@ -18199,16 +18199,16 @@ Möchten Sie sie jetzt auschecken?
Bytes
- KB
- KB
+ KiB
+ KiB
- GB
- GB
+ GiB
+ GiB
- TB
- TB
+ TiB
+ TiB
Enable crash reporting
@@ -27194,12 +27194,8 @@ zu deaktivieren, deaktiviert auch die folgenden Plugins:
Privat
- Create a private check-in that is never synced.
-Children of private check-ins are automatically private.
-Private check-ins are not pushed to the remote repository by default.
- Erstelle einen privaten Check-In, der niemals synchronisiert wird.
-Kinder von privaten Check-Ins sind automatisch privat.
-Private Check-Ins werden standardmäßig nicht zum entfernten Repository gepusht.
+ Create a private check-in that is never synced. Children of private check-ins are automatically private. Private check-ins are not pushed to the remote repository by default.
+ Erstelle einen privaten Check-In, der niemals synchronisiert wird. Kinder von privaten Check-Ins sind automatisch privat. Private Check-Ins werden standardmäßig nicht zum entfernten Repository gepusht.
Tag names to apply; comma-separated.
@@ -39112,7 +39108,7 @@ Sie werden erhalten.
&Configure Project
- Projekt &Konfigurieren
+ Projekt &konfigurieren
Enable Kit for Project "%1"
@@ -53204,12 +53200,9 @@ Wird ein Problem gefunden, dann wird die Anwendung angehalten und kann untersuch
Hint: The second line of a commit message should be empty.
Hinweis: Die zweite Zeile der Beschreibung sollte leer sein.
-
- <p>Writing good commit messages</p><ul><li>Avoid very short commit messages.</li><li>Consider the first line as subject (like in email) and keep it shorter than %n characters.</li><li>After an empty second line, a longer description can be added.</li><li>Describe why the change was done, not how it was done.</li></ul>
-
- <p>Gute Beschreibungen für Commits schreiben</p><ul><li>Vermeiden Sie sehr kurze Beschreibungen.</li><li>Betrachten Sie die erste Zeile als Betreff (wie in einer E-Mail) und halten Sie sie kürzer als ein Zeichen.</li><li>Eine längere Beschreibung kann nach einer leeren zweiten Zeile folgen.</li><li>Beschreiben Sie, weshalb die Änderung vorgenommen wurde, nicht wie sie vorgenommen wurde.</li></ul>
- <p>Gute Beschreibungen für Commits schreiben</p><ul><li>Vermeiden Sie sehr kurze Beschreibungen.</li><li>Betrachten Sie die erste Zeile als Betreff (wie in einer E-Mail) und halten Sie sie kürzer als %n Zeichen.</li><li>Eine längere Beschreibung kann nach einer leeren zweiten Zeile folgen.</li><li>Beschreiben Sie, weshalb die Änderung vorgenommen wurde, nicht wie sie vorgenommen wurde.</li></ul>
-
+
+ <p>Writing good commit messages</p><ul><li>Avoid very short commit messages.</li><li>Consider the first line as a subject (like in emails) and keep it shorter than 72 characters.</li><li>After an empty second line, a longer description can be added.</li><li>Describe why the change was done, not how it was done.</li></ul>
+ <p>Gute Beschreibungen für Commits schreiben</p><ul><li>Vermeiden Sie sehr kurze Beschreibungen.</li><li>Betrachten Sie die erste Zeile als Betreff (wie in einer E-Mail) und halten Sie sie kürzer als 72 Zeichen.</li><li>Eine längere Beschreibung kann nach einer leeren zweiten Zeile folgen.</li><li>Beschreiben Sie, weshalb die Änderung vorgenommen wurde, nicht wie sie vorgenommen wurde.</li></ul>
Update in progress
diff --git a/src/libs/qmljs/qmljsdocument.cpp b/src/libs/qmljs/qmljsdocument.cpp
index 16b17b0faee..4b79bdafccc 100644
--- a/src/libs/qmljs/qmljsdocument.cpp
+++ b/src/libs/qmljs/qmljsdocument.cpp
@@ -369,61 +369,62 @@ LibraryInfo::LibraryInfo(const QmlDirParser &parser, const QByteArray &fingerpri
QByteArray LibraryInfo::calculateFingerprint() const
{
QCryptographicHash hash(QCryptographicHash::Sha1);
- hash.addData(reinterpret_cast(&_status), sizeof(_status));
+ auto addData = [&hash](auto p, size_t len) {
+ hash.addData(QByteArrayView(reinterpret_cast(p), len));
+ };
+
+ addData(&_status, sizeof(_status));
int len = _components.size();
- hash.addData(reinterpret_cast(&len), sizeof(len));
+ addData(&len, sizeof(len));
for (const QmlDirParser::Component &component : _components) {
len = component.fileName.size();
- hash.addData(reinterpret_cast(&len), sizeof(len));
- hash.addData(reinterpret_cast(component.fileName.constData()),
- len * sizeofQChar);
- hash.addData(reinterpret_cast(&component.majorVersion), sizeof(component.majorVersion));
- hash.addData(reinterpret_cast(&component.minorVersion), sizeof(component.minorVersion));
+ addData(&len, sizeof(len));
+ addData(component.fileName.constData(), len * sizeofQChar);
+ addData(&component.majorVersion, sizeof(component.majorVersion));
+ addData(&component.minorVersion, sizeof(component.minorVersion));
len = component.typeName.size();
- hash.addData(reinterpret_cast(&len), sizeof(len));
- hash.addData(reinterpret_cast(component.typeName.constData()),
- component.typeName.size() * sizeofQChar);
+ addData(&len, sizeof(len));
+ addData(component.typeName.constData(), component.typeName.size() * sizeofQChar);
int flags = (component.singleton ? (1 << 0) : 0) + (component.internal ? (1 << 1) : 0);
- hash.addData(reinterpret_cast(&flags), sizeof(flags));
+ addData(&flags, sizeof(flags));
}
len = _plugins.size();
- hash.addData(reinterpret_cast(&len), sizeof(len));
+ addData(&len, sizeof(len));
for (const QmlDirParser::Plugin &plugin : _plugins) {
len = plugin.path.size();
- hash.addData(reinterpret_cast(&len), sizeof(len));
- hash.addData(reinterpret_cast(plugin.path.constData()), len * sizeofQChar);
+ addData(&len, sizeof(len));
+ addData(plugin.path.constData(), len * sizeofQChar);
len = plugin.name.size();
- hash.addData(reinterpret_cast(&len), sizeof(len));
- hash.addData(reinterpret_cast(plugin.name.constData()), len * sizeofQChar);
+ addData(&len, sizeof(len));
+ addData(plugin.name.constData(), len * sizeofQChar);
}
len = _typeinfos.size();
- hash.addData(reinterpret_cast(&len), sizeof(len));
+ addData(&len, sizeof(len));
for (const QString &typeinfo : _typeinfos) {
len = typeinfo.size();
- hash.addData(reinterpret_cast(&len), sizeof(len));
- hash.addData(reinterpret_cast(typeinfo.constData()),
- len * sizeofQChar);
+ addData(&len, sizeof(len));
+ addData(typeinfo.constData(), len * sizeofQChar);
}
len = _metaObjects.size();
- hash.addData(reinterpret_cast(&len), sizeof(len));
+ addData(&len, sizeof(len));
QList metaFingerprints;
for (const LanguageUtils::FakeMetaObject::ConstPtr &metaObject : _metaObjects)
metaFingerprints.append(metaObject->fingerprint());
std::sort(metaFingerprints.begin(), metaFingerprints.end());
for (const QByteArray &fp : std::as_const(metaFingerprints))
hash.addData(fp);
- hash.addData(reinterpret_cast(&_dumpStatus), sizeof(_dumpStatus));
+ addData(&_dumpStatus, sizeof(_dumpStatus));
len = _dumpError.size(); // localization dependent (avoid?)
- hash.addData(reinterpret_cast(&len), sizeof(len));
- hash.addData(reinterpret_cast(_dumpError.constData()), len * sizeofQChar);
+ addData(&len, sizeof(len));
+ addData(_dumpError.constData(), len * sizeofQChar);
len = _moduleApis.size();
- hash.addData(reinterpret_cast(&len), sizeof(len));
+ addData(&len, sizeof(len));
for (const ModuleApiInfo &moduleInfo : _moduleApis)
moduleInfo.addToHash(hash); // make it order independent?
len = _imports.size();
- hash.addData(reinterpret_cast(&len), sizeof(len));
+ addData(&len, sizeof(len));
for (const QmlDirParser::Import &import : _imports)
hash.addData(import.module.toUtf8()); // import order matters, keep order-dependent
diff --git a/src/libs/solutions/tasking/CMakeLists.txt b/src/libs/solutions/tasking/CMakeLists.txt
index 5beed2fe5b4..f70c910e042 100644
--- a/src/libs/solutions/tasking/CMakeLists.txt
+++ b/src/libs/solutions/tasking/CMakeLists.txt
@@ -1,9 +1,11 @@
add_qtc_library(Tasking OBJECT
# Never add dependencies to non-Qt libraries for this library
- DEPENDS Qt::Core
+ DEPENDS Qt::Concurrent Qt::Core Qt::Network
PUBLIC_DEFINES TASKING_LIBRARY
SOURCES
barrier.cpp barrier.h
+ concurrentcall.h
+ networkquery.cpp networkquery.h
tasking_global.h
tasktree.cpp tasktree.h
)
diff --git a/src/libs/solutions/tasking/barrier.h b/src/libs/solutions/tasking/barrier.h
index 6939da5b365..6f1afe39b09 100644
--- a/src/libs/solutions/tasking/barrier.h
+++ b/src/libs/solutions/tasking/barrier.h
@@ -34,7 +34,7 @@ private:
int m_current = -1;
};
-class TASKING_EXPORT BarrierTaskAdapter : public Tasking::TaskAdapter
+class TASKING_EXPORT BarrierTaskAdapter : public TaskAdapter
{
public:
BarrierTaskAdapter() { connect(task(), &Barrier::done, this, &TaskInterface::done); }
diff --git a/src/libs/solutions/tasking/concurrentcall.h b/src/libs/solutions/tasking/concurrentcall.h
new file mode 100644
index 00000000000..d7799159447
--- /dev/null
+++ b/src/libs/solutions/tasking/concurrentcall.h
@@ -0,0 +1,100 @@
+// 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 "tasking_global.h"
+
+#include "tasktree.h"
+
+#include
+
+namespace Tasking {
+
+// This class introduces the dependency to Qt::Concurrent, otherwise Tasking namespace
+// is independent on Qt::Concurrent.
+// Possibly, it could be placed inside Qt::Concurrent library, as a wrapper around
+// QtConcurrent::run() call.
+
+template
+class ConcurrentCall
+{
+ Q_DISABLE_COPY_MOVE(ConcurrentCall)
+
+public:
+ ConcurrentCall() = default;
+ template
+ void setConcurrentCallData(Function &&function, Args &&...args)
+ {
+ return wrapConcurrent(std::forward(function), std::forward(args)...);
+ }
+ void setThreadPool(QThreadPool *pool) { m_threadPool = pool; }
+ ResultType result() const
+ {
+ return m_future.resultCount() ? m_future.result() : ResultType();
+ }
+ QFuture future() const { return m_future; }
+
+private:
+ template
+ void wrapConcurrent(Function &&function, Args &&...args)
+ {
+ m_startHandler = [=] {
+ if (m_threadPool)
+ return QtConcurrent::run(m_threadPool, function, args...);
+ return QtConcurrent::run(function, args...);
+ };
+ }
+
+ template
+ void wrapConcurrent(std::reference_wrapper &&wrapper, Args &&...args)
+ {
+ m_startHandler = [=] {
+ if (m_threadPool) {
+ return QtConcurrent::run(m_threadPool,
+ std::forward(wrapper.get()), args...);
+ }
+ return QtConcurrent::run(std::forward(wrapper.get()), args...);
+ };
+ }
+
+ template
+ friend class ConcurrentCallTaskAdapter;
+
+ std::function()> m_startHandler;
+ QThreadPool *m_threadPool = nullptr;
+ QFuture m_future;
+};
+
+template
+class ConcurrentCallTaskAdapter : public TaskAdapter>
+{
+public:
+ ~ConcurrentCallTaskAdapter() {
+ if (m_watcher) {
+ m_watcher->cancel();
+ m_watcher->waitForFinished();
+ }
+ }
+
+ void start() {
+ if (!this->task()->m_startHandler) {
+ emit this->done(false); // TODO: Add runtime assert
+ return;
+ }
+ m_watcher.reset(new QFutureWatcher);
+ this->connect(m_watcher.get(), &QFutureWatcherBase::finished, this, [this] {
+ emit this->done(!m_watcher->isCanceled());
+ m_watcher.release()->deleteLater();
+ });
+ this->task()->m_future = this->task()->m_startHandler();
+ m_watcher->setFuture(this->task()->m_future);
+ }
+
+private:
+ std::unique_ptr> m_watcher;
+};
+
+} // namespace Tasking
+
+TASKING_DECLARE_TEMPLATE_TASK(ConcurrentCallTask, Tasking::ConcurrentCallTaskAdapter);
diff --git a/src/libs/solutions/tasking/networkquery.cpp b/src/libs/solutions/tasking/networkquery.cpp
new file mode 100644
index 00000000000..292d3c7d4aa
--- /dev/null
+++ b/src/libs/solutions/tasking/networkquery.cpp
@@ -0,0 +1,38 @@
+// Copyright (C) 2023 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR BSD-3-Clause
+
+#include "networkquery.h"
+
+#include
+
+namespace Tasking {
+
+void NetworkQuery::start()
+{
+ if (m_reply) {
+ qWarning("The NetworkQuery is already running. Ignoring the call to start().");
+ return;
+ }
+ if (!m_manager) {
+ qWarning("Can't start the NetworkQuery without the QNetworkAccessManager. "
+ "Stopping with an error.");
+ emit done(false);
+ return;
+ }
+ m_reply.reset(m_manager->get(m_request));
+ connect(m_reply.get(), &QNetworkReply::finished, this, [this] {
+ disconnect(m_reply.get(), nullptr, this, nullptr);
+ emit done(m_reply->error() == QNetworkReply::NoError);
+ m_reply.release()->deleteLater();
+ });
+ if (m_reply->isRunning())
+ emit started();
+}
+
+NetworkQuery::~NetworkQuery()
+{
+ if (m_reply)
+ m_reply->abort();
+}
+
+} // namespace Tasking
diff --git a/src/libs/solutions/tasking/networkquery.h b/src/libs/solutions/tasking/networkquery.h
new file mode 100644
index 00000000000..faf482df90d
--- /dev/null
+++ b/src/libs/solutions/tasking/networkquery.h
@@ -0,0 +1,55 @@
+// Copyright (C) 2023 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR BSD-3-Clause
+
+#pragma once
+
+#include "tasking_global.h"
+
+#include "tasktree.h"
+
+#include
+#include
+
+#include
+
+QT_BEGIN_NAMESPACE
+class QNetworkAccessManager;
+QT_END_NAMESPACE
+
+namespace Tasking {
+
+// This class introduces the dependency to Qt::Network, otherwise Tasking namespace
+// is independent on Qt::Network.
+// Possibly, it could be placed inside Qt::Network library, as a wrapper around QNetworkReply.
+
+class TASKING_EXPORT NetworkQuery final : public QObject
+{
+ Q_OBJECT
+
+public:
+ ~NetworkQuery();
+ void setRequest(const QNetworkRequest &request) { m_request = request; }
+ void setNetworkAccessManager(QNetworkAccessManager *manager) { m_manager = manager; }
+ QNetworkReply *reply() const { return m_reply.get(); }
+ void start();
+
+signals:
+ void started();
+ void done(bool success);
+
+private:
+ QNetworkRequest m_request;
+ QNetworkAccessManager *m_manager = nullptr;
+ std::unique_ptr m_reply;
+};
+
+class TASKING_EXPORT NetworkQueryTaskAdapter : public TaskAdapter
+{
+public:
+ NetworkQueryTaskAdapter() { connect(task(), &NetworkQuery::done, this, &TaskInterface::done); }
+ void start() final { task()->start(); }
+};
+
+} // namespace Tasking
+
+TASKING_DECLARE_TASK(NetworkQueryTask, Tasking::NetworkQueryTaskAdapter);
diff --git a/src/libs/solutions/tasking/tasking.qbs b/src/libs/solutions/tasking/tasking.qbs
index 8697b9c009b..fa0a5ebacc9 100644
--- a/src/libs/solutions/tasking/tasking.qbs
+++ b/src/libs/solutions/tasking/tasking.qbs
@@ -1,11 +1,14 @@
QtcLibrary {
name: "Tasking"
- Depends { name: "Qt"; submodules: ["core"] }
+ Depends { name: "Qt"; submodules: ["concurrent", "core", "network"] }
cpp.defines: base.concat("TASKING_LIBRARY")
files: [
"barrier.cpp",
"barrier.h",
+ "concurrentcall.h",
+ "networkquery.cpp",
+ "networkquery.h",
"tasking_global.h",
"tasktree.cpp",
"tasktree.h",
diff --git a/src/libs/solutions/tasking/tasktree.cpp b/src/libs/solutions/tasking/tasktree.cpp
index 071190dd9eb..2a4c7cefd98 100644
--- a/src/libs/solutions/tasking/tasktree.cpp
+++ b/src/libs/solutions/tasking/tasktree.cpp
@@ -9,6 +9,8 @@
#include
#include
+using namespace std::chrono;
+
namespace Tasking {
// That's cut down qtcassert.{c,h} to avoid the dependency.
@@ -41,11 +43,119 @@ private:
};
/*!
- \class Tasking::TaskItem
+ \class Tasking::GroupItem
\inheaderfile solutions/tasking/tasktree.h
\inmodule QtCreator
\ingroup mainclasses
- \brief The TaskItem class represents the basic element for composing nested tree structures.
+ \brief The GroupItem class represents the basic element for composing nested tree structures.
+*/
+
+/*!
+ \enum Tasking::WorkflowPolicy
+
+ This enum describes the possible behavior of the Group element when any group's child task
+ finishes its execution. It's also used when the running Group is stopped.
+
+ \value StopOnError
+ Default. Corresponds to the stopOnError global element.
+ If any child task finishes with an error, the group stops and finishes with an error.
+ If all child tasks finished with success, the group finishes with success.
+ If a group is empty, it finishes with success.
+ \value ContinueOnError
+ Corresponds to the continueOnError global element.
+ Similar to stopOnError, but in case any child finishes with an error,
+ the execution continues until all tasks finish, and the group reports an error
+ afterwards, even when some other tasks in the group finished with success.
+ If all child tasks finish successfully, the group finishes with success.
+ If a group is empty, it finishes with success.
+ \value StopOnDone
+ Corresponds to the stopOnDone global element.
+ If any child task finishes with success, the group stops and finishes with success.
+ If all child tasks finished with an error, the group finishes with an error.
+ If a group is empty, it finishes with an error.
+ \value ContinueOnDone
+ Corresponds to the continueOnDone global element.
+ Similar to stopOnDone, but in case any child finishes successfully,
+ the execution continues until all tasks finish, and the group reports success
+ afterwards, even when some other tasks in the group finished with an error.
+ If all child tasks finish with an error, the group finishes with an error.
+ If a group is empty, it finishes with an error.
+ \value StopOnFinished
+ Corresponds to the stopOnFinished global element.
+ The group starts as many tasks as it can. When any task finishes,
+ the group stops and reports the task's result.
+ Useful only in parallel mode.
+ In sequential mode, only the first task is started, and when finished,
+ the group finishes too, so the other tasks are always skipped.
+ If a group is empty, it finishes with an error.
+ \value FinishAllAndDone
+ Corresponds to the finishAllAndDone global element.
+ The group executes all tasks and ignores their return results. When all
+ tasks finished, the group finishes with success.
+ If a group is empty, it finishes with success.
+ \value FinishAllAndError
+ Corresponds to the finishAllAndError global element.
+ The group executes all tasks and ignores their return results. When all
+ tasks finished, the group finishes with an error.
+ If a group is empty, it finishes with an error.
+
+ Whenever a child task's result causes the Group to stop,
+ i.e. in case of StopOnError, StopOnDone, or StopOnFinished policies,
+ the Group stops the other running child tasks (if any - for example in parallel mode),
+ and skips executing tasks it has not started yet (for example, in the sequential mode -
+ those, that are placed after the failed task). Both stopping and skipping child tasks
+ may happen when parallelLimit is used.
+
+ The table below summarizes the differences between various workflow policies:
+
+ \table
+ \header
+ \li \l WorkflowPolicy
+ \li Executes all child tasks
+ \li Result
+ \li Result when the group is empty
+ \row
+ \li StopOnError
+ \li Stops when any child task finished with an error and reports an error
+ \li An error when at least one child task failed, success otherwise
+ \li Success
+ \row
+ \li ContinueOnError
+ \li Yes
+ \li An error when at least one child task failed, success otherwise
+ \li Success
+ \row
+ \li StopOnDone
+ \li Stops when any child task finished with success and reports success
+ \li Success when at least one child task succeeded, an error otherwise
+ \li An error
+ \row
+ \li ContinueOnDone
+ \li Yes
+ \li Success when at least one child task succeeded, an error otherwise
+ \li An error
+ \row
+ \li StopOnFinished
+ \li Stops when any child task finished and reports child task's result
+ \li Success or an error, depending on the finished child task's result
+ \li An error
+ \row
+ \li FinishAllAndDone
+ \li Yes
+ \li Success
+ \li Success
+ \row
+ \li FinishAllAndError
+ \li Yes
+ \li An error
+ \li An error
+ \endtable
+
+ If a child of a group is also a group, the child group runs its tasks according to its own
+ workflow policy. When a parent group stops the running child group because
+ of parent group's workflow policy, i.e. when the StopOnError, StopOnDone, or StopOnFinished
+ policy was used for the parent, the child group's result is reported according to the
+ \b Result column and to the \b {child group's workflow policy} row in the table above.
*/
/*!
@@ -74,6 +184,43 @@ private:
\sa sequential, parallelLimit
*/
+/*!
+ \variable stopOnError
+ A convenient global group's element describing the StopOnError workflow policy.
+
+ This is the default workflow policy of the Group element.
+*/
+
+/*!
+ \variable continueOnError
+ A convenient global group's element describing the ContinueOnError workflow policy.
+*/
+
+/*!
+ \variable stopOnDone
+ A convenient global group's element describing the StopOnDone workflow policy.
+*/
+
+/*!
+ \variable continueOnDone
+ A convenient global group's element describing the ContinueOnDone workflow policy.
+*/
+
+/*!
+ \variable stopOnFinished
+ A convenient global group's element describing the StopOnFinished workflow policy.
+*/
+
+/*!
+ \variable finishAllAndDone
+ A convenient global group's element describing the FinishAllAndDone workflow policy.
+*/
+
+/*!
+ \variable finishAllAndError
+ A convenient global group's element describing the FinishAllAndError workflow policy.
+*/
+
/*!
\enum Tasking::TaskAction
@@ -99,7 +246,7 @@ private:
*/
/*!
- \typealias TaskItem::GroupSetupHandler
+ \typealias GroupItem::GroupSetupHandler
Type alias for \c std::function.
@@ -130,7 +277,7 @@ private:
*/
/*!
- \typealias TaskItem::GroupEndHandler
+ \typealias GroupItem::GroupEndHandler
Type alias for \c std::function\.
@@ -143,13 +290,14 @@ private:
*/
/*!
- \fn template TaskItem onGroupSetup(SetupHandler &&handler)
+ \fn template GroupItem onGroupSetup(SetupHandler &&handler)
Constructs a group's element holding the group setup handler.
The \a handler is invoked whenever the group starts.
The passed \a handler is either of \c std::function or \c std::function
- type. For more information on possible argument type, refer to \l {TaskItem::GroupSetupHandler}.
+ type. For more information on possible argument type, refer to
+ \l {GroupItem::GroupSetupHandler}.
When the \a handler is invoked, none of the group's child tasks are running yet.
@@ -157,14 +305,14 @@ private:
after the storages are constructed, so that the \a handler may already
perform some initial modifications to the active storages.
- \sa TaskItem::GroupSetupHandler, onGroupDone, onGroupError
+ \sa GroupItem::GroupSetupHandler, onGroupDone, onGroupError
*/
/*!
Constructs a group's element holding the group done handler.
The \a handler is invoked whenever the group finishes with success.
Depending on the group's workflow policy, this handler may also be called
- when the running group is stopped (e.g. when optional element was used).
+ when the running group is stopped (e.g. when finishAllAndDone element was used).
When the \a handler is invoked, all of the group's child tasks are already finished.
@@ -172,9 +320,9 @@ private:
before the storages are destructed, so that the \a handler may still
perform a last read of the active storages' data.
- \sa TaskItem::GroupEndHandler, onGroupSetup, onGroupError
+ \sa GroupItem::GroupEndHandler, onGroupSetup, onGroupError
*/
-TaskItem onGroupDone(const TaskItem::GroupEndHandler &handler)
+GroupItem onGroupDone(const GroupItem::GroupEndHandler &handler)
{
return Group::onGroupDone(handler);
}
@@ -191,9 +339,9 @@ TaskItem onGroupDone(const TaskItem::GroupEndHandler &handler)
before the storages are destructed, so that the \a handler may still
perform a last read of the active storages' data.
- \sa TaskItem::GroupEndHandler, onGroupSetup, onGroupDone
+ \sa GroupItem::GroupEndHandler, onGroupSetup, onGroupDone
*/
-TaskItem onGroupError(const TaskItem::GroupEndHandler &handler)
+GroupItem onGroupError(const GroupItem::GroupEndHandler &handler)
{
return Group::onGroupError(handler);
}
@@ -239,24 +387,34 @@ TaskItem onGroupError(const TaskItem::GroupEndHandler &handler)
\sa sequential, parallel
*/
-TaskItem parallelLimit(int limit)
+GroupItem parallelLimit(int limit)
{
return Group::parallelLimit(qMax(limit, 0));
}
-TaskItem workflowPolicy(WorkflowPolicy policy)
+/*!
+ Constructs a group's workflow policy element for a given \a policy.
+
+ For convenience, global elements may be used instead.
+
+ \sa stopOnError, continueOnError, stopOnDone, continueOnDone, stopOnFinished, finishAllAndDone,
+ finishAllAndError, WorkflowPolicy
+*/
+GroupItem workflowPolicy(WorkflowPolicy policy)
{
return Group::workflowPolicy(policy);
}
-const TaskItem sequential = parallelLimit(1);
-const TaskItem parallel = parallelLimit(0);
-const TaskItem stopOnError = workflowPolicy(WorkflowPolicy::StopOnError);
-const TaskItem continueOnError = workflowPolicy(WorkflowPolicy::ContinueOnError);
-const TaskItem stopOnDone = workflowPolicy(WorkflowPolicy::StopOnDone);
-const TaskItem continueOnDone = workflowPolicy(WorkflowPolicy::ContinueOnDone);
-const TaskItem stopOnFinished = workflowPolicy(WorkflowPolicy::StopOnFinished);
-const TaskItem optional = workflowPolicy(WorkflowPolicy::Optional);
+const GroupItem sequential = parallelLimit(1);
+const GroupItem parallel = parallelLimit(0);
+
+const GroupItem stopOnError = workflowPolicy(WorkflowPolicy::StopOnError);
+const GroupItem continueOnError = workflowPolicy(WorkflowPolicy::ContinueOnError);
+const GroupItem stopOnDone = workflowPolicy(WorkflowPolicy::StopOnDone);
+const GroupItem continueOnDone = workflowPolicy(WorkflowPolicy::ContinueOnDone);
+const GroupItem stopOnFinished = workflowPolicy(WorkflowPolicy::StopOnFinished);
+const GroupItem finishAllAndDone = workflowPolicy(WorkflowPolicy::FinishAllAndDone);
+const GroupItem finishAllAndError = workflowPolicy(WorkflowPolicy::FinishAllAndError);
static TaskAction toTaskAction(bool success)
{
@@ -326,11 +484,11 @@ void TreeStorageBase::activateStorage(int id) const
m_storageData->m_activeStorage = id;
}
-void TaskItem::addChildren(const QList &children)
+void GroupItem::addChildren(const QList &children)
{
QTC_ASSERT(m_type == Type::Group, qWarning("Only Group may have children, skipping...");
return);
- for (const TaskItem &child : children) {
+ for (const GroupItem &child : children) {
switch (child.m_type) {
case Type::Group:
m_children.append(child);
@@ -377,7 +535,7 @@ void TaskItem::addChildren(const QList &children)
}
}
-void TaskItem::setTaskSetupHandler(const TaskSetupHandler &handler)
+void GroupItem::setTaskSetupHandler(const TaskSetupHandler &handler)
{
if (!handler) {
qWarning("Setting empty Setup Handler is no-op, skipping...");
@@ -388,7 +546,7 @@ void TaskItem::setTaskSetupHandler(const TaskSetupHandler &handler)
m_taskHandler.m_setupHandler = handler;
}
-void TaskItem::setTaskDoneHandler(const TaskEndHandler &handler)
+void GroupItem::setTaskDoneHandler(const TaskEndHandler &handler)
{
if (!handler) {
qWarning("Setting empty Done Handler is no-op, skipping...");
@@ -399,7 +557,7 @@ void TaskItem::setTaskDoneHandler(const TaskEndHandler &handler)
m_taskHandler.m_doneHandler = handler;
}
-void TaskItem::setTaskErrorHandler(const TaskEndHandler &handler)
+void GroupItem::setTaskErrorHandler(const TaskEndHandler &handler)
{
if (!handler) {
qWarning("Setting empty Error Handler is no-op, skipping...");
@@ -410,6 +568,23 @@ void TaskItem::setTaskErrorHandler(const TaskEndHandler &handler)
m_taskHandler.m_errorHandler = handler;
}
+GroupItem GroupItem::withTimeout(const GroupItem &item, milliseconds timeout,
+ const GroupEndHandler &handler)
+{
+ const TimeoutTask::EndHandler taskHandler = handler
+ ? [handler](const milliseconds &) { handler(); } : TimeoutTask::EndHandler();
+ return Group {
+ parallel,
+ stopOnFinished,
+ Group {
+ finishAllAndError,
+ TimeoutTask([timeout](milliseconds &timeoutData) { timeoutData = timeout; },
+ taskHandler)
+ },
+ item
+ };
+}
+
class TaskTreePrivate;
class TaskNode;
@@ -466,7 +641,7 @@ class TaskContainer
Q_DISABLE_COPY_MOVE(TaskContainer)
public:
- TaskContainer(TaskTreePrivate *taskTreePrivate, const TaskItem &task,
+ TaskContainer(TaskTreePrivate *taskTreePrivate, const GroupItem &task,
TaskNode *parentNode, TaskContainer *parentContainer)
: m_constData(taskTreePrivate, task, parentNode, parentContainer, this) {}
TaskAction start();
@@ -479,7 +654,7 @@ public:
bool isStarting() const { return isRunning() && m_runtimeData->m_startGuard.isLocked(); }
struct ConstData {
- ConstData(TaskTreePrivate *taskTreePrivate, const TaskItem &task, TaskNode *parentNode,
+ ConstData(TaskTreePrivate *taskTreePrivate, const GroupItem &task, TaskNode *parentNode,
TaskContainer *parentContainer, TaskContainer *thisContainer);
~ConstData() { qDeleteAll(m_children); }
TaskTreePrivate * const m_taskTreePrivate = nullptr;
@@ -488,7 +663,7 @@ public:
const int m_parallelLimit = 1;
const WorkflowPolicy m_workflowPolicy = WorkflowPolicy::StopOnError;
- const TaskItem::GroupHandler m_groupHandler;
+ const GroupItem::GroupHandler m_groupHandler;
const QList m_storageList;
const QList m_children;
const int m_taskCount = 0;
@@ -505,8 +680,8 @@ public:
const ConstData &m_constData;
const QList m_storageIdList;
- int m_doneCount = 0;
bool m_successBit = true;
+ int m_doneCount = 0;
Guard m_startGuard;
};
@@ -519,7 +694,7 @@ class TaskNode
Q_DISABLE_COPY_MOVE(TaskNode)
public:
- TaskNode(TaskTreePrivate *taskTreePrivate, const TaskItem &task,
+ TaskNode(TaskTreePrivate *taskTreePrivate, const GroupItem &task,
TaskContainer *parentContainer)
: m_taskHandler(task.taskHandler())
, m_container(taskTreePrivate, task, this, parentContainer)
@@ -537,7 +712,7 @@ public:
TaskTree *taskTree() const { return m_container.m_constData.m_taskTreePrivate->q; }
private:
- const TaskItem::TaskHandler m_taskHandler;
+ const GroupItem::TaskHandler m_taskHandler;
TaskContainer m_container;
std::unique_ptr m_task;
};
@@ -657,16 +832,16 @@ ReturnType invokeHandler(TaskContainer *container, Handler &&handler, Args &&...
}
static QList createChildren(TaskTreePrivate *taskTreePrivate, TaskContainer *container,
- const TaskItem &task)
+ const GroupItem &task)
{
QList result;
- const QList &children = task.children();
- for (const TaskItem &child : children)
+ const QList &children = task.children();
+ for (const GroupItem &child : children)
result.append(new TaskNode(taskTreePrivate, child, container));
return result;
}
-TaskContainer::ConstData::ConstData(TaskTreePrivate *taskTreePrivate, const TaskItem &task,
+TaskContainer::ConstData::ConstData(TaskTreePrivate *taskTreePrivate, const GroupItem &task,
TaskNode *parentNode, TaskContainer *parentContainer,
TaskContainer *thisContainer)
: m_taskTreePrivate(taskTreePrivate)
@@ -701,13 +876,28 @@ void TaskContainer::RuntimeData::callStorageDoneHandlers()
}
}
+static bool initialSuccessBit(WorkflowPolicy workflowPolicy)
+{
+ switch (workflowPolicy) {
+ case WorkflowPolicy::StopOnError:
+ case WorkflowPolicy::ContinueOnError:
+ case WorkflowPolicy::FinishAllAndDone:
+ return true;
+ case WorkflowPolicy::StopOnDone:
+ case WorkflowPolicy::ContinueOnDone:
+ case WorkflowPolicy::StopOnFinished:
+ case WorkflowPolicy::FinishAllAndError:
+ return false;
+ }
+ QTC_CHECK(false);
+ return false;
+}
+
TaskContainer::RuntimeData::RuntimeData(const ConstData &constData)
: m_constData(constData)
, m_storageIdList(createStorages(constData))
-{
- m_successBit = m_constData.m_workflowPolicy != WorkflowPolicy::StopOnDone
- && m_constData.m_workflowPolicy != WorkflowPolicy::ContinueOnDone;
-}
+ , m_successBit(initialSuccessBit(m_constData.m_workflowPolicy))
+{}
TaskContainer::RuntimeData::~RuntimeData()
{
@@ -720,10 +910,11 @@ TaskContainer::RuntimeData::~RuntimeData()
bool TaskContainer::RuntimeData::updateSuccessBit(bool success)
{
- if (m_constData.m_workflowPolicy == WorkflowPolicy::Optional)
- return m_successBit;
- if (m_constData.m_workflowPolicy == WorkflowPolicy::StopOnFinished) {
- m_successBit = success;
+ if (m_constData.m_workflowPolicy == WorkflowPolicy::FinishAllAndDone
+ || m_constData.m_workflowPolicy == WorkflowPolicy::FinishAllAndError
+ || m_constData.m_workflowPolicy == WorkflowPolicy::StopOnFinished) {
+ if (m_constData.m_workflowPolicy == WorkflowPolicy::StopOnFinished)
+ m_successBit = success;
return m_successBit;
}
@@ -753,7 +944,7 @@ TaskAction TaskContainer::start()
}
if (startAction == TaskAction::Continue) {
if (m_constData.m_children.isEmpty())
- startAction = TaskAction::StopWithDone;
+ startAction = toTaskAction(m_runtimeData->m_successBit);
}
return continueStart(startAction, 0);
}
@@ -845,7 +1036,7 @@ void TaskContainer::stop()
void TaskContainer::invokeEndHandler()
{
- const TaskItem::GroupHandler &groupHandler = m_constData.m_groupHandler;
+ const GroupItem::GroupHandler &groupHandler = m_constData.m_groupHandler;
if (m_runtimeData->m_successBit && groupHandler.m_doneHandler)
invokeHandler(this, groupHandler.m_doneHandler);
else if (!m_runtimeData->m_successBit && groupHandler.m_errorHandler)
@@ -893,6 +1084,7 @@ void TaskNode::stop()
if (!m_task) {
m_container.stop();
+ m_container.m_runtimeData->updateSuccessBit(false);
m_container.invokeEndHandler();
return;
}
@@ -1331,77 +1523,11 @@ void TaskNode::invokeEndHandler(bool success)
\section2 Workflow Policy
The workflow policy element in a Group specifies how the group should behave
- when any of its \e direct child's tasks finish:
+ when any of its \e direct child's tasks finish. For a detailed description of possible
+ policies, refer to WorkflowPolicy.
- \table
- \header
- \li Workflow Policy
- \li Description
- \row
- \li stopOnError
- \li Default. If a task finishes with an error, the group:
- \list 1
- \li Stops the running tasks (if any - for example, in parallel
- mode).
- \li Skips executing tasks it has not started yet (for example, in the
- sequential mode - those, that are placed after the failed task).
- \li Immediately finishes with an error.
- \endlist
- If all child tasks finish successfully, the group finishes with success.
- \row
- \li continueOnError
- \li Similar to stopOnError, but in case any child finishes with
- an error, the execution continues until all tasks finish,
- and the group reports an error afterwards, even when some other
- tasks in group finished with success.
- If a task finishes with an error, the group:
- \list 1
- \li Continues executing the tasks that are running or have not
- started yet.
- \li Finishes with an error when all tasks finish.
- \endlist
- If all tasks finish successfully, the group finishes with success.
- \row
- \li stopOnDone
- \li If a task finishes with success, the group:
- \list 1
- \li Stops the running tasks (if any - for example, in parallel
- mode).
- \li Skips executing tasks it has not started yet (for example, in the
- sequential mode - those, that are placed after the successfully finished task).
- \li Immediately finishes with success.
- \endlist
- If all tasks finish with an error, the group finishes with an error.
- \row
- \li continueOnDone
- \li Similar to stopOnDone, but in case any child finishes
- successfully, the execution continues until all tasks finish,
- and the group reports success afterwards, even when some other
- tasks in group finished with an error.
- If a task finishes with success, the group:
- \list 1
- \li Continues executing the tasks that are running or have not
- started yet.
- \li Finishes with success when all tasks finish.
- \endlist
- If all tasks finish with an error, the group finishes with an error.
- \row
- \li stopOnFinished
- \li The group starts as many tasks as it can. When a task finishes,
- the group stops and reports the task's result.
- Useful only in parallel mode.
- In sequential mode, only the first task is started, and when finished,
- the group finishes too, so the other tasks are ignored.
- \row
- \li optional
- \li The group executes all tasks and ignores their return state. When all
- tasks finish, the group finishes with success.
- \endtable
-
- When a Group is empty, it finishes immediately with success,
- regardless of its workflow policy.
- If a child of a group is also a group, the child group
- runs its tasks according to its own workflow policy.
+ If a child of a group is also a group, the child group runs its tasks
+ according to its own workflow policy.
\section2 Storage
@@ -1411,10 +1537,10 @@ void TaskNode::invokeEndHandler(bool success)
it from a source and writing it to a destination might look as follows:
\code
- static QByteArray load(const FilePath &fileName) { ... }
- static void save(const FilePath &fileName, const QByteArray &array) { ... }
+ static QByteArray load(const QString &fileName) { ... }
+ static void save(const QString &fileName, const QByteArray &array) { ... }
- static TaskItem diffRecipe(const FilePath &source, const FilePath &destination)
+ static GroupItem copyRecipe(const QString &source, const QString &destination)
{
struct CopyStorage { // [1] custom inter-task struct
QByteArray content; // [2] custom inter-task data
@@ -1448,6 +1574,13 @@ void TaskNode::invokeEndHandler(bool success)
};
return root;
}
+
+ const QString source = ...;
+ const QString destination = ...;
+ TaskTree taskTree(copyRecipe(source, destination));
+ connect(&taskTree, &TaskTree::done,
+ &taskTree, [] { qDebug() << "The copying finished successfully."; });
+ tasktree.start();
\endcode
In the example above, the inter-task data consists of a QByteArray content
@@ -1659,9 +1792,16 @@ bool TaskTree::isRunning() const
return d->m_root && d->m_root->isRunning();
}
-bool TaskTree::runBlocking(const QFuture &future, int timeoutMs)
+bool TaskTree::runBlocking()
{
- if (isRunning() || future.isCanceled())
+ QPromise dummy;
+ dummy.start();
+ return runBlocking(dummy.future());
+}
+
+bool TaskTree::runBlocking(const QFuture &future)
+{
+ if (future.isCanceled())
return false;
bool ok = false;
@@ -1680,17 +1820,7 @@ bool TaskTree::runBlocking(const QFuture &future, int timeoutMs)
connect(this, &TaskTree::done, &loop, [finalize] { finalize(true); });
connect(this, &TaskTree::errorOccurred, &loop, [finalize] { finalize(false); });
- start();
- if (!isRunning())
- return ok;
-
- QTimer timer;
- if (timeoutMs) {
- timer.setSingleShot(true);
- timer.setInterval(timeoutMs);
- connect(&timer, &QTimer::timeout, this, &TaskTree::stop);
- timer.start();
- }
+ QTimer::singleShot(0, this, &TaskTree::start);
loop.exec(QEventLoop::ExcludeUserInputEvents);
if (!ok) {
@@ -1700,11 +1830,19 @@ bool TaskTree::runBlocking(const QFuture &future, int timeoutMs)
return ok;
}
-bool TaskTree::runBlocking(int timeoutMs)
+bool TaskTree::runBlocking(const Group &recipe, milliseconds timeout)
{
QPromise dummy;
dummy.start();
- return runBlocking(dummy.future(), timeoutMs);
+ return TaskTree::runBlocking(recipe, dummy.future(), timeout);
+}
+
+bool TaskTree::runBlocking(const Group &recipe, const QFuture &future, milliseconds timeout)
+{
+ const Group root = timeout == milliseconds::max() ? recipe
+ : Group { recipe.withTimeout(timeout) };
+ TaskTree taskTree(root);
+ return taskTree.runBlocking(future);
}
int TaskTree::taskCount() const
@@ -1749,4 +1887,95 @@ void TaskTreeTaskAdapter::start()
task()->start();
}
+using TimeoutCallback = std::function;
+
+struct TimerData
+{
+ system_clock::time_point m_deadline;
+ QPointer m_context;
+ TimeoutCallback m_callback;
+};
+
+QMutex s_mutex;
+std::atomic_int s_timerId = 0;
+QHash s_timerIdToTimerData = {};
+QMultiMap s_deadlineToTimerId = {};
+
+static QList prepareForActivation(int timerId)
+{
+ QMutexLocker lock(&s_mutex);
+ const auto it = s_timerIdToTimerData.constFind(timerId);
+ if (it == s_timerIdToTimerData.cend())
+ return {}; // the timer was already activated
+
+ const system_clock::time_point deadline = it->m_deadline;
+ QList toActivate;
+ auto itMap = s_deadlineToTimerId.cbegin();
+ while (itMap != s_deadlineToTimerId.cend()) {
+ if (itMap.key() > deadline)
+ break;
+
+ const auto it = s_timerIdToTimerData.constFind(itMap.value());
+ if (it != s_timerIdToTimerData.cend()) {
+ toActivate.append(it.value());
+ s_timerIdToTimerData.erase(it);
+ }
+ itMap = s_deadlineToTimerId.erase(itMap);
+ }
+ return toActivate;
+}
+
+static void removeTimerId(int timerId)
+{
+ QMutexLocker lock(&s_mutex);
+ const auto it = s_timerIdToTimerData.constFind(timerId);
+ QTC_ASSERT(it != s_timerIdToTimerData.cend(),
+ qWarning("Removing active timerId failed."); return);
+
+ const system_clock::time_point deadline = it->m_deadline;
+ s_timerIdToTimerData.erase(it);
+
+ const int removedCount = s_deadlineToTimerId.remove(deadline, timerId);
+ QTC_ASSERT(removedCount == 1, qWarning("Removing active timerId failed."); return);
+}
+
+static void handleTimeout(int timerId)
+{
+ const QList toActivate = prepareForActivation(timerId);
+ for (const TimerData &timerData : toActivate) {
+ if (timerData.m_context)
+ QMetaObject::invokeMethod(timerData.m_context.get(), timerData.m_callback);
+ }
+}
+
+static int scheduleTimeout(milliseconds timeout, QObject *context, const TimeoutCallback &callback)
+{
+ const int timerId = s_timerId.fetch_add(1) + 1;
+ const system_clock::time_point deadline = system_clock::now() + timeout;
+ QTimer::singleShot(timeout, context, [timerId] { handleTimeout(timerId); });
+ QMutexLocker lock(&s_mutex);
+ s_timerIdToTimerData.emplace(timerId, TimerData{deadline, context, callback});
+ s_deadlineToTimerId.insert(deadline, timerId);
+ return timerId;
+}
+
+TimeoutTaskAdapter::TimeoutTaskAdapter()
+{
+ *task() = std::chrono::milliseconds::zero();
+}
+
+TimeoutTaskAdapter::~TimeoutTaskAdapter()
+{
+ if (m_timerId)
+ removeTimerId(*m_timerId);
+}
+
+void TimeoutTaskAdapter::start()
+{
+ if (*task() == milliseconds::zero())
+ QTimer::singleShot(0, this, [this] { emit done(true); });
+ else
+ m_timerId = scheduleTimeout(*task(), this, [this] { m_timerId = {}; emit done(true); });
+}
+
} // namespace Tasking
diff --git a/src/libs/solutions/tasking/tasktree.h b/src/libs/solutions/tasking/tasktree.h
index 1754e092631..dcd7b86ac18 100644
--- a/src/libs/solutions/tasking/tasktree.h
+++ b/src/libs/solutions/tasking/tasktree.h
@@ -16,6 +16,8 @@ QT_END_NAMESPACE
namespace Tasking {
+Q_NAMESPACE_EXPORT(TASKING_EXPORT)
+
class ExecutionContextActivator;
class TaskContainer;
class TaskTreePrivate;
@@ -99,16 +101,19 @@ private:
// b) On first done - continue executing all children and report done afterwards.
// 3. Stops on first finished child. In sequential mode it will never run other children then the first one.
// Useful only in parallel mode.
-// 4. Always run all children, ignore their result and report done afterwards.
+// 4. Always run all children, let them finish, ignore their results and report done afterwards.
+// 5. Always run all children, let them finish, ignore their results and report error afterwards.
enum class WorkflowPolicy {
- StopOnError, // 1a - Reports error on first child error, otherwise done (if all children were done).
- ContinueOnError, // 1b - The same, but children execution continues. Reports done when no children.
- StopOnDone, // 2a - Reports done on first child done, otherwise error (if all children were error).
- ContinueOnDone, // 2b - The same, but children execution continues. Reports error when no children.
- StopOnFinished, // 3 - Stops on first finished child and report its result.
- Optional // 4 - Reports done after all children finished.
+ StopOnError, // 1a - Reports error on first child error, otherwise done (if all children were done).
+ ContinueOnError, // 1b - The same, but children execution continues. Reports done when no children.
+ StopOnDone, // 2a - Reports done on first child done, otherwise error (if all children were error).
+ ContinueOnDone, // 2b - The same, but children execution continues. Reports error when no children.
+ StopOnFinished, // 3 - Stops on first finished child and report its result.
+ FinishAllAndDone, // 4 - Reports done after all children finished.
+ FinishAllAndError // 5 - Reports error after all children finished.
};
+Q_ENUM_NS(WorkflowPolicy);
enum class TaskAction
{
@@ -116,8 +121,9 @@ enum class TaskAction
StopWithDone,
StopWithError
};
+Q_ENUM_NS(TaskAction);
-class TASKING_EXPORT TaskItem
+class TASKING_EXPORT GroupItem
{
public:
// Internal, provided by QTC_DECLARE_CUSTOM_TASK
@@ -150,7 +156,7 @@ public:
std::optional m_workflowPolicy = {};
};
- QList children() const { return m_children; }
+ QList children() const { return m_children; }
GroupData groupData() const { return m_groupData; }
QList storageList() const { return m_storageList; }
TaskHandler taskHandler() const { return m_taskHandler; }
@@ -163,52 +169,59 @@ protected:
TaskHandler
};
- TaskItem() = default;
- TaskItem(const GroupData &data)
+ GroupItem() = default;
+ GroupItem(const GroupData &data)
: m_type(Type::GroupData)
, m_groupData(data) {}
- TaskItem(const TreeStorageBase &storage)
+ GroupItem(const TreeStorageBase &storage)
: m_type(Type::Storage)
, m_storageList{storage} {}
- TaskItem(const TaskHandler &handler)
+ GroupItem(const TaskHandler &handler)
: m_type(Type::TaskHandler)
, m_taskHandler(handler) {}
- void addChildren(const QList &children);
+ void addChildren(const QList &children);
void setTaskSetupHandler(const TaskSetupHandler &handler);
void setTaskDoneHandler(const TaskEndHandler &handler);
void setTaskErrorHandler(const TaskEndHandler &handler);
- static TaskItem groupHandler(const GroupHandler &handler) { return TaskItem({handler}); }
- static TaskItem parallelLimit(int limit) { return TaskItem({{}, limit}); }
- static TaskItem workflowPolicy(WorkflowPolicy policy) { return TaskItem({{}, {}, policy}); }
+ 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 GroupEndHandler &handler = {});
private:
Type m_type = Type::Group;
- QList m_children;
+ QList m_children;
GroupData m_groupData;
QList m_storageList;
TaskHandler m_taskHandler;
};
-class TASKING_EXPORT Group : public TaskItem
+class TASKING_EXPORT Group : public GroupItem
{
public:
- Group(const QList &children) { addChildren(children); }
- Group(std::initializer_list children) { addChildren(children); }
+ Group(const QList &children) { addChildren(children); }
+ Group(std::initializer_list children) { addChildren(children); }
// GroupData related:
template
- static TaskItem onGroupSetup(SetupHandler &&handler) {
+ static GroupItem onGroupSetup(SetupHandler &&handler) {
return groupHandler({wrapGroupSetup(std::forward(handler))});
}
- static TaskItem onGroupDone(const GroupEndHandler &handler) {
+ static GroupItem onGroupDone(const GroupEndHandler &handler) {
return groupHandler({{}, handler});
}
- static TaskItem onGroupError(const GroupEndHandler &handler) {
+ static GroupItem onGroupError(const GroupEndHandler &handler) {
return groupHandler({{}, {}, handler});
}
- using TaskItem::parallelLimit; // Default: 1 (sequential). 0 means unlimited (parallel).
- using TaskItem::workflowPolicy; // Default: WorkflowPolicy::StopOnError.
+ using GroupItem::parallelLimit; // Default: 1 (sequential). 0 means unlimited (parallel).
+ using GroupItem::workflowPolicy; // Default: WorkflowPolicy::StopOnError.
+
+ GroupItem withTimeout(std::chrono::milliseconds timeout,
+ const GroupEndHandler &handler = {}) const {
+ return GroupItem::withTimeout(*this, timeout, handler);
+ }
private:
template
@@ -231,29 +244,31 @@ private:
};
template
-static TaskItem onGroupSetup(SetupHandler &&handler)
+static GroupItem onGroupSetup(SetupHandler &&handler)
{
return Group::onGroupSetup(std::forward(handler));
}
-TASKING_EXPORT TaskItem onGroupDone(const TaskItem::GroupEndHandler &handler);
-TASKING_EXPORT TaskItem onGroupError(const TaskItem::GroupEndHandler &handler);
-TASKING_EXPORT TaskItem parallelLimit(int limit);
-TASKING_EXPORT TaskItem workflowPolicy(WorkflowPolicy policy);
+TASKING_EXPORT GroupItem onGroupDone(const GroupItem::GroupEndHandler &handler);
+TASKING_EXPORT GroupItem onGroupError(const GroupItem::GroupEndHandler &handler);
+TASKING_EXPORT GroupItem parallelLimit(int limit);
+TASKING_EXPORT GroupItem workflowPolicy(WorkflowPolicy policy);
-TASKING_EXPORT extern const TaskItem sequential;
-TASKING_EXPORT extern const TaskItem parallel;
-TASKING_EXPORT extern const TaskItem stopOnError;
-TASKING_EXPORT extern const TaskItem continueOnError;
-TASKING_EXPORT extern const TaskItem stopOnDone;
-TASKING_EXPORT extern const TaskItem continueOnDone;
-TASKING_EXPORT extern const TaskItem stopOnFinished;
-TASKING_EXPORT extern const TaskItem optional;
+TASKING_EXPORT extern const GroupItem sequential;
+TASKING_EXPORT extern const GroupItem parallel;
-class TASKING_EXPORT Storage : public TaskItem
+TASKING_EXPORT extern const GroupItem stopOnError;
+TASKING_EXPORT extern const GroupItem continueOnError;
+TASKING_EXPORT extern const GroupItem stopOnDone;
+TASKING_EXPORT extern const GroupItem continueOnDone;
+TASKING_EXPORT extern const GroupItem stopOnFinished;
+TASKING_EXPORT extern const GroupItem finishAllAndDone;
+TASKING_EXPORT extern const GroupItem finishAllAndError;
+
+class TASKING_EXPORT Storage : public GroupItem
{
public:
- Storage(const TreeStorageBase &storage) : TaskItem(storage) { }
+ Storage(const TreeStorageBase &storage) : GroupItem(storage) { }
};
// Synchronous invocation. Similarly to Group - isn't counted as a task inside taskCount()
@@ -266,7 +281,7 @@ public:
private:
template
- static QList init(Function &&function) {
+ static QList init(Function &&function) {
constexpr bool isInvocable = std::is_invocable_v>;
static_assert(isInvocable,
"Sync element: The synchronous function can't take any arguments.");
@@ -295,17 +310,17 @@ private:
};
template
-class CustomTask : public TaskItem
+class CustomTask : public GroupItem
{
public:
using Task = typename Adapter::Type;
using EndHandler = std::function;
static Adapter *createAdapter() { return new Adapter; }
- CustomTask() : TaskItem({&createAdapter}) {}
+ CustomTask() : GroupItem({&createAdapter}) {}
template
CustomTask(SetupFunction &&function, const EndHandler &done = {}, const EndHandler &error = {})
- : TaskItem({&createAdapter, wrapSetup(std::forward(function)),
- wrapEnd(done), wrapEnd(error)}) {}
+ : GroupItem({&createAdapter, wrapSetup(std::forward(function)),
+ wrapEnd(done), wrapEnd(error)}) {}
template
CustomTask &onSetup(SetupFunction &&function) {
@@ -321,9 +336,14 @@ public:
return *this;
}
+ GroupItem withTimeout(std::chrono::milliseconds timeout,
+ const GroupEndHandler &handler = {}) const {
+ return GroupItem::withTimeout(*this, timeout, handler);
+ }
+
private:
template
- static TaskItem::TaskSetupHandler wrapSetup(SetupFunction &&function) {
+ static GroupItem::TaskSetupHandler wrapSetup(SetupFunction &&function) {
static constexpr bool isDynamic = std::is_same_v, typename Adapter::Type &>>;
constexpr bool isVoid = std::is_same_v &future, int timeoutMs = 0);
- bool runBlocking(int timeoutMs = 0);
+ bool runBlocking();
+ bool runBlocking(const QFuture &future);
+ static bool runBlocking(const Group &recipe,
+ std::chrono::milliseconds timeout = std::chrono::milliseconds::max());
+ static bool runBlocking(const Group &recipe, const QFuture &future,
+ std::chrono::milliseconds timeout = std::chrono::milliseconds::max());
int taskCount() const;
int progressMaximum() const { return taskCount(); }
@@ -418,6 +442,17 @@ public:
void start() final;
};
+class TASKING_EXPORT TimeoutTaskAdapter : public TaskAdapter
+{
+public:
+ TimeoutTaskAdapter();
+ ~TimeoutTaskAdapter();
+ void start() final;
+
+private:
+ std::optional m_timerId;
+};
+
} // namespace Tasking
#define TASKING_DECLARE_TASK(CustomTaskName, TaskAdapterClass)\
@@ -430,3 +465,4 @@ using CustomTaskName = CustomTask>;\
} // namespace Tasking
TASKING_DECLARE_TASK(TaskTreeTask, TaskTreeTaskAdapter);
+TASKING_DECLARE_TASK(TimeoutTask, TimeoutTaskAdapter);
diff --git a/src/libs/utils/aspects.cpp b/src/libs/utils/aspects.cpp
index d3610b2c7da..999385e1ca9 100644
--- a/src/libs/utils/aspects.cpp
+++ b/src/libs/utils/aspects.cpp
@@ -670,6 +670,7 @@ public:
// Used to block recursive editingFinished signals for example when return is pressed, and
// the validation changes focus by opening a dialog
bool m_blockAutoApply = false;
+ bool m_allowPathFromDevice = true;
template void updateWidgetFromCheckStatus(StringAspect *aspect, Widget *w)
{
@@ -977,6 +978,13 @@ void StringAspect::setCommandVersionArguments(const QStringList &arguments)
d->m_pathChooserDisplay->setCommandVersionArguments(arguments);
}
+void StringAspect::setAllowPathFromDevice(bool allowPathFromDevice)
+{
+ d->m_allowPathFromDevice = allowPathFromDevice;
+ if (d->m_pathChooserDisplay)
+ d->m_pathChooserDisplay->setAllowPathFromDevice(allowPathFromDevice);
+}
+
/*!
Sets \a elideMode as label elide mode.
*/
@@ -1122,6 +1130,7 @@ void StringAspect::addToLayout(LayoutItem &parent)
d->m_pathChooserDisplay->setPromptDialogFilter(d->m_prompDialogFilter);
d->m_pathChooserDisplay->setPromptDialogTitle(d->m_prompDialogTitle);
d->m_pathChooserDisplay->setCommandVersionArguments(d->m_commandVersionArguments);
+ d->m_pathChooserDisplay->setAllowPathFromDevice(d->m_allowPathFromDevice);
if (defaultValue() == value())
d->m_pathChooserDisplay->setDefaultValue(defaultValue());
else
@@ -2153,8 +2162,11 @@ void DoubleAspect::setSingleStep(double step)
Its visual representation is a QComboBox with three items.
*/
-TriStateAspect::TriStateAspect(const QString &onString, const QString &offString,
+TriStateAspect::TriStateAspect(AspectContainer *container,
+ const QString &onString,
+ const QString &offString,
const QString &defaultString)
+ : SelectionAspect(container)
{
setDisplayStyle(DisplayStyle::ComboBox);
setDefaultValue(TriState::Default);
@@ -2308,7 +2320,7 @@ QList IntegersAspect::value() const
void IntegersAspect::setValue(const QList &value)
{
- BaseAspect::setValue(transform(value, &QVariant::fromValue));
+ BaseAspect::setValue(transform(value, [](int i) { return QVariant::fromValue(i); }));
}
QList IntegersAspect::defaultValue() const
@@ -2319,7 +2331,7 @@ QList IntegersAspect::defaultValue() const
void IntegersAspect::setDefaultValue(const QList &value)
{
- BaseAspect::setDefaultValue(transform(value, &QVariant::fromValue));
+ BaseAspect::setDefaultValue(transform(value, [](int i) { return QVariant::fromValue(i); }));
}
@@ -2334,6 +2346,10 @@ void IntegersAspect::setDefaultValue(const QList &value)
A text display does not have a real value.
*/
+TextDisplay::TextDisplay(AspectContainer *container)
+ : BaseAspect(container)
+{}
+
/*!
Constructs a text display showing the \a message with an icon representing
type \a type.
diff --git a/src/libs/utils/aspects.h b/src/libs/utils/aspects.h
index 35e8a62b8f7..b99c28c0bef 100644
--- a/src/libs/utils/aspects.h
+++ b/src/libs/utils/aspects.h
@@ -406,6 +406,7 @@ public:
void setOpenTerminalHandler(const std::function &openTerminal);
void setAutoApplyOnEditingFinished(bool applyOnEditingFinished);
void setElideMode(Qt::TextElideMode elideMode);
+ void setAllowPathFromDevice(bool allowPathFromDevice);
void validateInput();
@@ -548,7 +549,8 @@ class QTCREATOR_UTILS_EXPORT TriStateAspect : public SelectionAspect
Q_OBJECT
public:
- TriStateAspect(const QString &onString = {},
+ TriStateAspect(AspectContainer *container = nullptr,
+ const QString &onString = {},
const QString &offString = {},
const QString &defaultString = {});
@@ -608,6 +610,7 @@ class QTCREATOR_UTILS_EXPORT TextDisplay : public BaseAspect
Q_OBJECT
public:
+ explicit TextDisplay(AspectContainer *container);
TextDisplay(const QString &message = {},
InfoLabel::InfoType type = InfoLabel::None);
~TextDisplay() override;
diff --git a/src/libs/utils/devicefileaccess.cpp b/src/libs/utils/devicefileaccess.cpp
index f5bb1d20482..bd139d9b168 100644
--- a/src/libs/utils/devicefileaccess.cpp
+++ b/src/libs/utils/devicefileaccess.cpp
@@ -493,6 +493,20 @@ bool DesktopDeviceFileAccess::hasHardLinks(const FilePath &filePath) const
if (s.st_nlink > 1)
return true;
}
+#elif defined(Q_OS_WIN)
+ const HANDLE handle = CreateFile((wchar_t *) filePath.toUserOutput().utf16(),
+ 0,
+ FILE_SHARE_READ,
+ NULL,
+ OPEN_EXISTING,
+ FILE_FLAG_BACKUP_SEMANTICS,
+ NULL);
+ if (handle == INVALID_HANDLE_VALUE)
+ return false;
+
+ FILE_STANDARD_INFO info;
+ if (GetFileInformationByHandleEx(handle, FileStandardInfo, &info, sizeof(info)))
+ return info.NumberOfLinks > 1;
#else
Q_UNUSED(filePath)
#endif
diff --git a/src/libs/utils/deviceshell.cpp b/src/libs/utils/deviceshell.cpp
index ae983b6f482..f96c5da8f2d 100644
--- a/src/libs/utils/deviceshell.cpp
+++ b/src/libs/utils/deviceshell.cpp
@@ -104,7 +104,7 @@ RunResult DeviceShell::run(const CommandLine &cmd, const QByteArray &stdInData)
QWaitCondition waiter;
const int id = ++m_currentId;
- const auto it = m_commandOutput.insert(id, CommandRun{{-1, {}, {}}, &waiter});
+ m_commandOutput.insert(id, CommandRun{{-1, {}, {}}, &waiter});
QMetaObject::invokeMethod(m_shellProcess.get(), [this, id, cmd, stdInData] {
const QString command = QString("%1 \"%2\" %3\n").arg(id)
@@ -115,6 +115,7 @@ RunResult DeviceShell::run(const CommandLine &cmd, const QByteArray &stdInData)
waiter.wait(&m_commandMutex);
+ const auto it = m_commandOutput.constFind(id);
const RunResult result = *it;
m_commandOutput.erase(it);
diff --git a/src/libs/utils/deviceshell.h b/src/libs/utils/deviceshell.h
index 052aac1838a..e5bc4ad7afe 100644
--- a/src/libs/utils/deviceshell.h
+++ b/src/libs/utils/deviceshell.h
@@ -7,7 +7,7 @@
#include "fileutils.h"
-#include
+#include
#include
#include
#include
@@ -78,8 +78,7 @@ private:
int m_currentId{0};
QMutex m_commandMutex;
- // QMap is used here to preserve iterators
- QMap m_commandOutput;
+ QHash m_commandOutput;
QByteArray m_commandBuffer;
State m_shellScriptState = State::Unknown;
diff --git a/src/libs/utils/fancylineedit.cpp b/src/libs/utils/fancylineedit.cpp
index ae931ec1ca0..08b480c88cf 100644
--- a/src/libs/utils/fancylineedit.cpp
+++ b/src/libs/utils/fancylineedit.cpp
@@ -11,6 +11,7 @@
#include "utilsicons.h"
#include "utilstr.h"
+#include
#include
#include
#include
@@ -126,7 +127,7 @@ FancyLineEditPrivate::FancyLineEditPrivate(FancyLineEdit *parent) :
m_completionShortcut(completionShortcut()->key(), parent),
m_okTextColor(creatorTheme()->color(Theme::TextColorNormal)),
m_errorTextColor(creatorTheme()->color(Theme::TextColorError)),
- m_placeholderTextColor(creatorTheme()->color(Theme::PalettePlaceholderText))
+ m_placeholderTextColor(QApplication::palette().color(QPalette::PlaceholderText))
{
m_completionShortcut.setContext(Qt::WidgetShortcut);
diff --git a/src/libs/utils/filepath.cpp b/src/libs/utils/filepath.cpp
index ad871413a22..9059a37ecc3 100644
--- a/src/libs/utils/filepath.cpp
+++ b/src/libs/utils/filepath.cpp
@@ -1914,7 +1914,7 @@ FilePath FilePath::canonicalPath() const
return *this;
}
-#ifdef Q_OS_WINDOWS
+#ifdef Q_OS_WIN
DWORD flagsAndAttrs = FILE_ATTRIBUTE_NORMAL;
if (isDir())
flagsAndAttrs |= FILE_FLAG_BACKUP_SEMANTICS;
diff --git a/src/libs/utils/filestreamer.cpp b/src/libs/utils/filestreamer.cpp
index d24b61dbde3..eb9e057c1a1 100644
--- a/src/libs/utils/filestreamer.cpp
+++ b/src/libs/utils/filestreamer.cpp
@@ -30,7 +30,7 @@ public:
void start() {
QTC_ASSERT(!m_taskTree, return);
- const TaskItem task = m_filePath.needsDevice() ? remoteTask() : localTask();
+ const GroupItem task = m_filePath.needsDevice() ? remoteTask() : localTask();
m_taskTree.reset(new TaskTree({task}));
const auto finalize = [this](bool success) {
m_taskTree.release()->deleteLater();
@@ -49,8 +49,8 @@ protected:
std::unique_ptr m_taskTree;
private:
- virtual TaskItem remoteTask() = 0;
- virtual TaskItem localTask() = 0;
+ virtual GroupItem remoteTask() = 0;
+ virtual GroupItem localTask() = 0;
};
static void localRead(QPromise &promise, const FilePath &filePath)
@@ -84,7 +84,7 @@ signals:
void readyRead(const QByteArray &newData);
private:
- TaskItem remoteTask() final {
+ GroupItem remoteTask() final {
const auto setup = [this](Process &process) {
const QStringList args = {"if=" + m_filePath.path()};
const FilePath dd = m_filePath.withNewPath("dd");
@@ -96,7 +96,7 @@ private:
};
return ProcessTask(setup);
}
- TaskItem localTask() final {
+ GroupItem localTask() final {
const auto setup = [this](Async &async) {
async.setConcurrentCallData(localRead, m_filePath);
Async *asyncPtr = &async;
@@ -251,7 +251,7 @@ signals:
void started();
private:
- TaskItem remoteTask() final {
+ GroupItem remoteTask() final {
const auto setup = [this](Process &process) {
m_writeBuffer = new WriteBuffer(false, &process);
connect(m_writeBuffer, &WriteBuffer::writeRequested, &process, &Process::writeRaw);
@@ -272,7 +272,7 @@ private:
};
return ProcessTask(setup, finalize, finalize);
}
- TaskItem localTask() final {
+ GroupItem localTask() final {
const auto setup = [this](Async &async) {
m_writeBuffer = new WriteBuffer(isBuffered(), &async);
async.setConcurrentCallData(localWrite, m_filePath, m_writeData, m_writeBuffer);
@@ -375,8 +375,7 @@ static void transfer(QPromise &promise, const FilePath &source, const File
if (promise.isCanceled())
return;
- TaskTree taskTree(transferTask(source, destination));
- if (!taskTree.runBlocking(promise.future()))
+ if (!TaskTree::runBlocking(transferTask(source, destination), promise.future()))
promise.future().cancel();
}
@@ -391,7 +390,7 @@ public:
StreamResult m_streamResult = StreamResult::FinishedWithError;
std::unique_ptr m_taskTree;
- TaskItem task() {
+ GroupItem task() {
if (m_streamerMode == StreamMode::Reader)
return readerTask();
if (m_streamerMode == StreamMode::Writer)
@@ -400,7 +399,7 @@ public:
}
private:
- TaskItem readerTask() {
+ GroupItem readerTask() {
const auto setup = [this](FileStreamReader &reader) {
m_readBuffer.clear();
reader.setFilePath(m_source);
@@ -410,14 +409,14 @@ private:
};
return FileStreamReaderTask(setup);
}
- TaskItem writerTask() {
+ GroupItem writerTask() {
const auto setup = [this](FileStreamWriter &writer) {
writer.setFilePath(m_destination);
writer.setWriteData(m_writeBuffer);
};
return FileStreamWriterTask(setup);
}
- TaskItem transferTask() {
+ GroupItem transferTask() {
const auto setup = [this](Async &async) {
async.setConcurrentCallData(transfer, m_source, m_destination);
};
diff --git a/src/libs/utils/fileutils.cpp b/src/libs/utils/fileutils.cpp
index a6cbebf3681..2cecc2810b9 100644
--- a/src/libs/utils/fileutils.cpp
+++ b/src/libs/utils/fileutils.cpp
@@ -629,12 +629,18 @@ FilePathInfo::FileFlags fileInfoFlagsfromStatMode(const QString &hexString, int
FilePathInfo::FileFlags result;
- if (mode & IRUSR)
+ if (mode & IRUSR) {
result |= FilePathInfo::ReadOwnerPerm;
- if (mode & IWUSR)
+ result |= FilePathInfo::ReadUserPerm;
+ }
+ if (mode & IWUSR) {
result |= FilePathInfo::WriteOwnerPerm;
- if (mode & IXUSR)
+ result |= FilePathInfo::WriteUserPerm;
+ }
+ if (mode & IXUSR) {
result |= FilePathInfo::ExeOwnerPerm;
+ result |= FilePathInfo::ExeUserPerm;
+ }
if (mode & IRGRP)
result |= FilePathInfo::ReadGroupPerm;
if (mode & IWGRP)
diff --git a/src/libs/utils/layoutbuilder.cpp b/src/libs/utils/layoutbuilder.cpp
index bea7faafd3b..94aa80f02cc 100644
--- a/src/libs/utils/layoutbuilder.cpp
+++ b/src/libs/utils/layoutbuilder.cpp
@@ -676,24 +676,22 @@ LayoutItem st()
LayoutItem noMargin()
{
- LayoutItem item;
- item.onAdd = [](LayoutBuilder &builder) {
- if (auto layout = builder.stack.last().layout)
- layout->setContentsMargins(0, 0, 0, 0);
- else if (auto widget = builder.stack.last().widget)
- widget->setContentsMargins(0, 0, 0, 0);
- };
- return item;
+ return customMargin({});
}
LayoutItem normalMargin()
+{
+ return customMargin({9, 9, 9, 9});
+}
+
+LayoutItem customMargin(const QMargins &margin)
{
LayoutItem item;
- item.onAdd = [](LayoutBuilder &builder) {
+ item.onAdd = [margin](LayoutBuilder &builder) {
if (auto layout = builder.stack.last().layout)
- layout->setContentsMargins(9, 9, 9, 9);
+ layout->setContentsMargins(margin);
else if (auto widget = builder.stack.last().widget)
- widget->setContentsMargins(9, 9, 9, 9);
+ widget->setContentsMargins(margin);
};
return item;
}
diff --git a/src/libs/utils/layoutbuilder.h b/src/libs/utils/layoutbuilder.h
index d716ad034c5..4a756139897 100644
--- a/src/libs/utils/layoutbuilder.h
+++ b/src/libs/utils/layoutbuilder.h
@@ -11,12 +11,15 @@
#if defined(UTILS_LIBRARY)
# define QTCREATOR_UTILS_EXPORT Q_DECL_EXPORT
+#elif defined(UTILS_STATIC_LIBRARY)
+# define QTCREATOR_UTILS_EXPORT
#else
# define QTCREATOR_UTILS_EXPORT Q_DECL_IMPORT
#endif
QT_BEGIN_NAMESPACE
class QLayout;
+class QMargins;
class QObject;
class QWidget;
template T qobject_cast(QObject *object);
@@ -200,6 +203,7 @@ QTCREATOR_UTILS_EXPORT LayoutItem empty();
QTCREATOR_UTILS_EXPORT LayoutItem hr();
QTCREATOR_UTILS_EXPORT LayoutItem noMargin();
QTCREATOR_UTILS_EXPORT LayoutItem normalMargin();
+QTCREATOR_UTILS_EXPORT LayoutItem customMargin(const QMargins &margin);
QTCREATOR_UTILS_EXPORT LayoutItem withFormAlignment();
// "Setters"
diff --git a/src/libs/utils/tooltip/tips.cpp b/src/libs/utils/tooltip/tips.cpp
index ea20c735d80..180b8f960f2 100644
--- a/src/libs/utils/tooltip/tips.cpp
+++ b/src/libs/utils/tooltip/tips.cpp
@@ -133,9 +133,13 @@ TextTip::TextTip(QWidget *parent) : TipLabel(parent)
setWindowOpacity(style()->styleHint(QStyle::SH_ToolTipLabel_Opacity, nullptr, this) / 255.0);
}
-static bool likelyContainsLink(const QString &s)
+static bool likelyContainsLink(const QString &s, const Qt::TextFormat &format)
{
- return s.contains(QLatin1String("href"), Qt::CaseInsensitive);
+ if (s.contains(QLatin1String("href"), Qt::CaseInsensitive))
+ return true;
+ if (format == Qt::MarkdownText)
+ return s.contains("](");
+ return false;
}
void TextTip::setContent(const QVariant &content)
@@ -148,13 +152,13 @@ void TextTip::setContent(const QVariant &content)
m_format = item.second;
}
- bool containsLink = likelyContainsLink(m_text);
+ bool containsLink = likelyContainsLink(m_text, m_format);
setOpenExternalLinks(containsLink);
}
bool TextTip::isInteractive() const
{
- return likelyContainsLink(m_text);
+ return likelyContainsLink(m_text, m_format);
}
void TextTip::configure(const QPoint &pos)
diff --git a/src/plugins/android/androiddeployqtstep.cpp b/src/plugins/android/androiddeployqtstep.cpp
index f33ae5aa6b3..a9e9596e772 100644
--- a/src/plugins/android/androiddeployqtstep.cpp
+++ b/src/plugins/android/androiddeployqtstep.cpp
@@ -122,7 +122,7 @@ private:
QMap m_filesToPull;
QStringList m_androidABIs;
- BoolAspect *m_uninstallPreviousPackage = nullptr;
+ BoolAspect m_uninstallPreviousPackage{this};
bool m_uninstallPreviousPackageRun = false;
bool m_useAndroiddeployqt = false;
bool m_askForUninstall = false;
@@ -143,17 +143,16 @@ AndroidDeployQtStep::AndroidDeployQtStep(BuildStepList *parent, Id id)
setImmutable(true);
setUserExpanded(true);
- m_uninstallPreviousPackage = addAspect();
- m_uninstallPreviousPackage->setSettingsKey(UninstallPreviousPackageKey);
- m_uninstallPreviousPackage->setLabel(Tr::tr("Uninstall the existing app before deployment"),
+ m_uninstallPreviousPackage.setSettingsKey(UninstallPreviousPackageKey);
+ m_uninstallPreviousPackage.setLabel(Tr::tr("Uninstall the existing app before deployment"),
BoolAspect::LabelPlacement::AtCheckBox);
- m_uninstallPreviousPackage->setValue(false);
+ m_uninstallPreviousPackage.setValue(false);
const QtSupport::QtVersion * const qt = QtSupport::QtKitAspect::qtVersion(kit());
const bool forced = qt && qt->qtVersion() < QVersionNumber(5, 4, 0);
if (forced) {
- m_uninstallPreviousPackage->setValue(true);
- m_uninstallPreviousPackage->setEnabled(false);
+ m_uninstallPreviousPackage.setValue(true);
+ m_uninstallPreviousPackage.setEnabled(false);
}
connect(this, &AndroidDeployQtStep::askForUninstall,
@@ -274,7 +273,7 @@ bool AndroidDeployQtStep::init()
emit addOutput(Tr::tr("Deploying to %1").arg(m_serialNumber), OutputFormat::NormalMessage);
- m_uninstallPreviousPackageRun = m_uninstallPreviousPackage->value();
+ m_uninstallPreviousPackageRun = m_uninstallPreviousPackage();
if (m_uninstallPreviousPackageRun)
m_manifestName = AndroidManager::manifestPath(target());
diff --git a/src/plugins/autotest/ctest/ctestsettings.cpp b/src/plugins/autotest/ctest/ctestsettings.cpp
index e707c3edb09..a2f3e904270 100644
--- a/src/plugins/autotest/ctest/ctestsettings.cpp
+++ b/src/plugins/autotest/ctest/ctestsettings.cpp
@@ -20,8 +20,8 @@ CTestSettings::CTestSettings(Id settingsId)
setCategory(Constants::AUTOTEST_SETTINGS_CATEGORY);
setDisplayName(Tr::tr("CTest"));
- setLayouter([this](QWidget *w) {
- Row { Form {
+ setLayouter([this] {
+ return Row { Form {
outputOnFail, br,
scheduleRandom, br,
stopOnFailure, br,
@@ -39,7 +39,7 @@ CTestSettings::CTestSettings(Id settingsId)
Row { testLoad, threshold}
}
}
- }, st }.attachTo(w);
+ }, st };
});
outputOnFail.setSettingsKey("OutputOnFail");
diff --git a/src/plugins/autotest/testcodeparser.cpp b/src/plugins/autotest/testcodeparser.cpp
index 8553702432f..e78be579651 100644
--- a/src/plugins/autotest/testcodeparser.cpp
+++ b/src/plugins/autotest/testcodeparser.cpp
@@ -35,7 +35,7 @@ using namespace ProjectExplorer;
static bool isProjectParsing()
{
const BuildSystem *bs = ProjectManager::startupBuildSystem();
- return bs && bs->isParsing();
+ return bs && (bs->isParsing() || bs->isWaitingForParse());
}
TestCodeParser::TestCodeParser()
@@ -360,7 +360,7 @@ void TestCodeParser::scanForTests(const QSet &filePaths,
using namespace Tasking;
- QList tasks{parallelLimit(std::max(QThread::idealThreadCount() / 4, 1))};
+ QList tasks{parallelLimit(std::max(QThread::idealThreadCount() / 4, 1))};
for (const FilePath &file : filteredFiles) {
const auto setup = [this, codeParsers, file](Async &async) {
async.setConcurrentCallData(parseFileForTests, codeParsers, file);
diff --git a/src/plugins/autotest/testrunner.cpp b/src/plugins/autotest/testrunner.cpp
index 206dca8da41..23912f15d98 100644
--- a/src/plugins/autotest/testrunner.cpp
+++ b/src/plugins/autotest/testrunner.cpp
@@ -347,7 +347,7 @@ void TestRunner::runTestsHelper()
std::unique_ptr m_outputReader;
};
- QList tasks{optional};
+ QList tasks{finishAllAndDone};
for (ITestConfiguration *config : m_selectedTests) {
QTC_ASSERT(config, continue);
@@ -442,7 +442,7 @@ void TestRunner::runTestsHelper()
}
};
const Group group {
- optional,
+ finishAllAndDone,
Storage(storage),
onGroupSetup(onSetup),
ProcessTask(onProcessSetup, onProcessDone, onProcessDone)
diff --git a/src/plugins/autotoolsprojectmanager/autogenstep.cpp b/src/plugins/autotoolsprojectmanager/autogenstep.cpp
index c0a383205d0..090389716de 100644
--- a/src/plugins/autotoolsprojectmanager/autogenstep.cpp
+++ b/src/plugins/autotoolsprojectmanager/autogenstep.cpp
@@ -42,23 +42,23 @@ private:
void doRun() final;
bool m_runAutogen = false;
+ StringAspect m_arguments{this};
};
AutogenStep::AutogenStep(BuildStepList *bsl, Id id) : AbstractProcessStep(bsl, id)
{
- auto arguments = addAspect();
- arguments->setSettingsKey("AutotoolsProjectManager.AutogenStep.AdditionalArguments");
- arguments->setLabelText(Tr::tr("Arguments:"));
- arguments->setDisplayStyle(StringAspect::LineEditDisplay);
- arguments->setHistoryCompleter("AutotoolsPM.History.AutogenStepArgs");
+ m_arguments.setSettingsKey("AutotoolsProjectManager.AutogenStep.AdditionalArguments");
+ m_arguments.setLabelText(Tr::tr("Arguments:"));
+ m_arguments.setDisplayStyle(StringAspect::LineEditDisplay);
+ m_arguments.setHistoryCompleter("AutotoolsPM.History.AutogenStepArgs");
- connect(arguments, &BaseAspect::changed, this, [this] { m_runAutogen = true; });
+ connect(&m_arguments, &BaseAspect::changed, this, [this] { m_runAutogen = true; });
setWorkingDirectoryProvider([this] { return project()->projectDirectory(); });
- setCommandLineProvider([this, arguments] {
+ setCommandLineProvider([this] {
return CommandLine(project()->projectDirectory() / "autogen.sh",
- arguments->value(),
+ m_arguments(),
CommandLine::Raw);
});
diff --git a/src/plugins/bazaar/bazaarsettings.cpp b/src/plugins/bazaar/bazaarsettings.cpp
index 344bdc6a095..dc6ef77dd48 100644
--- a/src/plugins/bazaar/bazaarsettings.cpp
+++ b/src/plugins/bazaar/bazaarsettings.cpp
@@ -66,10 +66,10 @@ BazaarSettings::BazaarSettings()
timeout.setLabelText(Tr::tr("Timeout:"));
timeout.setSuffix(Tr::tr("s"));
- setLayouter([this](QWidget *widget) {
+ setLayouter([this] {
using namespace Layouting;
- Column {
+ return Column {
Group {
title(Tr::tr("Configuration")),
Row { binaryPath }
@@ -88,7 +88,7 @@ BazaarSettings::BazaarSettings()
Row { logCount, timeout, st }
},
st
- }.attachTo(widget);
+ };
});
}
diff --git a/src/plugins/beautifier/abstractsettings.cpp b/src/plugins/beautifier/abstractsettings.cpp
index 9b340cf9b37..1b4ff3aa10e 100644
--- a/src/plugins/beautifier/abstractsettings.cpp
+++ b/src/plugins/beautifier/abstractsettings.cpp
@@ -297,7 +297,7 @@ void AbstractSettings::read()
void AbstractSettings::readDocumentation()
{
- const FilePath filename = documentationFilePath();
+ const FilePath filename = documentationFilePath;
if (filename.isEmpty()) {
BeautifierPlugin::showError(Tr::tr("No documentation file specified."));
return;
diff --git a/src/plugins/beautifier/abstractsettings.h b/src/plugins/beautifier/abstractsettings.h
index 6b34baf58be..8e9ceea931d 100644
--- a/src/plugins/beautifier/abstractsettings.h
+++ b/src/plugins/beautifier/abstractsettings.h
@@ -51,7 +51,8 @@ public:
Utils::FilePathAspect command{this};
Utils::StringAspect supportedMimeTypes{this};
- Utils::FilePathAspect documentationFilePath; // Intentionally not saved.
+
+ Utils::FilePath documentationFilePath;
QVersionNumber version() const;
diff --git a/src/plugins/beautifier/artisticstyle/artisticstylesettings.cpp b/src/plugins/beautifier/artisticstyle/artisticstylesettings.cpp
index 36bd39c3c55..415d4ab20d6 100644
--- a/src/plugins/beautifier/artisticstyle/artisticstylesettings.cpp
+++ b/src/plugins/beautifier/artisticstyle/artisticstylesettings.cpp
@@ -59,11 +59,11 @@ ArtisticStyleSettings::ArtisticStyleSettings()
customStyle.setSettingsKey("customStyle");
- documentationFilePath.setFilePath(
+ documentationFilePath =
Core::ICore::userResourcePath(Beautifier::Constants::SETTINGS_DIRNAME)
.pathAppended(Beautifier::Constants::DOCUMENTATION_DIRNAME)
.pathAppended(SETTINGS_NAME)
- .stringAppended(".xml"));
+ .stringAppended(".xml");
read();
}
@@ -77,7 +77,7 @@ void ArtisticStyleSettings::createDocumentationFile() const
if (process.result() != ProcessResult::FinishedWithSuccess)
return;
- QFile file(documentationFilePath().toFSPathString());
+ QFile file(documentationFilePath.toFSPathString());
const QFileInfo fi(file);
if (!fi.exists())
fi.dir().mkpath(fi.absolutePath());
diff --git a/src/plugins/beautifier/clangformat/clangformatsettings.cpp b/src/plugins/beautifier/clangformat/clangformatsettings.cpp
index 40477b6ca82..6a31667edb7 100644
--- a/src/plugins/beautifier/clangformat/clangformatsettings.cpp
+++ b/src/plugins/beautifier/clangformat/clangformatsettings.cpp
@@ -63,16 +63,16 @@ ClangFormatSettings::ClangFormatSettings()
customStyle.setSettingsKey("customStyle");
- documentationFilePath.setFilePath(Core::ICore::userResourcePath(Constants::SETTINGS_DIRNAME)
+ documentationFilePath = Core::ICore::userResourcePath(Constants::SETTINGS_DIRNAME)
.pathAppended(Constants::DOCUMENTATION_DIRNAME)
- .pathAppended(SETTINGS_NAME).stringAppended(".xml"));
+ .pathAppended(SETTINGS_NAME).stringAppended(".xml");
read();
}
void ClangFormatSettings::createDocumentationFile() const
{
- QFile file(documentationFilePath().toFSPathString());
+ QFile file(documentationFilePath.toFSPathString());
const QFileInfo fi(file);
if (!fi.exists())
fi.dir().mkpath(fi.absolutePath());
diff --git a/src/plugins/beautifier/uncrustify/uncrustifysettings.cpp b/src/plugins/beautifier/uncrustify/uncrustifysettings.cpp
index 823471681fc..1aa9e8502c6 100644
--- a/src/plugins/beautifier/uncrustify/uncrustifysettings.cpp
+++ b/src/plugins/beautifier/uncrustify/uncrustifysettings.cpp
@@ -66,9 +66,9 @@ UncrustifySettings::UncrustifySettings()
specificConfigFile.setExpectedKind(Utils::PathChooser::File);
specificConfigFile.setPromptDialogFilter(Tr::tr("Uncrustify file (*.cfg)"));
- documentationFilePath.setFilePath(Core::ICore::userResourcePath(Constants::SETTINGS_DIRNAME)
+ documentationFilePath = Core::ICore::userResourcePath(Constants::SETTINGS_DIRNAME)
.pathAppended(Constants::DOCUMENTATION_DIRNAME)
- .pathAppended(SETTINGS_NAME).stringAppended(".xml"));
+ .pathAppended(SETTINGS_NAME).stringAppended(".xml");
read();
}
@@ -82,7 +82,7 @@ void UncrustifySettings::createDocumentationFile() const
if (process.result() != ProcessResult::FinishedWithSuccess)
return;
- QFile file(documentationFilePath().toFSPathString());
+ QFile file(documentationFilePath.toFSPathString());
const QFileInfo fi(file);
if (!fi.exists())
fi.dir().mkpath(fi.absolutePath());
diff --git a/src/plugins/clangcodemodel/clangdsemantichighlighting.cpp b/src/plugins/clangcodemodel/clangdsemantichighlighting.cpp
index 04bcc08fa2d..e1b82ab3770 100644
--- a/src/plugins/clangcodemodel/clangdsemantichighlighting.cpp
+++ b/src/plugins/clangcodemodel/clangdsemantichighlighting.cpp
@@ -421,8 +421,12 @@ void doSemanticHighlighting(
if (ClangdClient * const client = ClangModelManagerSupport::clientForFile(filePath))
client->setVirtualRanges(filePath, virtualRanges, docRevision);
}, Qt::QueuedConnection);
+#if QT_VERSION >= QT_VERSION_CHECK(6, 6, 0)
+ promise.addResults(results);
+#else
for (const HighlightingResult &r : results)
promise.addResult(r);
+#endif
}
}
diff --git a/src/plugins/clangcodemodel/clangmodelmanagersupport.cpp b/src/plugins/clangcodemodel/clangmodelmanagersupport.cpp
index 42e77c11a34..a14fb81b901 100644
--- a/src/plugins/clangcodemodel/clangmodelmanagersupport.cpp
+++ b/src/plugins/clangcodemodel/clangmodelmanagersupport.cpp
@@ -17,6 +17,7 @@
#include
#include
#include
+#include
#include
#include
@@ -686,6 +687,7 @@ void ClangModelManagerSupport::claimNonProjectSources(ClangdClient *client)
// for the respective project to force re-parsing of open documents and re-indexing.
// While this is not 100% bullet-proof, chances are good that in a typical session-based
// workflow, e.g. a git branch switch will hit at least one open file.
+// We also look for repository changes explicitly.
void ClangModelManagerSupport::watchForExternalChanges()
{
connect(DocumentManager::instance(), &DocumentManager::filesChangedExternally,
@@ -709,6 +711,23 @@ void ClangModelManagerSupport::watchForExternalChanges()
return;
}
});
+
+ connect(VcsManager::instance(), &VcsManager::repositoryChanged,
+ this, [this](const FilePath &repoDir) {
+ if (sessionModeEnabled()) {
+ if (ClangdClient * const client = clientForProject(nullptr))
+ scheduleClientRestart(client);
+ return;
+ }
+ for (const Project * const project : ProjectManager::projects()) {
+ const FilePath &projectDir = project->projectDirectory();
+ if (repoDir == projectDir || repoDir.isChildOf(projectDir)
+ || projectDir.isChildOf(repoDir)) {
+ if (ClangdClient * const client = clientForProject(project))
+ scheduleClientRestart(client);
+ }
+ }
+ });
}
// If Qt Creator changes a file that is not open (e.g. as part of a quickfix), we have to
diff --git a/src/plugins/clangtools/clangtoolruncontrol.cpp b/src/plugins/clangtools/clangtoolruncontrol.cpp
index 11353b04ae4..39de004ac89 100644
--- a/src/plugins/clangtools/clangtoolruncontrol.cpp
+++ b/src/plugins/clangtools/clangtoolruncontrol.cpp
@@ -183,7 +183,7 @@ void ClangToolRunWorker::start()
m_filesAnalyzed.clear();
m_filesNotAnalyzed.clear();
- QList tasks{parallelLimit(qMax(1, m_runSettings.parallelJobs()))};
+ QList tasks{parallelLimit(qMax(1, m_runSettings.parallelJobs()))};
for (const AnalyzeUnit &unit : std::as_const(unitsToProcess)) {
if (!m_diagnosticConfig.isEnabled(tool)
&& !m_runSettings.hasConfigFileForSourceFile(unit.file)) {
diff --git a/src/plugins/clangtools/clangtoolrunner.cpp b/src/plugins/clangtools/clangtoolrunner.cpp
index 40cbf75d47e..6681a9133dd 100644
--- a/src/plugins/clangtools/clangtoolrunner.cpp
+++ b/src/plugins/clangtools/clangtoolrunner.cpp
@@ -101,9 +101,9 @@ static FilePath createOutputFilePath(const FilePath &dirPath, const FilePath &fi
return {};
}
-TaskItem clangToolTask(const AnalyzeInputData &input,
- const AnalyzeSetupHandler &setupHandler,
- const AnalyzeOutputHandler &outputHandler)
+GroupItem clangToolTask(const AnalyzeInputData &input,
+ const AnalyzeSetupHandler &setupHandler,
+ const AnalyzeOutputHandler &outputHandler)
{
struct ClangToolStorage {
QString name;
@@ -186,7 +186,7 @@ TaskItem clangToolTask(const AnalyzeInputData &input,
Storage(storage),
onGroupSetup(onSetup),
Group {
- optional,
+ finishAllAndDone,
ProcessTask(onProcessSetup, onProcessDone, onProcessError)
}
};
diff --git a/src/plugins/clangtools/clangtoolrunner.h b/src/plugins/clangtools/clangtoolrunner.h
index 3a0f59f3417..a8d1204c224 100644
--- a/src/plugins/clangtools/clangtoolrunner.h
+++ b/src/plugins/clangtools/clangtoolrunner.h
@@ -10,7 +10,7 @@
#include
-namespace Tasking { class TaskItem; }
+namespace Tasking { class GroupItem; }
namespace ClangTools {
namespace Internal {
@@ -50,9 +50,9 @@ struct AnalyzeOutputData
using AnalyzeSetupHandler = std::function;
using AnalyzeOutputHandler = std::function;
-Tasking::TaskItem clangToolTask(const AnalyzeInputData &input,
- const AnalyzeSetupHandler &setupHandler,
- const AnalyzeOutputHandler &outputHandler);
+Tasking::GroupItem clangToolTask(const AnalyzeInputData &input,
+ const AnalyzeSetupHandler &setupHandler,
+ const AnalyzeOutputHandler &outputHandler);
} // namespace Internal
} // namespace ClangTools
diff --git a/src/plugins/clangtools/documentclangtoolrunner.cpp b/src/plugins/clangtools/documentclangtoolrunner.cpp
index 178022a91a6..93cd27bac38 100644
--- a/src/plugins/clangtools/documentclangtoolrunner.cpp
+++ b/src/plugins/clangtools/documentclangtoolrunner.cpp
@@ -190,7 +190,7 @@ void DocumentClangToolRunner::run()
vfso().update();
const ClangDiagnosticConfig config = diagnosticConfig(runSettings.diagnosticConfigId());
const Environment env = projectBuildEnvironment(project);
- QList tasks{parallel};
+ QList tasks{parallel};
const auto addClangTool = [this, &runSettings, &config, &env, &tasks](ClangToolType tool) {
if (!toolEnabled(tool, config, runSettings))
return;
@@ -209,7 +209,7 @@ void DocumentClangToolRunner::run()
return !m_document->isModified() || isVFSOverlaySupported(executable);
};
const auto outputHandler = [this](const AnalyzeOutputData &output) { onDone(output); };
- tasks.append(Group{optional, clangToolTask(input, setupHandler, outputHandler)});
+ tasks.append(Group{finishAllAndDone, clangToolTask(input, setupHandler, outputHandler)});
};
addClangTool(ClangToolType::Tidy);
addClangTool(ClangToolType::Clazy);
diff --git a/src/plugins/classview/classviewmanager.cpp b/src/plugins/classview/classviewmanager.cpp
index 7f4eeb955c6..90c834a6216 100644
--- a/src/plugins/classview/classviewmanager.cpp
+++ b/src/plugins/classview/classviewmanager.cpp
@@ -378,7 +378,7 @@ void Manager::gotoLocations(const QList &list)
int line;
int column;
textEditor->convertPosition(textEditor->position(), &line, &column);
- const SymbolLocation current(filePath, line, column);
+ const SymbolLocation current(filePath, line, column + 1);
if (auto it = locations.constFind(current), end = locations.constEnd(); it != end) {
// we already are at the symbol, cycle to next location
++it;
diff --git a/src/plugins/clearcase/clearcaseplugin.cpp b/src/plugins/clearcase/clearcaseplugin.cpp
index aa5c598c84c..943ffa194a4 100644
--- a/src/plugins/clearcase/clearcaseplugin.cpp
+++ b/src/plugins/clearcase/clearcaseplugin.cpp
@@ -227,6 +227,10 @@ private:
Q_INVOKABLE void updateStatusActions();
QString commitDisplayName() const final;
+ QString commitAbortTitle() const final;
+ QString commitAbortMessage() const final;
+ QString commitErrorMessage(const QString &error) const final;
+
void checkOutCurrentFile();
void addCurrentFile();
void undoCheckOutCurrent();
@@ -948,9 +952,27 @@ void ClearCasePluginPrivate::updateActions(VcsBasePluginPrivate::ActionState as)
QString ClearCasePluginPrivate::commitDisplayName() const
{
+ //: Name of the "commit" action of the VCS
return Tr::tr("Check In");
}
+QString ClearCasePluginPrivate::commitAbortTitle() const
+{
+ return Tr::tr("Close Check In Editor");
+}
+
+QString ClearCasePluginPrivate::commitAbortMessage() const
+{
+ return Tr::tr("Closing this editor will abort the check in.");
+}
+
+QString ClearCasePluginPrivate::commitErrorMessage(const QString &error) const
+{
+ if (error.isEmpty())
+ return Tr::tr("Cannot check in.");
+ return Tr::tr("Cannot check in: %1.").arg(error);
+}
+
void ClearCasePluginPrivate::checkOutCurrentFile()
{
const VcsBasePluginState state = currentState();
diff --git a/src/plugins/cmakeprojectmanager/cmakeeditor.cpp b/src/plugins/cmakeprojectmanager/cmakeeditor.cpp
index 3411fd85b58..5193661e57b 100644
--- a/src/plugins/cmakeprojectmanager/cmakeeditor.cpp
+++ b/src/plugins/cmakeprojectmanager/cmakeeditor.cpp
@@ -157,7 +157,7 @@ void CMakeEditorWidget::findLinkAt(const QTextCursor &cursor,
// find the beginning of a filename
QString buffer;
- int beginPos = column - 1;
+ int beginPos = column;
while (beginPos >= 0) {
if (isValidFileNameChar(block, beginPos)) {
buffer.prepend(block.at(beginPos));
diff --git a/src/plugins/cmakeprojectmanager/cmakeformatter.cpp b/src/plugins/cmakeprojectmanager/cmakeformatter.cpp
index 295b664b9a0..dca6d47e203 100644
--- a/src/plugins/cmakeprojectmanager/cmakeformatter.cpp
+++ b/src/plugins/cmakeprojectmanager/cmakeformatter.cpp
@@ -65,9 +65,9 @@ public:
autoFormatMime.setDefaultValue("text/x-cmake");
autoFormatMime.setLabelText(Tr::tr("Restrict to MIME types:"));
- setLayouter([this](QWidget *widget) {
+ setLayouter([this] {
using namespace Layouting;
- Column {
+ return Column {
Row { Tr::tr("CMakeFormat command:"), command },
Space(10),
Group {
@@ -79,7 +79,7 @@ public:
}
},
st
- }.attachTo(widget);
+ };
});
ActionContainer *menu = ActionManager::createMenu(Constants::CMAKEFORMATTER_MENU_ID);
diff --git a/src/plugins/conan/conaninstallstep.cpp b/src/plugins/conan/conaninstallstep.cpp
index cae573845e8..2a634190365 100644
--- a/src/plugins/conan/conaninstallstep.cpp
+++ b/src/plugins/conan/conaninstallstep.cpp
@@ -112,7 +112,7 @@ ConanInstallStep::ConanInstallStep(BuildStepList *bsl, Id id)
return param.summary(displayName());
});
- connect(ProjectManager::instance(), &ProjectManager::projectAdded, this, [this](Project * project) {
+ connect(ProjectManager::instance(), &ProjectManager::projectAdded, this, [](Project * project) {
connect(project, &Project::addedTarget, project, [project] (Target *target) {
connectTarget(project, target);
});
diff --git a/src/plugins/copilot/authwidget.cpp b/src/plugins/copilot/authwidget.cpp
index 31b4660b680..f29e3d3a150 100644
--- a/src/plugins/copilot/authwidget.cpp
+++ b/src/plugins/copilot/authwidget.cpp
@@ -93,7 +93,7 @@ void AuthWidget::updateClient(const Utils::FilePath &nodeJs, const Utils::FilePa
m_client = nullptr;
setState(Tr::tr("Sign in"), false);
m_button->setEnabled(false);
- if (!nodeJs.exists() || !agent.exists()) {
+ if (!nodeJs.isExecutableFile() || !agent.exists()) {
return;
}
diff --git a/src/plugins/copilot/copilot.qbs b/src/plugins/copilot/copilot.qbs
index cf59d954caa..714c45543d4 100644
--- a/src/plugins/copilot/copilot.qbs
+++ b/src/plugins/copilot/copilot.qbs
@@ -5,6 +5,7 @@ QtcPlugin {
Depends { name: "Core" }
Depends { name: "LanguageClient" }
+ Depends { name: "ProjectExplorer" }
Depends { name: "TextEditor" }
Depends { name: "Qt"; submodules: ["widgets", "xml", "network"] }
diff --git a/src/plugins/copilot/copilothoverhandler.cpp b/src/plugins/copilot/copilothoverhandler.cpp
index b252cedc77d..135cbd8390f 100644
--- a/src/plugins/copilot/copilothoverhandler.cpp
+++ b/src/plugins/copilot/copilothoverhandler.cpp
@@ -139,6 +139,7 @@ void CopilotHoverHandler::identifyMatch(TextEditorWidget *editorWidget,
void CopilotHoverHandler::operateTooltip(TextEditorWidget *editorWidget, const QPoint &point)
{
+ Q_UNUSED(point)
auto *suggestion = dynamic_cast(TextDocumentLayout::suggestion(m_block));
if (!suggestion)
@@ -147,8 +148,12 @@ void CopilotHoverHandler::operateTooltip(TextEditorWidget *editorWidget, const Q
auto tooltipWidget = new CopilotCompletionToolTip(suggestion->completions(),
suggestion->currentCompletion(),
editorWidget);
- const qreal deltay = 2 * editorWidget->textDocument()->fontSettings().lineSpacing();
- ToolTip::show(point - QPoint{0, int(deltay)}, tooltipWidget, editorWidget);
+
+ const QRect cursorRect = editorWidget->cursorRect(editorWidget->textCursor());
+ QPoint pos = editorWidget->viewport()->mapToGlobal(cursorRect.topLeft())
+ - Utils::ToolTip::offsetFromPosition();
+ pos.ry() -= tooltipWidget->sizeHint().height();
+ ToolTip::show(pos, tooltipWidget, editorWidget);
}
} // namespace Copilot::Internal
diff --git a/src/plugins/copilot/copilotplugin.cpp b/src/plugins/copilot/copilotplugin.cpp
index 43effda321c..526a6061cbe 100644
--- a/src/plugins/copilot/copilotplugin.cpp
+++ b/src/plugins/copilot/copilotplugin.cpp
@@ -120,6 +120,9 @@ void CopilotPlugin::extensionsInitialized()
void CopilotPlugin::restartClient()
{
LanguageClient::LanguageClientManager::shutdownClient(m_client);
+
+ if (!CopilotSettings::instance().nodeJsPath().isExecutableFile())
+ return;
m_client = new CopilotClient(CopilotSettings::instance().nodeJsPath(),
CopilotSettings::instance().distPath());
}
diff --git a/src/plugins/copilot/copilotsettings.cpp b/src/plugins/copilot/copilotsettings.cpp
index bac2c176afa..b8567f2feb4 100644
--- a/src/plugins/copilot/copilotsettings.cpp
+++ b/src/plugins/copilot/copilotsettings.cpp
@@ -53,7 +53,7 @@ CopilotSettings::CopilotSettings()
nodeJsPath.setHistoryCompleter("Copilot.NodePath.History");
nodeJsPath.setDisplayName(Tr::tr("Node.js Path"));
nodeJsPath.setToolTip(
- Tr::tr("Select path to node.js executable. See https://nodejs.org/de/download/"
+ Tr::tr("Select path to node.js executable. See https://nodejs.org/en/download/"
"for installation instructions."));
distPath.setExpectedKind(PathChooser::File);
@@ -63,7 +63,7 @@ CopilotSettings::CopilotSettings()
distPath.setHistoryCompleter("Copilot.DistPath.History");
distPath.setDisplayName(Tr::tr("Agent.js path"));
distPath.setToolTip(Tr::tr(
- "Select path to agent.js in copilot neovim plugin. See "
+ "Select path to agent.js in Copilot Neovim plugin. See "
"https://github.com/github/copilot.vim#getting-started for installation instructions."));
autoComplete.setDisplayName(Tr::tr("Auto Complete"));
@@ -71,7 +71,7 @@ CopilotSettings::CopilotSettings()
autoComplete.setLabelText(Tr::tr("Request completions automatically"));
autoComplete.setDefaultValue(true);
autoComplete.setToolTip(Tr::tr("Automatically request suggestions for the current text cursor "
- "position after changes to the document"));
+ "position after changes to the document."));
initEnableAspect(enableCopilot);
}
diff --git a/src/plugins/coreplugin/actionmanager/command.cpp b/src/plugins/coreplugin/actionmanager/command.cpp
index ab78bf50892..23b398791f2 100644
--- a/src/plugins/coreplugin/actionmanager/command.cpp
+++ b/src/plugins/coreplugin/actionmanager/command.cpp
@@ -347,8 +347,10 @@ void Internal::CommandPrivate::setCurrentContext(const Context &context)
m_context = context;
QAction *currentAction = nullptr;
- for (int i = 0; i < m_context.size(); ++i) {
- if (QAction *a = m_contextActionMap.value(m_context.at(i), nullptr)) {
+ for (const Id &id : std::as_const(m_context)) {
+ if (id == Constants::C_GLOBAL_CUTOFF)
+ break;
+ if (QAction *a = m_contextActionMap.value(id, nullptr)) {
currentAction = a;
break;
}
diff --git a/src/plugins/coreplugin/actionmanager/commandmappings.cpp b/src/plugins/coreplugin/actionmanager/commandmappings.cpp
index bfc62c3d184..15765698cbd 100644
--- a/src/plugins/coreplugin/actionmanager/commandmappings.cpp
+++ b/src/plugins/coreplugin/actionmanager/commandmappings.cpp
@@ -6,18 +6,17 @@
#include
#include
-#include
#include
+#include
+#include
#include
#include
#include
-#include
#include
#include
#include
#include
-#include
Q_DECLARE_METATYPE(Core::Internal::ShortcutItem*)
@@ -32,13 +31,10 @@ public:
CommandMappingsPrivate(CommandMappings *parent)
: q(parent)
{
- groupBox = new QGroupBox(parent);
- groupBox->setTitle(::Core::Tr::tr("Command Mappings"));
-
- filterEdit = new FancyLineEdit(groupBox);
+ filterEdit = new FancyLineEdit;
filterEdit->setFiltering(true);
- commandList = new QTreeWidget(groupBox);
+ commandList = new QTreeWidget;
commandList->setRootIsDecorated(false);
commandList->setUniformRowHeights(true);
commandList->setSortingEnabled(true);
@@ -49,33 +45,28 @@ public:
item->setText(1, ::Core::Tr::tr("Label"));
item->setText(0, ::Core::Tr::tr("Command"));
- defaultButton = new QPushButton(::Core::Tr::tr("Reset All"), groupBox);
+ defaultButton = new QPushButton(::Core::Tr::tr("Reset All"));
defaultButton->setToolTip(::Core::Tr::tr("Reset all to default."));
- resetButton = new QPushButton(::Core::Tr::tr("Reset"), groupBox);
+ resetButton = new QPushButton(::Core::Tr::tr("Reset"));
resetButton->setToolTip(::Core::Tr::tr("Reset to default."));
resetButton->setVisible(false);
- importButton = new QPushButton(::Core::Tr::tr("Import..."), groupBox);
- exportButton = new QPushButton(::Core::Tr::tr("Export..."), groupBox);
+ importButton = new QPushButton(::Core::Tr::tr("Import..."));
+ exportButton = new QPushButton(::Core::Tr::tr("Export..."));
- auto hboxLayout1 = new QHBoxLayout();
- hboxLayout1->addWidget(defaultButton);
- hboxLayout1->addWidget(resetButton);
- hboxLayout1->addStretch();
- hboxLayout1->addWidget(importButton);
- hboxLayout1->addWidget(exportButton);
-
- auto hboxLayout = new QHBoxLayout();
- hboxLayout->addWidget(filterEdit);
-
- auto vboxLayout1 = new QVBoxLayout(groupBox);
- vboxLayout1->addLayout(hboxLayout);
- vboxLayout1->addWidget(commandList);
- vboxLayout1->addLayout(hboxLayout1);
-
- auto vboxLayout = new QVBoxLayout(parent);
- vboxLayout->addWidget(groupBox);
+ using namespace Layouting;
+ Column {
+ Group {
+ title(::Core::Tr::tr("Command Mappings")),
+ bindTo(&groupBox),
+ Column {
+ filterEdit,
+ commandList,
+ Row { defaultButton, resetButton, st, importButton, exportButton },
+ },
+ },
+ }.attachTo(parent);
q->connect(exportButton, &QPushButton::clicked,
q, &CommandMappings::exportAction);
diff --git a/src/plugins/coreplugin/coreconstants.h b/src/plugins/coreplugin/coreconstants.h
index 0b4831e51b6..513d02eb6ee 100644
--- a/src/plugins/coreplugin/coreconstants.h
+++ b/src/plugins/coreplugin/coreconstants.h
@@ -46,6 +46,11 @@ const char C_EDITORMANAGER[] = "Core.EditorManager";
const char C_NAVIGATION_PANE[] = "Core.NavigationPane";
const char C_PROBLEM_PANE[] = "Core.ProblemPane";
const char C_GENERAL_OUTPUT_PANE[] = "Core.GeneralOutputPane";
+// Special context that leads to all "more specific" contexts to be ignored.
+// If you use Context(mycontextId, C_GLOBAL_CUTOFF) for a widget that has focus,
+// mycontextId will be enabled but the contexts for all parent widgets, the manually added
+// "additional" contexts, and the global context will be turned off.
+const char C_GLOBAL_CUTOFF[] = "Global Cutoff";
// Default editor kind
const char K_DEFAULT_TEXT_EDITOR_DISPLAY_NAME[] = QT_TRANSLATE_NOOP("QtC::Core", "Plain Text Editor");
diff --git a/src/plugins/coreplugin/dialogs/ioptionspage.cpp b/src/plugins/coreplugin/dialogs/ioptionspage.cpp
index 1912045af53..4def6095a11 100644
--- a/src/plugins/coreplugin/dialogs/ioptionspage.cpp
+++ b/src/plugins/coreplugin/dialogs/ioptionspage.cpp
@@ -199,15 +199,6 @@ void IOptionsPage::setSettings(AspectContainer *settings)
m_settings = settings;
}
-void IOptionsPage::setLayouter(const std::function &layouter)
-{
- m_widgetCreator = [layouter] {
- auto widget = new IOptionsPageWidget;
- layouter(widget);
- return widget;
- };
-}
-
void IOptionsPage::setLayouter(const std::function &layouter)
{
m_widgetCreator = [layouter] {
diff --git a/src/plugins/coreplugin/dialogs/ioptionspage.h b/src/plugins/coreplugin/dialogs/ioptionspage.h
index a38bf863c36..f4801b7c734 100644
--- a/src/plugins/coreplugin/dialogs/ioptionspage.h
+++ b/src/plugins/coreplugin/dialogs/ioptionspage.h
@@ -74,7 +74,6 @@ protected:
void setCategoryIcon(const Utils::Icon &categoryIcon) { m_categoryIcon = categoryIcon; }
void setCategoryIconPath(const Utils::FilePath &categoryIconPath);
void setSettings(Utils::AspectContainer *settings);
- void setLayouter(const std::function &layouter);
void setLayouter(const std::function &layouter);
// Used in FontSettingsPage. FIXME?
diff --git a/src/plugins/coreplugin/editormanager/editormanager.cpp b/src/plugins/coreplugin/editormanager/editormanager.cpp
index e7147e94cea..81262f5ebfe 100644
--- a/src/plugins/coreplugin/editormanager/editormanager.cpp
+++ b/src/plugins/coreplugin/editormanager/editormanager.cpp
@@ -42,7 +42,6 @@
#include
#include
#include
-#include
#include
#include
#include
@@ -70,6 +69,7 @@
#include
#include
#include
+#include
#include
#include
#include
@@ -3325,9 +3325,7 @@ IEditor *EditorManager::openEditorWithContents(Id editorId,
EditorManager::gotoOtherSplit();
QApplication::setOverrideCursor(QCursor(Qt::WaitCursor));
- Utils::ExecuteOnDestruction appRestoreCursor(&QApplication::restoreOverrideCursor);
- Q_UNUSED(appRestoreCursor)
-
+ const auto cleanup = qScopeGuard(&QApplication::restoreOverrideCursor);
const QString title = makeTitleUnique(titlePattern);
diff --git a/src/plugins/coreplugin/locator/ilocatorfilter.cpp b/src/plugins/coreplugin/locator/ilocatorfilter.cpp
index f6b39996d8f..0a4665361d2 100644
--- a/src/plugins/coreplugin/locator/ilocatorfilter.cpp
+++ b/src/plugins/coreplugin/locator/ilocatorfilter.cpp
@@ -450,7 +450,7 @@ void LocatorMatcher::start()
collectorStorage->m_collector = nullptr;
};
- QList parallelTasks {parallelLimit(d->m_parallelLimit)};
+ QList parallelTasks {parallelLimit(d->m_parallelLimit)};
const auto onSetup = [this, collectorStorage](const TreeStorage &storage,
int index) {
@@ -470,7 +470,7 @@ void LocatorMatcher::start()
for (const LocatorMatcherTask &task : std::as_const(d->m_tasks)) {
const auto storage = task.storage;
const Group group {
- optional,
+ finishAllAndDone,
Storage(storage),
onGroupSetup(onSetup(storage, index)),
onGroupDone(onDone(storage)),
@@ -597,7 +597,7 @@ QString ILocatorFilter::shortcutString() const
\internal
Sets the refresh recipe for refreshing cached data.
*/
-void ILocatorFilter::setRefreshRecipe(const std::optional &recipe)
+void ILocatorFilter::setRefreshRecipe(const std::optional &recipe)
{
m_refreshRecipe = recipe;
}
@@ -606,7 +606,7 @@ void ILocatorFilter::setRefreshRecipe(const std::optional &recipe)
Returns the refresh recipe for refreshing cached data. By default, the locator filter has
no recipe set, so that it won't be refreshed.
*/
-std::optional ILocatorFilter::refreshRecipe() const
+std::optional ILocatorFilter::refreshRecipe() const
{
return m_refreshRecipe;
}
diff --git a/src/plugins/coreplugin/locator/ilocatorfilter.h b/src/plugins/coreplugin/locator/ilocatorfilter.h
index b008c12bb5c..fbc68bc647c 100644
--- a/src/plugins/coreplugin/locator/ilocatorfilter.h
+++ b/src/plugins/coreplugin/locator/ilocatorfilter.h
@@ -139,7 +139,7 @@ class CORE_EXPORT LocatorMatcherTask final
public:
// The main task. Initial data (searchTerm) should be taken from storage.input().
// Results reporting is done via the storage.reportOutput().
- Tasking::TaskItem task = Tasking::Group{};
+ Tasking::GroupItem task = Tasking::Group{};
// When constructing the task, don't place the storage inside the task above.
Tasking::TreeStorage storage;
@@ -270,8 +270,8 @@ protected:
virtual void saveState(QJsonObject &object) const;
virtual void restoreState(const QJsonObject &object);
- void setRefreshRecipe(const std::optional &recipe);
- std::optional refreshRecipe() const;
+ void setRefreshRecipe(const std::optional &recipe);
+ std::optional refreshRecipe() const;
static bool isOldSetting(const QByteArray &state);
@@ -289,7 +289,7 @@ private:
QString m_description;
QString m_defaultShortcut;
std::optional m_defaultSearchText;
- std::optional m_refreshRecipe;
+ std::optional m_refreshRecipe;
QKeySequence m_defaultKeySequence;
bool m_defaultIncludedByDefault = false;
bool m_includedByDefault = m_defaultIncludedByDefault;
diff --git a/src/plugins/coreplugin/locator/locator.cpp b/src/plugins/coreplugin/locator/locator.cpp
index 55b82920329..cefce35a5b1 100644
--- a/src/plugins/coreplugin/locator/locator.cpp
+++ b/src/plugins/coreplugin/locator/locator.cpp
@@ -381,14 +381,14 @@ void Locator::refresh(const QList &filters)
m_refreshingFilters = Utils::filteredUnique(m_refreshingFilters + filters);
using namespace Tasking;
- QList tasks{parallel};
+ QList tasks{parallel};
for (ILocatorFilter *filter : std::as_const(m_refreshingFilters)) {
const auto task = filter->refreshRecipe();
if (!task.has_value())
continue;
const Group group {
- optional,
+ finishAllAndDone,
*task,
onGroupDone([this, filter] { m_refreshingFilters.removeOne(filter); })
};
diff --git a/src/plugins/coreplugin/loggingviewer.cpp b/src/plugins/coreplugin/loggingviewer.cpp
index a81ed5936db..63fba41a4df 100644
--- a/src/plugins/coreplugin/loggingviewer.cpp
+++ b/src/plugins/coreplugin/loggingviewer.cpp
@@ -11,7 +11,6 @@
#include
#include
-#include
#include
#include
#include
@@ -33,6 +32,7 @@
#include
#include
#include
+#include
#include
#include
#include
@@ -591,7 +591,7 @@ void LoggingViewManagerWidget::saveLoggingsToFile() const
{
// should we just let it continue without temporarily disabling?
const bool enabled = m_manager->isEnabled();
- Utils::ExecuteOnDestruction exec([this, enabled] { m_manager->setEnabled(enabled); });
+ const auto cleanup = qScopeGuard([this, enabled] { m_manager->setEnabled(enabled); });
if (enabled)
m_manager->setEnabled(false);
const Utils::FilePath fp = Utils::FileUtils::getSaveFilePath(ICore::dialogParent(),
diff --git a/src/plugins/coreplugin/plugindialog.cpp b/src/plugins/coreplugin/plugindialog.cpp
index f6ea25e719c..24d8c8dff12 100644
--- a/src/plugins/coreplugin/plugindialog.cpp
+++ b/src/plugins/coreplugin/plugindialog.cpp
@@ -17,14 +17,11 @@
#include
#include
+#include
-#include
#include
#include
-#include
-#include
#include
-#include
using namespace Utils;
@@ -35,30 +32,27 @@ PluginDialog::PluginDialog(QWidget *parent)
: QDialog(parent),
m_view(new ExtensionSystem::PluginView(this))
{
- auto vl = new QVBoxLayout(this);
-
- auto filterLayout = new QHBoxLayout;
- vl->addLayout(filterLayout);
auto filterEdit = new Utils::FancyLineEdit(this);
filterEdit->setFocus();
filterEdit->setFiltering(true);
connect(filterEdit, &Utils::FancyLineEdit::filterChanged,
m_view, &ExtensionSystem::PluginView::setFilter);
- filterLayout->addWidget(filterEdit);
-
- vl->addWidget(m_view);
-
- m_detailsButton = new QPushButton(Tr::tr("Details"), this);
- m_errorDetailsButton = new QPushButton(Tr::tr("Error Details"), this);
- m_installButton = new QPushButton(Tr::tr("Install Plugin..."), this);
- m_detailsButton->setEnabled(false);
- m_errorDetailsButton->setEnabled(false);
auto buttonBox = new QDialogButtonBox(QDialogButtonBox::Ok | QDialogButtonBox::Cancel);
- buttonBox->addButton(m_detailsButton, QDialogButtonBox::ActionRole);
- buttonBox->addButton(m_errorDetailsButton, QDialogButtonBox::ActionRole);
- buttonBox->addButton(m_installButton, QDialogButtonBox::ActionRole);
- vl->addWidget(buttonBox);
+ m_detailsButton = buttonBox->addButton(Tr::tr("Details"), QDialogButtonBox::ActionRole);
+ m_detailsButton->setEnabled(false);
+ m_errorDetailsButton = buttonBox->addButton(Tr::tr("Error Details"),
+ QDialogButtonBox::ActionRole);
+ m_errorDetailsButton->setEnabled(false);
+ m_installButton = buttonBox->addButton(Tr::tr("Install Plugin..."),
+ QDialogButtonBox::ActionRole);
+
+ using namespace Layouting;
+ Column {
+ filterEdit,
+ m_view,
+ buttonBox,
+ }.attachTo(this);
resize(650, 400);
setWindowTitle(Tr::tr("Installed Plugins"));
@@ -116,13 +110,16 @@ void PluginDialog::openDetails(ExtensionSystem::PluginSpec *spec)
return;
QDialog dialog(this);
dialog.setWindowTitle(Tr::tr("Plugin Details of %1").arg(spec->name()));
- auto layout = new QVBoxLayout;
- dialog.setLayout(layout);
auto details = new ExtensionSystem::PluginDetailsView(&dialog);
- layout->addWidget(details);
details->update(spec);
QDialogButtonBox *buttons = new QDialogButtonBox(QDialogButtonBox::Close, Qt::Horizontal, &dialog);
- layout->addWidget(buttons);
+
+ using namespace Layouting;
+ Column {
+ details,
+ buttons,
+ }.attachTo(&dialog);
+
connect(buttons, &QDialogButtonBox::accepted, &dialog, &QDialog::accept);
connect(buttons, &QDialogButtonBox::rejected, &dialog, &QDialog::reject);
dialog.resize(400, 500);
@@ -136,13 +133,16 @@ void PluginDialog::openErrorDetails()
return;
QDialog dialog(this);
dialog.setWindowTitle(Tr::tr("Plugin Errors of %1").arg(spec->name()));
- auto layout = new QVBoxLayout;
- dialog.setLayout(layout);
auto errors = new ExtensionSystem::PluginErrorView(&dialog);
- layout->addWidget(errors);
errors->update(spec);
QDialogButtonBox *buttons = new QDialogButtonBox(QDialogButtonBox::Close, Qt::Horizontal, &dialog);
- layout->addWidget(buttons);
+
+ using namespace Layouting;
+ Column {
+ errors,
+ buttons,
+ }.attachTo(&dialog);
+
connect(buttons, &QDialogButtonBox::accepted, &dialog, &QDialog::accept);
connect(buttons, &QDialogButtonBox::rejected, &dialog, &QDialog::reject);
dialog.resize(500, 300);
diff --git a/src/plugins/coreplugin/plugininstallwizard.cpp b/src/plugins/coreplugin/plugininstallwizard.cpp
index c5694016d49..ac2dfd6c240 100644
--- a/src/plugins/coreplugin/plugininstallwizard.cpp
+++ b/src/plugins/coreplugin/plugininstallwizard.cpp
@@ -15,6 +15,7 @@
#include