Merge remote-tracking branch 'origin/11.0'

Conflicts:
	tests/manual/subdirfileiterator/tst_subdirfileiterator.cpp

Change-Id: I6fa8fbed152efc4033fa69e1ab67ced7e2ad35bc
This commit is contained in:
Eike Ziller
2023-06-06 16:44:44 +02:00
276 changed files with 5450 additions and 3543 deletions

223
dist/changelog/changes-11.0.0.md vendored Normal file
View File

@@ -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

View File

@@ -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

View File

@@ -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.
*/

View File

@@ -18199,16 +18199,16 @@ Möchten Sie sie jetzt auschecken?</translation>
<translation>Bytes</translation>
</message>
<message>
<source>KB</source>
<translation>KB</translation>
<source>KiB</source>
<translation>KiB</translation>
</message>
<message>
<source>GB</source>
<translation>GB</translation>
<source>GiB</source>
<translation>GiB</translation>
</message>
<message>
<source>TB</source>
<translation>TB</translation>
<source>TiB</source>
<translation>TiB</translation>
</message>
<message>
<source>Enable crash reporting</source>
@@ -27194,12 +27194,8 @@ zu deaktivieren, deaktiviert auch die folgenden Plugins:
<translation>Privat</translation>
</message>
<message>
<source>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.</source>
<translation>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.</translation>
<source>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.</source>
<translation>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.</translation>
</message>
<message>
<source>Tag names to apply; comma-separated.</source>
@@ -39112,7 +39108,7 @@ Sie werden erhalten.</numerusform>
</message>
<message>
<source>&amp;Configure Project</source>
<translation>Projekt &amp;Konfigurieren</translation>
<translation>Projekt &amp;konfigurieren</translation>
</message>
<message>
<source>Enable Kit for Project &quot;%1&quot;</source>
@@ -53204,12 +53200,9 @@ Wird ein Problem gefunden, dann wird die Anwendung angehalten und kann untersuch
<source>Hint: The second line of a commit message should be empty.</source>
<translation>Hinweis: Die zweite Zeile der Beschreibung sollte leer sein.</translation>
</message>
<message numerus="yes">
<source>&lt;p&gt;Writing good commit messages&lt;/p&gt;&lt;ul&gt;&lt;li&gt;Avoid very short commit messages.&lt;/li&gt;&lt;li&gt;Consider the first line as subject (like in email) and keep it shorter than %n characters.&lt;/li&gt;&lt;li&gt;After an empty second line, a longer description can be added.&lt;/li&gt;&lt;li&gt;Describe why the change was done, not how it was done.&lt;/li&gt;&lt;/ul&gt;</source>
<translation>
<numerusform>&lt;p&gt;Gute Beschreibungen für Commits schreiben&lt;/p&gt;&lt;ul&gt;&lt;li&gt;Vermeiden Sie sehr kurze Beschreibungen.&lt;/li&gt;&lt;li&gt;Betrachten Sie die erste Zeile als Betreff (wie in einer E-Mail) und halten Sie sie kürzer als ein Zeichen.&lt;/li&gt;&lt;li&gt;Eine längere Beschreibung kann nach einer leeren zweiten Zeile folgen.&lt;/li&gt;&lt;li&gt;Beschreiben Sie, weshalb die Änderung vorgenommen wurde, nicht wie sie vorgenommen wurde.&lt;/li&gt;&lt;/ul&gt;</numerusform>
<numerusform>&lt;p&gt;Gute Beschreibungen für Commits schreiben&lt;/p&gt;&lt;ul&gt;&lt;li&gt;Vermeiden Sie sehr kurze Beschreibungen.&lt;/li&gt;&lt;li&gt;Betrachten Sie die erste Zeile als Betreff (wie in einer E-Mail) und halten Sie sie kürzer als %n Zeichen.&lt;/li&gt;&lt;li&gt;Eine längere Beschreibung kann nach einer leeren zweiten Zeile folgen.&lt;/li&gt;&lt;li&gt;Beschreiben Sie, weshalb die Änderung vorgenommen wurde, nicht wie sie vorgenommen wurde.&lt;/li&gt;&lt;/ul&gt;</numerusform>
</translation>
<message>
<source>&lt;p&gt;Writing good commit messages&lt;/p&gt;&lt;ul&gt;&lt;li&gt;Avoid very short commit messages.&lt;/li&gt;&lt;li&gt;Consider the first line as a subject (like in emails) and keep it shorter than 72 characters.&lt;/li&gt;&lt;li&gt;After an empty second line, a longer description can be added.&lt;/li&gt;&lt;li&gt;Describe why the change was done, not how it was done.&lt;/li&gt;&lt;/ul&gt;</source>
<translation>&lt;p&gt;Gute Beschreibungen für Commits schreiben&lt;/p&gt;&lt;ul&gt;&lt;li&gt;Vermeiden Sie sehr kurze Beschreibungen.&lt;/li&gt;&lt;li&gt;Betrachten Sie die erste Zeile als Betreff (wie in einer E-Mail) und halten Sie sie kürzer als 72 Zeichen.&lt;/li&gt;&lt;li&gt;Eine längere Beschreibung kann nach einer leeren zweiten Zeile folgen.&lt;/li&gt;&lt;li&gt;Beschreiben Sie, weshalb die Änderung vorgenommen wurde, nicht wie sie vorgenommen wurde.&lt;/li&gt;&lt;/ul&gt;</translation>
</message>
<message>
<source>Update in progress</source>

View File

@@ -369,61 +369,62 @@ LibraryInfo::LibraryInfo(const QmlDirParser &parser, const QByteArray &fingerpri
QByteArray LibraryInfo::calculateFingerprint() const
{
QCryptographicHash hash(QCryptographicHash::Sha1);
hash.addData(reinterpret_cast<const char *>(&_status), sizeof(_status));
auto addData = [&hash](auto p, size_t len) {
hash.addData(QByteArrayView(reinterpret_cast<const char *>(p), len));
};
addData(&_status, sizeof(_status));
int len = _components.size();
hash.addData(reinterpret_cast<const char *>(&len), sizeof(len));
addData(&len, sizeof(len));
for (const QmlDirParser::Component &component : _components) {
len = component.fileName.size();
hash.addData(reinterpret_cast<const char *>(&len), sizeof(len));
hash.addData(reinterpret_cast<const char *>(component.fileName.constData()),
len * sizeofQChar);
hash.addData(reinterpret_cast<const char *>(&component.majorVersion), sizeof(component.majorVersion));
hash.addData(reinterpret_cast<const char *>(&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<const char *>(&len), sizeof(len));
hash.addData(reinterpret_cast<const char *>(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<const char *>(&flags), sizeof(flags));
addData(&flags, sizeof(flags));
}
len = _plugins.size();
hash.addData(reinterpret_cast<const char *>(&len), sizeof(len));
addData(&len, sizeof(len));
for (const QmlDirParser::Plugin &plugin : _plugins) {
len = plugin.path.size();
hash.addData(reinterpret_cast<const char *>(&len), sizeof(len));
hash.addData(reinterpret_cast<const char *>(plugin.path.constData()), len * sizeofQChar);
addData(&len, sizeof(len));
addData(plugin.path.constData(), len * sizeofQChar);
len = plugin.name.size();
hash.addData(reinterpret_cast<const char *>(&len), sizeof(len));
hash.addData(reinterpret_cast<const char *>(plugin.name.constData()), len * sizeofQChar);
addData(&len, sizeof(len));
addData(plugin.name.constData(), len * sizeofQChar);
}
len = _typeinfos.size();
hash.addData(reinterpret_cast<const char *>(&len), sizeof(len));
addData(&len, sizeof(len));
for (const QString &typeinfo : _typeinfos) {
len = typeinfo.size();
hash.addData(reinterpret_cast<const char *>(&len), sizeof(len));
hash.addData(reinterpret_cast<const char *>(typeinfo.constData()),
len * sizeofQChar);
addData(&len, sizeof(len));
addData(typeinfo.constData(), len * sizeofQChar);
}
len = _metaObjects.size();
hash.addData(reinterpret_cast<const char *>(&len), sizeof(len));
addData(&len, sizeof(len));
QList<QByteArray> 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<const char *>(&_dumpStatus), sizeof(_dumpStatus));
addData(&_dumpStatus, sizeof(_dumpStatus));
len = _dumpError.size(); // localization dependent (avoid?)
hash.addData(reinterpret_cast<const char *>(&len), sizeof(len));
hash.addData(reinterpret_cast<const char *>(_dumpError.constData()), len * sizeofQChar);
addData(&len, sizeof(len));
addData(_dumpError.constData(), len * sizeofQChar);
len = _moduleApis.size();
hash.addData(reinterpret_cast<const char *>(&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<const char *>(&len), sizeof(len));
addData(&len, sizeof(len));
for (const QmlDirParser::Import &import : _imports)
hash.addData(import.module.toUtf8()); // import order matters, keep order-dependent

View File

@@ -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
)

View File

@@ -34,7 +34,7 @@ private:
int m_current = -1;
};
class TASKING_EXPORT BarrierTaskAdapter : public Tasking::TaskAdapter<Barrier>
class TASKING_EXPORT BarrierTaskAdapter : public TaskAdapter<Barrier>
{
public:
BarrierTaskAdapter() { connect(task(), &Barrier::done, this, &TaskInterface::done); }

View File

@@ -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 <QtConcurrent>
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 <typename ResultType>
class ConcurrentCall
{
Q_DISABLE_COPY_MOVE(ConcurrentCall)
public:
ConcurrentCall() = default;
template <typename Function, typename ...Args>
void setConcurrentCallData(Function &&function, Args &&...args)
{
return wrapConcurrent(std::forward<Function>(function), std::forward<Args>(args)...);
}
void setThreadPool(QThreadPool *pool) { m_threadPool = pool; }
ResultType result() const
{
return m_future.resultCount() ? m_future.result() : ResultType();
}
QFuture<ResultType> future() const { return m_future; }
private:
template <typename Function, typename ...Args>
void wrapConcurrent(Function &&function, Args &&...args)
{
m_startHandler = [=] {
if (m_threadPool)
return QtConcurrent::run(m_threadPool, function, args...);
return QtConcurrent::run(function, args...);
};
}
template <typename Function, typename ...Args>
void wrapConcurrent(std::reference_wrapper<const Function> &&wrapper, Args &&...args)
{
m_startHandler = [=] {
if (m_threadPool) {
return QtConcurrent::run(m_threadPool,
std::forward<const Function>(wrapper.get()), args...);
}
return QtConcurrent::run(std::forward<const Function>(wrapper.get()), args...);
};
}
template <typename T>
friend class ConcurrentCallTaskAdapter;
std::function<QFuture<ResultType>()> m_startHandler;
QThreadPool *m_threadPool = nullptr;
QFuture<ResultType> m_future;
};
template <typename ResultType>
class ConcurrentCallTaskAdapter : public TaskAdapter<ConcurrentCall<ResultType>>
{
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<ResultType>);
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<QFutureWatcher<ResultType>> m_watcher;
};
} // namespace Tasking
TASKING_DECLARE_TEMPLATE_TASK(ConcurrentCallTask, Tasking::ConcurrentCallTaskAdapter);

View File

@@ -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 <QNetworkAccessManager>
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

View File

@@ -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 <QNetworkReply>
#include <QNetworkRequest>
#include <memory>
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<QNetworkReply> m_reply;
};
class TASKING_EXPORT NetworkQueryTaskAdapter : public TaskAdapter<NetworkQuery>
{
public:
NetworkQueryTaskAdapter() { connect(task(), &NetworkQuery::done, this, &TaskInterface::done); }
void start() final { task()->start(); }
};
} // namespace Tasking
TASKING_DECLARE_TASK(NetworkQueryTask, Tasking::NetworkQueryTaskAdapter);

View File

@@ -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",

View File

@@ -9,6 +9,8 @@
#include <QSet>
#include <QTimer>
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<TaskAction()>.
@@ -130,7 +277,7 @@ private:
*/
/*!
\typealias TaskItem::GroupEndHandler
\typealias GroupItem::GroupEndHandler
Type alias for \c std::function\<void()\>.
@@ -143,13 +290,14 @@ private:
*/
/*!
\fn template <typename SetupHandler> TaskItem onGroupSetup(SetupHandler &&handler)
\fn template <typename SetupHandler> 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<TaskAction()> or \c std::function<void()>
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<TaskItem> &children)
void GroupItem::addChildren(const QList<GroupItem> &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<TaskItem> &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<TreeStorageBase> m_storageList;
const QList<TaskNode *> m_children;
const int m_taskCount = 0;
@@ -505,8 +680,8 @@ public:
const ConstData &m_constData;
const QList<int> 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<TaskInterface> m_task;
};
@@ -657,16 +832,16 @@ ReturnType invokeHandler(TaskContainer *container, Handler &&handler, Args &&...
}
static QList<TaskNode *> createChildren(TaskTreePrivate *taskTreePrivate, TaskContainer *container,
const TaskItem &task)
const GroupItem &task)
{
QList<TaskNode *> result;
const QList<TaskItem> &children = task.children();
for (const TaskItem &child : children)
const QList<GroupItem> &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<void> &future, int timeoutMs)
bool TaskTree::runBlocking()
{
if (isRunning() || future.isCanceled())
QPromise<void> dummy;
dummy.start();
return runBlocking(dummy.future());
}
bool TaskTree::runBlocking(const QFuture<void> &future)
{
if (future.isCanceled())
return false;
bool ok = false;
@@ -1680,17 +1820,7 @@ bool TaskTree::runBlocking(const QFuture<void> &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<void> &future, int timeoutMs)
return ok;
}
bool TaskTree::runBlocking(int timeoutMs)
bool TaskTree::runBlocking(const Group &recipe, milliseconds timeout)
{
QPromise<void> dummy;
dummy.start();
return runBlocking(dummy.future(), timeoutMs);
return TaskTree::runBlocking(recipe, dummy.future(), timeout);
}
bool TaskTree::runBlocking(const Group &recipe, const QFuture<void> &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<void()>;
struct TimerData
{
system_clock::time_point m_deadline;
QPointer<QObject> m_context;
TimeoutCallback m_callback;
};
QMutex s_mutex;
std::atomic_int s_timerId = 0;
QHash<int, TimerData> s_timerIdToTimerData = {};
QMultiMap<system_clock::time_point, int> s_deadlineToTimerId = {};
static QList<TimerData> 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<TimerData> 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<TimerData> 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

View File

@@ -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<WorkflowPolicy> m_workflowPolicy = {};
};
QList<TaskItem> children() const { return m_children; }
QList<GroupItem> children() const { return m_children; }
GroupData groupData() const { return m_groupData; }
QList<TreeStorageBase> 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<TaskItem> &children);
void addChildren(const QList<GroupItem> &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<TaskItem> m_children;
QList<GroupItem> m_children;
GroupData m_groupData;
QList<TreeStorageBase> m_storageList;
TaskHandler m_taskHandler;
};
class TASKING_EXPORT Group : public TaskItem
class TASKING_EXPORT Group : public GroupItem
{
public:
Group(const QList<TaskItem> &children) { addChildren(children); }
Group(std::initializer_list<TaskItem> children) { addChildren(children); }
Group(const QList<GroupItem> &children) { addChildren(children); }
Group(std::initializer_list<GroupItem> children) { addChildren(children); }
// GroupData related:
template <typename SetupHandler>
static TaskItem onGroupSetup(SetupHandler &&handler) {
static GroupItem onGroupSetup(SetupHandler &&handler) {
return groupHandler({wrapGroupSetup(std::forward<SetupHandler>(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<typename SetupHandler>
@@ -231,29 +244,31 @@ private:
};
template <typename SetupHandler>
static TaskItem onGroupSetup(SetupHandler &&handler)
static GroupItem onGroupSetup(SetupHandler &&handler)
{
return Group::onGroupSetup(std::forward<SetupHandler>(handler));
}
TASKING_EXPORT TaskItem onGroupDone(const TaskItem::GroupEndHandler &handler);
TASKING_EXPORT TaskItem onGroupError(const TaskItem::GroupEndHandler &handler);
TASKING_EXPORT TaskItem parallelLimit(int limit);
TASKING_EXPORT TaskItem workflowPolicy(WorkflowPolicy policy);
TASKING_EXPORT 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<typename Function>
static QList<TaskItem> init(Function &&function) {
static QList<GroupItem> init(Function &&function) {
constexpr bool isInvocable = std::is_invocable_v<std::decay_t<Function>>;
static_assert(isInvocable,
"Sync element: The synchronous function can't take any arguments.");
@@ -295,17 +310,17 @@ private:
};
template <typename Adapter>
class CustomTask : public TaskItem
class CustomTask : public GroupItem
{
public:
using Task = typename Adapter::Type;
using EndHandler = std::function<void(const Task &)>;
static Adapter *createAdapter() { return new Adapter; }
CustomTask() : TaskItem({&createAdapter}) {}
CustomTask() : GroupItem({&createAdapter}) {}
template <typename SetupFunction>
CustomTask(SetupFunction &&function, const EndHandler &done = {}, const EndHandler &error = {})
: TaskItem({&createAdapter, wrapSetup(std::forward<SetupFunction>(function)),
wrapEnd(done), wrapEnd(error)}) {}
: GroupItem({&createAdapter, wrapSetup(std::forward<SetupFunction>(function)),
wrapEnd(done), wrapEnd(error)}) {}
template <typename SetupFunction>
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<typename SetupFunction>
static TaskItem::TaskSetupHandler wrapSetup(SetupFunction &&function) {
static GroupItem::TaskSetupHandler wrapSetup(SetupFunction &&function) {
static constexpr bool isDynamic = std::is_same_v<TaskAction,
std::invoke_result_t<std::decay_t<SetupFunction>, typename Adapter::Type &>>;
constexpr bool isVoid = std::is_same_v<void,
@@ -370,8 +390,12 @@ public:
// Helper methods. They execute a local event loop with ExcludeUserInputEvents.
// The passed future is used for listening to the cancel event.
// Don't use it in main thread. To be used in non-main threads or in auto tests.
bool runBlocking(const QFuture<void> &future, int timeoutMs = 0);
bool runBlocking(int timeoutMs = 0);
bool runBlocking();
bool runBlocking(const QFuture<void> &future);
static bool runBlocking(const Group &recipe,
std::chrono::milliseconds timeout = std::chrono::milliseconds::max());
static bool runBlocking(const Group &recipe, const QFuture<void> &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<std::chrono::milliseconds>
{
public:
TimeoutTaskAdapter();
~TimeoutTaskAdapter();
void start() final;
private:
std::optional<int> m_timerId;
};
} // namespace Tasking
#define TASKING_DECLARE_TASK(CustomTaskName, TaskAdapterClass)\
@@ -430,3 +465,4 @@ using CustomTaskName = CustomTask<TaskAdapterClass<Args...>>;\
} // namespace Tasking
TASKING_DECLARE_TASK(TaskTreeTask, TaskTreeTaskAdapter);
TASKING_DECLARE_TASK(TimeoutTask, TimeoutTaskAdapter);

View File

@@ -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<class Widget> 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<int> IntegersAspect::value() const
void IntegersAspect::setValue(const QList<int> &value)
{
BaseAspect::setValue(transform(value, &QVariant::fromValue<int>));
BaseAspect::setValue(transform(value, [](int i) { return QVariant::fromValue<int>(i); }));
}
QList<int> IntegersAspect::defaultValue() const
@@ -2319,7 +2331,7 @@ QList<int> IntegersAspect::defaultValue() const
void IntegersAspect::setDefaultValue(const QList<int> &value)
{
BaseAspect::setDefaultValue(transform(value, &QVariant::fromValue<int>));
BaseAspect::setDefaultValue(transform(value, [](int i) { return QVariant::fromValue<int>(i); }));
}
@@ -2334,6 +2346,10 @@ void IntegersAspect::setDefaultValue(const QList<int> &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.

View File

@@ -406,6 +406,7 @@ public:
void setOpenTerminalHandler(const std::function<void()> &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;

View File

@@ -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

View File

@@ -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);

View File

@@ -7,7 +7,7 @@
#include "fileutils.h"
#include <QMap>
#include <QHash>
#include <QMutex>
#include <QProcess>
#include <QThread>
@@ -78,8 +78,7 @@ private:
int m_currentId{0};
QMutex m_commandMutex;
// QMap is used here to preserve iterators
QMap<quint64, CommandRun> m_commandOutput;
QHash<quint64, CommandRun> m_commandOutput;
QByteArray m_commandBuffer;
State m_shellScriptState = State::Unknown;

View File

@@ -11,6 +11,7 @@
#include "utilsicons.h"
#include "utilstr.h"
#include <QApplication>
#include <QKeyEvent>
#include <QKeySequence>
#include <QMenu>
@@ -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);

View File

@@ -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;

View File

@@ -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<TaskTree> m_taskTree;
private:
virtual TaskItem remoteTask() = 0;
virtual TaskItem localTask() = 0;
virtual GroupItem remoteTask() = 0;
virtual GroupItem localTask() = 0;
};
static void localRead(QPromise<QByteArray> &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<QByteArray> &async) {
async.setConcurrentCallData(localRead, m_filePath);
Async<QByteArray> *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<void> &async) {
m_writeBuffer = new WriteBuffer(isBuffered(), &async);
async.setConcurrentCallData(localWrite, m_filePath, m_writeData, m_writeBuffer);
@@ -375,8 +375,7 @@ static void transfer(QPromise<void> &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<TaskTree> 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<void> &async) {
async.setConcurrentCallData(transfer, m_source, m_destination);
};

View File

@@ -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)

View File

@@ -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;
}

View File

@@ -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 <class T> 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"

View File

@@ -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)

View File

@@ -122,7 +122,7 @@ private:
QMap<QString, FilePath> 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<BoolAspect>();
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());

View File

@@ -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");

View File

@@ -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<FilePath> &filePaths,
using namespace Tasking;
QList<TaskItem> tasks{parallelLimit(std::max(QThread::idealThreadCount() / 4, 1))};
QList<GroupItem> tasks{parallelLimit(std::max(QThread::idealThreadCount() / 4, 1))};
for (const FilePath &file : filteredFiles) {
const auto setup = [this, codeParsers, file](Async<TestParseResultPtr> &async) {
async.setConcurrentCallData(parseFileForTests, codeParsers, file);

View File

@@ -347,7 +347,7 @@ void TestRunner::runTestsHelper()
std::unique_ptr<TestOutputReader> m_outputReader;
};
QList<TaskItem> tasks{optional};
QList<GroupItem> 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)

View File

@@ -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<StringAspect>();
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);
});

View File

@@ -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);
};
});
}

View File

@@ -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;

View File

@@ -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;

View File

@@ -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());

View File

@@ -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());

View File

@@ -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());

View File

@@ -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
}
}

View File

@@ -17,6 +17,7 @@
#include <coreplugin/icore.h>
#include <coreplugin/messagemanager.h>
#include <coreplugin/session.h>
#include <coreplugin/vcsmanager.h>
#include <cppeditor/cppcodemodelsettings.h>
#include <cppeditor/cppeditorconstants.h>
@@ -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

View File

@@ -183,7 +183,7 @@ void ClangToolRunWorker::start()
m_filesAnalyzed.clear();
m_filesNotAnalyzed.clear();
QList<TaskItem> tasks{parallelLimit(qMax(1, m_runSettings.parallelJobs()))};
QList<GroupItem> 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)) {

View File

@@ -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)
}
};

View File

@@ -10,7 +10,7 @@
#include <utils/environment.h>
namespace Tasking { class TaskItem; }
namespace Tasking { class GroupItem; }
namespace ClangTools {
namespace Internal {
@@ -50,9 +50,9 @@ struct AnalyzeOutputData
using AnalyzeSetupHandler = std::function<bool()>;
using AnalyzeOutputHandler = std::function<void(const AnalyzeOutputData &)>;
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

View File

@@ -190,7 +190,7 @@ void DocumentClangToolRunner::run()
vfso().update();
const ClangDiagnosticConfig config = diagnosticConfig(runSettings.diagnosticConfigId());
const Environment env = projectBuildEnvironment(project);
QList<TaskItem> tasks{parallel};
QList<GroupItem> 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);

View File

@@ -378,7 +378,7 @@ void Manager::gotoLocations(const QList<QVariant> &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;

View File

@@ -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();

View File

@@ -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));

View File

@@ -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);

View File

@@ -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);
});

View File

@@ -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;
}

View File

@@ -5,6 +5,7 @@ QtcPlugin {
Depends { name: "Core" }
Depends { name: "LanguageClient" }
Depends { name: "ProjectExplorer" }
Depends { name: "TextEditor" }
Depends { name: "Qt"; submodules: ["widgets", "xml", "network"] }

View File

@@ -139,6 +139,7 @@ void CopilotHoverHandler::identifyMatch(TextEditorWidget *editorWidget,
void CopilotHoverHandler::operateTooltip(TextEditorWidget *editorWidget, const QPoint &point)
{
Q_UNUSED(point)
auto *suggestion = dynamic_cast<CopilotSuggestion *>(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

View File

@@ -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());
}

View File

@@ -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);
}

View File

@@ -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;
}

View File

@@ -6,18 +6,17 @@
#include <coreplugin/coreplugintr.h>
#include <coreplugin/dialogs/shortcutsettings.h>
#include <utils/headerviewstretcher.h>
#include <utils/fancylineedit.h>
#include <utils/headerviewstretcher.h>
#include <utils/layoutbuilder.h>
#include <utils/qtcassert.h>
#include <QDebug>
#include <QGroupBox>
#include <QHBoxLayout>
#include <QLabel>
#include <QPointer>
#include <QPushButton>
#include <QTreeWidgetItem>
#include <QVBoxLayout>
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);

View File

@@ -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");

View File

@@ -199,15 +199,6 @@ void IOptionsPage::setSettings(AspectContainer *settings)
m_settings = settings;
}
void IOptionsPage::setLayouter(const std::function<void(QWidget *w)> &layouter)
{
m_widgetCreator = [layouter] {
auto widget = new IOptionsPageWidget;
layouter(widget);
return widget;
};
}
void IOptionsPage::setLayouter(const std::function<Layouting::LayoutItem ()> &layouter)
{
m_widgetCreator = [layouter] {

View File

@@ -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<void(QWidget *w)> &layouter);
void setLayouter(const std::function<Layouting::LayoutItem()> &layouter);
// Used in FontSettingsPage. FIXME?

View File

@@ -42,7 +42,6 @@
#include <utils/algorithm.h>
#include <utils/checkablemessagebox.h>
#include <utils/environment.h>
#include <utils/executeondestruction.h>
#include <utils/filepath.h>
#include <utils/hostosinfo.h>
#include <utils/infobar.h>
@@ -70,6 +69,7 @@
#include <QPushButton>
#include <QRegularExpression>
#include <QRegularExpressionMatch>
#include <QScopeGuard>
#include <QSet>
#include <QSettings>
#include <QSplitter>
@@ -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);

View File

@@ -450,7 +450,7 @@ void LocatorMatcher::start()
collectorStorage->m_collector = nullptr;
};
QList<TaskItem> parallelTasks {parallelLimit(d->m_parallelLimit)};
QList<GroupItem> parallelTasks {parallelLimit(d->m_parallelLimit)};
const auto onSetup = [this, collectorStorage](const TreeStorage<LocatorStorage> &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<TaskItem> &recipe)
void ILocatorFilter::setRefreshRecipe(const std::optional<GroupItem> &recipe)
{
m_refreshRecipe = recipe;
}
@@ -606,7 +606,7 @@ void ILocatorFilter::setRefreshRecipe(const std::optional<TaskItem> &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<TaskItem> ILocatorFilter::refreshRecipe() const
std::optional<GroupItem> ILocatorFilter::refreshRecipe() const
{
return m_refreshRecipe;
}

View File

@@ -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<LocatorStorage> storage;
@@ -270,8 +270,8 @@ protected:
virtual void saveState(QJsonObject &object) const;
virtual void restoreState(const QJsonObject &object);
void setRefreshRecipe(const std::optional<Tasking::TaskItem> &recipe);
std::optional<Tasking::TaskItem> refreshRecipe() const;
void setRefreshRecipe(const std::optional<Tasking::GroupItem> &recipe);
std::optional<Tasking::GroupItem> refreshRecipe() const;
static bool isOldSetting(const QByteArray &state);
@@ -289,7 +289,7 @@ private:
QString m_description;
QString m_defaultShortcut;
std::optional<QString> m_defaultSearchText;
std::optional<Tasking::TaskItem> m_refreshRecipe;
std::optional<Tasking::GroupItem> m_refreshRecipe;
QKeySequence m_defaultKeySequence;
bool m_defaultIncludedByDefault = false;
bool m_includedByDefault = m_defaultIncludedByDefault;

View File

@@ -381,14 +381,14 @@ void Locator::refresh(const QList<ILocatorFilter *> &filters)
m_refreshingFilters = Utils::filteredUnique(m_refreshingFilters + filters);
using namespace Tasking;
QList<TaskItem> tasks{parallel};
QList<GroupItem> 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); })
};

View File

@@ -11,7 +11,6 @@
#include <utils/algorithm.h>
#include <utils/basetreeview.h>
#include <utils/executeondestruction.h>
#include <utils/fileutils.h>
#include <utils/listmodel.h>
#include <utils/qtcassert.h>
@@ -33,6 +32,7 @@
#include <QMessageBox>
#include <QPushButton>
#include <QRegularExpression>
#include <QScopeGuard>
#include <QSortFilterProxyModel>
#include <QStyledItemDelegate>
#include <QToolButton>
@@ -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(),

View File

@@ -17,14 +17,11 @@
#include <extensionsystem/pluginview.h>
#include <utils/fancylineedit.h>
#include <utils/layoutbuilder.h>
#include <QCheckBox>
#include <QDialog>
#include <QDialogButtonBox>
#include <QHBoxLayout>
#include <QLabel>
#include <QPushButton>
#include <QVBoxLayout>
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);

View File

@@ -15,6 +15,7 @@
#include <utils/fileutils.h>
#include <utils/hostosinfo.h>
#include <utils/infolabel.h>
#include <utils/layoutbuilder.h>
#include <utils/pathchooser.h>
#include <utils/process.h>
#include <utils/qtcassert.h>
@@ -33,7 +34,6 @@
#include <QPushButton>
#include <QRadioButton>
#include <QTextEdit>
#include <QVBoxLayout>
#include <memory>
@@ -80,19 +80,15 @@ public:
, m_data(data)
{
setTitle(Tr::tr("Source"));
auto vlayout = new QVBoxLayout;
setLayout(vlayout);
auto label = new QLabel(
"<p>"
+ Tr::tr("Choose source location. This can be a plugin library file or a zip file.")
+ "</p>");
label->setWordWrap(true);
vlayout->addWidget(label);
auto chooser = new PathChooser;
chooser->setExpectedKind(PathChooser::Any);
vlayout->addWidget(chooser);
connect(chooser, &PathChooser::textChanged, this, [this, chooser] {
m_data->sourcePath = chooser->filePath();
updateWarnings();
@@ -101,7 +97,8 @@ public:
m_info = new InfoLabel;
m_info->setType(InfoLabel::Error);
m_info->setVisible(false);
vlayout->addWidget(m_info);
Layouting::Column { label, chooser, m_info }.attachTo(this);
}
void updateWarnings()
@@ -153,8 +150,6 @@ public:
, m_data(data)
{
setTitle(Tr::tr("Check Archive"));
auto vlayout = new QVBoxLayout;
setLayout(vlayout);
m_label = new InfoLabel;
m_label->setElideMode(Qt::ElideNone);
@@ -163,13 +158,11 @@ public:
m_output = new QTextEdit;
m_output->setReadOnly(true);
auto hlayout = new QHBoxLayout;
hlayout->addWidget(m_label, 1);
hlayout->addStretch();
hlayout->addWidget(m_cancelButton);
vlayout->addLayout(hlayout);
vlayout->addWidget(m_output);
using namespace Layouting;
Column {
Row { m_label, st, m_cancelButton },
m_output,
}.attachTo(this);
}
void initializePage() final
@@ -322,13 +315,9 @@ public:
, m_data(data)
{
setTitle(Tr::tr("Install Location"));
auto vlayout = new QVBoxLayout;
setLayout(vlayout);
auto label = new QLabel("<p>" + Tr::tr("Choose install location.") + "</p>");
label->setWordWrap(true);
vlayout->addWidget(label);
vlayout->addSpacing(10);
auto localInstall = new QRadioButton(Tr::tr("User plugins"));
localInstall->setChecked(!m_data->installIntoApplication);
@@ -338,10 +327,6 @@ public:
localLabel->setWordWrap(true);
localLabel->setAttribute(Qt::WA_MacSmallSize, true);
vlayout->addWidget(localInstall);
vlayout->addWidget(localLabel);
vlayout->addSpacing(10);
auto appInstall = new QRadioButton(
Tr::tr("%1 installation").arg(Constants::IDE_DISPLAY_NAME));
appInstall->setChecked(m_data->installIntoApplication);
@@ -351,8 +336,11 @@ public:
.arg(Constants::IDE_DISPLAY_NAME));
appLabel->setWordWrap(true);
appLabel->setAttribute(Qt::WA_MacSmallSize, true);
vlayout->addWidget(appInstall);
vlayout->addWidget(appLabel);
using namespace Layouting;
Column {
label, Space(10), localInstall, localLabel, Space(10), appInstall, appLabel,
}.attachTo(this);
auto group = new QButtonGroup(this);
group->addButton(localInstall);
@@ -375,12 +363,9 @@ public:
{
setTitle(Tr::tr("Summary"));
auto vlayout = new QVBoxLayout;
setLayout(vlayout);
m_summaryLabel = new QLabel(this);
m_summaryLabel->setWordWrap(true);
vlayout->addWidget(m_summaryLabel);
Layouting::Column { m_summaryLabel }.attachTo(this);
}
void initializePage() final

View File

@@ -51,8 +51,7 @@ const char showCrashButtonKey[] = "ShowCrashButton";
// TODO: move to somewhere in Utils
static QString formatSize(qint64 size)
{
QStringList units {Tr::tr("Bytes"), Tr::tr("KB"), Tr::tr("MB"),
Tr::tr("GB"), Tr::tr("TB")};
QStringList units{Tr::tr("Bytes"), Tr::tr("KiB"), Tr::tr("MiB"), Tr::tr("GiB"), Tr::tr("TiB")};
double outputSize = size;
int i;
for (i = 0; i < units.size() - 1; ++i) {

View File

@@ -108,11 +108,11 @@ CppcheckOptions::CppcheckOptions()
readSettings();
}
std::function<void(QWidget *widget)> CppcheckOptions::layouter()
std::function<Layouting::LayoutItem()> CppcheckOptions::layouter()
{
return [this](QWidget *widget) {
return [this] {
using namespace Layouting;
Form {
return Form {
binary, br,
Tr::tr("Checks:"), Flow {
warning,
@@ -132,7 +132,7 @@ std::function<void(QWidget *widget)> CppcheckOptions::layouter()
addIncludePaths,
guessArguments
}
}.attachTo(widget);
};
};
}

View File

@@ -12,7 +12,7 @@ class CppcheckOptions final : public Core::PagedSettings
public:
CppcheckOptions();
std::function<void(QWidget *widget)> layouter();
std::function<Layouting::LayoutItem()> layouter();
Utils::FilePathAspect binary{this};
Utils::BoolAspect warning{this};

View File

@@ -25,6 +25,7 @@
#include <debugger/analyzer/analyzerconstants.h>
#include <debugger/debuggermainwindow.h>
#include <utils/layoutbuilder.h>
#include <utils/qtcassert.h>
#include <utils/utilsicons.h>
@@ -111,8 +112,7 @@ void CppcheckPluginPrivate::startManualRun()
manualRunTool.updateOptions();
auto optionsWidget = new QWidget;
options.layouter()(optionsWidget);
auto optionsWidget = options.layouter()().emerge();
ManualRunDialog dialog(optionsWidget, project);
if (dialog.exec() == ManualRunDialog::Rejected)

View File

@@ -64,7 +64,7 @@ void CppProjectUpdater::update(const ProjectUpdateInfo &projectUpdateInfo,
if (async.isResultAvailable())
storage->projectInfo = async.result();
};
QList<TaskItem> tasks{parallel};
QList<GroupItem> tasks{parallel};
tasks.append(AsyncTask<ProjectInfo::ConstPtr>(setupInfoGenerator, onInfoGeneratorDone));
for (QPointer<ExtraCompiler> compiler : compilers) {
if (compiler && compiler->isDirty())

View File

@@ -414,6 +414,7 @@ F2TestCase::F2TestCase(CppEditorAction action,
} else {
currentTextEditor->convertPosition(targetTestFile->m_targetCursorPosition,
&expectedLine, &expectedColumn);
++expectedColumn;
if (useClangd && (tag == "classDestructor" || tag == "fromDestructorDefinitionSymbol"
|| tag == "fromDestructorBody")) {
--expectedColumn; // clangd goes before the ~, built-in code model after

View File

@@ -166,7 +166,7 @@ void ResourcePreviewHoverHandler::operateTooltip(TextEditorWidget *editorWidget,
{
const QString tt = makeTooltip();
if (!tt.isEmpty())
Utils::ToolTip::show(point, tt, editorWidget);
Utils::ToolTip::show(point, tt, Qt::MarkdownText, editorWidget);
else
Utils::ToolTip::hide();
}
@@ -180,10 +180,8 @@ QString ResourcePreviewHoverHandler::makeTooltip() const
const Utils::MimeType mimeType = Utils::mimeTypeForFile(m_resPath);
if (mimeType.name().startsWith("image", Qt::CaseInsensitive))
ret += QString("<img src=\"file:///%1\" /><br/>").arg(m_resPath);
ret += QString("<a href=\"file:///%1\">%2</a>")
.arg(m_resPath, QDir::toNativeSeparators(m_resPath));
ret += QString("![image](%1) \n").arg(m_resPath);
ret += QString("[%1](%2)").arg(QDir::toNativeSeparators(m_resPath), m_resPath);
return ret;
}

View File

@@ -64,6 +64,7 @@ void SemanticHighlighter::run()
m_revision = documentRevision();
m_seenBlocks.clear();
m_nextResultToHandle = m_resultCount = 0;
qCDebug(log) << "starting runner for document revision" << m_revision;
m_watcher->setFuture(m_highlightingRunner());
}
@@ -92,6 +93,21 @@ void SemanticHighlighter::onHighlighterResultAvailable(int from, int to)
return;
}
QTC_CHECK(from == m_resultCount);
m_resultCount = to;
if (to - m_nextResultToHandle >= 100) {
handleHighlighterResults();
m_nextResultToHandle = to;
}
}
void SemanticHighlighter::handleHighlighterResults()
{
int from = m_nextResultToHandle;
const int to = m_resultCount;
if (from >= to)
return;
QElapsedTimer t;
t.start();
@@ -177,6 +193,8 @@ void SemanticHighlighter::onHighlighterFinished()
{
QTC_ASSERT(m_watcher, return);
handleHighlighterResults();
QElapsedTimer t;
t.start();

View File

@@ -67,6 +67,7 @@ public:
private:
void onHighlighterResultAvailable(int from, int to);
void handleHighlighterResults();
void onHighlighterFinished();
void connectWatcher();
@@ -82,6 +83,8 @@ private:
QScopedPointer<QFutureWatcher<TextEditor::HighlightingResult>> m_watcher;
QHash<int, QTextCharFormat> m_formatMap;
std::set<int> m_seenBlocks;
int m_nextResultToHandle = 0;
int m_resultCount = 0;
HighlightingRunner m_highlightingRunner;
};

View File

@@ -59,9 +59,9 @@ CvsSettings::CvsSettings()
diffIgnoreBlankLines.setSettingsKey("DiffIgnoreBlankLines");
setLayouter([this](QWidget *widget) {
setLayouter([this] {
using namespace Layouting;
Column {
return Column {
Group {
title(Tr::tr("Configuration")),
Form {
@@ -80,7 +80,7 @@ CvsSettings::CvsSettings()
}
},
st
}.attachTo(widget);
};
});
}

View File

@@ -101,11 +101,11 @@ DebuggerRunConfigurationAspect::DebuggerRunConfigurationAspect(Target *target)
addDataExtractor(this, &DebuggerRunConfigurationAspect::useMultiProcess, &Data::useMultiProcess);
addDataExtractor(this, &DebuggerRunConfigurationAspect::overrideStartup, &Data::overrideStartup);
m_cppAspect = new TriStateAspect(Tr::tr("Enabled"), Tr::tr("Disabled"), Tr::tr("Automatic"));
m_cppAspect = new TriStateAspect(nullptr, Tr::tr("Enabled"), Tr::tr("Disabled"), Tr::tr("Automatic"));
m_cppAspect->setLabelText(Tr::tr("C++ debugger:"));
m_cppAspect->setSettingsKey("RunConfiguration.UseCppDebugger");
m_qmlAspect = new TriStateAspect(Tr::tr("Enabled"), Tr::tr("Disabled"), Tr::tr("Automatic"));
m_qmlAspect = new TriStateAspect(nullptr, Tr::tr("Enabled"), Tr::tr("Disabled"), Tr::tr("Automatic"));
m_qmlAspect->setLabelText(Tr::tr("QML debugger:"));
m_qmlAspect->setSettingsKey("RunConfiguration.UseQmlDebugger");

View File

@@ -32,7 +32,7 @@ public:
setCategory(Constants::DEBUGGER_SETTINGS_CATEGORY);
setSettings(&debuggerSettings()->page2);
setLayouter([](QWidget *w) {
setLayouter([] {
using namespace Layouting;
DebuggerSettings &s = *debuggerSettings();
@@ -84,7 +84,7 @@ public:
Column { s.gdbPostAttachCommands },
};
Grid { general, extended, br, startup, attach }.attachTo(w);
return Grid { general, extended, br, startup, attach };
});
}
};

View File

@@ -128,7 +128,7 @@ DiffFilesController::DiffFilesController(IDocument *document)
outputList->resize(inputList.size());
using namespace std::placeholders;
QList<TaskItem> tasks {parallel, optional};
QList<GroupItem> tasks {parallel, finishAllAndDone};
for (int i = 0; i < inputList.size(); ++i) {
tasks.append(AsyncTask<FileData>(std::bind(setupDiff, _1, inputList.at(i)),
std::bind(onDiffDone, _1, i)));

View File

@@ -10,6 +10,13 @@
// Qt Creator. The idea is to keep this file here in a "clean" state that
// allows easy reuse with any QTextEdit or QPlainTextEdit derived class.
#ifndef FAKEVIM_STANDALONE
#include <texteditor/icodestylepreferences.h>
#include <texteditor/tabsettings.h>
#include <texteditor/texteditorsettings.h>
#include <texteditor/typingsettings.h>
#endif
#include <utils/hostosinfo.h>
#include <utils/layoutbuilder.h>
#include <utils/qtcassert.h>
@@ -18,8 +25,7 @@
using namespace Utils;
namespace FakeVim {
namespace Internal {
namespace FakeVim::Internal {
#ifdef FAKEVIM_STANDALONE
FvBaseAspect::FvBaseAspect()
@@ -62,13 +68,31 @@ QString FvBaseAspect::settingsKey() const
void setAutoApply(bool ) {}
#endif
static FakeVimSettings *s_settings;
FakeVimSettings &settings()
{
return *s_settings;
}
FakeVimSettings::FakeVimSettings()
{
setAutoApply(false);
s_settings = this;
#ifndef FAKEVIM_STANDALONE
const char SETTINGS_CATEGORY[] = "D.FakeVim";
const char SETTINGS_ID[] = "A.FakeVim.General";
setId(SETTINGS_ID);
setDisplayName(Tr::tr("General"));
setCategory(SETTINGS_CATEGORY);
setDisplayCategory(Tr::tr("FakeVim"));
setCategoryIconPath(":/fakevim/images/settingscategory_fakevim.png");
setup(&useFakeVim, false, "UseFakeVim", {}, Tr::tr("Use FakeVim"));
#endif
// Specific FakeVim settings
setup(&readVimRc, false, "ReadVimRc", {}, Tr::tr("Read .vimrc from location:"));
setup(&vimRcPath, QString(), "VimRcPath", {}, {}); // Tr::tr("Path to .vimrc")
@@ -135,6 +159,121 @@ FakeVimSettings::FakeVimSettings()
"%USERPROFILE%\\_vimrc on Windows, ~/.vimrc otherwise."));
vimRcPath.setPlaceHolderText(Tr::tr("Default: %1").arg(vimrcDefault));
vimRcPath.setDisplayStyle(FvStringAspect::PathChooserDisplay);
setLayouter([this] {
using namespace Layouting;
using namespace TextEditor;
Row bools {
Column {
autoIndent,
smartIndent,
expandTab,
smartTab,
hlSearch,
showCmd,
startOfLine,
passKeys,
blinkingCursor
},
Column {
incSearch,
useCoreSearch,
ignoreCase,
smartCase,
wrapScan,
showMarks,
passControlKey,
relativeNumber,
tildeOp
}
};
Row ints { shiftWidth, tabStop, scrollOff, st };
vimRcPath.setEnabler(&readVimRc);
Column strings {
backspace,
isKeyword,
Row {readVimRc, vimRcPath}
};
return Column {
useFakeVim,
Group {
title(Tr::tr("Vim Behavior")),
Column {
bools,
ints,
strings
}
},
Group {
title(Tr::tr("Plugin Emulation")),
Column {
emulateVimCommentary,
emulateReplaceWithRegister,
emulateArgTextObj,
emulateExchange,
emulateSurround
}
},
Row {
PushButton {
text(Tr::tr("Copy Text Editor Settings")),
onClicked([this] {
TabSettings ts = TextEditorSettings::codeStyle()->tabSettings();
TypingSettings tps = TextEditorSettings::typingSettings();
expandTab.setValue(ts.m_tabPolicy != TabSettings::TabsOnlyTabPolicy);
tabStop.setValue(ts.m_tabSize);
shiftWidth.setValue(ts.m_indentSize);
smartTab.setValue(tps.m_smartBackspaceBehavior
== TypingSettings::BackspaceFollowsPreviousIndents);
autoIndent.setValue(true);
smartIndent.setValue(tps.m_autoIndent);
incSearch.setValue(true);
}),
},
PushButton {
text(Tr::tr("Set Qt Style")),
onClicked([this] {
expandTab.setVolatileValue(true);
tabStop.setVolatileValue(4);
shiftWidth.setVolatileValue(4);
smartTab.setVolatileValue(true);
autoIndent.setVolatileValue(true);
smartIndent.setVolatileValue(true);
incSearch.setVolatileValue(true);
backspace.setVolatileValue(QString("indent,eol,start"));
passKeys.setVolatileValue(true);
}),
},
PushButton {
text(Tr::tr("Set Plain Style")),
onClicked([this] {
expandTab.setVolatileValue(false);
tabStop.setVolatileValue(8);
shiftWidth.setVolatileValue(8);
smartTab.setVolatileValue(false);
autoIndent.setVolatileValue(false);
smartIndent.setVolatileValue(false);
incSearch.setVolatileValue(false);
backspace.setVolatileValue(QString());
passKeys.setVolatileValue(false);
}),
},
st
},
st
};
});
readSettings();
#endif
}
@@ -187,11 +326,4 @@ void FakeVimSettings::setup(FvBaseAspect *aspect,
m_nameToAspect[shortName] = aspect;
}
FakeVimSettings *fakeVimSettings()
{
static FakeVimSettings s;
return &s;
}
} // namespace Internal
} // namespace FakeVim
} // FakeVim::Internal

View File

@@ -4,7 +4,7 @@
#pragma once
#ifndef FAKEVIM_STANDALONE
# include <utils/aspects.h>
# include <coreplugin/dialogs/ioptionspage.h>
#endif
#include <QCoreApplication>
@@ -13,8 +13,7 @@
#include <QString>
#include <QVariant>
namespace FakeVim {
namespace Internal {
namespace FakeVim::Internal {
#ifdef FAKEVIM_STANDALONE
class FvBaseAspect
@@ -68,7 +67,7 @@ public:
#else
using FvAspectContainer = Utils::AspectContainer;
using FvAspectContainer = Core::PagedSettings;
using FvBaseAspect = Utils::BaseAspect;
using FvBoolAspect = Utils::BoolAspect;
using FvIntegerAspect = Utils::IntegerAspect;
@@ -145,7 +144,6 @@ private:
QHash<FvBaseAspect *, QString> m_aspectToName;
};
FakeVimSettings *fakeVimSettings();
FakeVimSettings &settings();
} // namespace Internal
} // namespace FakeVim
} // FakeVim::Internal

View File

@@ -408,9 +408,8 @@ static QRegularExpression vimPatternToQtPattern(const QString &needle)
*/
// FIXME: Option smartcase should be used only if search was typed by user.
const bool ignoreCaseOption = fakeVimSettings()->ignoreCase.value();
const bool smartCaseOption = fakeVimSettings()->smartCase.value();
const bool initialIgnoreCase = ignoreCaseOption
const bool smartCaseOption = settings().smartCase();
const bool initialIgnoreCase = settings().ignoreCase()
&& !(smartCaseOption && needle.contains(QRegularExpression("[A-Z]")));
bool ignorecase = initialIgnoreCase;
@@ -2373,7 +2372,7 @@ public:
QString surroundFunction; // Used for storing the function name provided to ys{motion}f
} g;
FakeVimSettings &s = *fakeVimSettings();
FakeVimSettings &s = settings();
};
static void initSingleShotTimer(QTimer *timer,
@@ -2527,7 +2526,7 @@ void FakeVimHandler::Private::leaveFakeVim(bool needUpdate)
// The command might have destroyed the editor.
if (m_textedit || m_plaintextedit) {
if (s.showMarks.value())
if (s.showMarks())
updateSelection();
updateMiniBuffer();
@@ -2576,7 +2575,7 @@ bool FakeVimHandler::Private::wantsOverride(QKeyEvent *ev)
// We are interested in overriding most Ctrl key combinations.
if (isOnlyControlModifier(mods)
&& !s.passControlKey.value()
&& !s.passControlKey()
&& ((key >= Key_A && key <= Key_Z && key != Key_K)
|| key == Key_BracketLeft || key == Key_BracketRight)) {
// Ctrl-K is special as it is the Core's default notion of Locator
@@ -3059,7 +3058,7 @@ void FakeVimHandler::Private::stopIncrementalFind()
void FakeVimHandler::Private::updateFind(bool isComplete)
{
if (!isComplete && !s.incSearch.value())
if (!isComplete && !s.incSearch())
return;
g.currentMessage.clear();
@@ -3161,7 +3160,7 @@ void FakeVimHandler::Private::pushUndoState(bool overwrite)
pos = firstPositionInLine(lineForPosition(pos));
else if (isVisualBlockMode())
pos = blockAt(pos).position() + qMin(columnAt(anchor()), columnAt(position()));
} else if (g.movetype == MoveLineWise && s.startOfLine.value()) {
} else if (g.movetype == MoveLineWise && s.startOfLine()) {
QTextCursor tc = m_cursor;
if (g.submode == ShiftLeftSubMode || g.submode == ShiftRightSubMode
|| g.submode == IndentSubMode) {
@@ -3621,7 +3620,7 @@ void FakeVimHandler::Private::finishMovement(const QString &dotCommandMovement)
return;
} else if (g.submode == ExchangeSubMode) {
exchangeRange(currentRange());
} else if (g.submode == ReplaceWithRegisterSubMode && s.emulateReplaceWithRegister.value()) {
} else if (g.submode == ReplaceWithRegisterSubMode && s.emulateReplaceWithRegister()) {
pushUndoState(false);
beginEditBlock();
replaceWithRegister(currentRange());
@@ -3734,7 +3733,7 @@ void FakeVimHandler::Private::clearCurrentMode()
void FakeVimHandler::Private::updateSelection()
{
QList<QTextEdit::ExtraSelection> selections = m_extraSelections;
if (s.showMarks.value()) {
if (s.showMarks()) {
for (auto it = m_buffer->marks.cbegin(), end = m_buffer->marks.cend(); it != end; ++it) {
QTextEdit::ExtraSelection sel;
sel.cursor = m_cursor;
@@ -3753,7 +3752,7 @@ void FakeVimHandler::Private::updateSelection()
void FakeVimHandler::Private::updateHighlights()
{
if (s.useCoreSearch.value() || !s.hlSearch.value() || g.highlightsCleared) {
if (s.useCoreSearch() || !s.hlSearch() || g.highlightsCleared) {
if (m_highlighted.isEmpty())
return;
m_highlighted.clear();
@@ -3800,7 +3799,7 @@ void FakeVimHandler::Private::updateMiniBuffer()
} else if (!g.mapStates.isEmpty() && !g.mapStates.last().silent) {
// Do not reset previous message when after running a mapped command.
return;
} else if (g.mode == CommandMode && !g.currentCommand.isEmpty() && s.showCmd.value()) {
} else if (g.mode == CommandMode && !g.currentCommand.isEmpty() && s.showCmd()) {
msg = g.currentCommand;
messageLevel = MessageShowCmd;
} else if (g.mode == CommandMode && isVisualMode()) {
@@ -3907,7 +3906,7 @@ bool FakeVimHandler::Private::handleCommandSubSubMode(const Input &input)
handled = selectBlockTextObject(g.subsubdata.is('i'), '{', '}');
else if (input.is('"') || input.is('\'') || input.is('`'))
handled = selectQuotedStringTextObject(g.subsubdata.is('i'), input.asChar());
else if (input.is('a') && s.emulateArgTextObj.value())
else if (input.is('a') && s.emulateArgTextObj())
handled = selectArgumentTextObject(g.subsubdata.is('i'));
else
handled = false;
@@ -4050,7 +4049,7 @@ bool FakeVimHandler::Private::handleMovement(const Input &input)
g.subsubmode = NoSubSubMode;
} else if (input.is('/') || input.is('?')) {
g.lastSearchForward = input.is('/');
if (s.useCoreSearch.value()) {
if (s.useCoreSearch()) {
// re-use the core dialog.
g.findPending = true;
m_findStartPosition = position();
@@ -4225,7 +4224,7 @@ bool FakeVimHandler::Private::handleMovement(const Input &input)
m_cursor = EDITOR(cursorForPosition(QPoint(0, EDITOR(height()) / 2)));
handleStartOfLine();
} else if (input.is('n') || input.is('N')) {
if (s.useCoreSearch.value()) {
if (s.useCoreSearch()) {
bool forward = (input.is('n')) ? g.lastSearchForward : !g.lastSearchForward;
int pos = position();
q->findNextRequested(!forward);
@@ -4314,7 +4313,7 @@ EventResult FakeVimHandler::Private::handleCommandMode(const Input &input)
handled = handleNoSubMode(input);
} else if (g.submode == ExchangeSubMode) {
handled = handleExchangeSubMode(input);
} else if (g.submode == ChangeSubMode && input.is('x') && s.emulateExchange.value()) {
} else if (g.submode == ChangeSubMode && input.is('x') && s.emulateExchange()) {
// Exchange submode is "cx", so we need to switch over from ChangeSubMode here
g.submode = ExchangeSubMode;
handled = true;
@@ -4324,15 +4323,15 @@ EventResult FakeVimHandler::Private::handleCommandMode(const Input &input)
} else if (g.submode == AddSurroundingSubMode) {
handled = handleAddSurroundingSubMode(input);
} else if (g.submode == ChangeSubMode && (input.is('s') || input.is('S'))
&& s.emulateSurround.value()) {
&& s.emulateSurround()) {
g.submode = ChangeSurroundingSubMode;
g.surroundUpperCaseS = input.is('S');
handled = true;
} else if (g.submode == DeleteSubMode && input.is('s') && s.emulateSurround.value()) {
} else if (g.submode == DeleteSubMode && input.is('s') && s.emulateSurround()) {
g.submode = DeleteSurroundingSubMode;
handled = true;
} else if (g.submode == YankSubMode && (input.is('s') || input.is('S'))
&& s.emulateSurround.value()) {
&& s.emulateSurround()) {
g.submode = AddSurroundingSubMode;
g.movetype = MoveInclusive;
g.surroundUpperCaseS = input.is('S');
@@ -4341,10 +4340,9 @@ EventResult FakeVimHandler::Private::handleCommandMode(const Input &input)
|| g.submode == DeleteSubMode
|| g.submode == YankSubMode) {
handled = handleChangeDeleteYankSubModes(input);
} else if (g.submode == CommentSubMode && s.emulateVimCommentary.value()) {
} else if (g.submode == CommentSubMode && s.emulateVimCommentary()) {
handled = handleCommentSubMode(input);
} else if (g.submode == ReplaceWithRegisterSubMode
&& s.emulateReplaceWithRegister.value()) {
} else if (g.submode == ReplaceWithRegisterSubMode && s.emulateReplaceWithRegister()) {
handled = handleReplaceWithRegisterSubMode(input);
} else if (g.submode == ReplaceSubMode) {
handled = handleReplaceSubMode(input);
@@ -4487,7 +4485,7 @@ bool FakeVimHandler::Private::handleNoSubMode(const Input &input)
setTargetColumn();
} else if (input.isControl('a')) {
changeNumberTextObject(count());
} else if (g.gflag && input.is('c') && s.emulateVimCommentary.value()) {
} else if (g.gflag && input.is('c') && s.emulateVimCommentary()) {
if (isVisualMode()) {
pushUndoState();
@@ -4512,7 +4510,7 @@ bool FakeVimHandler::Private::handleNoSubMode(const Input &input)
pushUndoState();
setAnchor();
}
} else if (g.gflag && input.is('r') && s.emulateReplaceWithRegister.value()) {
} else if (g.gflag && input.is('r') && s.emulateReplaceWithRegister()) {
g.submode = ReplaceWithRegisterSubMode;
if (isVisualMode()) {
dotCommand = visualDotCommand() + QString::number(count()) + "gr";
@@ -4671,7 +4669,7 @@ bool FakeVimHandler::Private::handleNoSubMode(const Input &input)
int repeat = count();
while (--repeat >= 0)
redo();
} else if (input.is('S') && isVisualMode() && s.emulateSurround.value()) {
} else if (input.is('S') && isVisualMode() && s.emulateSurround()) {
g.submode = AddSurroundingSubMode;
g.subsubmode = SurroundSubSubMode;
} else if (input.is('s')) {
@@ -4756,7 +4754,7 @@ bool FakeVimHandler::Private::handleNoSubMode(const Input &input)
if (isVisualMode()) {
leaveVisualMode();
finishMovement();
} else if (g.gflag || (g.submode == InvertCaseSubMode && s.tildeOp.value())) {
} else if (g.gflag || (g.submode == InvertCaseSubMode && s.tildeOp())) {
if (atEndOfLine())
moveLeft();
setAnchor();
@@ -5404,8 +5402,8 @@ void FakeVimHandler::Private::handleInsertMode(const Input &input)
if (!handleInsertInEditor(Input(Qt::Key_Backspace, Qt::NoModifier))) {
joinPreviousEditBlock();
if (!m_buffer->lastInsertion.isEmpty()
|| s.backspace.value().contains("start")
|| s.backspace.value().contains("2")) {
|| s.backspace().contains("start")
|| s.backspace().contains("2")) {
const int line = cursorLine() + 1;
const Column col = cursorColumn();
QString data = lineContents(line);
@@ -5438,7 +5436,7 @@ void FakeVimHandler::Private::handleInsertMode(const Input &input)
} else if (input.isKey(Key_Tab)) {
if (q->tabPressedInInsertMode()) {
m_buffer->insertState.insertingSpaces = true;
if (s.expandTab.value()) {
if (s.expandTab()) {
const int ts = s.tabStop();
const int col = logicalCursorColumn();
QString str = QString(ts - col % ts, ' ');
@@ -5494,7 +5492,7 @@ void FakeVimHandler::Private::insertInInsertMode(const QString &text)
{
joinPreviousEditBlock();
insertText(text);
if (s.smartIndent.value() && isElectricCharacter(text.at(0))) {
if (s.smartIndent() && isElectricCharacter(text.at(0))) {
const QString leftText = block().text()
.left(position() - 1 - block().position());
if (leftText.simplified().isEmpty()) {
@@ -6265,7 +6263,7 @@ bool FakeVimHandler::Private::handleExMoveCommand(const ExCommand &cmd)
if (!insertAtEnd)
moveUp(1);
if (s.startOfLine.value())
if (s.startOfLine())
moveToFirstNonBlankOnLine();
if (lastAnchor.line >= startLine && lastAnchor.line <= endLine)
@@ -6794,7 +6792,7 @@ QTextCursor FakeVimHandler::Private::search(const SearchData &sd, int startPos,
}
if (tc.isNull()) {
if (s.wrapScan.value()) {
if (s.wrapScan()) {
tc = QTextCursor(document());
tc.movePosition(sd.forward ? StartOfDocument : EndOfDocument);
if (sd.forward)
@@ -6954,7 +6952,7 @@ void FakeVimHandler::Private::shiftRegionRight(int repeat)
std::swap(beginLine, endLine);
targetPos = position();
}
if (s.startOfLine.value())
if (s.startOfLine())
targetPos = firstPositionInLine(beginLine);
const int sw = s.shiftWidth();
@@ -7106,7 +7104,7 @@ void FakeVimHandler::Private::setupCharClass()
const QChar c = QLatin1Char(i);
m_charClass[i] = c.isSpace() ? 0 : 1;
}
const QString conf = s.isKeyword.value();
const QString conf = s.isKeyword();
for (const QString &part : conf.split(',')) {
if (part.contains('-')) {
const int from = someInt(part.section('-', 0, 0));
@@ -7594,7 +7592,7 @@ void FakeVimHandler::Private::transformText(const Range &range, const Transforma
void FakeVimHandler::Private::insertText(QTextCursor &tc, const QString &text)
{
if (s.passKeys.value()) {
if (s.passKeys()) {
if (tc.hasSelection() && text.isEmpty()) {
QKeyEvent event(QEvent::KeyPress, Qt::Key_Delete, Qt::NoModifier, QString());
passEventToEditor(event, tc);
@@ -7937,7 +7935,7 @@ void FakeVimHandler::Private::joinLines(int count, bool preserveSpace)
moveRight();
// If the line we started from is a comment, remove the comment string from the next line
if (startingLineIsComment && s.formatOptions.value().contains('f')) {
if (startingLineIsComment && s.formatOptions().contains('f')) {
if (characterAtCursor() == '/' && characterAt(position() + 1) == '/')
moveRight(2);
else if (characterAtCursor() == '*' || characterAtCursor() == '#')
@@ -7955,7 +7953,7 @@ void FakeVimHandler::Private::joinLines(int count, bool preserveSpace)
void FakeVimHandler::Private::insertNewLine()
{
if (m_buffer->editBlockLevel <= 1 && s.passKeys.value()) {
if (m_buffer->editBlockLevel <= 1 && s.passKeys()) {
QKeyEvent event(QEvent::KeyPress, Qt::Key_Return, Qt::NoModifier, "\n");
if (passEventToEditor(event, m_cursor))
return;
@@ -7967,7 +7965,7 @@ void FakeVimHandler::Private::insertNewLine()
bool FakeVimHandler::Private::handleInsertInEditor(const Input &input)
{
if (m_buffer->editBlockLevel > 0 || !s.passKeys.value())
if (m_buffer->editBlockLevel > 0 || !s.passKeys())
return false;
joinPreviousEditBlock();
@@ -8712,10 +8710,10 @@ QString FakeVimHandler::Private::tabExpand(int n) const
void FakeVimHandler::Private::insertAutomaticIndentation(bool goingDown, bool forceAutoIndent)
{
if (!forceAutoIndent && !s.autoIndent.value() && !s.smartIndent.value())
if (!forceAutoIndent && !s.autoIndent() && !s.smartIndent())
return;
if (s.smartIndent.value()) {
if (s.smartIndent()) {
QTextBlock bl = block();
Range range(bl.position(), bl.position());
indentText(range, '\n');
@@ -8734,7 +8732,7 @@ void FakeVimHandler::Private::insertAutomaticIndentation(bool goingDown, bool fo
void FakeVimHandler::Private::handleStartOfLine()
{
if (s.startOfLine.value())
if (s.startOfLine())
moveToFirstNonBlankOnLine();
}
@@ -9331,7 +9329,7 @@ void FakeVimHandler::Private::getRegisterType(int *reg, bool *isClipboard, bool
*reg = c.toLower().unicode();
if (c == '"') {
QStringList list = s.clipboard.value().split(',');
QStringList list = s.clipboard().split(',');
clipboard = list.contains("unnamedplus");
selection = list.contains("unnamed");
} else if (c == '+') {
@@ -9385,7 +9383,7 @@ void FakeVimHandler::updateGlobalMarksFilenames(const QString &oldFileName, cons
bool FakeVimHandler::eventFilter(QObject *ob, QEvent *ev)
{
#ifndef FAKEVIM_STANDALONE
if (!fakeVimSettings()->useFakeVim.value())
if (!settings().useFakeVim())
return QObject::eventFilter(ob, ev);
#endif

View File

@@ -340,134 +340,6 @@ private:
using ExCommandMap = QMap<QString, QRegularExpression>;
using UserCommandMap = QMap<int, QString>;
static void layoutPage(QWidget *widget)
{
using namespace Layouting;
FakeVimSettings &s = *fakeVimSettings();
Row bools {
Column {
s.autoIndent,
s.smartIndent,
s.expandTab,
s.smartTab,
s.hlSearch,
s.showCmd,
s.startOfLine,
s.passKeys,
s.blinkingCursor
},
Column {
s.incSearch,
s.useCoreSearch,
s.ignoreCase,
s.smartCase,
s.wrapScan,
s.showMarks,
s.passControlKey,
s.relativeNumber,
s.tildeOp
}
};
Row ints { s.shiftWidth, s.tabStop, s.scrollOff, st };
Column strings {
s.backspace,
s.isKeyword,
Row {s.readVimRc, s.vimRcPath}
};
Column {
s.useFakeVim,
Group {
title(Tr::tr("Vim Behavior")),
Column {
bools,
ints,
strings
}
},
Group {
title(Tr::tr("Plugin Emulation")),
Column {
s.emulateVimCommentary,
s.emulateReplaceWithRegister,
s.emulateArgTextObj,
s.emulateExchange,
s.emulateSurround
}
},
Row {
PushButton {
text(Tr::tr("Copy Text Editor Settings")),
onClicked([&s] {
TabSettings ts = TextEditorSettings::codeStyle()->tabSettings();
TypingSettings tps = TextEditorSettings::typingSettings();
s.expandTab.setValue(ts.m_tabPolicy != TabSettings::TabsOnlyTabPolicy);
s.tabStop.setValue(ts.m_tabSize);
s.shiftWidth.setValue(ts.m_indentSize);
s.smartTab.setValue(tps.m_smartBackspaceBehavior
== TypingSettings::BackspaceFollowsPreviousIndents);
s.autoIndent.setValue(true);
s.smartIndent.setValue(tps.m_autoIndent);
s.incSearch.setValue(true);
}),
},
PushButton {
text(Tr::tr("Set Qt Style")),
onClicked([&s] {
s.expandTab.setVolatileValue(true);
s.tabStop.setVolatileValue(4);
s.shiftWidth.setVolatileValue(4);
s.smartTab.setVolatileValue(true);
s.autoIndent.setVolatileValue(true);
s.smartIndent.setVolatileValue(true);
s.incSearch.setVolatileValue(true);
s.backspace.setVolatileValue(QString("indent,eol,start"));
s.passKeys.setVolatileValue(true);
}),
},
PushButton {
text(Tr::tr("Set Plain Style")),
onClicked([&s] {
s.expandTab.setVolatileValue(false);
s.tabStop.setVolatileValue(8);
s.shiftWidth.setVolatileValue(8);
s.smartTab.setVolatileValue(false);
s.autoIndent.setVolatileValue(false);
s.smartIndent.setVolatileValue(false);
s.incSearch.setVolatileValue(false);
s.backspace.setVolatileValue(QString());
s.passKeys.setVolatileValue(false);
}),
},
st
},
st
}.attachTo(widget);
s.vimRcPath.setEnabler(&s.readVimRc);
}
class FakeVimOptionPage : public IOptionsPage
{
public:
FakeVimOptionPage()
{
setId(SETTINGS_ID);
setDisplayName(Tr::tr("General"));
setCategory(SETTINGS_CATEGORY);
setDisplayCategory(Tr::tr("FakeVim"));
setCategoryIconPath(":/fakevim/images/settingscategory_fakevim.png");
setLayouter(&layoutPage);
setSettings(fakeVimSettings());
}
};
///////////////////////////////////////////////////////////////////////
//
@@ -507,7 +379,6 @@ public:
int cursorPos, int anchorPos, int messageLevel);
void handleExCommand(FakeVimHandler *handler, bool *handled, const ExCommand &cmd);
void writeSettings();
void readSettings();
void handleDelayedQuitAll(bool forced);
@@ -1107,7 +978,7 @@ IAssistProcessor *FakeVimCompletionAssistProvider::createProcessor(const AssistI
class FakeVimPluginRunData
{
public:
FakeVimOptionPage optionsPage;
FakeVimSettings settings;
FakeVimExCommandsPage exCommandsPage;
FakeVimUserCommandsPage userCommandsPage;
@@ -1179,7 +1050,7 @@ void FakeVimPluginPrivate::initialize()
Command *cmd = nullptr;
cmd = ActionManager::registerAction(fakeVimSettings()->useFakeVim.action(),
cmd = ActionManager::registerAction(settings().useFakeVim.action(),
INSTALL_HANDLER, Context(Core::Constants::C_GLOBAL), true);
cmd->setDefaultKeySequence(QKeySequence(useMacShortcuts ? Tr::tr("Meta+Shift+Y,Meta+Shift+Y")
: Tr::tr("Alt+Y,Alt+Y")));
@@ -1217,7 +1088,7 @@ void FakeVimPluginPrivate::initialize()
connect(DocumentManager::instance(), &DocumentManager::documentRenamed,
this, &FakeVimPluginPrivate::documentRenamed);
FakeVimSettings &s = *fakeVimSettings();
FakeVimSettings &s = settings();
connect(&s.useFakeVim, &FvBoolAspect::valueChanged,
this, &FakeVimPluginPrivate::setUseFakeVim);
connect(&s.readVimRc, &FvBaseAspect::changed,
@@ -1235,7 +1106,7 @@ void FakeVimPluginPrivate::initialize()
connect(this, &FakeVimPluginPrivate::delayedQuitAllRequested,
this, &FakeVimPluginPrivate::handleDelayedQuitAll, Qt::QueuedConnection);
setCursorBlinking(s.blinkingCursor.value());
setCursorBlinking(s.blinkingCursor());
}
void FakeVimPluginPrivate::userActionTriggered(int key)
@@ -1244,7 +1115,7 @@ void FakeVimPluginPrivate::userActionTriggered(int key)
FakeVimHandler *handler = m_editorToHandler[editor].handler;
if (handler) {
// If disabled, enable FakeVim mode just for single user command.
bool enableFakeVim = !fakeVimSettings()->useFakeVim.value();
bool enableFakeVim = !settings().useFakeVim();
if (enableFakeVim)
setUseFakeVimInternal(true);
@@ -1270,26 +1141,18 @@ void FakeVimPluginPrivate::createRelativeNumberWidget(IEditor *editor)
{
if (auto textEditor = TextEditorWidget::fromEditor(editor)) {
auto relativeNumbers = new RelativeNumbersColumn(textEditor);
connect(&fakeVimSettings()->relativeNumber, &FvBaseAspect::changed,
connect(&settings().relativeNumber, &FvBaseAspect::changed,
relativeNumbers, &QObject::deleteLater);
connect(&fakeVimSettings()->useFakeVim, &FvBaseAspect::changed,
connect(&settings().useFakeVim, &FvBaseAspect::changed,
relativeNumbers, &QObject::deleteLater);
relativeNumbers->show();
}
}
void FakeVimPluginPrivate::writeSettings()
{
QSettings *settings = ICore::settings();
fakeVimSettings()->writeSettings(settings);
}
void FakeVimPluginPrivate::readSettings()
{
QSettings *settings = ICore::settings();
fakeVimSettings()->readSettings(settings);
m_exCommandMap = m_defaultExCommandMap;
int size = settings->beginReadArray(exCommandMapGroup);
for (int i = 0; i < size; ++i) {
@@ -1318,9 +1181,9 @@ void FakeVimPluginPrivate::maybeReadVimRc()
//qDebug() << theFakeVimSetting(ConfigReadVimRc)
// << theFakeVimSetting(ConfigReadVimRc)->value();
//qDebug() << theFakeVimSetting(ConfigShiftWidth)->value();
if (!fakeVimSettings()->readVimRc.value())
if (!settings().readVimRc())
return;
QString fileName = fakeVimSettings()->vimRcPath.value();
QString fileName = settings().vimRcPath();
if (fileName.isEmpty()) {
fileName = QStandardPaths::writableLocation(QStandardPaths::HomeLocation)
+ QLatin1String(HostOsInfo::isWindowsHost() ? "/_vimrc" : "/.vimrc");
@@ -1330,7 +1193,6 @@ void FakeVimPluginPrivate::maybeReadVimRc()
QPlainTextEdit editor;
FakeVimHandler handler(&editor);
handler.handleCommand("source " + fileName);
//writeSettings();
//qDebug() << theFakeVimSetting(ConfigShiftWidth)->value();
}
@@ -1659,9 +1521,9 @@ void FakeVimPluginPrivate::editorOpened(IEditor *editor)
return;
TabSettings tabSettings;
tabSettings.m_indentSize = fakeVimSettings()->shiftWidth();
tabSettings.m_tabSize = fakeVimSettings()->tabStop();
tabSettings.m_tabPolicy = fakeVimSettings()->expandTab()
tabSettings.m_indentSize = settings().shiftWidth();
tabSettings.m_tabSize = settings().tabStop();
tabSettings.m_tabPolicy = settings().expandTab()
? TabSettings::SpacesOnlyTabPolicy : TabSettings::TabsOnlyTabPolicy;
tabSettings.m_continuationAlignBehavior =
tew->textDocument()->tabSettings().m_continuationAlignBehavior;
@@ -1885,19 +1747,15 @@ void FakeVimPluginPrivate::editorOpened(IEditor *editor)
*output = proc.cleanedStdOut();
});
connect(ICore::instance(), &ICore::saveSettingsRequested,
this, &FakeVimPluginPrivate::writeSettings);
handler->setCurrentFileName(editor->document()->filePath().toString());
handler->installEventFilter();
// pop up the bar
if (fakeVimSettings()->useFakeVim.value()) {
if (settings().useFakeVim()) {
resetCommandBuffer();
handler->setupWidget();
if (fakeVimSettings()->relativeNumber.value())
if (settings().relativeNumber())
createRelativeNumberWidget(editor);
}
}
@@ -1939,8 +1797,8 @@ void FakeVimPluginPrivate::setUseFakeVim(bool on)
//qDebug() << "SET USE FAKEVIM" << on;
Find::setUseFakeVim(on);
setUseFakeVimInternal(on);
setShowRelativeLineNumbers(fakeVimSettings()->relativeNumber.value());
setCursorBlinking(fakeVimSettings()->blinkingCursor.value());
setShowRelativeLineNumbers(settings().relativeNumber());
setCursorBlinking(settings().blinkingCursor());
}
void FakeVimPluginPrivate::setUseFakeVimInternal(bool on)
@@ -1968,7 +1826,7 @@ void FakeVimPluginPrivate::setUseFakeVimInternal(bool on)
void FakeVimPluginPrivate::setShowRelativeLineNumbers(bool on)
{
if (on && fakeVimSettings()->useFakeVim.value()) {
if (on && settings().useFakeVim()) {
for (auto it = m_editorToHandler.constBegin(); it != m_editorToHandler.constEnd(); ++it)
createRelativeNumberWidget(it.key());
}
@@ -1979,7 +1837,7 @@ void FakeVimPluginPrivate::setCursorBlinking(bool on)
if (m_savedCursorFlashTime == 0)
m_savedCursorFlashTime = QGuiApplication::styleHints()->cursorFlashTime();
const bool blink = on || !fakeVimSettings()->useFakeVim.value();
const bool blink = on || !settings().useFakeVim();
QGuiApplication::styleHints()->setCursorFlashTime(blink ? m_savedCursorFlashTime : 0);
}
@@ -2123,7 +1981,7 @@ void FakeVimPluginPrivate::handleDelayedQuitAll(bool forced)
void FakeVimPluginPrivate::quitFakeVim()
{
fakeVimSettings()->useFakeVim.setValue(false);
settings().useFakeVim.setValue(false);
}
void FakeVimPluginPrivate::resetCommandBuffer()

View File

@@ -93,8 +93,8 @@ FossilCommitWidget::FossilCommitWidget() : m_commitPanel(new QWidget)
m_invalidBranchLabel->setType(InfoLabel::Error);
m_isPrivateCheckBox = new QCheckBox(Tr::tr("Private"));
m_isPrivateCheckBox->setToolTip(Tr::tr("Create a private check-in that is never synced.\n"
"Children of private check-ins are automatically private.\n"
m_isPrivateCheckBox->setToolTip("<html>" + Tr::tr("Create a private check-in that is never synced. "
"Children of private check-ins are automatically private. "
"Private check-ins are not pushed to the remote repository by default."));
m_tagsLineEdit = new QLineEdit;

View File

@@ -88,9 +88,9 @@ FossilSettings::FossilSettings()
logCount.setToolTip(Tr::tr("The number of recent commit log entries to show. "
"Choose 0 to see all entries."));
setLayouter([this](QWidget *widget) {
setLayouter([this] {
using namespace Layouting;
Column {
return Column {
Group {
title(Tr::tr("Configuration")),
Row { binaryPath }
@@ -117,7 +117,7 @@ FossilSettings::FossilSettings()
},
},
st
}.attachTo(widget);
};
});
}

View File

@@ -34,7 +34,7 @@ PullOrPushDialog::PullOrPushDialog(Mode mode, QWidget *parent)
m_localPathChooser->setPromptDialogFilter(Tr::tr(Constants::FOSSIL_FILE_FILTER));
m_urlButton = new QRadioButton(Tr::tr("Specify URL:"));
m_urlButton->setToolTip(Tr::tr("For example: https://[user[:pass]@]host[:port]/[path]"));
m_urlButton->setToolTip(Tr::tr("For example: \"https://[user[:pass]@]host[:port]/[path]\"."));
m_urlLineEdit = new QLineEdit;
m_urlLineEdit->setEnabled(false);

View File

@@ -86,7 +86,7 @@
{
"name": "Repo",
"trDisplayName": "Remote repository:",
"trToolTip": "For example: https://[user[:pass]@]host[:port]/[path]",
"trToolTip": "For example: \"https://[user[:pass]@]host[:port]/[path]\".",
"type": "LineEdit",
"enabled": "%{isCloneRepo}",
"mandatory": false

View File

@@ -43,8 +43,8 @@ public:
curlChooser->setCommandVersionArguments({"-V"});
auto portSpinBox = new QSpinBox(this);
portSpinBox->setValue(p->server.port);
portSpinBox->setRange(1, 65535);
portSpinBox->setValue(p->server.port);
auto httpsCheckBox = new QCheckBox(Git::Tr::tr("HTTPS"));
httpsCheckBox->setChecked(p->https);

View File

@@ -441,7 +441,7 @@ ShowController::ShowController(IDocument *document, const QString &id)
};
using namespace std::placeholders;
QList<TaskItem> tasks {parallel, continueOnDone, onGroupError(onFollowsError)};
QList<GroupItem> tasks {parallel, continueOnDone, onGroupError(onFollowsError)};
for (int i = 0, total = parents.size(); i < total; ++i) {
tasks.append(ProcessTask(std::bind(setupFollow, _1, parents.at(i)),
std::bind(onFollowDone, _1, i)));
@@ -465,11 +465,11 @@ ShowController::ShowController(IDocument *document, const QString &id)
parallel,
onGroupSetup([this] { setStartupFile(VcsBase::source(this->document()).toString()); }),
Group {
optional,
finishAllAndDone,
ProcessTask(setupDescription, onDescriptionDone),
Group {
parallel,
optional,
finishAllAndDone,
onGroupSetup(desciptionDetailsSetup),
ProcessTask(setupBranches, onBranchesDone, onBranchesError),
ProcessTask(setupPrecedes, onPrecedesDone, onPrecedesError),
@@ -2873,7 +2873,7 @@ bool GitClient::addAndCommit(const FilePath &repositoryDirectory,
GitPlugin::updateCurrentBranch();
return true;
}
VcsOutputWindow::appendError(Tr::tr("Cannot commit %n files", nullptr, commitCount) + "\n");
VcsOutputWindow::appendError(Tr::tr("Cannot commit %n file(s)", nullptr, commitCount) + "\n");
return false;
}

View File

@@ -21,13 +21,12 @@
#include <utils/qtcassert.h>
#include <QCheckBox>
#include <QFuture>
#include <QHBoxLayout>
#include <QRegularExpressionValidator>
#include <QSettings>
#include <QTextStream>
using namespace Core;
using namespace TextEditor;
using namespace Utils;
using namespace VcsBase;
@@ -43,91 +42,106 @@ public:
QString id() const { return recurseSubmodules ? ref + ".Rec" : ref; }
};
class GitGrepRunner
static QStringView nextLine(QStringView *remainingInput)
{
using PromiseType = QPromise<SearchResultItems>;
public:
GitGrepRunner(const TextEditor::FileFindParameters &parameters)
: m_parameters(parameters)
{
m_directory = FilePath::fromString(parameters.additionalParameters.toString());
m_vcsBinary = GitClient::instance()->vcsBinary();
m_environment = GitClient::instance()->processEnvironment();
const int newLinePos = remainingInput->indexOf('\n');
if (newLinePos < 0) {
QStringView ret = *remainingInput;
*remainingInput = QStringView();
return ret;
}
QStringView ret = remainingInput->left(newLinePos);
*remainingInput = remainingInput->mid(newLinePos + 1);
return ret;
}
struct Match
{
Match() = default;
Match(int start, int length) :
matchStart(start), matchLength(length) {}
struct Match
{
Match() = default;
Match(int start, int length) :
matchStart(start), matchLength(length) {}
int matchStart = 0;
int matchLength = 0;
QStringList regexpCapturedTexts;
};
int matchStart = 0;
int matchLength = 0;
QStringList regexpCapturedTexts;
};
void processLine(const QString &line, SearchResultItems *resultList) const
{
static void processLine(QStringView line, SearchResultItems *resultList,
const std::optional<QRegularExpression> &regExp, const QString &ref,
const FilePath &directory)
{
if (line.isEmpty())
return;
static const QLatin1String boldRed("\x1b[1;31m");
static const QLatin1String resetColor("\x1b[m");
SearchResultItem result;
const int lineSeparator = line.indexOf(QChar::Null);
QStringView filePath = line.left(lineSeparator);
if (!ref.isEmpty() && filePath.startsWith(ref))
filePath = filePath.mid(ref.length());
result.setFilePath(directory.pathAppended(filePath.toString()));
const int textSeparator = line.indexOf(QChar::Null, lineSeparator + 1);
const int lineNumber = line.mid(lineSeparator + 1, textSeparator - lineSeparator - 1).toInt();
QString text = line.mid(textSeparator + 1).toString();
QList<Match> matches;
while (true) {
const int matchStart = text.indexOf(boldRed);
if (matchStart == -1)
break;
const int matchTextStart = matchStart + boldRed.size();
const int matchEnd = text.indexOf(resetColor, matchTextStart);
QTC_ASSERT(matchEnd != -1, break);
const int matchLength = matchEnd - matchTextStart;
Match match(matchStart, matchLength);
const QString matchText = text.mid(matchTextStart, matchLength);
if (regExp)
match.regexpCapturedTexts = regExp->match(matchText).capturedTexts();
matches.append(match);
text = text.left(matchStart) + matchText + text.mid(matchEnd + resetColor.size());
}
result.setDisplayText(text);
for (const auto &match : std::as_const(matches)) {
result.setMainRange(lineNumber, match.matchStart, match.matchLength);
result.setUserData(match.regexpCapturedTexts);
result.setUseTextEditorFont(true);
resultList->append(result);
}
}
static SearchResultItems parse(const QFuture<void> &future, const QString &input,
const std::optional<QRegularExpression> &regExp, const QString &ref,
const FilePath &directory)
{
SearchResultItems items;
QStringView remainingInput(input);
while (true) {
if (future.isCanceled())
return {};
if (remainingInput.isEmpty())
break;
const QStringView line = nextLine(&remainingInput);
if (line.isEmpty())
return;
static const QLatin1String boldRed("\x1b[1;31m");
static const QLatin1String resetColor("\x1b[m");
SearchResultItem result;
const int lineSeparator = line.indexOf(QChar::Null);
QString filePath = line.left(lineSeparator);
if (!m_ref.isEmpty() && filePath.startsWith(m_ref))
filePath.remove(0, m_ref.length());
result.setFilePath(m_directory.pathAppended(filePath));
const int textSeparator = line.indexOf(QChar::Null, lineSeparator + 1);
const int lineNumber = line.mid(lineSeparator + 1, textSeparator - lineSeparator - 1).toInt();
QString text = line.mid(textSeparator + 1);
QRegularExpression regexp;
QList<Match> matches;
if (m_parameters.flags & FindRegularExpression) {
const QRegularExpression::PatternOptions patternOptions =
(m_parameters.flags & FindCaseSensitively)
? QRegularExpression::NoPatternOption : QRegularExpression::CaseInsensitiveOption;
regexp.setPattern(m_parameters.text);
regexp.setPatternOptions(patternOptions);
}
for (;;) {
const int matchStart = text.indexOf(boldRed);
if (matchStart == -1)
break;
const int matchTextStart = matchStart + boldRed.size();
const int matchEnd = text.indexOf(resetColor, matchTextStart);
QTC_ASSERT(matchEnd != -1, break);
const int matchLength = matchEnd - matchTextStart;
Match match(matchStart, matchLength);
const QString matchText = text.mid(matchTextStart, matchLength);
if (m_parameters.flags & FindRegularExpression)
match.regexpCapturedTexts = regexp.match(matchText).capturedTexts();
matches.append(match);
text = text.left(matchStart) + matchText + text.mid(matchEnd + resetColor.size());
}
result.setDisplayText(text);
continue;
for (const auto &match : std::as_const(matches)) {
result.setMainRange(lineNumber, match.matchStart, match.matchLength);
result.setUserData(match.regexpCapturedTexts);
resultList->append(result);
}
processLine(line, &items, regExp, ref, directory);
}
return items;
}
void read(PromiseType &fi, const QString &text)
{
SearchResultItems resultList;
QString t = text;
QTextStream stream(&t);
while (!stream.atEnd() && !fi.isCanceled())
processLine(stream.readLine(), &resultList);
if (!resultList.isEmpty() && !fi.isCanceled())
fi.addResult(resultList);
}
static void runGitGrep(QPromise<SearchResultItems> &promise, const FileFindParameters &parameters)
{
const FilePath directory = FilePath::fromString(parameters.additionalParameters.toString());
const GitGrepParameters gitParameters
= parameters.searchEngineParameters.value<GitGrepParameters>();
const QString ref = gitParameters.ref.isEmpty() ? QString() : gitParameters.ref + ':';
const auto setupProcess = [&](Process &process) {
const FilePath vcsBinary = GitClient::instance()->vcsBinary();
const Environment environment = GitClient::instance()->processEnvironment();
void operator()(PromiseType &promise)
{
QStringList arguments = {
"-c", "color.grep.match=bold red",
"-c", "color.grep=always",
@@ -135,60 +149,41 @@ public:
"-c", "color.grep.lineNumber=",
"grep", "-zn", "--no-full-name"
};
if (!(m_parameters.flags & FindCaseSensitively))
if (!(parameters.flags & FindCaseSensitively))
arguments << "-i";
if (m_parameters.flags & FindWholeWords)
if (parameters.flags & FindWholeWords)
arguments << "-w";
if (m_parameters.flags & FindRegularExpression)
if (parameters.flags & FindRegularExpression)
arguments << "-P";
else
arguments << "-F";
arguments << "-e" << m_parameters.text;
GitGrepParameters params = m_parameters.searchEngineParameters.value<GitGrepParameters>();
if (params.recurseSubmodules)
arguments << "-e" << parameters.text;
if (gitParameters.recurseSubmodules)
arguments << "--recurse-submodules";
if (!params.ref.isEmpty()) {
arguments << params.ref;
m_ref = params.ref + ':';
if (!gitParameters.ref.isEmpty()) {
arguments << gitParameters.ref;
}
const QStringList filterArgs =
m_parameters.nameFilters.isEmpty() ? QStringList("*") // needed for exclusion filters
: m_parameters.nameFilters;
parameters.nameFilters.isEmpty() ? QStringList("*") // needed for exclusion filters
: parameters.nameFilters;
const QStringList exclusionArgs =
Utils::transform(m_parameters.exclusionFilters, [](const QString &filter) {
return QString(":!" + filter);
});
Utils::transform(parameters.exclusionFilters, [](const QString &filter) {
return QString(":!" + filter);
});
arguments << "--" << filterArgs << exclusionArgs;
Process process;
process.setEnvironment(m_environment);
process.setCommand({m_vcsBinary, arguments});
process.setWorkingDirectory(m_directory);
process.setStdOutCallback([this, &promise](const QString &text) { read(promise, text); });
process.start();
process.waitForFinished();
process.setEnvironment(environment);
process.setCommand({vcsBinary, arguments});
process.setWorkingDirectory(directory);
};
switch (process.result()) {
case ProcessResult::TerminatedAbnormally:
case ProcessResult::StartFailed:
case ProcessResult::Hang:
promise.future().cancel();
break;
case ProcessResult::FinishedWithSuccess:
case ProcessResult::FinishedWithError:
// When no results are found, git-grep exits with non-zero status.
// Do not consider this as an error.
break;
}
}
const auto outputParser = [&ref, &directory](const QFuture<void> &future, const QString &input,
const std::optional<QRegularExpression> &regExp) {
return parse(future, input, regExp, ref, directory);
};
private:
FilePath m_vcsBinary;
FilePath m_directory;
QString m_ref;
TextEditor::FileFindParameters m_parameters;
Environment m_environment;
};
TextEditor::searchInProcessOutput(promise, parameters, setupProcess, outputParser);
}
static bool isGitDirectory(const FilePath &path)
{
@@ -211,18 +206,16 @@ GitGrep::GitGrep(GitClient *client)
m_treeLineEdit->setValidator(new QRegularExpressionValidator(refExpression, this));
layout->addWidget(m_treeLineEdit);
// asynchronously check git version, add "recurse submodules" option if available
Utils::onResultReady(client->gitVersion(),
this,
Utils::onResultReady(client->gitVersion(), this,
[this, pLayout = QPointer<QHBoxLayout>(layout)](unsigned version) {
if (version >= 0x021300 && pLayout) {
m_recurseSubmodules = new QCheckBox(Tr::tr("Recurse submodules"));
pLayout->addWidget(m_recurseSubmodules);
}
});
TextEditor::FindInFiles *findInFiles = TextEditor::FindInFiles::instance();
if (version >= 0x021300 && pLayout) {
m_recurseSubmodules = new QCheckBox(Tr::tr("Recurse submodules"));
pLayout->addWidget(m_recurseSubmodules);
}
});
FindInFiles *findInFiles = FindInFiles::instance();
QTC_ASSERT(findInFiles, return);
connect(findInFiles, &TextEditor::FindInFiles::pathChanged,
m_widget, [this](const FilePath &path) {
connect(findInFiles, &FindInFiles::pathChanged, m_widget, [this](const FilePath &path) {
setEnabled(isGitDirectory(path));
});
connect(this, &SearchEngine::enabledChanged, m_widget, &QWidget::setEnabled);
@@ -271,14 +264,14 @@ void GitGrep::writeSettings(QSettings *settings) const
settings->setValue(GitGrepRef, m_treeLineEdit->text());
}
QFuture<SearchResultItems> GitGrep::executeSearch(const TextEditor::FileFindParameters &parameters,
TextEditor::BaseFileFind * /*baseFileFind*/)
QFuture<SearchResultItems> GitGrep::executeSearch(const FileFindParameters &parameters,
BaseFileFind *)
{
return Utils::asyncRun(GitGrepRunner(parameters));
return Utils::asyncRun(runGitGrep, parameters);
}
IEditor *GitGrep::openEditor(const SearchResultItem &item,
const TextEditor::FileFindParameters &parameters)
const FileFindParameters &parameters)
{
const GitGrepParameters params = parameters.searchEngineParameters.value<GitGrepParameters>();
const QStringList &itemPath = item.path();

View File

@@ -9,10 +9,7 @@ QT_BEGIN_NAMESPACE
class QCheckBox;
QT_END_NAMESPACE
namespace Utils {
class FancyLineEdit;
class SearchResultItem;
}
namespace Utils { class FancyLineEdit; }
namespace Git::Internal {

View File

@@ -90,8 +90,8 @@ GitSettings::GitSettings()
instantBlame.setSettingsKey("Git Instant");
instantBlame.setDefaultValue(true);
instantBlame.setLabelText(Tr::tr("Add instant blame annotations to editor"));
instantBlame.setToolTip(Tr::tr("Directly annotate each line in the editor "
"when scrolling through the document."));
instantBlame.setToolTip(
Tr::tr("Annotate the current line in the editor with Git \"blame\" output."));
graphLog.setSettingsKey("GraphLog");

View File

@@ -356,6 +356,7 @@ void Client::setName(const QString &name)
QString Client::name() const
{
if (d->m_project && !d->m_project->displayName().isEmpty())
//: <language client> for <project>
return Tr::tr("%1 for %2").arg(d->m_displayName, d->m_project->displayName());
return d->m_displayName;
}
@@ -555,11 +556,17 @@ Client::State Client::state() const
QString Client::stateString() const
{
switch (d->m_state){
//: language client state
case Uninitialized: return Tr::tr("uninitialized");
//: language client state
case InitializeRequested: return Tr::tr("initialize requested");
//: language client state
case Initialized: return Tr::tr("initialized");
//: language client state
case ShutdownRequested: return Tr::tr("shutdown requested");
//: language client state
case Shutdown: return Tr::tr("shut down");
//: language client state
case Error: return Tr::tr("error");
}
return {};
@@ -1970,7 +1977,7 @@ void ClientPrivate::initializeCallback(const InitializeRequest::Response &initRe
if (std::optional<ResponseError<InitializeError>> error = initResponse.error()) {
if (std::optional<InitializeError> data = error->data()) {
if (data->retry()) {
const QString title(Tr::tr("Language Server \"%1\" Initialize Error").arg(m_displayName));
const QString title(Tr::tr("Language Server \"%1\" Initialization Error").arg(m_displayName));
auto result = QMessageBox::warning(Core::ICore::dialogParent(),
title,
error->message(),
@@ -1983,7 +1990,7 @@ void ClientPrivate::initializeCallback(const InitializeRequest::Response &initRe
}
}
}
q->setError(Tr::tr("Initialize error: ") + error->message());
q->setError(Tr::tr("Initialization error: %1.").arg(error->message()));
emit q->finished();
return;
}

View File

@@ -8,6 +8,7 @@
#include <languageserverprotocol/progresssupport.h>
#include <QTime>
#include <QTimer>
using namespace LanguageServerProtocol;
@@ -81,9 +82,28 @@ void ProgressManager::beginProgress(const ProgressToken &token, const WorkDonePr
auto interface = new QFutureInterface<void>();
interface->reportStarted();
interface->setProgressRange(0, 100); // LSP always reports percentage of the task
const QString title = m_titles.value(token, begin.title());
Core::FutureProgress *progress = Core::ProgressManager::addTask(
interface->future(), title, languageClientProgressId(token));
ProgressItem progressItem;
progressItem.futureInterface = interface;
progressItem.title = m_titles.value(token, begin.title());
if (LOGPROGRESS().isDebugEnabled())
progressItem.timer.start();
progressItem.showBarTimer = new QTimer();
progressItem.showBarTimer->setSingleShot(true);
progressItem.showBarTimer->setInterval(750);
progressItem.showBarTimer->callOnTimeout([this, token]() { spawnProgressBar(token); });
progressItem.showBarTimer->start();
m_progress[token] = progressItem;
reportProgress(token, begin);
}
void ProgressManager::spawnProgressBar(const LanguageServerProtocol::ProgressToken &token)
{
ProgressItem &progressItem = m_progress[token];
QTC_ASSERT(progressItem.futureInterface, return);
Core::FutureProgress *progress
= Core::ProgressManager::addTask(progressItem.futureInterface->future(),
progressItem.title,
languageClientProgressId(token));
const std::function<void()> clickHandler = m_clickHandlers.value(token);
if (clickHandler)
QObject::connect(progress, &Core::FutureProgress::clicked, clickHandler);
@@ -92,23 +112,26 @@ void ProgressManager::beginProgress(const ProgressToken &token, const WorkDonePr
QObject::connect(progress, &Core::FutureProgress::canceled, cancelHandler);
else
progress->setCancelEnabled(false);
m_progress[token] = {progress, interface};
if (LOGPROGRESS().isDebugEnabled())
m_timer[token].start();
reportProgress(token, begin);
if (!progressItem.message.isEmpty()) {
progress->setSubtitle(progressItem.message);
progress->setSubtitleVisibleInStatusBar(true);
}
progressItem.progressInterface = progress;
}
void ProgressManager::reportProgress(const ProgressToken &token,
const WorkDoneProgressReport &report)
{
const LanguageClientProgress &progress = m_progress.value(token);
ProgressItem &progress = m_progress[token];
const std::optional<QString> &message = report.message();
if (progress.progressInterface) {
const std::optional<QString> &message = report.message();
if (message.has_value()) {
progress.progressInterface->setSubtitle(*message);
const bool showSubtitle = !message->isEmpty();
progress.progressInterface->setSubtitleVisibleInStatusBar(showSubtitle);
}
} else if (message.has_value()) {
progress.message = *message;
}
if (progress.futureInterface) {
if (const std::optional<double> &percentage = report.percentage(); percentage.has_value())
@@ -118,7 +141,7 @@ void ProgressManager::reportProgress(const ProgressToken &token,
void ProgressManager::endProgress(const ProgressToken &token, const WorkDoneProgressEnd &end)
{
const LanguageClientProgress &progress = m_progress.value(token);
const ProgressItem &progress = m_progress.value(token);
const QString &message = end.message().value_or(QString());
if (progress.progressInterface) {
if (!message.isEmpty()) {
@@ -127,11 +150,11 @@ void ProgressManager::endProgress(const ProgressToken &token, const WorkDoneProg
}
progress.progressInterface->setSubtitle(message);
progress.progressInterface->setSubtitleVisibleInStatusBar(!message.isEmpty());
auto timer = m_timer.take(token);
if (timer.isValid()) {
if (progress.timer.isValid()) {
qCDebug(LOGPROGRESS) << QString("%1 took %2")
.arg(progress.progressInterface->title())
.arg(QTime::fromMSecsSinceStartOfDay(timer.elapsed())
.arg(QTime::fromMSecsSinceStartOfDay(
progress.timer.elapsed())
.toString(Qt::ISODateWithMs));
}
}
@@ -140,7 +163,8 @@ void ProgressManager::endProgress(const ProgressToken &token, const WorkDoneProg
void ProgressManager::endProgressReport(const ProgressToken &token)
{
const LanguageClientProgress &progress = m_progress.take(token);
ProgressItem progress = m_progress.take(token);
delete progress.showBarTimer;
if (progress.futureInterface)
progress.futureInterface->reportFinished();
delete progress.futureInterface;

View File

@@ -11,6 +11,10 @@
#include <QFutureInterface>
#include <QPointer>
QT_BEGIN_NAMESPACE
class QTimer;
QT_END_NAMESPACE
namespace LanguageServerProtocol {
class ProgressParams;
class ProgressToken;
@@ -46,15 +50,20 @@ private:
const LanguageServerProtocol::WorkDoneProgressReport &report);
void endProgress(const LanguageServerProtocol::ProgressToken &token,
const LanguageServerProtocol::WorkDoneProgressEnd &end);
void spawnProgressBar(const LanguageServerProtocol::ProgressToken &token);
struct LanguageClientProgress {
struct ProgressItem
{
QPointer<Core::FutureProgress> progressInterface = nullptr;
QFutureInterface<void> *futureInterface = nullptr;
QElapsedTimer timer;
QTimer *showBarTimer = nullptr;
QString message;
QString title;
};
QMap<LanguageServerProtocol::ProgressToken, LanguageClientProgress> m_progress;
QMap<LanguageServerProtocol::ProgressToken, ProgressItem> m_progress;
QMap<LanguageServerProtocol::ProgressToken, QString> m_titles;
QMap<LanguageServerProtocol::ProgressToken, QElapsedTimer> m_timer;
QMap<LanguageServerProtocol::ProgressToken, std::function<void()>> m_clickHandlers;
QMap<LanguageServerProtocol::ProgressToken, std::function<void()>> m_cancelHandlers;
};

View File

@@ -9,7 +9,6 @@ add_qtc_plugin(Macros
macrolocatorfilter.cpp macrolocatorfilter.h
macromanager.cpp macromanager.h
macrooptionspage.cpp macrooptionspage.h
macrooptionswidget.cpp macrooptionswidget.h
macros.qrc
macrosconstants.h
macrosplugin.cpp macrosplugin.h

View File

@@ -3,15 +3,195 @@
#include "macrooptionspage.h"
#include "macro.h"
#include "macromanager.h"
#include "macrooptionswidget.h"
#include "macrosconstants.h"
#include "macrostr.h"
#include <coreplugin/actionmanager/actionmanager.h>
#include <coreplugin/actionmanager/command.h>
#include <coreplugin/coreconstants.h>
#include <coreplugin/icore.h>
#include <texteditor/texteditorconstants.h>
namespace Macros {
namespace Internal {
#include <utils/layoutbuilder.h>
#include <QAction>
#include <QDir>
#include <QFileInfo>
#include <QGroupBox>
#include <QHeaderView>
#include <QLabel>
#include <QLineEdit>
#include <QMap>
#include <QPushButton>
#include <QStringList>
#include <QTreeWidget>
#include <QTreeWidgetItem>
namespace Macros::Internal {
const int NAME_ROLE = Qt::UserRole;
const int WRITE_ROLE = Qt::UserRole + 1;
class MacroOptionsWidget final : public Core::IOptionsPageWidget
{
public:
MacroOptionsWidget();
void initialize();
void apply() final;
private:
void remove();
void changeCurrentItem(QTreeWidgetItem *current);
void createTable();
void changeDescription(const QString &description);
QStringList m_macroToRemove;
bool m_changingCurrent = false;
QMap<QString, QString> m_macroToChange;
QTreeWidget *m_treeWidget;
QPushButton *m_removeButton;
QGroupBox *m_macroGroup;
QLineEdit *m_description;
};
MacroOptionsWidget::MacroOptionsWidget()
{
m_treeWidget = new QTreeWidget;
m_treeWidget->setTextElideMode(Qt::ElideLeft);
m_treeWidget->setUniformRowHeights(true);
m_treeWidget->setSortingEnabled(true);
m_treeWidget->setColumnCount(3);
m_treeWidget->header()->setSortIndicatorShown(true);
m_treeWidget->header()->setStretchLastSection(true);
m_treeWidget->header()->setSortIndicator(0, Qt::AscendingOrder);
m_treeWidget->setHeaderLabels({Tr::tr("Name"), Tr::tr("Description"), Tr::tr("Shortcut")});
m_description = new QLineEdit;
m_removeButton = new QPushButton(Tr::tr("Remove"));
m_macroGroup = new QGroupBox(Tr::tr("Macro"), this);
using namespace Layouting;
Row {
Tr::tr("Description:"), m_description
}.attachTo(m_macroGroup);
Column {
Group {
title(Tr::tr("Preferences")),
Row {
m_treeWidget,
Column { m_removeButton, st },
}
},
m_macroGroup
}.attachTo(this);
connect(m_treeWidget, &QTreeWidget::currentItemChanged,
this, &MacroOptionsWidget::changeCurrentItem);
connect(m_removeButton, &QPushButton::clicked,
this, &MacroOptionsWidget::remove);
connect(m_description, &QLineEdit::textChanged,
this, &MacroOptionsWidget::changeDescription);
initialize();
}
void MacroOptionsWidget::initialize()
{
m_macroToRemove.clear();
m_macroToChange.clear();
m_treeWidget->clear();
changeCurrentItem(nullptr);
// Create the treeview
createTable();
}
void MacroOptionsWidget::createTable()
{
QDir dir(MacroManager::macrosDirectory());
const Utils::Id base = Utils::Id(Constants::PREFIX_MACRO);
for (Macro *macro : MacroManager::macros()) {
QFileInfo fileInfo(macro->fileName());
if (fileInfo.absoluteDir() == dir.absolutePath()) {
auto macroItem = new QTreeWidgetItem(m_treeWidget);
macroItem->setText(0, macro->displayName());
macroItem->setText(1, macro->description());
macroItem->setData(0, NAME_ROLE, macro->displayName());
macroItem->setData(0, WRITE_ROLE, macro->isWritable());
Core::Command *command =
Core::ActionManager::command(base.withSuffix(macro->displayName()));
if (command && command->action()) {
macroItem->setText(2,
command->action()->shortcut().toString(QKeySequence::NativeText));
}
}
}
}
void MacroOptionsWidget::changeCurrentItem(QTreeWidgetItem *current)
{
m_changingCurrent = true;
m_removeButton->setEnabled(current);
m_macroGroup->setEnabled(current);
if (!current) {
m_description->clear();
} else {
m_description->setText(current->text(1));
m_description->setEnabled(current->data(0, WRITE_ROLE).toBool());
}
m_changingCurrent = false;
}
void MacroOptionsWidget::remove()
{
QTreeWidgetItem *current = m_treeWidget->currentItem();
m_macroToRemove.append(current->data(0, NAME_ROLE).toString());
delete current;
}
void MacroOptionsWidget::apply()
{
// Remove macro
for (const QString &name : std::as_const(m_macroToRemove)) {
MacroManager::instance()->deleteMacro(name);
m_macroToChange.remove(name);
}
// Change macro
for (auto it = m_macroToChange.cbegin(), end = m_macroToChange.cend(); it != end; ++it)
MacroManager::instance()->changeMacro(it.key(), it.value());
// Reinitialize the page
initialize();
}
void MacroOptionsWidget::changeDescription(const QString &description)
{
QTreeWidgetItem *current = m_treeWidget->currentItem();
if (m_changingCurrent || !current)
return;
QString macroName = current->data(0, NAME_ROLE).toString();
m_macroToChange[macroName] = description;
current->setText(1, description);
QFont font = current->font(1);
font.setItalic(true);
current->setFont(1, font);
}
MacroOptionsPage::MacroOptionsPage()
{
@@ -21,5 +201,4 @@ MacroOptionsPage::MacroOptionsPage()
setWidgetCreator([] { return new MacroOptionsWidget; });
}
} // Internal
} // Macros
} // Macros::Internal

View File

@@ -5,8 +5,7 @@
#include <coreplugin/dialogs/ioptionspage.h>
namespace Macros {
namespace Internal {
namespace Macros::Internal {
class MacroOptionsPage final : public Core::IOptionsPage
{
@@ -14,5 +13,4 @@ public:
MacroOptionsPage();
};
} // namespace Internal
} // namespace Macros
} // Macros::Internal

View File

@@ -1,166 +0,0 @@
// Copyright (C) 2016 Nicolas Arnaud-Cormos
// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only WITH Qt-GPL-exception-1.0
#include "macrooptionswidget.h"
#include "macro.h"
#include "macromanager.h"
#include "macrosconstants.h"
#include "macrostr.h"
#include <coreplugin/icore.h>
#include <coreplugin/coreconstants.h>
#include <coreplugin/actionmanager/actionmanager.h>
#include <coreplugin/actionmanager/command.h>
#include <utils/layoutbuilder.h>
#include <QAction>
#include <QDir>
#include <QFileInfo>
#include <QGroupBox>
#include <QHeaderView>
#include <QLabel>
#include <QLineEdit>
#include <QPushButton>
#include <QTreeWidget>
#include <QTreeWidgetItem>
namespace Macros::Internal {
const int NAME_ROLE = Qt::UserRole;
const int WRITE_ROLE = Qt::UserRole + 1;
MacroOptionsWidget::MacroOptionsWidget()
{
m_treeWidget = new QTreeWidget;
m_treeWidget->setTextElideMode(Qt::ElideLeft);
m_treeWidget->setUniformRowHeights(true);
m_treeWidget->setSortingEnabled(true);
m_treeWidget->setColumnCount(3);
m_treeWidget->header()->setSortIndicatorShown(true);
m_treeWidget->header()->setStretchLastSection(true);
m_treeWidget->header()->setSortIndicator(0, Qt::AscendingOrder);
m_treeWidget->setHeaderLabels({Tr::tr("Name"), Tr::tr("Description"), Tr::tr("Shortcut")});
m_description = new QLineEdit;
m_removeButton = new QPushButton(Tr::tr("Remove"));
m_macroGroup = new QGroupBox(Tr::tr("Macro"), this);
using namespace Layouting;
Row {
Tr::tr("Description:"), m_description
}.attachTo(m_macroGroup);
Column {
Group {
title(Tr::tr("Preferences")),
Row {
m_treeWidget,
Column { m_removeButton, st },
}
},
m_macroGroup
}.attachTo(this);
connect(m_treeWidget, &QTreeWidget::currentItemChanged,
this, &MacroOptionsWidget::changeCurrentItem);
connect(m_removeButton, &QPushButton::clicked,
this, &MacroOptionsWidget::remove);
connect(m_description, &QLineEdit::textChanged,
this, &MacroOptionsWidget::changeDescription);
initialize();
}
MacroOptionsWidget::~MacroOptionsWidget() = default;
void MacroOptionsWidget::initialize()
{
m_macroToRemove.clear();
m_macroToChange.clear();
m_treeWidget->clear();
changeCurrentItem(nullptr);
// Create the treeview
createTable();
}
void MacroOptionsWidget::createTable()
{
QDir dir(MacroManager::macrosDirectory());
const Utils::Id base = Utils::Id(Constants::PREFIX_MACRO);
for (Macro *macro : MacroManager::macros()) {
QFileInfo fileInfo(macro->fileName());
if (fileInfo.absoluteDir() == dir.absolutePath()) {
auto macroItem = new QTreeWidgetItem(m_treeWidget);
macroItem->setText(0, macro->displayName());
macroItem->setText(1, macro->description());
macroItem->setData(0, NAME_ROLE, macro->displayName());
macroItem->setData(0, WRITE_ROLE, macro->isWritable());
Core::Command *command =
Core::ActionManager::command(base.withSuffix(macro->displayName()));
if (command && command->action()) {
macroItem->setText(2,
command->action()->shortcut().toString(QKeySequence::NativeText));
}
}
}
}
void MacroOptionsWidget::changeCurrentItem(QTreeWidgetItem *current)
{
m_changingCurrent = true;
m_removeButton->setEnabled(current);
m_macroGroup->setEnabled(current);
if (!current) {
m_description->clear();
} else {
m_description->setText(current->text(1));
m_description->setEnabled(current->data(0, WRITE_ROLE).toBool());
}
m_changingCurrent = false;
}
void MacroOptionsWidget::remove()
{
QTreeWidgetItem *current = m_treeWidget->currentItem();
m_macroToRemove.append(current->data(0, NAME_ROLE).toString());
delete current;
}
void MacroOptionsWidget::apply()
{
// Remove macro
for (const QString &name : std::as_const(m_macroToRemove)) {
MacroManager::instance()->deleteMacro(name);
m_macroToChange.remove(name);
}
// Change macro
for (auto it = m_macroToChange.cbegin(), end = m_macroToChange.cend(); it != end; ++it)
MacroManager::instance()->changeMacro(it.key(), it.value());
// Reinitialize the page
initialize();
}
void MacroOptionsWidget::changeDescription(const QString &description)
{
QTreeWidgetItem *current = m_treeWidget->currentItem();
if (m_changingCurrent || !current)
return;
QString macroName = current->data(0, NAME_ROLE).toString();
m_macroToChange[macroName] = description;
current->setText(1, description);
QFont font = current->font(1);
font.setItalic(true);
current->setFont(1, font);
}
} // Macros::Internal

View File

@@ -1,55 +0,0 @@
// Copyright (C) 2016 Nicolas Arnaud-Cormos
// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only WITH Qt-GPL-exception-1.0
#pragma once
#include <coreplugin/dialogs/ioptionspage.h>
#include <QStringList>
#include <QMap>
QT_BEGIN_NAMESPACE
class QGroupBox;
class QLineEdit;
class QPushButton;
class QTreeWidget;
class QTreeWidgetItem;
QT_END_NAMESPACE
namespace Macros {
namespace Internal {
class MacroOptionsWidget final : public Core::IOptionsPageWidget
{
Q_OBJECT
public:
MacroOptionsWidget();
~MacroOptionsWidget() final;
void initialize();
void apply() final;
private:
void remove();
void changeCurrentItem(QTreeWidgetItem *current);
void createTable();
void changeDescription(const QString &description);
private:
QStringList m_macroToRemove;
bool m_changingCurrent = false;
QMap<QString, QString> m_macroToChange;
QTreeWidget *m_treeWidget;
QPushButton *m_removeButton;
QGroupBox *m_macroGroup;
QLineEdit *m_description;
};
} // namespace Internal
} // namespace Macros

View File

@@ -29,8 +29,6 @@ QtcPlugin {
"macromanager.h",
"macrooptionspage.cpp",
"macrooptionspage.h",
"macrooptionswidget.cpp",
"macrooptionswidget.h",
"macros.qrc",
"macrosconstants.h",
"macrosplugin.cpp",

View File

@@ -24,7 +24,7 @@ add_qtc_plugin(McuSupport
settingshandler.cpp settingshandler.h
mcuqmlprojectnode.cpp mcuqmlprojectnode.h
mcubuildstep.cpp mcubuildstep.h
dialogs/mcukitcreationdialog.h dialogs/mcukitcreationdialog.cpp dialogs/mcukitcreationdialog.ui
dialogs/mcukitcreationdialog.cpp dialogs/mcukitcreationdialog.h
)
add_subdirectory(test)

Some files were not shown because too many files have changed in this diff Show More