forked from qt-creator/qt-creator
Merge remote-tracking branch 'origin/11.0'
Conflicts: tests/manual/subdirfileiterator/tst_subdirfileiterator.cpp Change-Id: I6fa8fbed152efc4033fa69e1ab67ced7e2ad35bc
This commit is contained in:
223
dist/changelog/changes-11.0.0.md
vendored
Normal file
223
dist/changelog/changes-11.0.0.md
vendored
Normal 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
|
||||||
@@ -482,8 +482,9 @@
|
|||||||
\row
|
\row
|
||||||
\li Add Class Member
|
\li Add Class Member
|
||||||
\li Adds a member declaration for the class member being
|
\li Adds a member declaration for the class member being
|
||||||
initialized if it is not yet declared. You must enter
|
initialized if it is not yet declared. If \QC cannot
|
||||||
the data type of the member.
|
automatically detect the data type of the member, you
|
||||||
|
must add it.
|
||||||
\li Identifier
|
\li Identifier
|
||||||
\row
|
\row
|
||||||
\li Create Implementations for Member Functions
|
\li Create Implementations for Member Functions
|
||||||
|
|||||||
@@ -99,4 +99,7 @@
|
|||||||
|
|
||||||
\image qtcreator-toggle-progress-bar.webp {Toggle Progress Details button}
|
\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.
|
||||||
*/
|
*/
|
||||||
|
|||||||
@@ -18199,16 +18199,16 @@ Möchten Sie sie jetzt auschecken?</translation>
|
|||||||
<translation>Bytes</translation>
|
<translation>Bytes</translation>
|
||||||
</message>
|
</message>
|
||||||
<message>
|
<message>
|
||||||
<source>KB</source>
|
<source>KiB</source>
|
||||||
<translation>KB</translation>
|
<translation>KiB</translation>
|
||||||
</message>
|
</message>
|
||||||
<message>
|
<message>
|
||||||
<source>GB</source>
|
<source>GiB</source>
|
||||||
<translation>GB</translation>
|
<translation>GiB</translation>
|
||||||
</message>
|
</message>
|
||||||
<message>
|
<message>
|
||||||
<source>TB</source>
|
<source>TiB</source>
|
||||||
<translation>TB</translation>
|
<translation>TiB</translation>
|
||||||
</message>
|
</message>
|
||||||
<message>
|
<message>
|
||||||
<source>Enable crash reporting</source>
|
<source>Enable crash reporting</source>
|
||||||
@@ -27194,12 +27194,8 @@ zu deaktivieren, deaktiviert auch die folgenden Plugins:
|
|||||||
<translation>Privat</translation>
|
<translation>Privat</translation>
|
||||||
</message>
|
</message>
|
||||||
<message>
|
<message>
|
||||||
<source>Create a private check-in that is never synced.
|
<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>
|
||||||
Children of private check-ins are automatically private.
|
<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>
|
||||||
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>
|
||||||
<message>
|
<message>
|
||||||
<source>Tag names to apply; comma-separated.</source>
|
<source>Tag names to apply; comma-separated.</source>
|
||||||
@@ -39112,7 +39108,7 @@ Sie werden erhalten.</numerusform>
|
|||||||
</message>
|
</message>
|
||||||
<message>
|
<message>
|
||||||
<source>&Configure Project</source>
|
<source>&Configure Project</source>
|
||||||
<translation>Projekt &Konfigurieren</translation>
|
<translation>Projekt &konfigurieren</translation>
|
||||||
</message>
|
</message>
|
||||||
<message>
|
<message>
|
||||||
<source>Enable Kit for Project "%1"</source>
|
<source>Enable Kit for Project "%1"</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>
|
<source>Hint: The second line of a commit message should be empty.</source>
|
||||||
<translation>Hinweis: Die zweite Zeile der Beschreibung sollte leer sein.</translation>
|
<translation>Hinweis: Die zweite Zeile der Beschreibung sollte leer sein.</translation>
|
||||||
</message>
|
</message>
|
||||||
<message numerus="yes">
|
<message>
|
||||||
<source><p>Writing good commit messages</p><ul><li>Avoid very short commit messages.</li><li>Consider the first line as subject (like in email) and keep it shorter than %n characters.</li><li>After an empty second line, a longer description can be added.</li><li>Describe why the change was done, not how it was done.</li></ul></source>
|
<source><p>Writing good commit messages</p><ul><li>Avoid very short commit messages.</li><li>Consider the first line as a subject (like in emails) and keep it shorter than 72 characters.</li><li>After an empty second line, a longer description can be added.</li><li>Describe why the change was done, not how it was done.</li></ul></source>
|
||||||
<translation>
|
<translation><p>Gute Beschreibungen für Commits schreiben</p><ul><li>Vermeiden Sie sehr kurze Beschreibungen.</li><li>Betrachten Sie die erste Zeile als Betreff (wie in einer E-Mail) und halten Sie sie kürzer als 72 Zeichen.</li><li>Eine längere Beschreibung kann nach einer leeren zweiten Zeile folgen.</li><li>Beschreiben Sie, weshalb die Änderung vorgenommen wurde, nicht wie sie vorgenommen wurde.</li></ul></translation>
|
||||||
<numerusform><p>Gute Beschreibungen für Commits schreiben</p><ul><li>Vermeiden Sie sehr kurze Beschreibungen.</li><li>Betrachten Sie die erste Zeile als Betreff (wie in einer E-Mail) und halten Sie sie kürzer als ein Zeichen.</li><li>Eine längere Beschreibung kann nach einer leeren zweiten Zeile folgen.</li><li>Beschreiben Sie, weshalb die Änderung vorgenommen wurde, nicht wie sie vorgenommen wurde.</li></ul></numerusform>
|
|
||||||
<numerusform><p>Gute Beschreibungen für Commits schreiben</p><ul><li>Vermeiden Sie sehr kurze Beschreibungen.</li><li>Betrachten Sie die erste Zeile als Betreff (wie in einer E-Mail) und halten Sie sie kürzer als %n Zeichen.</li><li>Eine längere Beschreibung kann nach einer leeren zweiten Zeile folgen.</li><li>Beschreiben Sie, weshalb die Änderung vorgenommen wurde, nicht wie sie vorgenommen wurde.</li></ul></numerusform>
|
|
||||||
</translation>
|
|
||||||
</message>
|
</message>
|
||||||
<message>
|
<message>
|
||||||
<source>Update in progress</source>
|
<source>Update in progress</source>
|
||||||
|
|||||||
@@ -369,61 +369,62 @@ LibraryInfo::LibraryInfo(const QmlDirParser &parser, const QByteArray &fingerpri
|
|||||||
QByteArray LibraryInfo::calculateFingerprint() const
|
QByteArray LibraryInfo::calculateFingerprint() const
|
||||||
{
|
{
|
||||||
QCryptographicHash hash(QCryptographicHash::Sha1);
|
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();
|
int len = _components.size();
|
||||||
hash.addData(reinterpret_cast<const char *>(&len), sizeof(len));
|
addData(&len, sizeof(len));
|
||||||
for (const QmlDirParser::Component &component : _components) {
|
for (const QmlDirParser::Component &component : _components) {
|
||||||
len = component.fileName.size();
|
len = component.fileName.size();
|
||||||
hash.addData(reinterpret_cast<const char *>(&len), sizeof(len));
|
addData(&len, sizeof(len));
|
||||||
hash.addData(reinterpret_cast<const char *>(component.fileName.constData()),
|
addData(component.fileName.constData(), len * sizeofQChar);
|
||||||
len * sizeofQChar);
|
addData(&component.majorVersion, sizeof(component.majorVersion));
|
||||||
hash.addData(reinterpret_cast<const char *>(&component.majorVersion), sizeof(component.majorVersion));
|
addData(&component.minorVersion, sizeof(component.minorVersion));
|
||||||
hash.addData(reinterpret_cast<const char *>(&component.minorVersion), sizeof(component.minorVersion));
|
|
||||||
len = component.typeName.size();
|
len = component.typeName.size();
|
||||||
hash.addData(reinterpret_cast<const char *>(&len), sizeof(len));
|
addData(&len, sizeof(len));
|
||||||
hash.addData(reinterpret_cast<const char *>(component.typeName.constData()),
|
addData(component.typeName.constData(), component.typeName.size() * sizeofQChar);
|
||||||
component.typeName.size() * sizeofQChar);
|
|
||||||
int flags = (component.singleton ? (1 << 0) : 0) + (component.internal ? (1 << 1) : 0);
|
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();
|
len = _plugins.size();
|
||||||
hash.addData(reinterpret_cast<const char *>(&len), sizeof(len));
|
addData(&len, sizeof(len));
|
||||||
for (const QmlDirParser::Plugin &plugin : _plugins) {
|
for (const QmlDirParser::Plugin &plugin : _plugins) {
|
||||||
len = plugin.path.size();
|
len = plugin.path.size();
|
||||||
hash.addData(reinterpret_cast<const char *>(&len), sizeof(len));
|
addData(&len, sizeof(len));
|
||||||
hash.addData(reinterpret_cast<const char *>(plugin.path.constData()), len * sizeofQChar);
|
addData(plugin.path.constData(), len * sizeofQChar);
|
||||||
len = plugin.name.size();
|
len = plugin.name.size();
|
||||||
hash.addData(reinterpret_cast<const char *>(&len), sizeof(len));
|
addData(&len, sizeof(len));
|
||||||
hash.addData(reinterpret_cast<const char *>(plugin.name.constData()), len * sizeofQChar);
|
addData(plugin.name.constData(), len * sizeofQChar);
|
||||||
}
|
}
|
||||||
len = _typeinfos.size();
|
len = _typeinfos.size();
|
||||||
hash.addData(reinterpret_cast<const char *>(&len), sizeof(len));
|
addData(&len, sizeof(len));
|
||||||
for (const QString &typeinfo : _typeinfos) {
|
for (const QString &typeinfo : _typeinfos) {
|
||||||
len = typeinfo.size();
|
len = typeinfo.size();
|
||||||
hash.addData(reinterpret_cast<const char *>(&len), sizeof(len));
|
addData(&len, sizeof(len));
|
||||||
hash.addData(reinterpret_cast<const char *>(typeinfo.constData()),
|
addData(typeinfo.constData(), len * sizeofQChar);
|
||||||
len * sizeofQChar);
|
|
||||||
}
|
}
|
||||||
len = _metaObjects.size();
|
len = _metaObjects.size();
|
||||||
hash.addData(reinterpret_cast<const char *>(&len), sizeof(len));
|
addData(&len, sizeof(len));
|
||||||
QList<QByteArray> metaFingerprints;
|
QList<QByteArray> metaFingerprints;
|
||||||
for (const LanguageUtils::FakeMetaObject::ConstPtr &metaObject : _metaObjects)
|
for (const LanguageUtils::FakeMetaObject::ConstPtr &metaObject : _metaObjects)
|
||||||
metaFingerprints.append(metaObject->fingerprint());
|
metaFingerprints.append(metaObject->fingerprint());
|
||||||
std::sort(metaFingerprints.begin(), metaFingerprints.end());
|
std::sort(metaFingerprints.begin(), metaFingerprints.end());
|
||||||
for (const QByteArray &fp : std::as_const(metaFingerprints))
|
for (const QByteArray &fp : std::as_const(metaFingerprints))
|
||||||
hash.addData(fp);
|
hash.addData(fp);
|
||||||
hash.addData(reinterpret_cast<const char *>(&_dumpStatus), sizeof(_dumpStatus));
|
addData(&_dumpStatus, sizeof(_dumpStatus));
|
||||||
len = _dumpError.size(); // localization dependent (avoid?)
|
len = _dumpError.size(); // localization dependent (avoid?)
|
||||||
hash.addData(reinterpret_cast<const char *>(&len), sizeof(len));
|
addData(&len, sizeof(len));
|
||||||
hash.addData(reinterpret_cast<const char *>(_dumpError.constData()), len * sizeofQChar);
|
addData(_dumpError.constData(), len * sizeofQChar);
|
||||||
|
|
||||||
len = _moduleApis.size();
|
len = _moduleApis.size();
|
||||||
hash.addData(reinterpret_cast<const char *>(&len), sizeof(len));
|
addData(&len, sizeof(len));
|
||||||
for (const ModuleApiInfo &moduleInfo : _moduleApis)
|
for (const ModuleApiInfo &moduleInfo : _moduleApis)
|
||||||
moduleInfo.addToHash(hash); // make it order independent?
|
moduleInfo.addToHash(hash); // make it order independent?
|
||||||
|
|
||||||
len = _imports.size();
|
len = _imports.size();
|
||||||
hash.addData(reinterpret_cast<const char *>(&len), sizeof(len));
|
addData(&len, sizeof(len));
|
||||||
for (const QmlDirParser::Import &import : _imports)
|
for (const QmlDirParser::Import &import : _imports)
|
||||||
hash.addData(import.module.toUtf8()); // import order matters, keep order-dependent
|
hash.addData(import.module.toUtf8()); // import order matters, keep order-dependent
|
||||||
|
|
||||||
|
|||||||
@@ -1,9 +1,11 @@
|
|||||||
add_qtc_library(Tasking OBJECT
|
add_qtc_library(Tasking OBJECT
|
||||||
# Never add dependencies to non-Qt libraries for this library
|
# Never add dependencies to non-Qt libraries for this library
|
||||||
DEPENDS Qt::Core
|
DEPENDS Qt::Concurrent Qt::Core Qt::Network
|
||||||
PUBLIC_DEFINES TASKING_LIBRARY
|
PUBLIC_DEFINES TASKING_LIBRARY
|
||||||
SOURCES
|
SOURCES
|
||||||
barrier.cpp barrier.h
|
barrier.cpp barrier.h
|
||||||
|
concurrentcall.h
|
||||||
|
networkquery.cpp networkquery.h
|
||||||
tasking_global.h
|
tasking_global.h
|
||||||
tasktree.cpp tasktree.h
|
tasktree.cpp tasktree.h
|
||||||
)
|
)
|
||||||
|
|||||||
@@ -34,7 +34,7 @@ private:
|
|||||||
int m_current = -1;
|
int m_current = -1;
|
||||||
};
|
};
|
||||||
|
|
||||||
class TASKING_EXPORT BarrierTaskAdapter : public Tasking::TaskAdapter<Barrier>
|
class TASKING_EXPORT BarrierTaskAdapter : public TaskAdapter<Barrier>
|
||||||
{
|
{
|
||||||
public:
|
public:
|
||||||
BarrierTaskAdapter() { connect(task(), &Barrier::done, this, &TaskInterface::done); }
|
BarrierTaskAdapter() { connect(task(), &Barrier::done, this, &TaskInterface::done); }
|
||||||
|
|||||||
100
src/libs/solutions/tasking/concurrentcall.h
Normal file
100
src/libs/solutions/tasking/concurrentcall.h
Normal 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);
|
||||||
38
src/libs/solutions/tasking/networkquery.cpp
Normal file
38
src/libs/solutions/tasking/networkquery.cpp
Normal 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
|
||||||
55
src/libs/solutions/tasking/networkquery.h
Normal file
55
src/libs/solutions/tasking/networkquery.h
Normal 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);
|
||||||
@@ -1,11 +1,14 @@
|
|||||||
QtcLibrary {
|
QtcLibrary {
|
||||||
name: "Tasking"
|
name: "Tasking"
|
||||||
Depends { name: "Qt"; submodules: ["core"] }
|
Depends { name: "Qt"; submodules: ["concurrent", "core", "network"] }
|
||||||
cpp.defines: base.concat("TASKING_LIBRARY")
|
cpp.defines: base.concat("TASKING_LIBRARY")
|
||||||
|
|
||||||
files: [
|
files: [
|
||||||
"barrier.cpp",
|
"barrier.cpp",
|
||||||
"barrier.h",
|
"barrier.h",
|
||||||
|
"concurrentcall.h",
|
||||||
|
"networkquery.cpp",
|
||||||
|
"networkquery.h",
|
||||||
"tasking_global.h",
|
"tasking_global.h",
|
||||||
"tasktree.cpp",
|
"tasktree.cpp",
|
||||||
"tasktree.h",
|
"tasktree.h",
|
||||||
|
|||||||
@@ -9,6 +9,8 @@
|
|||||||
#include <QSet>
|
#include <QSet>
|
||||||
#include <QTimer>
|
#include <QTimer>
|
||||||
|
|
||||||
|
using namespace std::chrono;
|
||||||
|
|
||||||
namespace Tasking {
|
namespace Tasking {
|
||||||
|
|
||||||
// That's cut down qtcassert.{c,h} to avoid the dependency.
|
// 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
|
\inheaderfile solutions/tasking/tasktree.h
|
||||||
\inmodule QtCreator
|
\inmodule QtCreator
|
||||||
\ingroup mainclasses
|
\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
|
\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
|
\enum Tasking::TaskAction
|
||||||
|
|
||||||
@@ -99,7 +246,7 @@ private:
|
|||||||
*/
|
*/
|
||||||
|
|
||||||
/*!
|
/*!
|
||||||
\typealias TaskItem::GroupSetupHandler
|
\typealias GroupItem::GroupSetupHandler
|
||||||
|
|
||||||
Type alias for \c std::function<TaskAction()>.
|
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()\>.
|
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.
|
Constructs a group's element holding the group setup handler.
|
||||||
The \a handler is invoked whenever the group starts.
|
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()>
|
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.
|
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
|
after the storages are constructed, so that the \a handler may already
|
||||||
perform some initial modifications to the active storages.
|
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.
|
Constructs a group's element holding the group done handler.
|
||||||
The \a handler is invoked whenever the group finishes with success.
|
The \a handler is invoked whenever the group finishes with success.
|
||||||
Depending on the group's workflow policy, this handler may also be called
|
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.
|
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
|
before the storages are destructed, so that the \a handler may still
|
||||||
perform a last read of the active storages' data.
|
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);
|
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
|
before the storages are destructed, so that the \a handler may still
|
||||||
perform a last read of the active storages' data.
|
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);
|
return Group::onGroupError(handler);
|
||||||
}
|
}
|
||||||
@@ -239,24 +387,34 @@ TaskItem onGroupError(const TaskItem::GroupEndHandler &handler)
|
|||||||
|
|
||||||
\sa sequential, parallel
|
\sa sequential, parallel
|
||||||
*/
|
*/
|
||||||
TaskItem parallelLimit(int limit)
|
GroupItem parallelLimit(int limit)
|
||||||
{
|
{
|
||||||
return Group::parallelLimit(qMax(limit, 0));
|
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);
|
return Group::workflowPolicy(policy);
|
||||||
}
|
}
|
||||||
|
|
||||||
const TaskItem sequential = parallelLimit(1);
|
const GroupItem sequential = parallelLimit(1);
|
||||||
const TaskItem parallel = parallelLimit(0);
|
const GroupItem parallel = parallelLimit(0);
|
||||||
const TaskItem stopOnError = workflowPolicy(WorkflowPolicy::StopOnError);
|
|
||||||
const TaskItem continueOnError = workflowPolicy(WorkflowPolicy::ContinueOnError);
|
const GroupItem stopOnError = workflowPolicy(WorkflowPolicy::StopOnError);
|
||||||
const TaskItem stopOnDone = workflowPolicy(WorkflowPolicy::StopOnDone);
|
const GroupItem continueOnError = workflowPolicy(WorkflowPolicy::ContinueOnError);
|
||||||
const TaskItem continueOnDone = workflowPolicy(WorkflowPolicy::ContinueOnDone);
|
const GroupItem stopOnDone = workflowPolicy(WorkflowPolicy::StopOnDone);
|
||||||
const TaskItem stopOnFinished = workflowPolicy(WorkflowPolicy::StopOnFinished);
|
const GroupItem continueOnDone = workflowPolicy(WorkflowPolicy::ContinueOnDone);
|
||||||
const TaskItem optional = workflowPolicy(WorkflowPolicy::Optional);
|
const GroupItem stopOnFinished = workflowPolicy(WorkflowPolicy::StopOnFinished);
|
||||||
|
const GroupItem finishAllAndDone = workflowPolicy(WorkflowPolicy::FinishAllAndDone);
|
||||||
|
const GroupItem finishAllAndError = workflowPolicy(WorkflowPolicy::FinishAllAndError);
|
||||||
|
|
||||||
static TaskAction toTaskAction(bool success)
|
static TaskAction toTaskAction(bool success)
|
||||||
{
|
{
|
||||||
@@ -326,11 +484,11 @@ void TreeStorageBase::activateStorage(int id) const
|
|||||||
m_storageData->m_activeStorage = id;
|
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...");
|
QTC_ASSERT(m_type == Type::Group, qWarning("Only Group may have children, skipping...");
|
||||||
return);
|
return);
|
||||||
for (const TaskItem &child : children) {
|
for (const GroupItem &child : children) {
|
||||||
switch (child.m_type) {
|
switch (child.m_type) {
|
||||||
case Type::Group:
|
case Type::Group:
|
||||||
m_children.append(child);
|
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) {
|
if (!handler) {
|
||||||
qWarning("Setting empty Setup Handler is no-op, skipping...");
|
qWarning("Setting empty Setup Handler is no-op, skipping...");
|
||||||
@@ -388,7 +546,7 @@ void TaskItem::setTaskSetupHandler(const TaskSetupHandler &handler)
|
|||||||
m_taskHandler.m_setupHandler = handler;
|
m_taskHandler.m_setupHandler = handler;
|
||||||
}
|
}
|
||||||
|
|
||||||
void TaskItem::setTaskDoneHandler(const TaskEndHandler &handler)
|
void GroupItem::setTaskDoneHandler(const TaskEndHandler &handler)
|
||||||
{
|
{
|
||||||
if (!handler) {
|
if (!handler) {
|
||||||
qWarning("Setting empty Done Handler is no-op, skipping...");
|
qWarning("Setting empty Done Handler is no-op, skipping...");
|
||||||
@@ -399,7 +557,7 @@ void TaskItem::setTaskDoneHandler(const TaskEndHandler &handler)
|
|||||||
m_taskHandler.m_doneHandler = handler;
|
m_taskHandler.m_doneHandler = handler;
|
||||||
}
|
}
|
||||||
|
|
||||||
void TaskItem::setTaskErrorHandler(const TaskEndHandler &handler)
|
void GroupItem::setTaskErrorHandler(const TaskEndHandler &handler)
|
||||||
{
|
{
|
||||||
if (!handler) {
|
if (!handler) {
|
||||||
qWarning("Setting empty Error Handler is no-op, skipping...");
|
qWarning("Setting empty Error Handler is no-op, skipping...");
|
||||||
@@ -410,6 +568,23 @@ void TaskItem::setTaskErrorHandler(const TaskEndHandler &handler)
|
|||||||
m_taskHandler.m_errorHandler = 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 TaskTreePrivate;
|
||||||
class TaskNode;
|
class TaskNode;
|
||||||
|
|
||||||
@@ -466,7 +641,7 @@ class TaskContainer
|
|||||||
Q_DISABLE_COPY_MOVE(TaskContainer)
|
Q_DISABLE_COPY_MOVE(TaskContainer)
|
||||||
|
|
||||||
public:
|
public:
|
||||||
TaskContainer(TaskTreePrivate *taskTreePrivate, const TaskItem &task,
|
TaskContainer(TaskTreePrivate *taskTreePrivate, const GroupItem &task,
|
||||||
TaskNode *parentNode, TaskContainer *parentContainer)
|
TaskNode *parentNode, TaskContainer *parentContainer)
|
||||||
: m_constData(taskTreePrivate, task, parentNode, parentContainer, this) {}
|
: m_constData(taskTreePrivate, task, parentNode, parentContainer, this) {}
|
||||||
TaskAction start();
|
TaskAction start();
|
||||||
@@ -479,7 +654,7 @@ public:
|
|||||||
bool isStarting() const { return isRunning() && m_runtimeData->m_startGuard.isLocked(); }
|
bool isStarting() const { return isRunning() && m_runtimeData->m_startGuard.isLocked(); }
|
||||||
|
|
||||||
struct ConstData {
|
struct ConstData {
|
||||||
ConstData(TaskTreePrivate *taskTreePrivate, const TaskItem &task, TaskNode *parentNode,
|
ConstData(TaskTreePrivate *taskTreePrivate, const GroupItem &task, TaskNode *parentNode,
|
||||||
TaskContainer *parentContainer, TaskContainer *thisContainer);
|
TaskContainer *parentContainer, TaskContainer *thisContainer);
|
||||||
~ConstData() { qDeleteAll(m_children); }
|
~ConstData() { qDeleteAll(m_children); }
|
||||||
TaskTreePrivate * const m_taskTreePrivate = nullptr;
|
TaskTreePrivate * const m_taskTreePrivate = nullptr;
|
||||||
@@ -488,7 +663,7 @@ public:
|
|||||||
|
|
||||||
const int m_parallelLimit = 1;
|
const int m_parallelLimit = 1;
|
||||||
const WorkflowPolicy m_workflowPolicy = WorkflowPolicy::StopOnError;
|
const WorkflowPolicy m_workflowPolicy = WorkflowPolicy::StopOnError;
|
||||||
const TaskItem::GroupHandler m_groupHandler;
|
const GroupItem::GroupHandler m_groupHandler;
|
||||||
const QList<TreeStorageBase> m_storageList;
|
const QList<TreeStorageBase> m_storageList;
|
||||||
const QList<TaskNode *> m_children;
|
const QList<TaskNode *> m_children;
|
||||||
const int m_taskCount = 0;
|
const int m_taskCount = 0;
|
||||||
@@ -505,8 +680,8 @@ public:
|
|||||||
|
|
||||||
const ConstData &m_constData;
|
const ConstData &m_constData;
|
||||||
const QList<int> m_storageIdList;
|
const QList<int> m_storageIdList;
|
||||||
int m_doneCount = 0;
|
|
||||||
bool m_successBit = true;
|
bool m_successBit = true;
|
||||||
|
int m_doneCount = 0;
|
||||||
Guard m_startGuard;
|
Guard m_startGuard;
|
||||||
};
|
};
|
||||||
|
|
||||||
@@ -519,7 +694,7 @@ class TaskNode
|
|||||||
Q_DISABLE_COPY_MOVE(TaskNode)
|
Q_DISABLE_COPY_MOVE(TaskNode)
|
||||||
|
|
||||||
public:
|
public:
|
||||||
TaskNode(TaskTreePrivate *taskTreePrivate, const TaskItem &task,
|
TaskNode(TaskTreePrivate *taskTreePrivate, const GroupItem &task,
|
||||||
TaskContainer *parentContainer)
|
TaskContainer *parentContainer)
|
||||||
: m_taskHandler(task.taskHandler())
|
: m_taskHandler(task.taskHandler())
|
||||||
, m_container(taskTreePrivate, task, this, parentContainer)
|
, m_container(taskTreePrivate, task, this, parentContainer)
|
||||||
@@ -537,7 +712,7 @@ public:
|
|||||||
TaskTree *taskTree() const { return m_container.m_constData.m_taskTreePrivate->q; }
|
TaskTree *taskTree() const { return m_container.m_constData.m_taskTreePrivate->q; }
|
||||||
|
|
||||||
private:
|
private:
|
||||||
const TaskItem::TaskHandler m_taskHandler;
|
const GroupItem::TaskHandler m_taskHandler;
|
||||||
TaskContainer m_container;
|
TaskContainer m_container;
|
||||||
std::unique_ptr<TaskInterface> m_task;
|
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,
|
static QList<TaskNode *> createChildren(TaskTreePrivate *taskTreePrivate, TaskContainer *container,
|
||||||
const TaskItem &task)
|
const GroupItem &task)
|
||||||
{
|
{
|
||||||
QList<TaskNode *> result;
|
QList<TaskNode *> result;
|
||||||
const QList<TaskItem> &children = task.children();
|
const QList<GroupItem> &children = task.children();
|
||||||
for (const TaskItem &child : children)
|
for (const GroupItem &child : children)
|
||||||
result.append(new TaskNode(taskTreePrivate, child, container));
|
result.append(new TaskNode(taskTreePrivate, child, container));
|
||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
|
|
||||||
TaskContainer::ConstData::ConstData(TaskTreePrivate *taskTreePrivate, const TaskItem &task,
|
TaskContainer::ConstData::ConstData(TaskTreePrivate *taskTreePrivate, const GroupItem &task,
|
||||||
TaskNode *parentNode, TaskContainer *parentContainer,
|
TaskNode *parentNode, TaskContainer *parentContainer,
|
||||||
TaskContainer *thisContainer)
|
TaskContainer *thisContainer)
|
||||||
: m_taskTreePrivate(taskTreePrivate)
|
: 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)
|
TaskContainer::RuntimeData::RuntimeData(const ConstData &constData)
|
||||||
: m_constData(constData)
|
: m_constData(constData)
|
||||||
, m_storageIdList(createStorages(constData))
|
, m_storageIdList(createStorages(constData))
|
||||||
{
|
, m_successBit(initialSuccessBit(m_constData.m_workflowPolicy))
|
||||||
m_successBit = m_constData.m_workflowPolicy != WorkflowPolicy::StopOnDone
|
{}
|
||||||
&& m_constData.m_workflowPolicy != WorkflowPolicy::ContinueOnDone;
|
|
||||||
}
|
|
||||||
|
|
||||||
TaskContainer::RuntimeData::~RuntimeData()
|
TaskContainer::RuntimeData::~RuntimeData()
|
||||||
{
|
{
|
||||||
@@ -720,10 +910,11 @@ TaskContainer::RuntimeData::~RuntimeData()
|
|||||||
|
|
||||||
bool TaskContainer::RuntimeData::updateSuccessBit(bool success)
|
bool TaskContainer::RuntimeData::updateSuccessBit(bool success)
|
||||||
{
|
{
|
||||||
if (m_constData.m_workflowPolicy == WorkflowPolicy::Optional)
|
if (m_constData.m_workflowPolicy == WorkflowPolicy::FinishAllAndDone
|
||||||
return m_successBit;
|
|| m_constData.m_workflowPolicy == WorkflowPolicy::FinishAllAndError
|
||||||
if (m_constData.m_workflowPolicy == WorkflowPolicy::StopOnFinished) {
|
|| m_constData.m_workflowPolicy == WorkflowPolicy::StopOnFinished) {
|
||||||
m_successBit = success;
|
if (m_constData.m_workflowPolicy == WorkflowPolicy::StopOnFinished)
|
||||||
|
m_successBit = success;
|
||||||
return m_successBit;
|
return m_successBit;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -753,7 +944,7 @@ TaskAction TaskContainer::start()
|
|||||||
}
|
}
|
||||||
if (startAction == TaskAction::Continue) {
|
if (startAction == TaskAction::Continue) {
|
||||||
if (m_constData.m_children.isEmpty())
|
if (m_constData.m_children.isEmpty())
|
||||||
startAction = TaskAction::StopWithDone;
|
startAction = toTaskAction(m_runtimeData->m_successBit);
|
||||||
}
|
}
|
||||||
return continueStart(startAction, 0);
|
return continueStart(startAction, 0);
|
||||||
}
|
}
|
||||||
@@ -845,7 +1036,7 @@ void TaskContainer::stop()
|
|||||||
|
|
||||||
void TaskContainer::invokeEndHandler()
|
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)
|
if (m_runtimeData->m_successBit && groupHandler.m_doneHandler)
|
||||||
invokeHandler(this, groupHandler.m_doneHandler);
|
invokeHandler(this, groupHandler.m_doneHandler);
|
||||||
else if (!m_runtimeData->m_successBit && groupHandler.m_errorHandler)
|
else if (!m_runtimeData->m_successBit && groupHandler.m_errorHandler)
|
||||||
@@ -893,6 +1084,7 @@ void TaskNode::stop()
|
|||||||
|
|
||||||
if (!m_task) {
|
if (!m_task) {
|
||||||
m_container.stop();
|
m_container.stop();
|
||||||
|
m_container.m_runtimeData->updateSuccessBit(false);
|
||||||
m_container.invokeEndHandler();
|
m_container.invokeEndHandler();
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
@@ -1331,77 +1523,11 @@ void TaskNode::invokeEndHandler(bool success)
|
|||||||
\section2 Workflow Policy
|
\section2 Workflow Policy
|
||||||
|
|
||||||
The workflow policy element in a Group specifies how the group should behave
|
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
|
If a child of a group is also a group, the child group runs its tasks
|
||||||
\header
|
according to its own workflow policy.
|
||||||
\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.
|
|
||||||
|
|
||||||
\section2 Storage
|
\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:
|
it from a source and writing it to a destination might look as follows:
|
||||||
|
|
||||||
\code
|
\code
|
||||||
static QByteArray load(const FilePath &fileName) { ... }
|
static QByteArray load(const QString &fileName) { ... }
|
||||||
static void save(const FilePath &fileName, const QByteArray &array) { ... }
|
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
|
struct CopyStorage { // [1] custom inter-task struct
|
||||||
QByteArray content; // [2] custom inter-task data
|
QByteArray content; // [2] custom inter-task data
|
||||||
@@ -1448,6 +1574,13 @@ void TaskNode::invokeEndHandler(bool success)
|
|||||||
};
|
};
|
||||||
return root;
|
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
|
\endcode
|
||||||
|
|
||||||
In the example above, the inter-task data consists of a QByteArray content
|
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();
|
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;
|
return false;
|
||||||
|
|
||||||
bool ok = 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::done, &loop, [finalize] { finalize(true); });
|
||||||
connect(this, &TaskTree::errorOccurred, &loop, [finalize] { finalize(false); });
|
connect(this, &TaskTree::errorOccurred, &loop, [finalize] { finalize(false); });
|
||||||
start();
|
QTimer::singleShot(0, this, &TaskTree::start);
|
||||||
if (!isRunning())
|
|
||||||
return ok;
|
|
||||||
|
|
||||||
QTimer timer;
|
|
||||||
if (timeoutMs) {
|
|
||||||
timer.setSingleShot(true);
|
|
||||||
timer.setInterval(timeoutMs);
|
|
||||||
connect(&timer, &QTimer::timeout, this, &TaskTree::stop);
|
|
||||||
timer.start();
|
|
||||||
}
|
|
||||||
|
|
||||||
loop.exec(QEventLoop::ExcludeUserInputEvents);
|
loop.exec(QEventLoop::ExcludeUserInputEvents);
|
||||||
if (!ok) {
|
if (!ok) {
|
||||||
@@ -1700,11 +1830,19 @@ bool TaskTree::runBlocking(const QFuture<void> &future, int timeoutMs)
|
|||||||
return ok;
|
return ok;
|
||||||
}
|
}
|
||||||
|
|
||||||
bool TaskTree::runBlocking(int timeoutMs)
|
bool TaskTree::runBlocking(const Group &recipe, milliseconds timeout)
|
||||||
{
|
{
|
||||||
QPromise<void> dummy;
|
QPromise<void> dummy;
|
||||||
dummy.start();
|
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
|
int TaskTree::taskCount() const
|
||||||
@@ -1749,4 +1887,95 @@ void TaskTreeTaskAdapter::start()
|
|||||||
task()->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
|
} // namespace Tasking
|
||||||
|
|||||||
@@ -16,6 +16,8 @@ QT_END_NAMESPACE
|
|||||||
|
|
||||||
namespace Tasking {
|
namespace Tasking {
|
||||||
|
|
||||||
|
Q_NAMESPACE_EXPORT(TASKING_EXPORT)
|
||||||
|
|
||||||
class ExecutionContextActivator;
|
class ExecutionContextActivator;
|
||||||
class TaskContainer;
|
class TaskContainer;
|
||||||
class TaskTreePrivate;
|
class TaskTreePrivate;
|
||||||
@@ -99,16 +101,19 @@ private:
|
|||||||
// b) On first done - continue executing all children and report done afterwards.
|
// 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.
|
// 3. Stops on first finished child. In sequential mode it will never run other children then the first one.
|
||||||
// Useful only in parallel mode.
|
// 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 {
|
enum class WorkflowPolicy {
|
||||||
StopOnError, // 1a - Reports error on first child error, otherwise done (if all children were done).
|
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.
|
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).
|
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.
|
ContinueOnDone, // 2b - The same, but children execution continues. Reports error when no children.
|
||||||
StopOnFinished, // 3 - Stops on first finished child and report its result.
|
StopOnFinished, // 3 - Stops on first finished child and report its result.
|
||||||
Optional // 4 - Reports done after all children finished.
|
FinishAllAndDone, // 4 - Reports done after all children finished.
|
||||||
|
FinishAllAndError // 5 - Reports error after all children finished.
|
||||||
};
|
};
|
||||||
|
Q_ENUM_NS(WorkflowPolicy);
|
||||||
|
|
||||||
enum class TaskAction
|
enum class TaskAction
|
||||||
{
|
{
|
||||||
@@ -116,8 +121,9 @@ enum class TaskAction
|
|||||||
StopWithDone,
|
StopWithDone,
|
||||||
StopWithError
|
StopWithError
|
||||||
};
|
};
|
||||||
|
Q_ENUM_NS(TaskAction);
|
||||||
|
|
||||||
class TASKING_EXPORT TaskItem
|
class TASKING_EXPORT GroupItem
|
||||||
{
|
{
|
||||||
public:
|
public:
|
||||||
// Internal, provided by QTC_DECLARE_CUSTOM_TASK
|
// Internal, provided by QTC_DECLARE_CUSTOM_TASK
|
||||||
@@ -150,7 +156,7 @@ public:
|
|||||||
std::optional<WorkflowPolicy> m_workflowPolicy = {};
|
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; }
|
GroupData groupData() const { return m_groupData; }
|
||||||
QList<TreeStorageBase> storageList() const { return m_storageList; }
|
QList<TreeStorageBase> storageList() const { return m_storageList; }
|
||||||
TaskHandler taskHandler() const { return m_taskHandler; }
|
TaskHandler taskHandler() const { return m_taskHandler; }
|
||||||
@@ -163,52 +169,59 @@ protected:
|
|||||||
TaskHandler
|
TaskHandler
|
||||||
};
|
};
|
||||||
|
|
||||||
TaskItem() = default;
|
GroupItem() = default;
|
||||||
TaskItem(const GroupData &data)
|
GroupItem(const GroupData &data)
|
||||||
: m_type(Type::GroupData)
|
: m_type(Type::GroupData)
|
||||||
, m_groupData(data) {}
|
, m_groupData(data) {}
|
||||||
TaskItem(const TreeStorageBase &storage)
|
GroupItem(const TreeStorageBase &storage)
|
||||||
: m_type(Type::Storage)
|
: m_type(Type::Storage)
|
||||||
, m_storageList{storage} {}
|
, m_storageList{storage} {}
|
||||||
TaskItem(const TaskHandler &handler)
|
GroupItem(const TaskHandler &handler)
|
||||||
: m_type(Type::TaskHandler)
|
: m_type(Type::TaskHandler)
|
||||||
, m_taskHandler(handler) {}
|
, m_taskHandler(handler) {}
|
||||||
void addChildren(const QList<TaskItem> &children);
|
void addChildren(const QList<GroupItem> &children);
|
||||||
|
|
||||||
void setTaskSetupHandler(const TaskSetupHandler &handler);
|
void setTaskSetupHandler(const TaskSetupHandler &handler);
|
||||||
void setTaskDoneHandler(const TaskEndHandler &handler);
|
void setTaskDoneHandler(const TaskEndHandler &handler);
|
||||||
void setTaskErrorHandler(const TaskEndHandler &handler);
|
void setTaskErrorHandler(const TaskEndHandler &handler);
|
||||||
static TaskItem groupHandler(const GroupHandler &handler) { return TaskItem({handler}); }
|
static GroupItem groupHandler(const GroupHandler &handler) { return GroupItem({handler}); }
|
||||||
static TaskItem parallelLimit(int limit) { return TaskItem({{}, limit}); }
|
static GroupItem parallelLimit(int limit) { return GroupItem({{}, limit}); }
|
||||||
static TaskItem workflowPolicy(WorkflowPolicy policy) { return TaskItem({{}, {}, policy}); }
|
static GroupItem workflowPolicy(WorkflowPolicy policy) { return GroupItem({{}, {}, policy}); }
|
||||||
|
static GroupItem withTimeout(const GroupItem &item, std::chrono::milliseconds timeout,
|
||||||
|
const GroupEndHandler &handler = {});
|
||||||
|
|
||||||
private:
|
private:
|
||||||
Type m_type = Type::Group;
|
Type m_type = Type::Group;
|
||||||
QList<TaskItem> m_children;
|
QList<GroupItem> m_children;
|
||||||
GroupData m_groupData;
|
GroupData m_groupData;
|
||||||
QList<TreeStorageBase> m_storageList;
|
QList<TreeStorageBase> m_storageList;
|
||||||
TaskHandler m_taskHandler;
|
TaskHandler m_taskHandler;
|
||||||
};
|
};
|
||||||
|
|
||||||
class TASKING_EXPORT Group : public TaskItem
|
class TASKING_EXPORT Group : public GroupItem
|
||||||
{
|
{
|
||||||
public:
|
public:
|
||||||
Group(const QList<TaskItem> &children) { addChildren(children); }
|
Group(const QList<GroupItem> &children) { addChildren(children); }
|
||||||
Group(std::initializer_list<TaskItem> children) { addChildren(children); }
|
Group(std::initializer_list<GroupItem> children) { addChildren(children); }
|
||||||
|
|
||||||
// GroupData related:
|
// GroupData related:
|
||||||
template <typename SetupHandler>
|
template <typename SetupHandler>
|
||||||
static TaskItem onGroupSetup(SetupHandler &&handler) {
|
static GroupItem onGroupSetup(SetupHandler &&handler) {
|
||||||
return groupHandler({wrapGroupSetup(std::forward<SetupHandler>(handler))});
|
return groupHandler({wrapGroupSetup(std::forward<SetupHandler>(handler))});
|
||||||
}
|
}
|
||||||
static TaskItem onGroupDone(const GroupEndHandler &handler) {
|
static GroupItem onGroupDone(const GroupEndHandler &handler) {
|
||||||
return groupHandler({{}, handler});
|
return groupHandler({{}, handler});
|
||||||
}
|
}
|
||||||
static TaskItem onGroupError(const GroupEndHandler &handler) {
|
static GroupItem onGroupError(const GroupEndHandler &handler) {
|
||||||
return groupHandler({{}, {}, handler});
|
return groupHandler({{}, {}, handler});
|
||||||
}
|
}
|
||||||
using TaskItem::parallelLimit; // Default: 1 (sequential). 0 means unlimited (parallel).
|
using GroupItem::parallelLimit; // Default: 1 (sequential). 0 means unlimited (parallel).
|
||||||
using TaskItem::workflowPolicy; // Default: WorkflowPolicy::StopOnError.
|
using GroupItem::workflowPolicy; // Default: WorkflowPolicy::StopOnError.
|
||||||
|
|
||||||
|
GroupItem withTimeout(std::chrono::milliseconds timeout,
|
||||||
|
const GroupEndHandler &handler = {}) const {
|
||||||
|
return GroupItem::withTimeout(*this, timeout, handler);
|
||||||
|
}
|
||||||
|
|
||||||
private:
|
private:
|
||||||
template<typename SetupHandler>
|
template<typename SetupHandler>
|
||||||
@@ -231,29 +244,31 @@ private:
|
|||||||
};
|
};
|
||||||
|
|
||||||
template <typename SetupHandler>
|
template <typename SetupHandler>
|
||||||
static TaskItem onGroupSetup(SetupHandler &&handler)
|
static GroupItem onGroupSetup(SetupHandler &&handler)
|
||||||
{
|
{
|
||||||
return Group::onGroupSetup(std::forward<SetupHandler>(handler));
|
return Group::onGroupSetup(std::forward<SetupHandler>(handler));
|
||||||
}
|
}
|
||||||
|
|
||||||
TASKING_EXPORT TaskItem onGroupDone(const TaskItem::GroupEndHandler &handler);
|
TASKING_EXPORT GroupItem onGroupDone(const GroupItem::GroupEndHandler &handler);
|
||||||
TASKING_EXPORT TaskItem onGroupError(const TaskItem::GroupEndHandler &handler);
|
TASKING_EXPORT GroupItem onGroupError(const GroupItem::GroupEndHandler &handler);
|
||||||
TASKING_EXPORT TaskItem parallelLimit(int limit);
|
TASKING_EXPORT GroupItem parallelLimit(int limit);
|
||||||
TASKING_EXPORT TaskItem workflowPolicy(WorkflowPolicy policy);
|
TASKING_EXPORT GroupItem workflowPolicy(WorkflowPolicy policy);
|
||||||
|
|
||||||
TASKING_EXPORT extern const TaskItem sequential;
|
TASKING_EXPORT extern const GroupItem sequential;
|
||||||
TASKING_EXPORT extern const TaskItem parallel;
|
TASKING_EXPORT extern const GroupItem 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;
|
|
||||||
|
|
||||||
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:
|
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()
|
// Synchronous invocation. Similarly to Group - isn't counted as a task inside taskCount()
|
||||||
@@ -266,7 +281,7 @@ public:
|
|||||||
|
|
||||||
private:
|
private:
|
||||||
template<typename Function>
|
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>>;
|
constexpr bool isInvocable = std::is_invocable_v<std::decay_t<Function>>;
|
||||||
static_assert(isInvocable,
|
static_assert(isInvocable,
|
||||||
"Sync element: The synchronous function can't take any arguments.");
|
"Sync element: The synchronous function can't take any arguments.");
|
||||||
@@ -295,17 +310,17 @@ private:
|
|||||||
};
|
};
|
||||||
|
|
||||||
template <typename Adapter>
|
template <typename Adapter>
|
||||||
class CustomTask : public TaskItem
|
class CustomTask : public GroupItem
|
||||||
{
|
{
|
||||||
public:
|
public:
|
||||||
using Task = typename Adapter::Type;
|
using Task = typename Adapter::Type;
|
||||||
using EndHandler = std::function<void(const Task &)>;
|
using EndHandler = std::function<void(const Task &)>;
|
||||||
static Adapter *createAdapter() { return new Adapter; }
|
static Adapter *createAdapter() { return new Adapter; }
|
||||||
CustomTask() : TaskItem({&createAdapter}) {}
|
CustomTask() : GroupItem({&createAdapter}) {}
|
||||||
template <typename SetupFunction>
|
template <typename SetupFunction>
|
||||||
CustomTask(SetupFunction &&function, const EndHandler &done = {}, const EndHandler &error = {})
|
CustomTask(SetupFunction &&function, const EndHandler &done = {}, const EndHandler &error = {})
|
||||||
: TaskItem({&createAdapter, wrapSetup(std::forward<SetupFunction>(function)),
|
: GroupItem({&createAdapter, wrapSetup(std::forward<SetupFunction>(function)),
|
||||||
wrapEnd(done), wrapEnd(error)}) {}
|
wrapEnd(done), wrapEnd(error)}) {}
|
||||||
|
|
||||||
template <typename SetupFunction>
|
template <typename SetupFunction>
|
||||||
CustomTask &onSetup(SetupFunction &&function) {
|
CustomTask &onSetup(SetupFunction &&function) {
|
||||||
@@ -321,9 +336,14 @@ public:
|
|||||||
return *this;
|
return *this;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
GroupItem withTimeout(std::chrono::milliseconds timeout,
|
||||||
|
const GroupEndHandler &handler = {}) const {
|
||||||
|
return GroupItem::withTimeout(*this, timeout, handler);
|
||||||
|
}
|
||||||
|
|
||||||
private:
|
private:
|
||||||
template<typename SetupFunction>
|
template<typename SetupFunction>
|
||||||
static TaskItem::TaskSetupHandler wrapSetup(SetupFunction &&function) {
|
static GroupItem::TaskSetupHandler wrapSetup(SetupFunction &&function) {
|
||||||
static constexpr bool isDynamic = std::is_same_v<TaskAction,
|
static constexpr bool isDynamic = std::is_same_v<TaskAction,
|
||||||
std::invoke_result_t<std::decay_t<SetupFunction>, typename Adapter::Type &>>;
|
std::invoke_result_t<std::decay_t<SetupFunction>, typename Adapter::Type &>>;
|
||||||
constexpr bool isVoid = std::is_same_v<void,
|
constexpr bool isVoid = std::is_same_v<void,
|
||||||
@@ -370,8 +390,12 @@ public:
|
|||||||
// Helper methods. They execute a local event loop with ExcludeUserInputEvents.
|
// Helper methods. They execute a local event loop with ExcludeUserInputEvents.
|
||||||
// The passed future is used for listening to the cancel event.
|
// 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.
|
// 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();
|
||||||
bool runBlocking(int timeoutMs = 0);
|
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 taskCount() const;
|
||||||
int progressMaximum() const { return taskCount(); }
|
int progressMaximum() const { return taskCount(); }
|
||||||
@@ -418,6 +442,17 @@ public:
|
|||||||
void start() final;
|
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
|
} // namespace Tasking
|
||||||
|
|
||||||
#define TASKING_DECLARE_TASK(CustomTaskName, TaskAdapterClass)\
|
#define TASKING_DECLARE_TASK(CustomTaskName, TaskAdapterClass)\
|
||||||
@@ -430,3 +465,4 @@ using CustomTaskName = CustomTask<TaskAdapterClass<Args...>>;\
|
|||||||
} // namespace Tasking
|
} // namespace Tasking
|
||||||
|
|
||||||
TASKING_DECLARE_TASK(TaskTreeTask, TaskTreeTaskAdapter);
|
TASKING_DECLARE_TASK(TaskTreeTask, TaskTreeTaskAdapter);
|
||||||
|
TASKING_DECLARE_TASK(TimeoutTask, TimeoutTaskAdapter);
|
||||||
|
|||||||
@@ -670,6 +670,7 @@ public:
|
|||||||
// Used to block recursive editingFinished signals for example when return is pressed, and
|
// Used to block recursive editingFinished signals for example when return is pressed, and
|
||||||
// the validation changes focus by opening a dialog
|
// the validation changes focus by opening a dialog
|
||||||
bool m_blockAutoApply = false;
|
bool m_blockAutoApply = false;
|
||||||
|
bool m_allowPathFromDevice = true;
|
||||||
|
|
||||||
template<class Widget> void updateWidgetFromCheckStatus(StringAspect *aspect, Widget *w)
|
template<class Widget> void updateWidgetFromCheckStatus(StringAspect *aspect, Widget *w)
|
||||||
{
|
{
|
||||||
@@ -977,6 +978,13 @@ void StringAspect::setCommandVersionArguments(const QStringList &arguments)
|
|||||||
d->m_pathChooserDisplay->setCommandVersionArguments(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.
|
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->setPromptDialogFilter(d->m_prompDialogFilter);
|
||||||
d->m_pathChooserDisplay->setPromptDialogTitle(d->m_prompDialogTitle);
|
d->m_pathChooserDisplay->setPromptDialogTitle(d->m_prompDialogTitle);
|
||||||
d->m_pathChooserDisplay->setCommandVersionArguments(d->m_commandVersionArguments);
|
d->m_pathChooserDisplay->setCommandVersionArguments(d->m_commandVersionArguments);
|
||||||
|
d->m_pathChooserDisplay->setAllowPathFromDevice(d->m_allowPathFromDevice);
|
||||||
if (defaultValue() == value())
|
if (defaultValue() == value())
|
||||||
d->m_pathChooserDisplay->setDefaultValue(defaultValue());
|
d->m_pathChooserDisplay->setDefaultValue(defaultValue());
|
||||||
else
|
else
|
||||||
@@ -2153,8 +2162,11 @@ void DoubleAspect::setSingleStep(double step)
|
|||||||
Its visual representation is a QComboBox with three items.
|
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)
|
const QString &defaultString)
|
||||||
|
: SelectionAspect(container)
|
||||||
{
|
{
|
||||||
setDisplayStyle(DisplayStyle::ComboBox);
|
setDisplayStyle(DisplayStyle::ComboBox);
|
||||||
setDefaultValue(TriState::Default);
|
setDefaultValue(TriState::Default);
|
||||||
@@ -2308,7 +2320,7 @@ QList<int> IntegersAspect::value() const
|
|||||||
|
|
||||||
void IntegersAspect::setValue(const QList<int> &value)
|
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
|
QList<int> IntegersAspect::defaultValue() const
|
||||||
@@ -2319,7 +2331,7 @@ QList<int> IntegersAspect::defaultValue() const
|
|||||||
|
|
||||||
void IntegersAspect::setDefaultValue(const QList<int> &value)
|
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.
|
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
|
Constructs a text display showing the \a message with an icon representing
|
||||||
type \a type.
|
type \a type.
|
||||||
|
|||||||
@@ -406,6 +406,7 @@ public:
|
|||||||
void setOpenTerminalHandler(const std::function<void()> &openTerminal);
|
void setOpenTerminalHandler(const std::function<void()> &openTerminal);
|
||||||
void setAutoApplyOnEditingFinished(bool applyOnEditingFinished);
|
void setAutoApplyOnEditingFinished(bool applyOnEditingFinished);
|
||||||
void setElideMode(Qt::TextElideMode elideMode);
|
void setElideMode(Qt::TextElideMode elideMode);
|
||||||
|
void setAllowPathFromDevice(bool allowPathFromDevice);
|
||||||
|
|
||||||
void validateInput();
|
void validateInput();
|
||||||
|
|
||||||
@@ -548,7 +549,8 @@ class QTCREATOR_UTILS_EXPORT TriStateAspect : public SelectionAspect
|
|||||||
Q_OBJECT
|
Q_OBJECT
|
||||||
|
|
||||||
public:
|
public:
|
||||||
TriStateAspect(const QString &onString = {},
|
TriStateAspect(AspectContainer *container = nullptr,
|
||||||
|
const QString &onString = {},
|
||||||
const QString &offString = {},
|
const QString &offString = {},
|
||||||
const QString &defaultString = {});
|
const QString &defaultString = {});
|
||||||
|
|
||||||
@@ -608,6 +610,7 @@ class QTCREATOR_UTILS_EXPORT TextDisplay : public BaseAspect
|
|||||||
Q_OBJECT
|
Q_OBJECT
|
||||||
|
|
||||||
public:
|
public:
|
||||||
|
explicit TextDisplay(AspectContainer *container);
|
||||||
TextDisplay(const QString &message = {},
|
TextDisplay(const QString &message = {},
|
||||||
InfoLabel::InfoType type = InfoLabel::None);
|
InfoLabel::InfoType type = InfoLabel::None);
|
||||||
~TextDisplay() override;
|
~TextDisplay() override;
|
||||||
|
|||||||
@@ -493,6 +493,20 @@ bool DesktopDeviceFileAccess::hasHardLinks(const FilePath &filePath) const
|
|||||||
if (s.st_nlink > 1)
|
if (s.st_nlink > 1)
|
||||||
return true;
|
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
|
#else
|
||||||
Q_UNUSED(filePath)
|
Q_UNUSED(filePath)
|
||||||
#endif
|
#endif
|
||||||
|
|||||||
@@ -104,7 +104,7 @@ RunResult DeviceShell::run(const CommandLine &cmd, const QByteArray &stdInData)
|
|||||||
|
|
||||||
QWaitCondition waiter;
|
QWaitCondition waiter;
|
||||||
const int id = ++m_currentId;
|
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] {
|
QMetaObject::invokeMethod(m_shellProcess.get(), [this, id, cmd, stdInData] {
|
||||||
const QString command = QString("%1 \"%2\" %3\n").arg(id)
|
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);
|
waiter.wait(&m_commandMutex);
|
||||||
|
|
||||||
|
const auto it = m_commandOutput.constFind(id);
|
||||||
const RunResult result = *it;
|
const RunResult result = *it;
|
||||||
m_commandOutput.erase(it);
|
m_commandOutput.erase(it);
|
||||||
|
|
||||||
|
|||||||
@@ -7,7 +7,7 @@
|
|||||||
|
|
||||||
#include "fileutils.h"
|
#include "fileutils.h"
|
||||||
|
|
||||||
#include <QMap>
|
#include <QHash>
|
||||||
#include <QMutex>
|
#include <QMutex>
|
||||||
#include <QProcess>
|
#include <QProcess>
|
||||||
#include <QThread>
|
#include <QThread>
|
||||||
@@ -78,8 +78,7 @@ private:
|
|||||||
int m_currentId{0};
|
int m_currentId{0};
|
||||||
|
|
||||||
QMutex m_commandMutex;
|
QMutex m_commandMutex;
|
||||||
// QMap is used here to preserve iterators
|
QHash<quint64, CommandRun> m_commandOutput;
|
||||||
QMap<quint64, CommandRun> m_commandOutput;
|
|
||||||
QByteArray m_commandBuffer;
|
QByteArray m_commandBuffer;
|
||||||
|
|
||||||
State m_shellScriptState = State::Unknown;
|
State m_shellScriptState = State::Unknown;
|
||||||
|
|||||||
@@ -11,6 +11,7 @@
|
|||||||
#include "utilsicons.h"
|
#include "utilsicons.h"
|
||||||
#include "utilstr.h"
|
#include "utilstr.h"
|
||||||
|
|
||||||
|
#include <QApplication>
|
||||||
#include <QKeyEvent>
|
#include <QKeyEvent>
|
||||||
#include <QKeySequence>
|
#include <QKeySequence>
|
||||||
#include <QMenu>
|
#include <QMenu>
|
||||||
@@ -126,7 +127,7 @@ FancyLineEditPrivate::FancyLineEditPrivate(FancyLineEdit *parent) :
|
|||||||
m_completionShortcut(completionShortcut()->key(), parent),
|
m_completionShortcut(completionShortcut()->key(), parent),
|
||||||
m_okTextColor(creatorTheme()->color(Theme::TextColorNormal)),
|
m_okTextColor(creatorTheme()->color(Theme::TextColorNormal)),
|
||||||
m_errorTextColor(creatorTheme()->color(Theme::TextColorError)),
|
m_errorTextColor(creatorTheme()->color(Theme::TextColorError)),
|
||||||
m_placeholderTextColor(creatorTheme()->color(Theme::PalettePlaceholderText))
|
m_placeholderTextColor(QApplication::palette().color(QPalette::PlaceholderText))
|
||||||
|
|
||||||
{
|
{
|
||||||
m_completionShortcut.setContext(Qt::WidgetShortcut);
|
m_completionShortcut.setContext(Qt::WidgetShortcut);
|
||||||
|
|||||||
@@ -1914,7 +1914,7 @@ FilePath FilePath::canonicalPath() const
|
|||||||
return *this;
|
return *this;
|
||||||
}
|
}
|
||||||
|
|
||||||
#ifdef Q_OS_WINDOWS
|
#ifdef Q_OS_WIN
|
||||||
DWORD flagsAndAttrs = FILE_ATTRIBUTE_NORMAL;
|
DWORD flagsAndAttrs = FILE_ATTRIBUTE_NORMAL;
|
||||||
if (isDir())
|
if (isDir())
|
||||||
flagsAndAttrs |= FILE_FLAG_BACKUP_SEMANTICS;
|
flagsAndAttrs |= FILE_FLAG_BACKUP_SEMANTICS;
|
||||||
|
|||||||
@@ -30,7 +30,7 @@ public:
|
|||||||
void start() {
|
void start() {
|
||||||
QTC_ASSERT(!m_taskTree, return);
|
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}));
|
m_taskTree.reset(new TaskTree({task}));
|
||||||
const auto finalize = [this](bool success) {
|
const auto finalize = [this](bool success) {
|
||||||
m_taskTree.release()->deleteLater();
|
m_taskTree.release()->deleteLater();
|
||||||
@@ -49,8 +49,8 @@ protected:
|
|||||||
std::unique_ptr<TaskTree> m_taskTree;
|
std::unique_ptr<TaskTree> m_taskTree;
|
||||||
|
|
||||||
private:
|
private:
|
||||||
virtual TaskItem remoteTask() = 0;
|
virtual GroupItem remoteTask() = 0;
|
||||||
virtual TaskItem localTask() = 0;
|
virtual GroupItem localTask() = 0;
|
||||||
};
|
};
|
||||||
|
|
||||||
static void localRead(QPromise<QByteArray> &promise, const FilePath &filePath)
|
static void localRead(QPromise<QByteArray> &promise, const FilePath &filePath)
|
||||||
@@ -84,7 +84,7 @@ signals:
|
|||||||
void readyRead(const QByteArray &newData);
|
void readyRead(const QByteArray &newData);
|
||||||
|
|
||||||
private:
|
private:
|
||||||
TaskItem remoteTask() final {
|
GroupItem remoteTask() final {
|
||||||
const auto setup = [this](Process &process) {
|
const auto setup = [this](Process &process) {
|
||||||
const QStringList args = {"if=" + m_filePath.path()};
|
const QStringList args = {"if=" + m_filePath.path()};
|
||||||
const FilePath dd = m_filePath.withNewPath("dd");
|
const FilePath dd = m_filePath.withNewPath("dd");
|
||||||
@@ -96,7 +96,7 @@ private:
|
|||||||
};
|
};
|
||||||
return ProcessTask(setup);
|
return ProcessTask(setup);
|
||||||
}
|
}
|
||||||
TaskItem localTask() final {
|
GroupItem localTask() final {
|
||||||
const auto setup = [this](Async<QByteArray> &async) {
|
const auto setup = [this](Async<QByteArray> &async) {
|
||||||
async.setConcurrentCallData(localRead, m_filePath);
|
async.setConcurrentCallData(localRead, m_filePath);
|
||||||
Async<QByteArray> *asyncPtr = &async;
|
Async<QByteArray> *asyncPtr = &async;
|
||||||
@@ -251,7 +251,7 @@ signals:
|
|||||||
void started();
|
void started();
|
||||||
|
|
||||||
private:
|
private:
|
||||||
TaskItem remoteTask() final {
|
GroupItem remoteTask() final {
|
||||||
const auto setup = [this](Process &process) {
|
const auto setup = [this](Process &process) {
|
||||||
m_writeBuffer = new WriteBuffer(false, &process);
|
m_writeBuffer = new WriteBuffer(false, &process);
|
||||||
connect(m_writeBuffer, &WriteBuffer::writeRequested, &process, &Process::writeRaw);
|
connect(m_writeBuffer, &WriteBuffer::writeRequested, &process, &Process::writeRaw);
|
||||||
@@ -272,7 +272,7 @@ private:
|
|||||||
};
|
};
|
||||||
return ProcessTask(setup, finalize, finalize);
|
return ProcessTask(setup, finalize, finalize);
|
||||||
}
|
}
|
||||||
TaskItem localTask() final {
|
GroupItem localTask() final {
|
||||||
const auto setup = [this](Async<void> &async) {
|
const auto setup = [this](Async<void> &async) {
|
||||||
m_writeBuffer = new WriteBuffer(isBuffered(), &async);
|
m_writeBuffer = new WriteBuffer(isBuffered(), &async);
|
||||||
async.setConcurrentCallData(localWrite, m_filePath, m_writeData, m_writeBuffer);
|
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())
|
if (promise.isCanceled())
|
||||||
return;
|
return;
|
||||||
|
|
||||||
TaskTree taskTree(transferTask(source, destination));
|
if (!TaskTree::runBlocking(transferTask(source, destination), promise.future()))
|
||||||
if (!taskTree.runBlocking(promise.future()))
|
|
||||||
promise.future().cancel();
|
promise.future().cancel();
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -391,7 +390,7 @@ public:
|
|||||||
StreamResult m_streamResult = StreamResult::FinishedWithError;
|
StreamResult m_streamResult = StreamResult::FinishedWithError;
|
||||||
std::unique_ptr<TaskTree> m_taskTree;
|
std::unique_ptr<TaskTree> m_taskTree;
|
||||||
|
|
||||||
TaskItem task() {
|
GroupItem task() {
|
||||||
if (m_streamerMode == StreamMode::Reader)
|
if (m_streamerMode == StreamMode::Reader)
|
||||||
return readerTask();
|
return readerTask();
|
||||||
if (m_streamerMode == StreamMode::Writer)
|
if (m_streamerMode == StreamMode::Writer)
|
||||||
@@ -400,7 +399,7 @@ public:
|
|||||||
}
|
}
|
||||||
|
|
||||||
private:
|
private:
|
||||||
TaskItem readerTask() {
|
GroupItem readerTask() {
|
||||||
const auto setup = [this](FileStreamReader &reader) {
|
const auto setup = [this](FileStreamReader &reader) {
|
||||||
m_readBuffer.clear();
|
m_readBuffer.clear();
|
||||||
reader.setFilePath(m_source);
|
reader.setFilePath(m_source);
|
||||||
@@ -410,14 +409,14 @@ private:
|
|||||||
};
|
};
|
||||||
return FileStreamReaderTask(setup);
|
return FileStreamReaderTask(setup);
|
||||||
}
|
}
|
||||||
TaskItem writerTask() {
|
GroupItem writerTask() {
|
||||||
const auto setup = [this](FileStreamWriter &writer) {
|
const auto setup = [this](FileStreamWriter &writer) {
|
||||||
writer.setFilePath(m_destination);
|
writer.setFilePath(m_destination);
|
||||||
writer.setWriteData(m_writeBuffer);
|
writer.setWriteData(m_writeBuffer);
|
||||||
};
|
};
|
||||||
return FileStreamWriterTask(setup);
|
return FileStreamWriterTask(setup);
|
||||||
}
|
}
|
||||||
TaskItem transferTask() {
|
GroupItem transferTask() {
|
||||||
const auto setup = [this](Async<void> &async) {
|
const auto setup = [this](Async<void> &async) {
|
||||||
async.setConcurrentCallData(transfer, m_source, m_destination);
|
async.setConcurrentCallData(transfer, m_source, m_destination);
|
||||||
};
|
};
|
||||||
|
|||||||
@@ -629,12 +629,18 @@ FilePathInfo::FileFlags fileInfoFlagsfromStatMode(const QString &hexString, int
|
|||||||
|
|
||||||
FilePathInfo::FileFlags result;
|
FilePathInfo::FileFlags result;
|
||||||
|
|
||||||
if (mode & IRUSR)
|
if (mode & IRUSR) {
|
||||||
result |= FilePathInfo::ReadOwnerPerm;
|
result |= FilePathInfo::ReadOwnerPerm;
|
||||||
if (mode & IWUSR)
|
result |= FilePathInfo::ReadUserPerm;
|
||||||
|
}
|
||||||
|
if (mode & IWUSR) {
|
||||||
result |= FilePathInfo::WriteOwnerPerm;
|
result |= FilePathInfo::WriteOwnerPerm;
|
||||||
if (mode & IXUSR)
|
result |= FilePathInfo::WriteUserPerm;
|
||||||
|
}
|
||||||
|
if (mode & IXUSR) {
|
||||||
result |= FilePathInfo::ExeOwnerPerm;
|
result |= FilePathInfo::ExeOwnerPerm;
|
||||||
|
result |= FilePathInfo::ExeUserPerm;
|
||||||
|
}
|
||||||
if (mode & IRGRP)
|
if (mode & IRGRP)
|
||||||
result |= FilePathInfo::ReadGroupPerm;
|
result |= FilePathInfo::ReadGroupPerm;
|
||||||
if (mode & IWGRP)
|
if (mode & IWGRP)
|
||||||
|
|||||||
@@ -676,24 +676,22 @@ LayoutItem st()
|
|||||||
|
|
||||||
LayoutItem noMargin()
|
LayoutItem noMargin()
|
||||||
{
|
{
|
||||||
LayoutItem item;
|
return customMargin({});
|
||||||
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;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
LayoutItem normalMargin()
|
LayoutItem normalMargin()
|
||||||
|
{
|
||||||
|
return customMargin({9, 9, 9, 9});
|
||||||
|
}
|
||||||
|
|
||||||
|
LayoutItem customMargin(const QMargins &margin)
|
||||||
{
|
{
|
||||||
LayoutItem item;
|
LayoutItem item;
|
||||||
item.onAdd = [](LayoutBuilder &builder) {
|
item.onAdd = [margin](LayoutBuilder &builder) {
|
||||||
if (auto layout = builder.stack.last().layout)
|
if (auto layout = builder.stack.last().layout)
|
||||||
layout->setContentsMargins(9, 9, 9, 9);
|
layout->setContentsMargins(margin);
|
||||||
else if (auto widget = builder.stack.last().widget)
|
else if (auto widget = builder.stack.last().widget)
|
||||||
widget->setContentsMargins(9, 9, 9, 9);
|
widget->setContentsMargins(margin);
|
||||||
};
|
};
|
||||||
return item;
|
return item;
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -11,12 +11,15 @@
|
|||||||
|
|
||||||
#if defined(UTILS_LIBRARY)
|
#if defined(UTILS_LIBRARY)
|
||||||
# define QTCREATOR_UTILS_EXPORT Q_DECL_EXPORT
|
# define QTCREATOR_UTILS_EXPORT Q_DECL_EXPORT
|
||||||
|
#elif defined(UTILS_STATIC_LIBRARY)
|
||||||
|
# define QTCREATOR_UTILS_EXPORT
|
||||||
#else
|
#else
|
||||||
# define QTCREATOR_UTILS_EXPORT Q_DECL_IMPORT
|
# define QTCREATOR_UTILS_EXPORT Q_DECL_IMPORT
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
QT_BEGIN_NAMESPACE
|
QT_BEGIN_NAMESPACE
|
||||||
class QLayout;
|
class QLayout;
|
||||||
|
class QMargins;
|
||||||
class QObject;
|
class QObject;
|
||||||
class QWidget;
|
class QWidget;
|
||||||
template <class T> T qobject_cast(QObject *object);
|
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 hr();
|
||||||
QTCREATOR_UTILS_EXPORT LayoutItem noMargin();
|
QTCREATOR_UTILS_EXPORT LayoutItem noMargin();
|
||||||
QTCREATOR_UTILS_EXPORT LayoutItem normalMargin();
|
QTCREATOR_UTILS_EXPORT LayoutItem normalMargin();
|
||||||
|
QTCREATOR_UTILS_EXPORT LayoutItem customMargin(const QMargins &margin);
|
||||||
QTCREATOR_UTILS_EXPORT LayoutItem withFormAlignment();
|
QTCREATOR_UTILS_EXPORT LayoutItem withFormAlignment();
|
||||||
|
|
||||||
// "Setters"
|
// "Setters"
|
||||||
|
|||||||
@@ -133,9 +133,13 @@ TextTip::TextTip(QWidget *parent) : TipLabel(parent)
|
|||||||
setWindowOpacity(style()->styleHint(QStyle::SH_ToolTipLabel_Opacity, nullptr, this) / 255.0);
|
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)
|
void TextTip::setContent(const QVariant &content)
|
||||||
@@ -148,13 +152,13 @@ void TextTip::setContent(const QVariant &content)
|
|||||||
m_format = item.second;
|
m_format = item.second;
|
||||||
}
|
}
|
||||||
|
|
||||||
bool containsLink = likelyContainsLink(m_text);
|
bool containsLink = likelyContainsLink(m_text, m_format);
|
||||||
setOpenExternalLinks(containsLink);
|
setOpenExternalLinks(containsLink);
|
||||||
}
|
}
|
||||||
|
|
||||||
bool TextTip::isInteractive() const
|
bool TextTip::isInteractive() const
|
||||||
{
|
{
|
||||||
return likelyContainsLink(m_text);
|
return likelyContainsLink(m_text, m_format);
|
||||||
}
|
}
|
||||||
|
|
||||||
void TextTip::configure(const QPoint &pos)
|
void TextTip::configure(const QPoint &pos)
|
||||||
|
|||||||
@@ -122,7 +122,7 @@ private:
|
|||||||
QMap<QString, FilePath> m_filesToPull;
|
QMap<QString, FilePath> m_filesToPull;
|
||||||
|
|
||||||
QStringList m_androidABIs;
|
QStringList m_androidABIs;
|
||||||
BoolAspect *m_uninstallPreviousPackage = nullptr;
|
BoolAspect m_uninstallPreviousPackage{this};
|
||||||
bool m_uninstallPreviousPackageRun = false;
|
bool m_uninstallPreviousPackageRun = false;
|
||||||
bool m_useAndroiddeployqt = false;
|
bool m_useAndroiddeployqt = false;
|
||||||
bool m_askForUninstall = false;
|
bool m_askForUninstall = false;
|
||||||
@@ -143,17 +143,16 @@ AndroidDeployQtStep::AndroidDeployQtStep(BuildStepList *parent, Id id)
|
|||||||
setImmutable(true);
|
setImmutable(true);
|
||||||
setUserExpanded(true);
|
setUserExpanded(true);
|
||||||
|
|
||||||
m_uninstallPreviousPackage = addAspect<BoolAspect>();
|
m_uninstallPreviousPackage.setSettingsKey(UninstallPreviousPackageKey);
|
||||||
m_uninstallPreviousPackage->setSettingsKey(UninstallPreviousPackageKey);
|
m_uninstallPreviousPackage.setLabel(Tr::tr("Uninstall the existing app before deployment"),
|
||||||
m_uninstallPreviousPackage->setLabel(Tr::tr("Uninstall the existing app before deployment"),
|
|
||||||
BoolAspect::LabelPlacement::AtCheckBox);
|
BoolAspect::LabelPlacement::AtCheckBox);
|
||||||
m_uninstallPreviousPackage->setValue(false);
|
m_uninstallPreviousPackage.setValue(false);
|
||||||
|
|
||||||
const QtSupport::QtVersion * const qt = QtSupport::QtKitAspect::qtVersion(kit());
|
const QtSupport::QtVersion * const qt = QtSupport::QtKitAspect::qtVersion(kit());
|
||||||
const bool forced = qt && qt->qtVersion() < QVersionNumber(5, 4, 0);
|
const bool forced = qt && qt->qtVersion() < QVersionNumber(5, 4, 0);
|
||||||
if (forced) {
|
if (forced) {
|
||||||
m_uninstallPreviousPackage->setValue(true);
|
m_uninstallPreviousPackage.setValue(true);
|
||||||
m_uninstallPreviousPackage->setEnabled(false);
|
m_uninstallPreviousPackage.setEnabled(false);
|
||||||
}
|
}
|
||||||
|
|
||||||
connect(this, &AndroidDeployQtStep::askForUninstall,
|
connect(this, &AndroidDeployQtStep::askForUninstall,
|
||||||
@@ -274,7 +273,7 @@ bool AndroidDeployQtStep::init()
|
|||||||
|
|
||||||
emit addOutput(Tr::tr("Deploying to %1").arg(m_serialNumber), OutputFormat::NormalMessage);
|
emit addOutput(Tr::tr("Deploying to %1").arg(m_serialNumber), OutputFormat::NormalMessage);
|
||||||
|
|
||||||
m_uninstallPreviousPackageRun = m_uninstallPreviousPackage->value();
|
m_uninstallPreviousPackageRun = m_uninstallPreviousPackage();
|
||||||
if (m_uninstallPreviousPackageRun)
|
if (m_uninstallPreviousPackageRun)
|
||||||
m_manifestName = AndroidManager::manifestPath(target());
|
m_manifestName = AndroidManager::manifestPath(target());
|
||||||
|
|
||||||
|
|||||||
@@ -20,8 +20,8 @@ CTestSettings::CTestSettings(Id settingsId)
|
|||||||
setCategory(Constants::AUTOTEST_SETTINGS_CATEGORY);
|
setCategory(Constants::AUTOTEST_SETTINGS_CATEGORY);
|
||||||
setDisplayName(Tr::tr("CTest"));
|
setDisplayName(Tr::tr("CTest"));
|
||||||
|
|
||||||
setLayouter([this](QWidget *w) {
|
setLayouter([this] {
|
||||||
Row { Form {
|
return Row { Form {
|
||||||
outputOnFail, br,
|
outputOnFail, br,
|
||||||
scheduleRandom, br,
|
scheduleRandom, br,
|
||||||
stopOnFailure, br,
|
stopOnFailure, br,
|
||||||
@@ -39,7 +39,7 @@ CTestSettings::CTestSettings(Id settingsId)
|
|||||||
Row { testLoad, threshold}
|
Row { testLoad, threshold}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}, st }.attachTo(w);
|
}, st };
|
||||||
});
|
});
|
||||||
|
|
||||||
outputOnFail.setSettingsKey("OutputOnFail");
|
outputOnFail.setSettingsKey("OutputOnFail");
|
||||||
|
|||||||
@@ -35,7 +35,7 @@ using namespace ProjectExplorer;
|
|||||||
static bool isProjectParsing()
|
static bool isProjectParsing()
|
||||||
{
|
{
|
||||||
const BuildSystem *bs = ProjectManager::startupBuildSystem();
|
const BuildSystem *bs = ProjectManager::startupBuildSystem();
|
||||||
return bs && bs->isParsing();
|
return bs && (bs->isParsing() || bs->isWaitingForParse());
|
||||||
}
|
}
|
||||||
|
|
||||||
TestCodeParser::TestCodeParser()
|
TestCodeParser::TestCodeParser()
|
||||||
@@ -360,7 +360,7 @@ void TestCodeParser::scanForTests(const QSet<FilePath> &filePaths,
|
|||||||
|
|
||||||
using namespace Tasking;
|
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) {
|
for (const FilePath &file : filteredFiles) {
|
||||||
const auto setup = [this, codeParsers, file](Async<TestParseResultPtr> &async) {
|
const auto setup = [this, codeParsers, file](Async<TestParseResultPtr> &async) {
|
||||||
async.setConcurrentCallData(parseFileForTests, codeParsers, file);
|
async.setConcurrentCallData(parseFileForTests, codeParsers, file);
|
||||||
|
|||||||
@@ -347,7 +347,7 @@ void TestRunner::runTestsHelper()
|
|||||||
std::unique_ptr<TestOutputReader> m_outputReader;
|
std::unique_ptr<TestOutputReader> m_outputReader;
|
||||||
};
|
};
|
||||||
|
|
||||||
QList<TaskItem> tasks{optional};
|
QList<GroupItem> tasks{finishAllAndDone};
|
||||||
|
|
||||||
for (ITestConfiguration *config : m_selectedTests) {
|
for (ITestConfiguration *config : m_selectedTests) {
|
||||||
QTC_ASSERT(config, continue);
|
QTC_ASSERT(config, continue);
|
||||||
@@ -442,7 +442,7 @@ void TestRunner::runTestsHelper()
|
|||||||
}
|
}
|
||||||
};
|
};
|
||||||
const Group group {
|
const Group group {
|
||||||
optional,
|
finishAllAndDone,
|
||||||
Storage(storage),
|
Storage(storage),
|
||||||
onGroupSetup(onSetup),
|
onGroupSetup(onSetup),
|
||||||
ProcessTask(onProcessSetup, onProcessDone, onProcessDone)
|
ProcessTask(onProcessSetup, onProcessDone, onProcessDone)
|
||||||
|
|||||||
@@ -42,23 +42,23 @@ private:
|
|||||||
void doRun() final;
|
void doRun() final;
|
||||||
|
|
||||||
bool m_runAutogen = false;
|
bool m_runAutogen = false;
|
||||||
|
StringAspect m_arguments{this};
|
||||||
};
|
};
|
||||||
|
|
||||||
AutogenStep::AutogenStep(BuildStepList *bsl, Id id) : AbstractProcessStep(bsl, id)
|
AutogenStep::AutogenStep(BuildStepList *bsl, Id id) : AbstractProcessStep(bsl, id)
|
||||||
{
|
{
|
||||||
auto arguments = addAspect<StringAspect>();
|
m_arguments.setSettingsKey("AutotoolsProjectManager.AutogenStep.AdditionalArguments");
|
||||||
arguments->setSettingsKey("AutotoolsProjectManager.AutogenStep.AdditionalArguments");
|
m_arguments.setLabelText(Tr::tr("Arguments:"));
|
||||||
arguments->setLabelText(Tr::tr("Arguments:"));
|
m_arguments.setDisplayStyle(StringAspect::LineEditDisplay);
|
||||||
arguments->setDisplayStyle(StringAspect::LineEditDisplay);
|
m_arguments.setHistoryCompleter("AutotoolsPM.History.AutogenStepArgs");
|
||||||
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(); });
|
setWorkingDirectoryProvider([this] { return project()->projectDirectory(); });
|
||||||
|
|
||||||
setCommandLineProvider([this, arguments] {
|
setCommandLineProvider([this] {
|
||||||
return CommandLine(project()->projectDirectory() / "autogen.sh",
|
return CommandLine(project()->projectDirectory() / "autogen.sh",
|
||||||
arguments->value(),
|
m_arguments(),
|
||||||
CommandLine::Raw);
|
CommandLine::Raw);
|
||||||
});
|
});
|
||||||
|
|
||||||
|
|||||||
@@ -66,10 +66,10 @@ BazaarSettings::BazaarSettings()
|
|||||||
timeout.setLabelText(Tr::tr("Timeout:"));
|
timeout.setLabelText(Tr::tr("Timeout:"));
|
||||||
timeout.setSuffix(Tr::tr("s"));
|
timeout.setSuffix(Tr::tr("s"));
|
||||||
|
|
||||||
setLayouter([this](QWidget *widget) {
|
setLayouter([this] {
|
||||||
using namespace Layouting;
|
using namespace Layouting;
|
||||||
|
|
||||||
Column {
|
return Column {
|
||||||
Group {
|
Group {
|
||||||
title(Tr::tr("Configuration")),
|
title(Tr::tr("Configuration")),
|
||||||
Row { binaryPath }
|
Row { binaryPath }
|
||||||
@@ -88,7 +88,7 @@ BazaarSettings::BazaarSettings()
|
|||||||
Row { logCount, timeout, st }
|
Row { logCount, timeout, st }
|
||||||
},
|
},
|
||||||
st
|
st
|
||||||
}.attachTo(widget);
|
};
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -297,7 +297,7 @@ void AbstractSettings::read()
|
|||||||
|
|
||||||
void AbstractSettings::readDocumentation()
|
void AbstractSettings::readDocumentation()
|
||||||
{
|
{
|
||||||
const FilePath filename = documentationFilePath();
|
const FilePath filename = documentationFilePath;
|
||||||
if (filename.isEmpty()) {
|
if (filename.isEmpty()) {
|
||||||
BeautifierPlugin::showError(Tr::tr("No documentation file specified."));
|
BeautifierPlugin::showError(Tr::tr("No documentation file specified."));
|
||||||
return;
|
return;
|
||||||
|
|||||||
@@ -51,7 +51,8 @@ public:
|
|||||||
|
|
||||||
Utils::FilePathAspect command{this};
|
Utils::FilePathAspect command{this};
|
||||||
Utils::StringAspect supportedMimeTypes{this};
|
Utils::StringAspect supportedMimeTypes{this};
|
||||||
Utils::FilePathAspect documentationFilePath; // Intentionally not saved.
|
|
||||||
|
Utils::FilePath documentationFilePath;
|
||||||
|
|
||||||
QVersionNumber version() const;
|
QVersionNumber version() const;
|
||||||
|
|
||||||
|
|||||||
@@ -59,11 +59,11 @@ ArtisticStyleSettings::ArtisticStyleSettings()
|
|||||||
|
|
||||||
customStyle.setSettingsKey("customStyle");
|
customStyle.setSettingsKey("customStyle");
|
||||||
|
|
||||||
documentationFilePath.setFilePath(
|
documentationFilePath =
|
||||||
Core::ICore::userResourcePath(Beautifier::Constants::SETTINGS_DIRNAME)
|
Core::ICore::userResourcePath(Beautifier::Constants::SETTINGS_DIRNAME)
|
||||||
.pathAppended(Beautifier::Constants::DOCUMENTATION_DIRNAME)
|
.pathAppended(Beautifier::Constants::DOCUMENTATION_DIRNAME)
|
||||||
.pathAppended(SETTINGS_NAME)
|
.pathAppended(SETTINGS_NAME)
|
||||||
.stringAppended(".xml"));
|
.stringAppended(".xml");
|
||||||
|
|
||||||
read();
|
read();
|
||||||
}
|
}
|
||||||
@@ -77,7 +77,7 @@ void ArtisticStyleSettings::createDocumentationFile() const
|
|||||||
if (process.result() != ProcessResult::FinishedWithSuccess)
|
if (process.result() != ProcessResult::FinishedWithSuccess)
|
||||||
return;
|
return;
|
||||||
|
|
||||||
QFile file(documentationFilePath().toFSPathString());
|
QFile file(documentationFilePath.toFSPathString());
|
||||||
const QFileInfo fi(file);
|
const QFileInfo fi(file);
|
||||||
if (!fi.exists())
|
if (!fi.exists())
|
||||||
fi.dir().mkpath(fi.absolutePath());
|
fi.dir().mkpath(fi.absolutePath());
|
||||||
|
|||||||
@@ -63,16 +63,16 @@ ClangFormatSettings::ClangFormatSettings()
|
|||||||
|
|
||||||
customStyle.setSettingsKey("customStyle");
|
customStyle.setSettingsKey("customStyle");
|
||||||
|
|
||||||
documentationFilePath.setFilePath(Core::ICore::userResourcePath(Constants::SETTINGS_DIRNAME)
|
documentationFilePath = Core::ICore::userResourcePath(Constants::SETTINGS_DIRNAME)
|
||||||
.pathAppended(Constants::DOCUMENTATION_DIRNAME)
|
.pathAppended(Constants::DOCUMENTATION_DIRNAME)
|
||||||
.pathAppended(SETTINGS_NAME).stringAppended(".xml"));
|
.pathAppended(SETTINGS_NAME).stringAppended(".xml");
|
||||||
|
|
||||||
read();
|
read();
|
||||||
}
|
}
|
||||||
|
|
||||||
void ClangFormatSettings::createDocumentationFile() const
|
void ClangFormatSettings::createDocumentationFile() const
|
||||||
{
|
{
|
||||||
QFile file(documentationFilePath().toFSPathString());
|
QFile file(documentationFilePath.toFSPathString());
|
||||||
const QFileInfo fi(file);
|
const QFileInfo fi(file);
|
||||||
if (!fi.exists())
|
if (!fi.exists())
|
||||||
fi.dir().mkpath(fi.absolutePath());
|
fi.dir().mkpath(fi.absolutePath());
|
||||||
|
|||||||
@@ -66,9 +66,9 @@ UncrustifySettings::UncrustifySettings()
|
|||||||
specificConfigFile.setExpectedKind(Utils::PathChooser::File);
|
specificConfigFile.setExpectedKind(Utils::PathChooser::File);
|
||||||
specificConfigFile.setPromptDialogFilter(Tr::tr("Uncrustify file (*.cfg)"));
|
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(Constants::DOCUMENTATION_DIRNAME)
|
||||||
.pathAppended(SETTINGS_NAME).stringAppended(".xml"));
|
.pathAppended(SETTINGS_NAME).stringAppended(".xml");
|
||||||
|
|
||||||
read();
|
read();
|
||||||
}
|
}
|
||||||
@@ -82,7 +82,7 @@ void UncrustifySettings::createDocumentationFile() const
|
|||||||
if (process.result() != ProcessResult::FinishedWithSuccess)
|
if (process.result() != ProcessResult::FinishedWithSuccess)
|
||||||
return;
|
return;
|
||||||
|
|
||||||
QFile file(documentationFilePath().toFSPathString());
|
QFile file(documentationFilePath.toFSPathString());
|
||||||
const QFileInfo fi(file);
|
const QFileInfo fi(file);
|
||||||
if (!fi.exists())
|
if (!fi.exists())
|
||||||
fi.dir().mkpath(fi.absolutePath());
|
fi.dir().mkpath(fi.absolutePath());
|
||||||
|
|||||||
@@ -421,8 +421,12 @@ void doSemanticHighlighting(
|
|||||||
if (ClangdClient * const client = ClangModelManagerSupport::clientForFile(filePath))
|
if (ClangdClient * const client = ClangModelManagerSupport::clientForFile(filePath))
|
||||||
client->setVirtualRanges(filePath, virtualRanges, docRevision);
|
client->setVirtualRanges(filePath, virtualRanges, docRevision);
|
||||||
}, Qt::QueuedConnection);
|
}, Qt::QueuedConnection);
|
||||||
|
#if QT_VERSION >= QT_VERSION_CHECK(6, 6, 0)
|
||||||
|
promise.addResults(results);
|
||||||
|
#else
|
||||||
for (const HighlightingResult &r : results)
|
for (const HighlightingResult &r : results)
|
||||||
promise.addResult(r);
|
promise.addResult(r);
|
||||||
|
#endif
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -17,6 +17,7 @@
|
|||||||
#include <coreplugin/icore.h>
|
#include <coreplugin/icore.h>
|
||||||
#include <coreplugin/messagemanager.h>
|
#include <coreplugin/messagemanager.h>
|
||||||
#include <coreplugin/session.h>
|
#include <coreplugin/session.h>
|
||||||
|
#include <coreplugin/vcsmanager.h>
|
||||||
|
|
||||||
#include <cppeditor/cppcodemodelsettings.h>
|
#include <cppeditor/cppcodemodelsettings.h>
|
||||||
#include <cppeditor/cppeditorconstants.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.
|
// 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
|
// 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.
|
// workflow, e.g. a git branch switch will hit at least one open file.
|
||||||
|
// We also look for repository changes explicitly.
|
||||||
void ClangModelManagerSupport::watchForExternalChanges()
|
void ClangModelManagerSupport::watchForExternalChanges()
|
||||||
{
|
{
|
||||||
connect(DocumentManager::instance(), &DocumentManager::filesChangedExternally,
|
connect(DocumentManager::instance(), &DocumentManager::filesChangedExternally,
|
||||||
@@ -709,6 +711,23 @@ void ClangModelManagerSupport::watchForExternalChanges()
|
|||||||
return;
|
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
|
// If Qt Creator changes a file that is not open (e.g. as part of a quickfix), we have to
|
||||||
|
|||||||
@@ -183,7 +183,7 @@ void ClangToolRunWorker::start()
|
|||||||
m_filesAnalyzed.clear();
|
m_filesAnalyzed.clear();
|
||||||
m_filesNotAnalyzed.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)) {
|
for (const AnalyzeUnit &unit : std::as_const(unitsToProcess)) {
|
||||||
if (!m_diagnosticConfig.isEnabled(tool)
|
if (!m_diagnosticConfig.isEnabled(tool)
|
||||||
&& !m_runSettings.hasConfigFileForSourceFile(unit.file)) {
|
&& !m_runSettings.hasConfigFileForSourceFile(unit.file)) {
|
||||||
|
|||||||
@@ -101,9 +101,9 @@ static FilePath createOutputFilePath(const FilePath &dirPath, const FilePath &fi
|
|||||||
return {};
|
return {};
|
||||||
}
|
}
|
||||||
|
|
||||||
TaskItem clangToolTask(const AnalyzeInputData &input,
|
GroupItem clangToolTask(const AnalyzeInputData &input,
|
||||||
const AnalyzeSetupHandler &setupHandler,
|
const AnalyzeSetupHandler &setupHandler,
|
||||||
const AnalyzeOutputHandler &outputHandler)
|
const AnalyzeOutputHandler &outputHandler)
|
||||||
{
|
{
|
||||||
struct ClangToolStorage {
|
struct ClangToolStorage {
|
||||||
QString name;
|
QString name;
|
||||||
@@ -186,7 +186,7 @@ TaskItem clangToolTask(const AnalyzeInputData &input,
|
|||||||
Storage(storage),
|
Storage(storage),
|
||||||
onGroupSetup(onSetup),
|
onGroupSetup(onSetup),
|
||||||
Group {
|
Group {
|
||||||
optional,
|
finishAllAndDone,
|
||||||
ProcessTask(onProcessSetup, onProcessDone, onProcessError)
|
ProcessTask(onProcessSetup, onProcessDone, onProcessError)
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|||||||
@@ -10,7 +10,7 @@
|
|||||||
|
|
||||||
#include <utils/environment.h>
|
#include <utils/environment.h>
|
||||||
|
|
||||||
namespace Tasking { class TaskItem; }
|
namespace Tasking { class GroupItem; }
|
||||||
|
|
||||||
namespace ClangTools {
|
namespace ClangTools {
|
||||||
namespace Internal {
|
namespace Internal {
|
||||||
@@ -50,9 +50,9 @@ struct AnalyzeOutputData
|
|||||||
using AnalyzeSetupHandler = std::function<bool()>;
|
using AnalyzeSetupHandler = std::function<bool()>;
|
||||||
using AnalyzeOutputHandler = std::function<void(const AnalyzeOutputData &)>;
|
using AnalyzeOutputHandler = std::function<void(const AnalyzeOutputData &)>;
|
||||||
|
|
||||||
Tasking::TaskItem clangToolTask(const AnalyzeInputData &input,
|
Tasking::GroupItem clangToolTask(const AnalyzeInputData &input,
|
||||||
const AnalyzeSetupHandler &setupHandler,
|
const AnalyzeSetupHandler &setupHandler,
|
||||||
const AnalyzeOutputHandler &outputHandler);
|
const AnalyzeOutputHandler &outputHandler);
|
||||||
|
|
||||||
} // namespace Internal
|
} // namespace Internal
|
||||||
} // namespace ClangTools
|
} // namespace ClangTools
|
||||||
|
|||||||
@@ -190,7 +190,7 @@ void DocumentClangToolRunner::run()
|
|||||||
vfso().update();
|
vfso().update();
|
||||||
const ClangDiagnosticConfig config = diagnosticConfig(runSettings.diagnosticConfigId());
|
const ClangDiagnosticConfig config = diagnosticConfig(runSettings.diagnosticConfigId());
|
||||||
const Environment env = projectBuildEnvironment(project);
|
const Environment env = projectBuildEnvironment(project);
|
||||||
QList<TaskItem> tasks{parallel};
|
QList<GroupItem> tasks{parallel};
|
||||||
const auto addClangTool = [this, &runSettings, &config, &env, &tasks](ClangToolType tool) {
|
const auto addClangTool = [this, &runSettings, &config, &env, &tasks](ClangToolType tool) {
|
||||||
if (!toolEnabled(tool, config, runSettings))
|
if (!toolEnabled(tool, config, runSettings))
|
||||||
return;
|
return;
|
||||||
@@ -209,7 +209,7 @@ void DocumentClangToolRunner::run()
|
|||||||
return !m_document->isModified() || isVFSOverlaySupported(executable);
|
return !m_document->isModified() || isVFSOverlaySupported(executable);
|
||||||
};
|
};
|
||||||
const auto outputHandler = [this](const AnalyzeOutputData &output) { onDone(output); };
|
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::Tidy);
|
||||||
addClangTool(ClangToolType::Clazy);
|
addClangTool(ClangToolType::Clazy);
|
||||||
|
|||||||
@@ -378,7 +378,7 @@ void Manager::gotoLocations(const QList<QVariant> &list)
|
|||||||
int line;
|
int line;
|
||||||
int column;
|
int column;
|
||||||
textEditor->convertPosition(textEditor->position(), &line, &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) {
|
if (auto it = locations.constFind(current), end = locations.constEnd(); it != end) {
|
||||||
// we already are at the symbol, cycle to next location
|
// we already are at the symbol, cycle to next location
|
||||||
++it;
|
++it;
|
||||||
|
|||||||
@@ -227,6 +227,10 @@ private:
|
|||||||
Q_INVOKABLE void updateStatusActions();
|
Q_INVOKABLE void updateStatusActions();
|
||||||
|
|
||||||
QString commitDisplayName() const final;
|
QString commitDisplayName() const final;
|
||||||
|
QString commitAbortTitle() const final;
|
||||||
|
QString commitAbortMessage() const final;
|
||||||
|
QString commitErrorMessage(const QString &error) const final;
|
||||||
|
|
||||||
void checkOutCurrentFile();
|
void checkOutCurrentFile();
|
||||||
void addCurrentFile();
|
void addCurrentFile();
|
||||||
void undoCheckOutCurrent();
|
void undoCheckOutCurrent();
|
||||||
@@ -948,9 +952,27 @@ void ClearCasePluginPrivate::updateActions(VcsBasePluginPrivate::ActionState as)
|
|||||||
|
|
||||||
QString ClearCasePluginPrivate::commitDisplayName() const
|
QString ClearCasePluginPrivate::commitDisplayName() const
|
||||||
{
|
{
|
||||||
|
//: Name of the "commit" action of the VCS
|
||||||
return Tr::tr("Check In");
|
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()
|
void ClearCasePluginPrivate::checkOutCurrentFile()
|
||||||
{
|
{
|
||||||
const VcsBasePluginState state = currentState();
|
const VcsBasePluginState state = currentState();
|
||||||
|
|||||||
@@ -157,7 +157,7 @@ void CMakeEditorWidget::findLinkAt(const QTextCursor &cursor,
|
|||||||
|
|
||||||
// find the beginning of a filename
|
// find the beginning of a filename
|
||||||
QString buffer;
|
QString buffer;
|
||||||
int beginPos = column - 1;
|
int beginPos = column;
|
||||||
while (beginPos >= 0) {
|
while (beginPos >= 0) {
|
||||||
if (isValidFileNameChar(block, beginPos)) {
|
if (isValidFileNameChar(block, beginPos)) {
|
||||||
buffer.prepend(block.at(beginPos));
|
buffer.prepend(block.at(beginPos));
|
||||||
|
|||||||
@@ -65,9 +65,9 @@ public:
|
|||||||
autoFormatMime.setDefaultValue("text/x-cmake");
|
autoFormatMime.setDefaultValue("text/x-cmake");
|
||||||
autoFormatMime.setLabelText(Tr::tr("Restrict to MIME types:"));
|
autoFormatMime.setLabelText(Tr::tr("Restrict to MIME types:"));
|
||||||
|
|
||||||
setLayouter([this](QWidget *widget) {
|
setLayouter([this] {
|
||||||
using namespace Layouting;
|
using namespace Layouting;
|
||||||
Column {
|
return Column {
|
||||||
Row { Tr::tr("CMakeFormat command:"), command },
|
Row { Tr::tr("CMakeFormat command:"), command },
|
||||||
Space(10),
|
Space(10),
|
||||||
Group {
|
Group {
|
||||||
@@ -79,7 +79,7 @@ public:
|
|||||||
}
|
}
|
||||||
},
|
},
|
||||||
st
|
st
|
||||||
}.attachTo(widget);
|
};
|
||||||
});
|
});
|
||||||
|
|
||||||
ActionContainer *menu = ActionManager::createMenu(Constants::CMAKEFORMATTER_MENU_ID);
|
ActionContainer *menu = ActionManager::createMenu(Constants::CMAKEFORMATTER_MENU_ID);
|
||||||
|
|||||||
@@ -112,7 +112,7 @@ ConanInstallStep::ConanInstallStep(BuildStepList *bsl, Id id)
|
|||||||
return param.summary(displayName());
|
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) {
|
connect(project, &Project::addedTarget, project, [project] (Target *target) {
|
||||||
connectTarget(project, target);
|
connectTarget(project, target);
|
||||||
});
|
});
|
||||||
|
|||||||
@@ -93,7 +93,7 @@ void AuthWidget::updateClient(const Utils::FilePath &nodeJs, const Utils::FilePa
|
|||||||
m_client = nullptr;
|
m_client = nullptr;
|
||||||
setState(Tr::tr("Sign in"), false);
|
setState(Tr::tr("Sign in"), false);
|
||||||
m_button->setEnabled(false);
|
m_button->setEnabled(false);
|
||||||
if (!nodeJs.exists() || !agent.exists()) {
|
if (!nodeJs.isExecutableFile() || !agent.exists()) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -5,6 +5,7 @@ QtcPlugin {
|
|||||||
|
|
||||||
Depends { name: "Core" }
|
Depends { name: "Core" }
|
||||||
Depends { name: "LanguageClient" }
|
Depends { name: "LanguageClient" }
|
||||||
|
Depends { name: "ProjectExplorer" }
|
||||||
Depends { name: "TextEditor" }
|
Depends { name: "TextEditor" }
|
||||||
Depends { name: "Qt"; submodules: ["widgets", "xml", "network"] }
|
Depends { name: "Qt"; submodules: ["widgets", "xml", "network"] }
|
||||||
|
|
||||||
|
|||||||
@@ -139,6 +139,7 @@ void CopilotHoverHandler::identifyMatch(TextEditorWidget *editorWidget,
|
|||||||
|
|
||||||
void CopilotHoverHandler::operateTooltip(TextEditorWidget *editorWidget, const QPoint &point)
|
void CopilotHoverHandler::operateTooltip(TextEditorWidget *editorWidget, const QPoint &point)
|
||||||
{
|
{
|
||||||
|
Q_UNUSED(point)
|
||||||
auto *suggestion = dynamic_cast<CopilotSuggestion *>(TextDocumentLayout::suggestion(m_block));
|
auto *suggestion = dynamic_cast<CopilotSuggestion *>(TextDocumentLayout::suggestion(m_block));
|
||||||
|
|
||||||
if (!suggestion)
|
if (!suggestion)
|
||||||
@@ -147,8 +148,12 @@ void CopilotHoverHandler::operateTooltip(TextEditorWidget *editorWidget, const Q
|
|||||||
auto tooltipWidget = new CopilotCompletionToolTip(suggestion->completions(),
|
auto tooltipWidget = new CopilotCompletionToolTip(suggestion->completions(),
|
||||||
suggestion->currentCompletion(),
|
suggestion->currentCompletion(),
|
||||||
editorWidget);
|
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
|
} // namespace Copilot::Internal
|
||||||
|
|||||||
@@ -120,6 +120,9 @@ void CopilotPlugin::extensionsInitialized()
|
|||||||
void CopilotPlugin::restartClient()
|
void CopilotPlugin::restartClient()
|
||||||
{
|
{
|
||||||
LanguageClient::LanguageClientManager::shutdownClient(m_client);
|
LanguageClient::LanguageClientManager::shutdownClient(m_client);
|
||||||
|
|
||||||
|
if (!CopilotSettings::instance().nodeJsPath().isExecutableFile())
|
||||||
|
return;
|
||||||
m_client = new CopilotClient(CopilotSettings::instance().nodeJsPath(),
|
m_client = new CopilotClient(CopilotSettings::instance().nodeJsPath(),
|
||||||
CopilotSettings::instance().distPath());
|
CopilotSettings::instance().distPath());
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -53,7 +53,7 @@ CopilotSettings::CopilotSettings()
|
|||||||
nodeJsPath.setHistoryCompleter("Copilot.NodePath.History");
|
nodeJsPath.setHistoryCompleter("Copilot.NodePath.History");
|
||||||
nodeJsPath.setDisplayName(Tr::tr("Node.js Path"));
|
nodeJsPath.setDisplayName(Tr::tr("Node.js Path"));
|
||||||
nodeJsPath.setToolTip(
|
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."));
|
"for installation instructions."));
|
||||||
|
|
||||||
distPath.setExpectedKind(PathChooser::File);
|
distPath.setExpectedKind(PathChooser::File);
|
||||||
@@ -63,7 +63,7 @@ CopilotSettings::CopilotSettings()
|
|||||||
distPath.setHistoryCompleter("Copilot.DistPath.History");
|
distPath.setHistoryCompleter("Copilot.DistPath.History");
|
||||||
distPath.setDisplayName(Tr::tr("Agent.js path"));
|
distPath.setDisplayName(Tr::tr("Agent.js path"));
|
||||||
distPath.setToolTip(Tr::tr(
|
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."));
|
"https://github.com/github/copilot.vim#getting-started for installation instructions."));
|
||||||
|
|
||||||
autoComplete.setDisplayName(Tr::tr("Auto Complete"));
|
autoComplete.setDisplayName(Tr::tr("Auto Complete"));
|
||||||
@@ -71,7 +71,7 @@ CopilotSettings::CopilotSettings()
|
|||||||
autoComplete.setLabelText(Tr::tr("Request completions automatically"));
|
autoComplete.setLabelText(Tr::tr("Request completions automatically"));
|
||||||
autoComplete.setDefaultValue(true);
|
autoComplete.setDefaultValue(true);
|
||||||
autoComplete.setToolTip(Tr::tr("Automatically request suggestions for the current text cursor "
|
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);
|
initEnableAspect(enableCopilot);
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -347,8 +347,10 @@ void Internal::CommandPrivate::setCurrentContext(const Context &context)
|
|||||||
m_context = context;
|
m_context = context;
|
||||||
|
|
||||||
QAction *currentAction = nullptr;
|
QAction *currentAction = nullptr;
|
||||||
for (int i = 0; i < m_context.size(); ++i) {
|
for (const Id &id : std::as_const(m_context)) {
|
||||||
if (QAction *a = m_contextActionMap.value(m_context.at(i), nullptr)) {
|
if (id == Constants::C_GLOBAL_CUTOFF)
|
||||||
|
break;
|
||||||
|
if (QAction *a = m_contextActionMap.value(id, nullptr)) {
|
||||||
currentAction = a;
|
currentAction = a;
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -6,18 +6,17 @@
|
|||||||
#include <coreplugin/coreplugintr.h>
|
#include <coreplugin/coreplugintr.h>
|
||||||
#include <coreplugin/dialogs/shortcutsettings.h>
|
#include <coreplugin/dialogs/shortcutsettings.h>
|
||||||
|
|
||||||
#include <utils/headerviewstretcher.h>
|
|
||||||
#include <utils/fancylineedit.h>
|
#include <utils/fancylineedit.h>
|
||||||
|
#include <utils/headerviewstretcher.h>
|
||||||
|
#include <utils/layoutbuilder.h>
|
||||||
#include <utils/qtcassert.h>
|
#include <utils/qtcassert.h>
|
||||||
|
|
||||||
#include <QDebug>
|
#include <QDebug>
|
||||||
#include <QGroupBox>
|
#include <QGroupBox>
|
||||||
#include <QHBoxLayout>
|
|
||||||
#include <QLabel>
|
#include <QLabel>
|
||||||
#include <QPointer>
|
#include <QPointer>
|
||||||
#include <QPushButton>
|
#include <QPushButton>
|
||||||
#include <QTreeWidgetItem>
|
#include <QTreeWidgetItem>
|
||||||
#include <QVBoxLayout>
|
|
||||||
|
|
||||||
Q_DECLARE_METATYPE(Core::Internal::ShortcutItem*)
|
Q_DECLARE_METATYPE(Core::Internal::ShortcutItem*)
|
||||||
|
|
||||||
@@ -32,13 +31,10 @@ public:
|
|||||||
CommandMappingsPrivate(CommandMappings *parent)
|
CommandMappingsPrivate(CommandMappings *parent)
|
||||||
: q(parent)
|
: q(parent)
|
||||||
{
|
{
|
||||||
groupBox = new QGroupBox(parent);
|
filterEdit = new FancyLineEdit;
|
||||||
groupBox->setTitle(::Core::Tr::tr("Command Mappings"));
|
|
||||||
|
|
||||||
filterEdit = new FancyLineEdit(groupBox);
|
|
||||||
filterEdit->setFiltering(true);
|
filterEdit->setFiltering(true);
|
||||||
|
|
||||||
commandList = new QTreeWidget(groupBox);
|
commandList = new QTreeWidget;
|
||||||
commandList->setRootIsDecorated(false);
|
commandList->setRootIsDecorated(false);
|
||||||
commandList->setUniformRowHeights(true);
|
commandList->setUniformRowHeights(true);
|
||||||
commandList->setSortingEnabled(true);
|
commandList->setSortingEnabled(true);
|
||||||
@@ -49,33 +45,28 @@ public:
|
|||||||
item->setText(1, ::Core::Tr::tr("Label"));
|
item->setText(1, ::Core::Tr::tr("Label"));
|
||||||
item->setText(0, ::Core::Tr::tr("Command"));
|
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."));
|
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->setToolTip(::Core::Tr::tr("Reset to default."));
|
||||||
resetButton->setVisible(false);
|
resetButton->setVisible(false);
|
||||||
|
|
||||||
importButton = new QPushButton(::Core::Tr::tr("Import..."), groupBox);
|
importButton = new QPushButton(::Core::Tr::tr("Import..."));
|
||||||
exportButton = new QPushButton(::Core::Tr::tr("Export..."), groupBox);
|
exportButton = new QPushButton(::Core::Tr::tr("Export..."));
|
||||||
|
|
||||||
auto hboxLayout1 = new QHBoxLayout();
|
using namespace Layouting;
|
||||||
hboxLayout1->addWidget(defaultButton);
|
Column {
|
||||||
hboxLayout1->addWidget(resetButton);
|
Group {
|
||||||
hboxLayout1->addStretch();
|
title(::Core::Tr::tr("Command Mappings")),
|
||||||
hboxLayout1->addWidget(importButton);
|
bindTo(&groupBox),
|
||||||
hboxLayout1->addWidget(exportButton);
|
Column {
|
||||||
|
filterEdit,
|
||||||
auto hboxLayout = new QHBoxLayout();
|
commandList,
|
||||||
hboxLayout->addWidget(filterEdit);
|
Row { defaultButton, resetButton, st, importButton, exportButton },
|
||||||
|
},
|
||||||
auto vboxLayout1 = new QVBoxLayout(groupBox);
|
},
|
||||||
vboxLayout1->addLayout(hboxLayout);
|
}.attachTo(parent);
|
||||||
vboxLayout1->addWidget(commandList);
|
|
||||||
vboxLayout1->addLayout(hboxLayout1);
|
|
||||||
|
|
||||||
auto vboxLayout = new QVBoxLayout(parent);
|
|
||||||
vboxLayout->addWidget(groupBox);
|
|
||||||
|
|
||||||
q->connect(exportButton, &QPushButton::clicked,
|
q->connect(exportButton, &QPushButton::clicked,
|
||||||
q, &CommandMappings::exportAction);
|
q, &CommandMappings::exportAction);
|
||||||
|
|||||||
@@ -46,6 +46,11 @@ const char C_EDITORMANAGER[] = "Core.EditorManager";
|
|||||||
const char C_NAVIGATION_PANE[] = "Core.NavigationPane";
|
const char C_NAVIGATION_PANE[] = "Core.NavigationPane";
|
||||||
const char C_PROBLEM_PANE[] = "Core.ProblemPane";
|
const char C_PROBLEM_PANE[] = "Core.ProblemPane";
|
||||||
const char C_GENERAL_OUTPUT_PANE[] = "Core.GeneralOutputPane";
|
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
|
// Default editor kind
|
||||||
const char K_DEFAULT_TEXT_EDITOR_DISPLAY_NAME[] = QT_TRANSLATE_NOOP("QtC::Core", "Plain Text Editor");
|
const char K_DEFAULT_TEXT_EDITOR_DISPLAY_NAME[] = QT_TRANSLATE_NOOP("QtC::Core", "Plain Text Editor");
|
||||||
|
|||||||
@@ -199,15 +199,6 @@ void IOptionsPage::setSettings(AspectContainer *settings)
|
|||||||
m_settings = 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)
|
void IOptionsPage::setLayouter(const std::function<Layouting::LayoutItem ()> &layouter)
|
||||||
{
|
{
|
||||||
m_widgetCreator = [layouter] {
|
m_widgetCreator = [layouter] {
|
||||||
|
|||||||
@@ -74,7 +74,6 @@ protected:
|
|||||||
void setCategoryIcon(const Utils::Icon &categoryIcon) { m_categoryIcon = categoryIcon; }
|
void setCategoryIcon(const Utils::Icon &categoryIcon) { m_categoryIcon = categoryIcon; }
|
||||||
void setCategoryIconPath(const Utils::FilePath &categoryIconPath);
|
void setCategoryIconPath(const Utils::FilePath &categoryIconPath);
|
||||||
void setSettings(Utils::AspectContainer *settings);
|
void setSettings(Utils::AspectContainer *settings);
|
||||||
void setLayouter(const std::function<void(QWidget *w)> &layouter);
|
|
||||||
void setLayouter(const std::function<Layouting::LayoutItem()> &layouter);
|
void setLayouter(const std::function<Layouting::LayoutItem()> &layouter);
|
||||||
|
|
||||||
// Used in FontSettingsPage. FIXME?
|
// Used in FontSettingsPage. FIXME?
|
||||||
|
|||||||
@@ -42,7 +42,6 @@
|
|||||||
#include <utils/algorithm.h>
|
#include <utils/algorithm.h>
|
||||||
#include <utils/checkablemessagebox.h>
|
#include <utils/checkablemessagebox.h>
|
||||||
#include <utils/environment.h>
|
#include <utils/environment.h>
|
||||||
#include <utils/executeondestruction.h>
|
|
||||||
#include <utils/filepath.h>
|
#include <utils/filepath.h>
|
||||||
#include <utils/hostosinfo.h>
|
#include <utils/hostosinfo.h>
|
||||||
#include <utils/infobar.h>
|
#include <utils/infobar.h>
|
||||||
@@ -70,6 +69,7 @@
|
|||||||
#include <QPushButton>
|
#include <QPushButton>
|
||||||
#include <QRegularExpression>
|
#include <QRegularExpression>
|
||||||
#include <QRegularExpressionMatch>
|
#include <QRegularExpressionMatch>
|
||||||
|
#include <QScopeGuard>
|
||||||
#include <QSet>
|
#include <QSet>
|
||||||
#include <QSettings>
|
#include <QSettings>
|
||||||
#include <QSplitter>
|
#include <QSplitter>
|
||||||
@@ -3325,9 +3325,7 @@ IEditor *EditorManager::openEditorWithContents(Id editorId,
|
|||||||
EditorManager::gotoOtherSplit();
|
EditorManager::gotoOtherSplit();
|
||||||
|
|
||||||
QApplication::setOverrideCursor(QCursor(Qt::WaitCursor));
|
QApplication::setOverrideCursor(QCursor(Qt::WaitCursor));
|
||||||
Utils::ExecuteOnDestruction appRestoreCursor(&QApplication::restoreOverrideCursor);
|
const auto cleanup = qScopeGuard(&QApplication::restoreOverrideCursor);
|
||||||
Q_UNUSED(appRestoreCursor)
|
|
||||||
|
|
||||||
|
|
||||||
const QString title = makeTitleUnique(titlePattern);
|
const QString title = makeTitleUnique(titlePattern);
|
||||||
|
|
||||||
|
|||||||
@@ -450,7 +450,7 @@ void LocatorMatcher::start()
|
|||||||
collectorStorage->m_collector = nullptr;
|
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,
|
const auto onSetup = [this, collectorStorage](const TreeStorage<LocatorStorage> &storage,
|
||||||
int index) {
|
int index) {
|
||||||
@@ -470,7 +470,7 @@ void LocatorMatcher::start()
|
|||||||
for (const LocatorMatcherTask &task : std::as_const(d->m_tasks)) {
|
for (const LocatorMatcherTask &task : std::as_const(d->m_tasks)) {
|
||||||
const auto storage = task.storage;
|
const auto storage = task.storage;
|
||||||
const Group group {
|
const Group group {
|
||||||
optional,
|
finishAllAndDone,
|
||||||
Storage(storage),
|
Storage(storage),
|
||||||
onGroupSetup(onSetup(storage, index)),
|
onGroupSetup(onSetup(storage, index)),
|
||||||
onGroupDone(onDone(storage)),
|
onGroupDone(onDone(storage)),
|
||||||
@@ -597,7 +597,7 @@ QString ILocatorFilter::shortcutString() const
|
|||||||
\internal
|
\internal
|
||||||
Sets the refresh recipe for refreshing cached data.
|
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;
|
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
|
Returns the refresh recipe for refreshing cached data. By default, the locator filter has
|
||||||
no recipe set, so that it won't be refreshed.
|
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;
|
return m_refreshRecipe;
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -139,7 +139,7 @@ class CORE_EXPORT LocatorMatcherTask final
|
|||||||
public:
|
public:
|
||||||
// The main task. Initial data (searchTerm) should be taken from storage.input().
|
// The main task. Initial data (searchTerm) should be taken from storage.input().
|
||||||
// Results reporting is done via the storage.reportOutput().
|
// 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.
|
// When constructing the task, don't place the storage inside the task above.
|
||||||
Tasking::TreeStorage<LocatorStorage> storage;
|
Tasking::TreeStorage<LocatorStorage> storage;
|
||||||
@@ -270,8 +270,8 @@ protected:
|
|||||||
virtual void saveState(QJsonObject &object) const;
|
virtual void saveState(QJsonObject &object) const;
|
||||||
virtual void restoreState(const QJsonObject &object);
|
virtual void restoreState(const QJsonObject &object);
|
||||||
|
|
||||||
void setRefreshRecipe(const std::optional<Tasking::TaskItem> &recipe);
|
void setRefreshRecipe(const std::optional<Tasking::GroupItem> &recipe);
|
||||||
std::optional<Tasking::TaskItem> refreshRecipe() const;
|
std::optional<Tasking::GroupItem> refreshRecipe() const;
|
||||||
|
|
||||||
static bool isOldSetting(const QByteArray &state);
|
static bool isOldSetting(const QByteArray &state);
|
||||||
|
|
||||||
@@ -289,7 +289,7 @@ private:
|
|||||||
QString m_description;
|
QString m_description;
|
||||||
QString m_defaultShortcut;
|
QString m_defaultShortcut;
|
||||||
std::optional<QString> m_defaultSearchText;
|
std::optional<QString> m_defaultSearchText;
|
||||||
std::optional<Tasking::TaskItem> m_refreshRecipe;
|
std::optional<Tasking::GroupItem> m_refreshRecipe;
|
||||||
QKeySequence m_defaultKeySequence;
|
QKeySequence m_defaultKeySequence;
|
||||||
bool m_defaultIncludedByDefault = false;
|
bool m_defaultIncludedByDefault = false;
|
||||||
bool m_includedByDefault = m_defaultIncludedByDefault;
|
bool m_includedByDefault = m_defaultIncludedByDefault;
|
||||||
|
|||||||
@@ -381,14 +381,14 @@ void Locator::refresh(const QList<ILocatorFilter *> &filters)
|
|||||||
m_refreshingFilters = Utils::filteredUnique(m_refreshingFilters + filters);
|
m_refreshingFilters = Utils::filteredUnique(m_refreshingFilters + filters);
|
||||||
|
|
||||||
using namespace Tasking;
|
using namespace Tasking;
|
||||||
QList<TaskItem> tasks{parallel};
|
QList<GroupItem> tasks{parallel};
|
||||||
for (ILocatorFilter *filter : std::as_const(m_refreshingFilters)) {
|
for (ILocatorFilter *filter : std::as_const(m_refreshingFilters)) {
|
||||||
const auto task = filter->refreshRecipe();
|
const auto task = filter->refreshRecipe();
|
||||||
if (!task.has_value())
|
if (!task.has_value())
|
||||||
continue;
|
continue;
|
||||||
|
|
||||||
const Group group {
|
const Group group {
|
||||||
optional,
|
finishAllAndDone,
|
||||||
*task,
|
*task,
|
||||||
onGroupDone([this, filter] { m_refreshingFilters.removeOne(filter); })
|
onGroupDone([this, filter] { m_refreshingFilters.removeOne(filter); })
|
||||||
};
|
};
|
||||||
|
|||||||
@@ -11,7 +11,6 @@
|
|||||||
|
|
||||||
#include <utils/algorithm.h>
|
#include <utils/algorithm.h>
|
||||||
#include <utils/basetreeview.h>
|
#include <utils/basetreeview.h>
|
||||||
#include <utils/executeondestruction.h>
|
|
||||||
#include <utils/fileutils.h>
|
#include <utils/fileutils.h>
|
||||||
#include <utils/listmodel.h>
|
#include <utils/listmodel.h>
|
||||||
#include <utils/qtcassert.h>
|
#include <utils/qtcassert.h>
|
||||||
@@ -33,6 +32,7 @@
|
|||||||
#include <QMessageBox>
|
#include <QMessageBox>
|
||||||
#include <QPushButton>
|
#include <QPushButton>
|
||||||
#include <QRegularExpression>
|
#include <QRegularExpression>
|
||||||
|
#include <QScopeGuard>
|
||||||
#include <QSortFilterProxyModel>
|
#include <QSortFilterProxyModel>
|
||||||
#include <QStyledItemDelegate>
|
#include <QStyledItemDelegate>
|
||||||
#include <QToolButton>
|
#include <QToolButton>
|
||||||
@@ -591,7 +591,7 @@ void LoggingViewManagerWidget::saveLoggingsToFile() const
|
|||||||
{
|
{
|
||||||
// should we just let it continue without temporarily disabling?
|
// should we just let it continue without temporarily disabling?
|
||||||
const bool enabled = m_manager->isEnabled();
|
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)
|
if (enabled)
|
||||||
m_manager->setEnabled(false);
|
m_manager->setEnabled(false);
|
||||||
const Utils::FilePath fp = Utils::FileUtils::getSaveFilePath(ICore::dialogParent(),
|
const Utils::FilePath fp = Utils::FileUtils::getSaveFilePath(ICore::dialogParent(),
|
||||||
|
|||||||
@@ -17,14 +17,11 @@
|
|||||||
#include <extensionsystem/pluginview.h>
|
#include <extensionsystem/pluginview.h>
|
||||||
|
|
||||||
#include <utils/fancylineedit.h>
|
#include <utils/fancylineedit.h>
|
||||||
|
#include <utils/layoutbuilder.h>
|
||||||
|
|
||||||
#include <QCheckBox>
|
|
||||||
#include <QDialog>
|
#include <QDialog>
|
||||||
#include <QDialogButtonBox>
|
#include <QDialogButtonBox>
|
||||||
#include <QHBoxLayout>
|
|
||||||
#include <QLabel>
|
|
||||||
#include <QPushButton>
|
#include <QPushButton>
|
||||||
#include <QVBoxLayout>
|
|
||||||
|
|
||||||
using namespace Utils;
|
using namespace Utils;
|
||||||
|
|
||||||
@@ -35,30 +32,27 @@ PluginDialog::PluginDialog(QWidget *parent)
|
|||||||
: QDialog(parent),
|
: QDialog(parent),
|
||||||
m_view(new ExtensionSystem::PluginView(this))
|
m_view(new ExtensionSystem::PluginView(this))
|
||||||
{
|
{
|
||||||
auto vl = new QVBoxLayout(this);
|
|
||||||
|
|
||||||
auto filterLayout = new QHBoxLayout;
|
|
||||||
vl->addLayout(filterLayout);
|
|
||||||
auto filterEdit = new Utils::FancyLineEdit(this);
|
auto filterEdit = new Utils::FancyLineEdit(this);
|
||||||
filterEdit->setFocus();
|
filterEdit->setFocus();
|
||||||
filterEdit->setFiltering(true);
|
filterEdit->setFiltering(true);
|
||||||
connect(filterEdit, &Utils::FancyLineEdit::filterChanged,
|
connect(filterEdit, &Utils::FancyLineEdit::filterChanged,
|
||||||
m_view, &ExtensionSystem::PluginView::setFilter);
|
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);
|
auto buttonBox = new QDialogButtonBox(QDialogButtonBox::Ok | QDialogButtonBox::Cancel);
|
||||||
buttonBox->addButton(m_detailsButton, QDialogButtonBox::ActionRole);
|
m_detailsButton = buttonBox->addButton(Tr::tr("Details"), QDialogButtonBox::ActionRole);
|
||||||
buttonBox->addButton(m_errorDetailsButton, QDialogButtonBox::ActionRole);
|
m_detailsButton->setEnabled(false);
|
||||||
buttonBox->addButton(m_installButton, QDialogButtonBox::ActionRole);
|
m_errorDetailsButton = buttonBox->addButton(Tr::tr("Error Details"),
|
||||||
vl->addWidget(buttonBox);
|
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);
|
resize(650, 400);
|
||||||
setWindowTitle(Tr::tr("Installed Plugins"));
|
setWindowTitle(Tr::tr("Installed Plugins"));
|
||||||
@@ -116,13 +110,16 @@ void PluginDialog::openDetails(ExtensionSystem::PluginSpec *spec)
|
|||||||
return;
|
return;
|
||||||
QDialog dialog(this);
|
QDialog dialog(this);
|
||||||
dialog.setWindowTitle(Tr::tr("Plugin Details of %1").arg(spec->name()));
|
dialog.setWindowTitle(Tr::tr("Plugin Details of %1").arg(spec->name()));
|
||||||
auto layout = new QVBoxLayout;
|
|
||||||
dialog.setLayout(layout);
|
|
||||||
auto details = new ExtensionSystem::PluginDetailsView(&dialog);
|
auto details = new ExtensionSystem::PluginDetailsView(&dialog);
|
||||||
layout->addWidget(details);
|
|
||||||
details->update(spec);
|
details->update(spec);
|
||||||
QDialogButtonBox *buttons = new QDialogButtonBox(QDialogButtonBox::Close, Qt::Horizontal, &dialog);
|
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::accepted, &dialog, &QDialog::accept);
|
||||||
connect(buttons, &QDialogButtonBox::rejected, &dialog, &QDialog::reject);
|
connect(buttons, &QDialogButtonBox::rejected, &dialog, &QDialog::reject);
|
||||||
dialog.resize(400, 500);
|
dialog.resize(400, 500);
|
||||||
@@ -136,13 +133,16 @@ void PluginDialog::openErrorDetails()
|
|||||||
return;
|
return;
|
||||||
QDialog dialog(this);
|
QDialog dialog(this);
|
||||||
dialog.setWindowTitle(Tr::tr("Plugin Errors of %1").arg(spec->name()));
|
dialog.setWindowTitle(Tr::tr("Plugin Errors of %1").arg(spec->name()));
|
||||||
auto layout = new QVBoxLayout;
|
|
||||||
dialog.setLayout(layout);
|
|
||||||
auto errors = new ExtensionSystem::PluginErrorView(&dialog);
|
auto errors = new ExtensionSystem::PluginErrorView(&dialog);
|
||||||
layout->addWidget(errors);
|
|
||||||
errors->update(spec);
|
errors->update(spec);
|
||||||
QDialogButtonBox *buttons = new QDialogButtonBox(QDialogButtonBox::Close, Qt::Horizontal, &dialog);
|
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::accepted, &dialog, &QDialog::accept);
|
||||||
connect(buttons, &QDialogButtonBox::rejected, &dialog, &QDialog::reject);
|
connect(buttons, &QDialogButtonBox::rejected, &dialog, &QDialog::reject);
|
||||||
dialog.resize(500, 300);
|
dialog.resize(500, 300);
|
||||||
|
|||||||
@@ -15,6 +15,7 @@
|
|||||||
#include <utils/fileutils.h>
|
#include <utils/fileutils.h>
|
||||||
#include <utils/hostosinfo.h>
|
#include <utils/hostosinfo.h>
|
||||||
#include <utils/infolabel.h>
|
#include <utils/infolabel.h>
|
||||||
|
#include <utils/layoutbuilder.h>
|
||||||
#include <utils/pathchooser.h>
|
#include <utils/pathchooser.h>
|
||||||
#include <utils/process.h>
|
#include <utils/process.h>
|
||||||
#include <utils/qtcassert.h>
|
#include <utils/qtcassert.h>
|
||||||
@@ -33,7 +34,6 @@
|
|||||||
#include <QPushButton>
|
#include <QPushButton>
|
||||||
#include <QRadioButton>
|
#include <QRadioButton>
|
||||||
#include <QTextEdit>
|
#include <QTextEdit>
|
||||||
#include <QVBoxLayout>
|
|
||||||
|
|
||||||
#include <memory>
|
#include <memory>
|
||||||
|
|
||||||
@@ -80,19 +80,15 @@ public:
|
|||||||
, m_data(data)
|
, m_data(data)
|
||||||
{
|
{
|
||||||
setTitle(Tr::tr("Source"));
|
setTitle(Tr::tr("Source"));
|
||||||
auto vlayout = new QVBoxLayout;
|
|
||||||
setLayout(vlayout);
|
|
||||||
|
|
||||||
auto label = new QLabel(
|
auto label = new QLabel(
|
||||||
"<p>"
|
"<p>"
|
||||||
+ Tr::tr("Choose source location. This can be a plugin library file or a zip file.")
|
+ Tr::tr("Choose source location. This can be a plugin library file or a zip file.")
|
||||||
+ "</p>");
|
+ "</p>");
|
||||||
label->setWordWrap(true);
|
label->setWordWrap(true);
|
||||||
vlayout->addWidget(label);
|
|
||||||
|
|
||||||
auto chooser = new PathChooser;
|
auto chooser = new PathChooser;
|
||||||
chooser->setExpectedKind(PathChooser::Any);
|
chooser->setExpectedKind(PathChooser::Any);
|
||||||
vlayout->addWidget(chooser);
|
|
||||||
connect(chooser, &PathChooser::textChanged, this, [this, chooser] {
|
connect(chooser, &PathChooser::textChanged, this, [this, chooser] {
|
||||||
m_data->sourcePath = chooser->filePath();
|
m_data->sourcePath = chooser->filePath();
|
||||||
updateWarnings();
|
updateWarnings();
|
||||||
@@ -101,7 +97,8 @@ public:
|
|||||||
m_info = new InfoLabel;
|
m_info = new InfoLabel;
|
||||||
m_info->setType(InfoLabel::Error);
|
m_info->setType(InfoLabel::Error);
|
||||||
m_info->setVisible(false);
|
m_info->setVisible(false);
|
||||||
vlayout->addWidget(m_info);
|
|
||||||
|
Layouting::Column { label, chooser, m_info }.attachTo(this);
|
||||||
}
|
}
|
||||||
|
|
||||||
void updateWarnings()
|
void updateWarnings()
|
||||||
@@ -153,8 +150,6 @@ public:
|
|||||||
, m_data(data)
|
, m_data(data)
|
||||||
{
|
{
|
||||||
setTitle(Tr::tr("Check Archive"));
|
setTitle(Tr::tr("Check Archive"));
|
||||||
auto vlayout = new QVBoxLayout;
|
|
||||||
setLayout(vlayout);
|
|
||||||
|
|
||||||
m_label = new InfoLabel;
|
m_label = new InfoLabel;
|
||||||
m_label->setElideMode(Qt::ElideNone);
|
m_label->setElideMode(Qt::ElideNone);
|
||||||
@@ -163,13 +158,11 @@ public:
|
|||||||
m_output = new QTextEdit;
|
m_output = new QTextEdit;
|
||||||
m_output->setReadOnly(true);
|
m_output->setReadOnly(true);
|
||||||
|
|
||||||
auto hlayout = new QHBoxLayout;
|
using namespace Layouting;
|
||||||
hlayout->addWidget(m_label, 1);
|
Column {
|
||||||
hlayout->addStretch();
|
Row { m_label, st, m_cancelButton },
|
||||||
hlayout->addWidget(m_cancelButton);
|
m_output,
|
||||||
|
}.attachTo(this);
|
||||||
vlayout->addLayout(hlayout);
|
|
||||||
vlayout->addWidget(m_output);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void initializePage() final
|
void initializePage() final
|
||||||
@@ -322,13 +315,9 @@ public:
|
|||||||
, m_data(data)
|
, m_data(data)
|
||||||
{
|
{
|
||||||
setTitle(Tr::tr("Install Location"));
|
setTitle(Tr::tr("Install Location"));
|
||||||
auto vlayout = new QVBoxLayout;
|
|
||||||
setLayout(vlayout);
|
|
||||||
|
|
||||||
auto label = new QLabel("<p>" + Tr::tr("Choose install location.") + "</p>");
|
auto label = new QLabel("<p>" + Tr::tr("Choose install location.") + "</p>");
|
||||||
label->setWordWrap(true);
|
label->setWordWrap(true);
|
||||||
vlayout->addWidget(label);
|
|
||||||
vlayout->addSpacing(10);
|
|
||||||
|
|
||||||
auto localInstall = new QRadioButton(Tr::tr("User plugins"));
|
auto localInstall = new QRadioButton(Tr::tr("User plugins"));
|
||||||
localInstall->setChecked(!m_data->installIntoApplication);
|
localInstall->setChecked(!m_data->installIntoApplication);
|
||||||
@@ -338,10 +327,6 @@ public:
|
|||||||
localLabel->setWordWrap(true);
|
localLabel->setWordWrap(true);
|
||||||
localLabel->setAttribute(Qt::WA_MacSmallSize, true);
|
localLabel->setAttribute(Qt::WA_MacSmallSize, true);
|
||||||
|
|
||||||
vlayout->addWidget(localInstall);
|
|
||||||
vlayout->addWidget(localLabel);
|
|
||||||
vlayout->addSpacing(10);
|
|
||||||
|
|
||||||
auto appInstall = new QRadioButton(
|
auto appInstall = new QRadioButton(
|
||||||
Tr::tr("%1 installation").arg(Constants::IDE_DISPLAY_NAME));
|
Tr::tr("%1 installation").arg(Constants::IDE_DISPLAY_NAME));
|
||||||
appInstall->setChecked(m_data->installIntoApplication);
|
appInstall->setChecked(m_data->installIntoApplication);
|
||||||
@@ -351,8 +336,11 @@ public:
|
|||||||
.arg(Constants::IDE_DISPLAY_NAME));
|
.arg(Constants::IDE_DISPLAY_NAME));
|
||||||
appLabel->setWordWrap(true);
|
appLabel->setWordWrap(true);
|
||||||
appLabel->setAttribute(Qt::WA_MacSmallSize, 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);
|
auto group = new QButtonGroup(this);
|
||||||
group->addButton(localInstall);
|
group->addButton(localInstall);
|
||||||
@@ -375,12 +363,9 @@ public:
|
|||||||
{
|
{
|
||||||
setTitle(Tr::tr("Summary"));
|
setTitle(Tr::tr("Summary"));
|
||||||
|
|
||||||
auto vlayout = new QVBoxLayout;
|
|
||||||
setLayout(vlayout);
|
|
||||||
|
|
||||||
m_summaryLabel = new QLabel(this);
|
m_summaryLabel = new QLabel(this);
|
||||||
m_summaryLabel->setWordWrap(true);
|
m_summaryLabel->setWordWrap(true);
|
||||||
vlayout->addWidget(m_summaryLabel);
|
Layouting::Column { m_summaryLabel }.attachTo(this);
|
||||||
}
|
}
|
||||||
|
|
||||||
void initializePage() final
|
void initializePage() final
|
||||||
|
|||||||
@@ -51,8 +51,7 @@ const char showCrashButtonKey[] = "ShowCrashButton";
|
|||||||
// TODO: move to somewhere in Utils
|
// TODO: move to somewhere in Utils
|
||||||
static QString formatSize(qint64 size)
|
static QString formatSize(qint64 size)
|
||||||
{
|
{
|
||||||
QStringList units {Tr::tr("Bytes"), Tr::tr("KB"), Tr::tr("MB"),
|
QStringList units{Tr::tr("Bytes"), Tr::tr("KiB"), Tr::tr("MiB"), Tr::tr("GiB"), Tr::tr("TiB")};
|
||||||
Tr::tr("GB"), Tr::tr("TB")};
|
|
||||||
double outputSize = size;
|
double outputSize = size;
|
||||||
int i;
|
int i;
|
||||||
for (i = 0; i < units.size() - 1; ++i) {
|
for (i = 0; i < units.size() - 1; ++i) {
|
||||||
|
|||||||
@@ -108,11 +108,11 @@ CppcheckOptions::CppcheckOptions()
|
|||||||
readSettings();
|
readSettings();
|
||||||
}
|
}
|
||||||
|
|
||||||
std::function<void(QWidget *widget)> CppcheckOptions::layouter()
|
std::function<Layouting::LayoutItem()> CppcheckOptions::layouter()
|
||||||
{
|
{
|
||||||
return [this](QWidget *widget) {
|
return [this] {
|
||||||
using namespace Layouting;
|
using namespace Layouting;
|
||||||
Form {
|
return Form {
|
||||||
binary, br,
|
binary, br,
|
||||||
Tr::tr("Checks:"), Flow {
|
Tr::tr("Checks:"), Flow {
|
||||||
warning,
|
warning,
|
||||||
@@ -132,7 +132,7 @@ std::function<void(QWidget *widget)> CppcheckOptions::layouter()
|
|||||||
addIncludePaths,
|
addIncludePaths,
|
||||||
guessArguments
|
guessArguments
|
||||||
}
|
}
|
||||||
}.attachTo(widget);
|
};
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -12,7 +12,7 @@ class CppcheckOptions final : public Core::PagedSettings
|
|||||||
public:
|
public:
|
||||||
CppcheckOptions();
|
CppcheckOptions();
|
||||||
|
|
||||||
std::function<void(QWidget *widget)> layouter();
|
std::function<Layouting::LayoutItem()> layouter();
|
||||||
|
|
||||||
Utils::FilePathAspect binary{this};
|
Utils::FilePathAspect binary{this};
|
||||||
Utils::BoolAspect warning{this};
|
Utils::BoolAspect warning{this};
|
||||||
|
|||||||
@@ -25,6 +25,7 @@
|
|||||||
#include <debugger/analyzer/analyzerconstants.h>
|
#include <debugger/analyzer/analyzerconstants.h>
|
||||||
#include <debugger/debuggermainwindow.h>
|
#include <debugger/debuggermainwindow.h>
|
||||||
|
|
||||||
|
#include <utils/layoutbuilder.h>
|
||||||
#include <utils/qtcassert.h>
|
#include <utils/qtcassert.h>
|
||||||
#include <utils/utilsicons.h>
|
#include <utils/utilsicons.h>
|
||||||
|
|
||||||
@@ -111,8 +112,7 @@ void CppcheckPluginPrivate::startManualRun()
|
|||||||
|
|
||||||
manualRunTool.updateOptions();
|
manualRunTool.updateOptions();
|
||||||
|
|
||||||
auto optionsWidget = new QWidget;
|
auto optionsWidget = options.layouter()().emerge();
|
||||||
options.layouter()(optionsWidget);
|
|
||||||
|
|
||||||
ManualRunDialog dialog(optionsWidget, project);
|
ManualRunDialog dialog(optionsWidget, project);
|
||||||
if (dialog.exec() == ManualRunDialog::Rejected)
|
if (dialog.exec() == ManualRunDialog::Rejected)
|
||||||
|
|||||||
@@ -64,7 +64,7 @@ void CppProjectUpdater::update(const ProjectUpdateInfo &projectUpdateInfo,
|
|||||||
if (async.isResultAvailable())
|
if (async.isResultAvailable())
|
||||||
storage->projectInfo = async.result();
|
storage->projectInfo = async.result();
|
||||||
};
|
};
|
||||||
QList<TaskItem> tasks{parallel};
|
QList<GroupItem> tasks{parallel};
|
||||||
tasks.append(AsyncTask<ProjectInfo::ConstPtr>(setupInfoGenerator, onInfoGeneratorDone));
|
tasks.append(AsyncTask<ProjectInfo::ConstPtr>(setupInfoGenerator, onInfoGeneratorDone));
|
||||||
for (QPointer<ExtraCompiler> compiler : compilers) {
|
for (QPointer<ExtraCompiler> compiler : compilers) {
|
||||||
if (compiler && compiler->isDirty())
|
if (compiler && compiler->isDirty())
|
||||||
|
|||||||
@@ -414,6 +414,7 @@ F2TestCase::F2TestCase(CppEditorAction action,
|
|||||||
} else {
|
} else {
|
||||||
currentTextEditor->convertPosition(targetTestFile->m_targetCursorPosition,
|
currentTextEditor->convertPosition(targetTestFile->m_targetCursorPosition,
|
||||||
&expectedLine, &expectedColumn);
|
&expectedLine, &expectedColumn);
|
||||||
|
++expectedColumn;
|
||||||
if (useClangd && (tag == "classDestructor" || tag == "fromDestructorDefinitionSymbol"
|
if (useClangd && (tag == "classDestructor" || tag == "fromDestructorDefinitionSymbol"
|
||||||
|| tag == "fromDestructorBody")) {
|
|| tag == "fromDestructorBody")) {
|
||||||
--expectedColumn; // clangd goes before the ~, built-in code model after
|
--expectedColumn; // clangd goes before the ~, built-in code model after
|
||||||
|
|||||||
@@ -166,7 +166,7 @@ void ResourcePreviewHoverHandler::operateTooltip(TextEditorWidget *editorWidget,
|
|||||||
{
|
{
|
||||||
const QString tt = makeTooltip();
|
const QString tt = makeTooltip();
|
||||||
if (!tt.isEmpty())
|
if (!tt.isEmpty())
|
||||||
Utils::ToolTip::show(point, tt, editorWidget);
|
Utils::ToolTip::show(point, tt, Qt::MarkdownText, editorWidget);
|
||||||
else
|
else
|
||||||
Utils::ToolTip::hide();
|
Utils::ToolTip::hide();
|
||||||
}
|
}
|
||||||
@@ -180,10 +180,8 @@ QString ResourcePreviewHoverHandler::makeTooltip() const
|
|||||||
|
|
||||||
const Utils::MimeType mimeType = Utils::mimeTypeForFile(m_resPath);
|
const Utils::MimeType mimeType = Utils::mimeTypeForFile(m_resPath);
|
||||||
if (mimeType.name().startsWith("image", Qt::CaseInsensitive))
|
if (mimeType.name().startsWith("image", Qt::CaseInsensitive))
|
||||||
ret += QString("<img src=\"file:///%1\" /><br/>").arg(m_resPath);
|
ret += QString(" \n").arg(m_resPath);
|
||||||
|
ret += QString("[%1](%2)").arg(QDir::toNativeSeparators(m_resPath), m_resPath);
|
||||||
ret += QString("<a href=\"file:///%1\">%2</a>")
|
|
||||||
.arg(m_resPath, QDir::toNativeSeparators(m_resPath));
|
|
||||||
return ret;
|
return ret;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -64,6 +64,7 @@ void SemanticHighlighter::run()
|
|||||||
|
|
||||||
m_revision = documentRevision();
|
m_revision = documentRevision();
|
||||||
m_seenBlocks.clear();
|
m_seenBlocks.clear();
|
||||||
|
m_nextResultToHandle = m_resultCount = 0;
|
||||||
qCDebug(log) << "starting runner for document revision" << m_revision;
|
qCDebug(log) << "starting runner for document revision" << m_revision;
|
||||||
m_watcher->setFuture(m_highlightingRunner());
|
m_watcher->setFuture(m_highlightingRunner());
|
||||||
}
|
}
|
||||||
@@ -92,6 +93,21 @@ void SemanticHighlighter::onHighlighterResultAvailable(int from, int to)
|
|||||||
return;
|
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;
|
QElapsedTimer t;
|
||||||
t.start();
|
t.start();
|
||||||
|
|
||||||
@@ -177,6 +193,8 @@ void SemanticHighlighter::onHighlighterFinished()
|
|||||||
{
|
{
|
||||||
QTC_ASSERT(m_watcher, return);
|
QTC_ASSERT(m_watcher, return);
|
||||||
|
|
||||||
|
handleHighlighterResults();
|
||||||
|
|
||||||
QElapsedTimer t;
|
QElapsedTimer t;
|
||||||
t.start();
|
t.start();
|
||||||
|
|
||||||
|
|||||||
@@ -67,6 +67,7 @@ public:
|
|||||||
|
|
||||||
private:
|
private:
|
||||||
void onHighlighterResultAvailable(int from, int to);
|
void onHighlighterResultAvailable(int from, int to);
|
||||||
|
void handleHighlighterResults();
|
||||||
void onHighlighterFinished();
|
void onHighlighterFinished();
|
||||||
|
|
||||||
void connectWatcher();
|
void connectWatcher();
|
||||||
@@ -82,6 +83,8 @@ private:
|
|||||||
QScopedPointer<QFutureWatcher<TextEditor::HighlightingResult>> m_watcher;
|
QScopedPointer<QFutureWatcher<TextEditor::HighlightingResult>> m_watcher;
|
||||||
QHash<int, QTextCharFormat> m_formatMap;
|
QHash<int, QTextCharFormat> m_formatMap;
|
||||||
std::set<int> m_seenBlocks;
|
std::set<int> m_seenBlocks;
|
||||||
|
int m_nextResultToHandle = 0;
|
||||||
|
int m_resultCount = 0;
|
||||||
|
|
||||||
HighlightingRunner m_highlightingRunner;
|
HighlightingRunner m_highlightingRunner;
|
||||||
};
|
};
|
||||||
|
|||||||
@@ -59,9 +59,9 @@ CvsSettings::CvsSettings()
|
|||||||
|
|
||||||
diffIgnoreBlankLines.setSettingsKey("DiffIgnoreBlankLines");
|
diffIgnoreBlankLines.setSettingsKey("DiffIgnoreBlankLines");
|
||||||
|
|
||||||
setLayouter([this](QWidget *widget) {
|
setLayouter([this] {
|
||||||
using namespace Layouting;
|
using namespace Layouting;
|
||||||
Column {
|
return Column {
|
||||||
Group {
|
Group {
|
||||||
title(Tr::tr("Configuration")),
|
title(Tr::tr("Configuration")),
|
||||||
Form {
|
Form {
|
||||||
@@ -80,7 +80,7 @@ CvsSettings::CvsSettings()
|
|||||||
}
|
}
|
||||||
},
|
},
|
||||||
st
|
st
|
||||||
}.attachTo(widget);
|
};
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -101,11 +101,11 @@ DebuggerRunConfigurationAspect::DebuggerRunConfigurationAspect(Target *target)
|
|||||||
addDataExtractor(this, &DebuggerRunConfigurationAspect::useMultiProcess, &Data::useMultiProcess);
|
addDataExtractor(this, &DebuggerRunConfigurationAspect::useMultiProcess, &Data::useMultiProcess);
|
||||||
addDataExtractor(this, &DebuggerRunConfigurationAspect::overrideStartup, &Data::overrideStartup);
|
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->setLabelText(Tr::tr("C++ debugger:"));
|
||||||
m_cppAspect->setSettingsKey("RunConfiguration.UseCppDebugger");
|
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->setLabelText(Tr::tr("QML debugger:"));
|
||||||
m_qmlAspect->setSettingsKey("RunConfiguration.UseQmlDebugger");
|
m_qmlAspect->setSettingsKey("RunConfiguration.UseQmlDebugger");
|
||||||
|
|
||||||
|
|||||||
@@ -32,7 +32,7 @@ public:
|
|||||||
setCategory(Constants::DEBUGGER_SETTINGS_CATEGORY);
|
setCategory(Constants::DEBUGGER_SETTINGS_CATEGORY);
|
||||||
setSettings(&debuggerSettings()->page2);
|
setSettings(&debuggerSettings()->page2);
|
||||||
|
|
||||||
setLayouter([](QWidget *w) {
|
setLayouter([] {
|
||||||
using namespace Layouting;
|
using namespace Layouting;
|
||||||
DebuggerSettings &s = *debuggerSettings();
|
DebuggerSettings &s = *debuggerSettings();
|
||||||
|
|
||||||
@@ -84,7 +84,7 @@ public:
|
|||||||
Column { s.gdbPostAttachCommands },
|
Column { s.gdbPostAttachCommands },
|
||||||
};
|
};
|
||||||
|
|
||||||
Grid { general, extended, br, startup, attach }.attachTo(w);
|
return Grid { general, extended, br, startup, attach };
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|||||||
@@ -128,7 +128,7 @@ DiffFilesController::DiffFilesController(IDocument *document)
|
|||||||
outputList->resize(inputList.size());
|
outputList->resize(inputList.size());
|
||||||
|
|
||||||
using namespace std::placeholders;
|
using namespace std::placeholders;
|
||||||
QList<TaskItem> tasks {parallel, optional};
|
QList<GroupItem> tasks {parallel, finishAllAndDone};
|
||||||
for (int i = 0; i < inputList.size(); ++i) {
|
for (int i = 0; i < inputList.size(); ++i) {
|
||||||
tasks.append(AsyncTask<FileData>(std::bind(setupDiff, _1, inputList.at(i)),
|
tasks.append(AsyncTask<FileData>(std::bind(setupDiff, _1, inputList.at(i)),
|
||||||
std::bind(onDiffDone, _1, i)));
|
std::bind(onDiffDone, _1, i)));
|
||||||
|
|||||||
@@ -10,6 +10,13 @@
|
|||||||
// Qt Creator. The idea is to keep this file here in a "clean" state that
|
// 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.
|
// 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/hostosinfo.h>
|
||||||
#include <utils/layoutbuilder.h>
|
#include <utils/layoutbuilder.h>
|
||||||
#include <utils/qtcassert.h>
|
#include <utils/qtcassert.h>
|
||||||
@@ -18,8 +25,7 @@
|
|||||||
|
|
||||||
using namespace Utils;
|
using namespace Utils;
|
||||||
|
|
||||||
namespace FakeVim {
|
namespace FakeVim::Internal {
|
||||||
namespace Internal {
|
|
||||||
|
|
||||||
#ifdef FAKEVIM_STANDALONE
|
#ifdef FAKEVIM_STANDALONE
|
||||||
FvBaseAspect::FvBaseAspect()
|
FvBaseAspect::FvBaseAspect()
|
||||||
@@ -62,13 +68,31 @@ QString FvBaseAspect::settingsKey() const
|
|||||||
void setAutoApply(bool ) {}
|
void setAutoApply(bool ) {}
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
|
||||||
|
static FakeVimSettings *s_settings;
|
||||||
|
|
||||||
|
FakeVimSettings &settings()
|
||||||
|
{
|
||||||
|
return *s_settings;
|
||||||
|
}
|
||||||
|
|
||||||
FakeVimSettings::FakeVimSettings()
|
FakeVimSettings::FakeVimSettings()
|
||||||
{
|
{
|
||||||
setAutoApply(false);
|
s_settings = this;
|
||||||
|
|
||||||
#ifndef FAKEVIM_STANDALONE
|
#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"));
|
setup(&useFakeVim, false, "UseFakeVim", {}, Tr::tr("Use FakeVim"));
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
// Specific FakeVim settings
|
// Specific FakeVim settings
|
||||||
setup(&readVimRc, false, "ReadVimRc", {}, Tr::tr("Read .vimrc from location:"));
|
setup(&readVimRc, false, "ReadVimRc", {}, Tr::tr("Read .vimrc from location:"));
|
||||||
setup(&vimRcPath, QString(), "VimRcPath", {}, {}); // Tr::tr("Path to .vimrc")
|
setup(&vimRcPath, QString(), "VimRcPath", {}, {}); // Tr::tr("Path to .vimrc")
|
||||||
@@ -135,6 +159,121 @@ FakeVimSettings::FakeVimSettings()
|
|||||||
"%USERPROFILE%\\_vimrc on Windows, ~/.vimrc otherwise."));
|
"%USERPROFILE%\\_vimrc on Windows, ~/.vimrc otherwise."));
|
||||||
vimRcPath.setPlaceHolderText(Tr::tr("Default: %1").arg(vimrcDefault));
|
vimRcPath.setPlaceHolderText(Tr::tr("Default: %1").arg(vimrcDefault));
|
||||||
vimRcPath.setDisplayStyle(FvStringAspect::PathChooserDisplay);
|
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
|
#endif
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -187,11 +326,4 @@ void FakeVimSettings::setup(FvBaseAspect *aspect,
|
|||||||
m_nameToAspect[shortName] = aspect;
|
m_nameToAspect[shortName] = aspect;
|
||||||
}
|
}
|
||||||
|
|
||||||
FakeVimSettings *fakeVimSettings()
|
} // FakeVim::Internal
|
||||||
{
|
|
||||||
static FakeVimSettings s;
|
|
||||||
return &s;
|
|
||||||
}
|
|
||||||
|
|
||||||
} // namespace Internal
|
|
||||||
} // namespace FakeVim
|
|
||||||
|
|||||||
@@ -4,7 +4,7 @@
|
|||||||
#pragma once
|
#pragma once
|
||||||
|
|
||||||
#ifndef FAKEVIM_STANDALONE
|
#ifndef FAKEVIM_STANDALONE
|
||||||
# include <utils/aspects.h>
|
# include <coreplugin/dialogs/ioptionspage.h>
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
#include <QCoreApplication>
|
#include <QCoreApplication>
|
||||||
@@ -13,8 +13,7 @@
|
|||||||
#include <QString>
|
#include <QString>
|
||||||
#include <QVariant>
|
#include <QVariant>
|
||||||
|
|
||||||
namespace FakeVim {
|
namespace FakeVim::Internal {
|
||||||
namespace Internal {
|
|
||||||
|
|
||||||
#ifdef FAKEVIM_STANDALONE
|
#ifdef FAKEVIM_STANDALONE
|
||||||
class FvBaseAspect
|
class FvBaseAspect
|
||||||
@@ -68,7 +67,7 @@ public:
|
|||||||
|
|
||||||
#else
|
#else
|
||||||
|
|
||||||
using FvAspectContainer = Utils::AspectContainer;
|
using FvAspectContainer = Core::PagedSettings;
|
||||||
using FvBaseAspect = Utils::BaseAspect;
|
using FvBaseAspect = Utils::BaseAspect;
|
||||||
using FvBoolAspect = Utils::BoolAspect;
|
using FvBoolAspect = Utils::BoolAspect;
|
||||||
using FvIntegerAspect = Utils::IntegerAspect;
|
using FvIntegerAspect = Utils::IntegerAspect;
|
||||||
@@ -145,7 +144,6 @@ private:
|
|||||||
QHash<FvBaseAspect *, QString> m_aspectToName;
|
QHash<FvBaseAspect *, QString> m_aspectToName;
|
||||||
};
|
};
|
||||||
|
|
||||||
FakeVimSettings *fakeVimSettings();
|
FakeVimSettings &settings();
|
||||||
|
|
||||||
} // namespace Internal
|
} // FakeVim::Internal
|
||||||
} // namespace FakeVim
|
|
||||||
|
|||||||
@@ -408,9 +408,8 @@ static QRegularExpression vimPatternToQtPattern(const QString &needle)
|
|||||||
*/
|
*/
|
||||||
|
|
||||||
// FIXME: Option smartcase should be used only if search was typed by user.
|
// FIXME: Option smartcase should be used only if search was typed by user.
|
||||||
const bool ignoreCaseOption = fakeVimSettings()->ignoreCase.value();
|
const bool smartCaseOption = settings().smartCase();
|
||||||
const bool smartCaseOption = fakeVimSettings()->smartCase.value();
|
const bool initialIgnoreCase = settings().ignoreCase()
|
||||||
const bool initialIgnoreCase = ignoreCaseOption
|
|
||||||
&& !(smartCaseOption && needle.contains(QRegularExpression("[A-Z]")));
|
&& !(smartCaseOption && needle.contains(QRegularExpression("[A-Z]")));
|
||||||
|
|
||||||
bool ignorecase = initialIgnoreCase;
|
bool ignorecase = initialIgnoreCase;
|
||||||
@@ -2373,7 +2372,7 @@ public:
|
|||||||
QString surroundFunction; // Used for storing the function name provided to ys{motion}f
|
QString surroundFunction; // Used for storing the function name provided to ys{motion}f
|
||||||
} g;
|
} g;
|
||||||
|
|
||||||
FakeVimSettings &s = *fakeVimSettings();
|
FakeVimSettings &s = settings();
|
||||||
};
|
};
|
||||||
|
|
||||||
static void initSingleShotTimer(QTimer *timer,
|
static void initSingleShotTimer(QTimer *timer,
|
||||||
@@ -2527,7 +2526,7 @@ void FakeVimHandler::Private::leaveFakeVim(bool needUpdate)
|
|||||||
|
|
||||||
// The command might have destroyed the editor.
|
// The command might have destroyed the editor.
|
||||||
if (m_textedit || m_plaintextedit) {
|
if (m_textedit || m_plaintextedit) {
|
||||||
if (s.showMarks.value())
|
if (s.showMarks())
|
||||||
updateSelection();
|
updateSelection();
|
||||||
|
|
||||||
updateMiniBuffer();
|
updateMiniBuffer();
|
||||||
@@ -2576,7 +2575,7 @@ bool FakeVimHandler::Private::wantsOverride(QKeyEvent *ev)
|
|||||||
|
|
||||||
// We are interested in overriding most Ctrl key combinations.
|
// We are interested in overriding most Ctrl key combinations.
|
||||||
if (isOnlyControlModifier(mods)
|
if (isOnlyControlModifier(mods)
|
||||||
&& !s.passControlKey.value()
|
&& !s.passControlKey()
|
||||||
&& ((key >= Key_A && key <= Key_Z && key != Key_K)
|
&& ((key >= Key_A && key <= Key_Z && key != Key_K)
|
||||||
|| key == Key_BracketLeft || key == Key_BracketRight)) {
|
|| key == Key_BracketLeft || key == Key_BracketRight)) {
|
||||||
// Ctrl-K is special as it is the Core's default notion of Locator
|
// 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)
|
void FakeVimHandler::Private::updateFind(bool isComplete)
|
||||||
{
|
{
|
||||||
if (!isComplete && !s.incSearch.value())
|
if (!isComplete && !s.incSearch())
|
||||||
return;
|
return;
|
||||||
|
|
||||||
g.currentMessage.clear();
|
g.currentMessage.clear();
|
||||||
@@ -3161,7 +3160,7 @@ void FakeVimHandler::Private::pushUndoState(bool overwrite)
|
|||||||
pos = firstPositionInLine(lineForPosition(pos));
|
pos = firstPositionInLine(lineForPosition(pos));
|
||||||
else if (isVisualBlockMode())
|
else if (isVisualBlockMode())
|
||||||
pos = blockAt(pos).position() + qMin(columnAt(anchor()), columnAt(position()));
|
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;
|
QTextCursor tc = m_cursor;
|
||||||
if (g.submode == ShiftLeftSubMode || g.submode == ShiftRightSubMode
|
if (g.submode == ShiftLeftSubMode || g.submode == ShiftRightSubMode
|
||||||
|| g.submode == IndentSubMode) {
|
|| g.submode == IndentSubMode) {
|
||||||
@@ -3621,7 +3620,7 @@ void FakeVimHandler::Private::finishMovement(const QString &dotCommandMovement)
|
|||||||
return;
|
return;
|
||||||
} else if (g.submode == ExchangeSubMode) {
|
} else if (g.submode == ExchangeSubMode) {
|
||||||
exchangeRange(currentRange());
|
exchangeRange(currentRange());
|
||||||
} else if (g.submode == ReplaceWithRegisterSubMode && s.emulateReplaceWithRegister.value()) {
|
} else if (g.submode == ReplaceWithRegisterSubMode && s.emulateReplaceWithRegister()) {
|
||||||
pushUndoState(false);
|
pushUndoState(false);
|
||||||
beginEditBlock();
|
beginEditBlock();
|
||||||
replaceWithRegister(currentRange());
|
replaceWithRegister(currentRange());
|
||||||
@@ -3734,7 +3733,7 @@ void FakeVimHandler::Private::clearCurrentMode()
|
|||||||
void FakeVimHandler::Private::updateSelection()
|
void FakeVimHandler::Private::updateSelection()
|
||||||
{
|
{
|
||||||
QList<QTextEdit::ExtraSelection> selections = m_extraSelections;
|
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) {
|
for (auto it = m_buffer->marks.cbegin(), end = m_buffer->marks.cend(); it != end; ++it) {
|
||||||
QTextEdit::ExtraSelection sel;
|
QTextEdit::ExtraSelection sel;
|
||||||
sel.cursor = m_cursor;
|
sel.cursor = m_cursor;
|
||||||
@@ -3753,7 +3752,7 @@ void FakeVimHandler::Private::updateSelection()
|
|||||||
|
|
||||||
void FakeVimHandler::Private::updateHighlights()
|
void FakeVimHandler::Private::updateHighlights()
|
||||||
{
|
{
|
||||||
if (s.useCoreSearch.value() || !s.hlSearch.value() || g.highlightsCleared) {
|
if (s.useCoreSearch() || !s.hlSearch() || g.highlightsCleared) {
|
||||||
if (m_highlighted.isEmpty())
|
if (m_highlighted.isEmpty())
|
||||||
return;
|
return;
|
||||||
m_highlighted.clear();
|
m_highlighted.clear();
|
||||||
@@ -3800,7 +3799,7 @@ void FakeVimHandler::Private::updateMiniBuffer()
|
|||||||
} else if (!g.mapStates.isEmpty() && !g.mapStates.last().silent) {
|
} else if (!g.mapStates.isEmpty() && !g.mapStates.last().silent) {
|
||||||
// Do not reset previous message when after running a mapped command.
|
// Do not reset previous message when after running a mapped command.
|
||||||
return;
|
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;
|
msg = g.currentCommand;
|
||||||
messageLevel = MessageShowCmd;
|
messageLevel = MessageShowCmd;
|
||||||
} else if (g.mode == CommandMode && isVisualMode()) {
|
} else if (g.mode == CommandMode && isVisualMode()) {
|
||||||
@@ -3907,7 +3906,7 @@ bool FakeVimHandler::Private::handleCommandSubSubMode(const Input &input)
|
|||||||
handled = selectBlockTextObject(g.subsubdata.is('i'), '{', '}');
|
handled = selectBlockTextObject(g.subsubdata.is('i'), '{', '}');
|
||||||
else if (input.is('"') || input.is('\'') || input.is('`'))
|
else if (input.is('"') || input.is('\'') || input.is('`'))
|
||||||
handled = selectQuotedStringTextObject(g.subsubdata.is('i'), input.asChar());
|
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'));
|
handled = selectArgumentTextObject(g.subsubdata.is('i'));
|
||||||
else
|
else
|
||||||
handled = false;
|
handled = false;
|
||||||
@@ -4050,7 +4049,7 @@ bool FakeVimHandler::Private::handleMovement(const Input &input)
|
|||||||
g.subsubmode = NoSubSubMode;
|
g.subsubmode = NoSubSubMode;
|
||||||
} else if (input.is('/') || input.is('?')) {
|
} else if (input.is('/') || input.is('?')) {
|
||||||
g.lastSearchForward = input.is('/');
|
g.lastSearchForward = input.is('/');
|
||||||
if (s.useCoreSearch.value()) {
|
if (s.useCoreSearch()) {
|
||||||
// re-use the core dialog.
|
// re-use the core dialog.
|
||||||
g.findPending = true;
|
g.findPending = true;
|
||||||
m_findStartPosition = position();
|
m_findStartPosition = position();
|
||||||
@@ -4225,7 +4224,7 @@ bool FakeVimHandler::Private::handleMovement(const Input &input)
|
|||||||
m_cursor = EDITOR(cursorForPosition(QPoint(0, EDITOR(height()) / 2)));
|
m_cursor = EDITOR(cursorForPosition(QPoint(0, EDITOR(height()) / 2)));
|
||||||
handleStartOfLine();
|
handleStartOfLine();
|
||||||
} else if (input.is('n') || input.is('N')) {
|
} else if (input.is('n') || input.is('N')) {
|
||||||
if (s.useCoreSearch.value()) {
|
if (s.useCoreSearch()) {
|
||||||
bool forward = (input.is('n')) ? g.lastSearchForward : !g.lastSearchForward;
|
bool forward = (input.is('n')) ? g.lastSearchForward : !g.lastSearchForward;
|
||||||
int pos = position();
|
int pos = position();
|
||||||
q->findNextRequested(!forward);
|
q->findNextRequested(!forward);
|
||||||
@@ -4314,7 +4313,7 @@ EventResult FakeVimHandler::Private::handleCommandMode(const Input &input)
|
|||||||
handled = handleNoSubMode(input);
|
handled = handleNoSubMode(input);
|
||||||
} else if (g.submode == ExchangeSubMode) {
|
} else if (g.submode == ExchangeSubMode) {
|
||||||
handled = handleExchangeSubMode(input);
|
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
|
// Exchange submode is "cx", so we need to switch over from ChangeSubMode here
|
||||||
g.submode = ExchangeSubMode;
|
g.submode = ExchangeSubMode;
|
||||||
handled = true;
|
handled = true;
|
||||||
@@ -4324,15 +4323,15 @@ EventResult FakeVimHandler::Private::handleCommandMode(const Input &input)
|
|||||||
} else if (g.submode == AddSurroundingSubMode) {
|
} else if (g.submode == AddSurroundingSubMode) {
|
||||||
handled = handleAddSurroundingSubMode(input);
|
handled = handleAddSurroundingSubMode(input);
|
||||||
} else if (g.submode == ChangeSubMode && (input.is('s') || input.is('S'))
|
} else if (g.submode == ChangeSubMode && (input.is('s') || input.is('S'))
|
||||||
&& s.emulateSurround.value()) {
|
&& s.emulateSurround()) {
|
||||||
g.submode = ChangeSurroundingSubMode;
|
g.submode = ChangeSurroundingSubMode;
|
||||||
g.surroundUpperCaseS = input.is('S');
|
g.surroundUpperCaseS = input.is('S');
|
||||||
handled = true;
|
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;
|
g.submode = DeleteSurroundingSubMode;
|
||||||
handled = true;
|
handled = true;
|
||||||
} else if (g.submode == YankSubMode && (input.is('s') || input.is('S'))
|
} else if (g.submode == YankSubMode && (input.is('s') || input.is('S'))
|
||||||
&& s.emulateSurround.value()) {
|
&& s.emulateSurround()) {
|
||||||
g.submode = AddSurroundingSubMode;
|
g.submode = AddSurroundingSubMode;
|
||||||
g.movetype = MoveInclusive;
|
g.movetype = MoveInclusive;
|
||||||
g.surroundUpperCaseS = input.is('S');
|
g.surroundUpperCaseS = input.is('S');
|
||||||
@@ -4341,10 +4340,9 @@ EventResult FakeVimHandler::Private::handleCommandMode(const Input &input)
|
|||||||
|| g.submode == DeleteSubMode
|
|| g.submode == DeleteSubMode
|
||||||
|| g.submode == YankSubMode) {
|
|| g.submode == YankSubMode) {
|
||||||
handled = handleChangeDeleteYankSubModes(input);
|
handled = handleChangeDeleteYankSubModes(input);
|
||||||
} else if (g.submode == CommentSubMode && s.emulateVimCommentary.value()) {
|
} else if (g.submode == CommentSubMode && s.emulateVimCommentary()) {
|
||||||
handled = handleCommentSubMode(input);
|
handled = handleCommentSubMode(input);
|
||||||
} else if (g.submode == ReplaceWithRegisterSubMode
|
} else if (g.submode == ReplaceWithRegisterSubMode && s.emulateReplaceWithRegister()) {
|
||||||
&& s.emulateReplaceWithRegister.value()) {
|
|
||||||
handled = handleReplaceWithRegisterSubMode(input);
|
handled = handleReplaceWithRegisterSubMode(input);
|
||||||
} else if (g.submode == ReplaceSubMode) {
|
} else if (g.submode == ReplaceSubMode) {
|
||||||
handled = handleReplaceSubMode(input);
|
handled = handleReplaceSubMode(input);
|
||||||
@@ -4487,7 +4485,7 @@ bool FakeVimHandler::Private::handleNoSubMode(const Input &input)
|
|||||||
setTargetColumn();
|
setTargetColumn();
|
||||||
} else if (input.isControl('a')) {
|
} else if (input.isControl('a')) {
|
||||||
changeNumberTextObject(count());
|
changeNumberTextObject(count());
|
||||||
} else if (g.gflag && input.is('c') && s.emulateVimCommentary.value()) {
|
} else if (g.gflag && input.is('c') && s.emulateVimCommentary()) {
|
||||||
if (isVisualMode()) {
|
if (isVisualMode()) {
|
||||||
pushUndoState();
|
pushUndoState();
|
||||||
|
|
||||||
@@ -4512,7 +4510,7 @@ bool FakeVimHandler::Private::handleNoSubMode(const Input &input)
|
|||||||
pushUndoState();
|
pushUndoState();
|
||||||
setAnchor();
|
setAnchor();
|
||||||
}
|
}
|
||||||
} else if (g.gflag && input.is('r') && s.emulateReplaceWithRegister.value()) {
|
} else if (g.gflag && input.is('r') && s.emulateReplaceWithRegister()) {
|
||||||
g.submode = ReplaceWithRegisterSubMode;
|
g.submode = ReplaceWithRegisterSubMode;
|
||||||
if (isVisualMode()) {
|
if (isVisualMode()) {
|
||||||
dotCommand = visualDotCommand() + QString::number(count()) + "gr";
|
dotCommand = visualDotCommand() + QString::number(count()) + "gr";
|
||||||
@@ -4671,7 +4669,7 @@ bool FakeVimHandler::Private::handleNoSubMode(const Input &input)
|
|||||||
int repeat = count();
|
int repeat = count();
|
||||||
while (--repeat >= 0)
|
while (--repeat >= 0)
|
||||||
redo();
|
redo();
|
||||||
} else if (input.is('S') && isVisualMode() && s.emulateSurround.value()) {
|
} else if (input.is('S') && isVisualMode() && s.emulateSurround()) {
|
||||||
g.submode = AddSurroundingSubMode;
|
g.submode = AddSurroundingSubMode;
|
||||||
g.subsubmode = SurroundSubSubMode;
|
g.subsubmode = SurroundSubSubMode;
|
||||||
} else if (input.is('s')) {
|
} else if (input.is('s')) {
|
||||||
@@ -4756,7 +4754,7 @@ bool FakeVimHandler::Private::handleNoSubMode(const Input &input)
|
|||||||
if (isVisualMode()) {
|
if (isVisualMode()) {
|
||||||
leaveVisualMode();
|
leaveVisualMode();
|
||||||
finishMovement();
|
finishMovement();
|
||||||
} else if (g.gflag || (g.submode == InvertCaseSubMode && s.tildeOp.value())) {
|
} else if (g.gflag || (g.submode == InvertCaseSubMode && s.tildeOp())) {
|
||||||
if (atEndOfLine())
|
if (atEndOfLine())
|
||||||
moveLeft();
|
moveLeft();
|
||||||
setAnchor();
|
setAnchor();
|
||||||
@@ -5404,8 +5402,8 @@ void FakeVimHandler::Private::handleInsertMode(const Input &input)
|
|||||||
if (!handleInsertInEditor(Input(Qt::Key_Backspace, Qt::NoModifier))) {
|
if (!handleInsertInEditor(Input(Qt::Key_Backspace, Qt::NoModifier))) {
|
||||||
joinPreviousEditBlock();
|
joinPreviousEditBlock();
|
||||||
if (!m_buffer->lastInsertion.isEmpty()
|
if (!m_buffer->lastInsertion.isEmpty()
|
||||||
|| s.backspace.value().contains("start")
|
|| s.backspace().contains("start")
|
||||||
|| s.backspace.value().contains("2")) {
|
|| s.backspace().contains("2")) {
|
||||||
const int line = cursorLine() + 1;
|
const int line = cursorLine() + 1;
|
||||||
const Column col = cursorColumn();
|
const Column col = cursorColumn();
|
||||||
QString data = lineContents(line);
|
QString data = lineContents(line);
|
||||||
@@ -5438,7 +5436,7 @@ void FakeVimHandler::Private::handleInsertMode(const Input &input)
|
|||||||
} else if (input.isKey(Key_Tab)) {
|
} else if (input.isKey(Key_Tab)) {
|
||||||
if (q->tabPressedInInsertMode()) {
|
if (q->tabPressedInInsertMode()) {
|
||||||
m_buffer->insertState.insertingSpaces = true;
|
m_buffer->insertState.insertingSpaces = true;
|
||||||
if (s.expandTab.value()) {
|
if (s.expandTab()) {
|
||||||
const int ts = s.tabStop();
|
const int ts = s.tabStop();
|
||||||
const int col = logicalCursorColumn();
|
const int col = logicalCursorColumn();
|
||||||
QString str = QString(ts - col % ts, ' ');
|
QString str = QString(ts - col % ts, ' ');
|
||||||
@@ -5494,7 +5492,7 @@ void FakeVimHandler::Private::insertInInsertMode(const QString &text)
|
|||||||
{
|
{
|
||||||
joinPreviousEditBlock();
|
joinPreviousEditBlock();
|
||||||
insertText(text);
|
insertText(text);
|
||||||
if (s.smartIndent.value() && isElectricCharacter(text.at(0))) {
|
if (s.smartIndent() && isElectricCharacter(text.at(0))) {
|
||||||
const QString leftText = block().text()
|
const QString leftText = block().text()
|
||||||
.left(position() - 1 - block().position());
|
.left(position() - 1 - block().position());
|
||||||
if (leftText.simplified().isEmpty()) {
|
if (leftText.simplified().isEmpty()) {
|
||||||
@@ -6265,7 +6263,7 @@ bool FakeVimHandler::Private::handleExMoveCommand(const ExCommand &cmd)
|
|||||||
|
|
||||||
if (!insertAtEnd)
|
if (!insertAtEnd)
|
||||||
moveUp(1);
|
moveUp(1);
|
||||||
if (s.startOfLine.value())
|
if (s.startOfLine())
|
||||||
moveToFirstNonBlankOnLine();
|
moveToFirstNonBlankOnLine();
|
||||||
|
|
||||||
if (lastAnchor.line >= startLine && lastAnchor.line <= endLine)
|
if (lastAnchor.line >= startLine && lastAnchor.line <= endLine)
|
||||||
@@ -6794,7 +6792,7 @@ QTextCursor FakeVimHandler::Private::search(const SearchData &sd, int startPos,
|
|||||||
}
|
}
|
||||||
|
|
||||||
if (tc.isNull()) {
|
if (tc.isNull()) {
|
||||||
if (s.wrapScan.value()) {
|
if (s.wrapScan()) {
|
||||||
tc = QTextCursor(document());
|
tc = QTextCursor(document());
|
||||||
tc.movePosition(sd.forward ? StartOfDocument : EndOfDocument);
|
tc.movePosition(sd.forward ? StartOfDocument : EndOfDocument);
|
||||||
if (sd.forward)
|
if (sd.forward)
|
||||||
@@ -6954,7 +6952,7 @@ void FakeVimHandler::Private::shiftRegionRight(int repeat)
|
|||||||
std::swap(beginLine, endLine);
|
std::swap(beginLine, endLine);
|
||||||
targetPos = position();
|
targetPos = position();
|
||||||
}
|
}
|
||||||
if (s.startOfLine.value())
|
if (s.startOfLine())
|
||||||
targetPos = firstPositionInLine(beginLine);
|
targetPos = firstPositionInLine(beginLine);
|
||||||
|
|
||||||
const int sw = s.shiftWidth();
|
const int sw = s.shiftWidth();
|
||||||
@@ -7106,7 +7104,7 @@ void FakeVimHandler::Private::setupCharClass()
|
|||||||
const QChar c = QLatin1Char(i);
|
const QChar c = QLatin1Char(i);
|
||||||
m_charClass[i] = c.isSpace() ? 0 : 1;
|
m_charClass[i] = c.isSpace() ? 0 : 1;
|
||||||
}
|
}
|
||||||
const QString conf = s.isKeyword.value();
|
const QString conf = s.isKeyword();
|
||||||
for (const QString &part : conf.split(',')) {
|
for (const QString &part : conf.split(',')) {
|
||||||
if (part.contains('-')) {
|
if (part.contains('-')) {
|
||||||
const int from = someInt(part.section('-', 0, 0));
|
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)
|
void FakeVimHandler::Private::insertText(QTextCursor &tc, const QString &text)
|
||||||
{
|
{
|
||||||
if (s.passKeys.value()) {
|
if (s.passKeys()) {
|
||||||
if (tc.hasSelection() && text.isEmpty()) {
|
if (tc.hasSelection() && text.isEmpty()) {
|
||||||
QKeyEvent event(QEvent::KeyPress, Qt::Key_Delete, Qt::NoModifier, QString());
|
QKeyEvent event(QEvent::KeyPress, Qt::Key_Delete, Qt::NoModifier, QString());
|
||||||
passEventToEditor(event, tc);
|
passEventToEditor(event, tc);
|
||||||
@@ -7937,7 +7935,7 @@ void FakeVimHandler::Private::joinLines(int count, bool preserveSpace)
|
|||||||
moveRight();
|
moveRight();
|
||||||
|
|
||||||
// If the line we started from is a comment, remove the comment string from the next line
|
// 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) == '/')
|
if (characterAtCursor() == '/' && characterAt(position() + 1) == '/')
|
||||||
moveRight(2);
|
moveRight(2);
|
||||||
else if (characterAtCursor() == '*' || characterAtCursor() == '#')
|
else if (characterAtCursor() == '*' || characterAtCursor() == '#')
|
||||||
@@ -7955,7 +7953,7 @@ void FakeVimHandler::Private::joinLines(int count, bool preserveSpace)
|
|||||||
|
|
||||||
void FakeVimHandler::Private::insertNewLine()
|
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");
|
QKeyEvent event(QEvent::KeyPress, Qt::Key_Return, Qt::NoModifier, "\n");
|
||||||
if (passEventToEditor(event, m_cursor))
|
if (passEventToEditor(event, m_cursor))
|
||||||
return;
|
return;
|
||||||
@@ -7967,7 +7965,7 @@ void FakeVimHandler::Private::insertNewLine()
|
|||||||
|
|
||||||
bool FakeVimHandler::Private::handleInsertInEditor(const Input &input)
|
bool FakeVimHandler::Private::handleInsertInEditor(const Input &input)
|
||||||
{
|
{
|
||||||
if (m_buffer->editBlockLevel > 0 || !s.passKeys.value())
|
if (m_buffer->editBlockLevel > 0 || !s.passKeys())
|
||||||
return false;
|
return false;
|
||||||
|
|
||||||
joinPreviousEditBlock();
|
joinPreviousEditBlock();
|
||||||
@@ -8712,10 +8710,10 @@ QString FakeVimHandler::Private::tabExpand(int n) const
|
|||||||
|
|
||||||
void FakeVimHandler::Private::insertAutomaticIndentation(bool goingDown, bool forceAutoIndent)
|
void FakeVimHandler::Private::insertAutomaticIndentation(bool goingDown, bool forceAutoIndent)
|
||||||
{
|
{
|
||||||
if (!forceAutoIndent && !s.autoIndent.value() && !s.smartIndent.value())
|
if (!forceAutoIndent && !s.autoIndent() && !s.smartIndent())
|
||||||
return;
|
return;
|
||||||
|
|
||||||
if (s.smartIndent.value()) {
|
if (s.smartIndent()) {
|
||||||
QTextBlock bl = block();
|
QTextBlock bl = block();
|
||||||
Range range(bl.position(), bl.position());
|
Range range(bl.position(), bl.position());
|
||||||
indentText(range, '\n');
|
indentText(range, '\n');
|
||||||
@@ -8734,7 +8732,7 @@ void FakeVimHandler::Private::insertAutomaticIndentation(bool goingDown, bool fo
|
|||||||
|
|
||||||
void FakeVimHandler::Private::handleStartOfLine()
|
void FakeVimHandler::Private::handleStartOfLine()
|
||||||
{
|
{
|
||||||
if (s.startOfLine.value())
|
if (s.startOfLine())
|
||||||
moveToFirstNonBlankOnLine();
|
moveToFirstNonBlankOnLine();
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -9331,7 +9329,7 @@ void FakeVimHandler::Private::getRegisterType(int *reg, bool *isClipboard, bool
|
|||||||
*reg = c.toLower().unicode();
|
*reg = c.toLower().unicode();
|
||||||
|
|
||||||
if (c == '"') {
|
if (c == '"') {
|
||||||
QStringList list = s.clipboard.value().split(',');
|
QStringList list = s.clipboard().split(',');
|
||||||
clipboard = list.contains("unnamedplus");
|
clipboard = list.contains("unnamedplus");
|
||||||
selection = list.contains("unnamed");
|
selection = list.contains("unnamed");
|
||||||
} else if (c == '+') {
|
} else if (c == '+') {
|
||||||
@@ -9385,7 +9383,7 @@ void FakeVimHandler::updateGlobalMarksFilenames(const QString &oldFileName, cons
|
|||||||
bool FakeVimHandler::eventFilter(QObject *ob, QEvent *ev)
|
bool FakeVimHandler::eventFilter(QObject *ob, QEvent *ev)
|
||||||
{
|
{
|
||||||
#ifndef FAKEVIM_STANDALONE
|
#ifndef FAKEVIM_STANDALONE
|
||||||
if (!fakeVimSettings()->useFakeVim.value())
|
if (!settings().useFakeVim())
|
||||||
return QObject::eventFilter(ob, ev);
|
return QObject::eventFilter(ob, ev);
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
|||||||
@@ -340,134 +340,6 @@ private:
|
|||||||
using ExCommandMap = QMap<QString, QRegularExpression>;
|
using ExCommandMap = QMap<QString, QRegularExpression>;
|
||||||
using UserCommandMap = QMap<int, QString>;
|
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);
|
int cursorPos, int anchorPos, int messageLevel);
|
||||||
void handleExCommand(FakeVimHandler *handler, bool *handled, const ExCommand &cmd);
|
void handleExCommand(FakeVimHandler *handler, bool *handled, const ExCommand &cmd);
|
||||||
|
|
||||||
void writeSettings();
|
|
||||||
void readSettings();
|
void readSettings();
|
||||||
|
|
||||||
void handleDelayedQuitAll(bool forced);
|
void handleDelayedQuitAll(bool forced);
|
||||||
@@ -1107,7 +978,7 @@ IAssistProcessor *FakeVimCompletionAssistProvider::createProcessor(const AssistI
|
|||||||
class FakeVimPluginRunData
|
class FakeVimPluginRunData
|
||||||
{
|
{
|
||||||
public:
|
public:
|
||||||
FakeVimOptionPage optionsPage;
|
FakeVimSettings settings;
|
||||||
FakeVimExCommandsPage exCommandsPage;
|
FakeVimExCommandsPage exCommandsPage;
|
||||||
FakeVimUserCommandsPage userCommandsPage;
|
FakeVimUserCommandsPage userCommandsPage;
|
||||||
|
|
||||||
@@ -1179,7 +1050,7 @@ void FakeVimPluginPrivate::initialize()
|
|||||||
|
|
||||||
Command *cmd = nullptr;
|
Command *cmd = nullptr;
|
||||||
|
|
||||||
cmd = ActionManager::registerAction(fakeVimSettings()->useFakeVim.action(),
|
cmd = ActionManager::registerAction(settings().useFakeVim.action(),
|
||||||
INSTALL_HANDLER, Context(Core::Constants::C_GLOBAL), true);
|
INSTALL_HANDLER, Context(Core::Constants::C_GLOBAL), true);
|
||||||
cmd->setDefaultKeySequence(QKeySequence(useMacShortcuts ? Tr::tr("Meta+Shift+Y,Meta+Shift+Y")
|
cmd->setDefaultKeySequence(QKeySequence(useMacShortcuts ? Tr::tr("Meta+Shift+Y,Meta+Shift+Y")
|
||||||
: Tr::tr("Alt+Y,Alt+Y")));
|
: Tr::tr("Alt+Y,Alt+Y")));
|
||||||
@@ -1217,7 +1088,7 @@ void FakeVimPluginPrivate::initialize()
|
|||||||
connect(DocumentManager::instance(), &DocumentManager::documentRenamed,
|
connect(DocumentManager::instance(), &DocumentManager::documentRenamed,
|
||||||
this, &FakeVimPluginPrivate::documentRenamed);
|
this, &FakeVimPluginPrivate::documentRenamed);
|
||||||
|
|
||||||
FakeVimSettings &s = *fakeVimSettings();
|
FakeVimSettings &s = settings();
|
||||||
connect(&s.useFakeVim, &FvBoolAspect::valueChanged,
|
connect(&s.useFakeVim, &FvBoolAspect::valueChanged,
|
||||||
this, &FakeVimPluginPrivate::setUseFakeVim);
|
this, &FakeVimPluginPrivate::setUseFakeVim);
|
||||||
connect(&s.readVimRc, &FvBaseAspect::changed,
|
connect(&s.readVimRc, &FvBaseAspect::changed,
|
||||||
@@ -1235,7 +1106,7 @@ void FakeVimPluginPrivate::initialize()
|
|||||||
connect(this, &FakeVimPluginPrivate::delayedQuitAllRequested,
|
connect(this, &FakeVimPluginPrivate::delayedQuitAllRequested,
|
||||||
this, &FakeVimPluginPrivate::handleDelayedQuitAll, Qt::QueuedConnection);
|
this, &FakeVimPluginPrivate::handleDelayedQuitAll, Qt::QueuedConnection);
|
||||||
|
|
||||||
setCursorBlinking(s.blinkingCursor.value());
|
setCursorBlinking(s.blinkingCursor());
|
||||||
}
|
}
|
||||||
|
|
||||||
void FakeVimPluginPrivate::userActionTriggered(int key)
|
void FakeVimPluginPrivate::userActionTriggered(int key)
|
||||||
@@ -1244,7 +1115,7 @@ void FakeVimPluginPrivate::userActionTriggered(int key)
|
|||||||
FakeVimHandler *handler = m_editorToHandler[editor].handler;
|
FakeVimHandler *handler = m_editorToHandler[editor].handler;
|
||||||
if (handler) {
|
if (handler) {
|
||||||
// If disabled, enable FakeVim mode just for single user command.
|
// If disabled, enable FakeVim mode just for single user command.
|
||||||
bool enableFakeVim = !fakeVimSettings()->useFakeVim.value();
|
bool enableFakeVim = !settings().useFakeVim();
|
||||||
if (enableFakeVim)
|
if (enableFakeVim)
|
||||||
setUseFakeVimInternal(true);
|
setUseFakeVimInternal(true);
|
||||||
|
|
||||||
@@ -1270,26 +1141,18 @@ void FakeVimPluginPrivate::createRelativeNumberWidget(IEditor *editor)
|
|||||||
{
|
{
|
||||||
if (auto textEditor = TextEditorWidget::fromEditor(editor)) {
|
if (auto textEditor = TextEditorWidget::fromEditor(editor)) {
|
||||||
auto relativeNumbers = new RelativeNumbersColumn(textEditor);
|
auto relativeNumbers = new RelativeNumbersColumn(textEditor);
|
||||||
connect(&fakeVimSettings()->relativeNumber, &FvBaseAspect::changed,
|
connect(&settings().relativeNumber, &FvBaseAspect::changed,
|
||||||
relativeNumbers, &QObject::deleteLater);
|
relativeNumbers, &QObject::deleteLater);
|
||||||
connect(&fakeVimSettings()->useFakeVim, &FvBaseAspect::changed,
|
connect(&settings().useFakeVim, &FvBaseAspect::changed,
|
||||||
relativeNumbers, &QObject::deleteLater);
|
relativeNumbers, &QObject::deleteLater);
|
||||||
relativeNumbers->show();
|
relativeNumbers->show();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void FakeVimPluginPrivate::writeSettings()
|
|
||||||
{
|
|
||||||
QSettings *settings = ICore::settings();
|
|
||||||
fakeVimSettings()->writeSettings(settings);
|
|
||||||
}
|
|
||||||
|
|
||||||
void FakeVimPluginPrivate::readSettings()
|
void FakeVimPluginPrivate::readSettings()
|
||||||
{
|
{
|
||||||
QSettings *settings = ICore::settings();
|
QSettings *settings = ICore::settings();
|
||||||
|
|
||||||
fakeVimSettings()->readSettings(settings);
|
|
||||||
|
|
||||||
m_exCommandMap = m_defaultExCommandMap;
|
m_exCommandMap = m_defaultExCommandMap;
|
||||||
int size = settings->beginReadArray(exCommandMapGroup);
|
int size = settings->beginReadArray(exCommandMapGroup);
|
||||||
for (int i = 0; i < size; ++i) {
|
for (int i = 0; i < size; ++i) {
|
||||||
@@ -1318,9 +1181,9 @@ void FakeVimPluginPrivate::maybeReadVimRc()
|
|||||||
//qDebug() << theFakeVimSetting(ConfigReadVimRc)
|
//qDebug() << theFakeVimSetting(ConfigReadVimRc)
|
||||||
// << theFakeVimSetting(ConfigReadVimRc)->value();
|
// << theFakeVimSetting(ConfigReadVimRc)->value();
|
||||||
//qDebug() << theFakeVimSetting(ConfigShiftWidth)->value();
|
//qDebug() << theFakeVimSetting(ConfigShiftWidth)->value();
|
||||||
if (!fakeVimSettings()->readVimRc.value())
|
if (!settings().readVimRc())
|
||||||
return;
|
return;
|
||||||
QString fileName = fakeVimSettings()->vimRcPath.value();
|
QString fileName = settings().vimRcPath();
|
||||||
if (fileName.isEmpty()) {
|
if (fileName.isEmpty()) {
|
||||||
fileName = QStandardPaths::writableLocation(QStandardPaths::HomeLocation)
|
fileName = QStandardPaths::writableLocation(QStandardPaths::HomeLocation)
|
||||||
+ QLatin1String(HostOsInfo::isWindowsHost() ? "/_vimrc" : "/.vimrc");
|
+ QLatin1String(HostOsInfo::isWindowsHost() ? "/_vimrc" : "/.vimrc");
|
||||||
@@ -1330,7 +1193,6 @@ void FakeVimPluginPrivate::maybeReadVimRc()
|
|||||||
QPlainTextEdit editor;
|
QPlainTextEdit editor;
|
||||||
FakeVimHandler handler(&editor);
|
FakeVimHandler handler(&editor);
|
||||||
handler.handleCommand("source " + fileName);
|
handler.handleCommand("source " + fileName);
|
||||||
//writeSettings();
|
|
||||||
//qDebug() << theFakeVimSetting(ConfigShiftWidth)->value();
|
//qDebug() << theFakeVimSetting(ConfigShiftWidth)->value();
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -1659,9 +1521,9 @@ void FakeVimPluginPrivate::editorOpened(IEditor *editor)
|
|||||||
return;
|
return;
|
||||||
|
|
||||||
TabSettings tabSettings;
|
TabSettings tabSettings;
|
||||||
tabSettings.m_indentSize = fakeVimSettings()->shiftWidth();
|
tabSettings.m_indentSize = settings().shiftWidth();
|
||||||
tabSettings.m_tabSize = fakeVimSettings()->tabStop();
|
tabSettings.m_tabSize = settings().tabStop();
|
||||||
tabSettings.m_tabPolicy = fakeVimSettings()->expandTab()
|
tabSettings.m_tabPolicy = settings().expandTab()
|
||||||
? TabSettings::SpacesOnlyTabPolicy : TabSettings::TabsOnlyTabPolicy;
|
? TabSettings::SpacesOnlyTabPolicy : TabSettings::TabsOnlyTabPolicy;
|
||||||
tabSettings.m_continuationAlignBehavior =
|
tabSettings.m_continuationAlignBehavior =
|
||||||
tew->textDocument()->tabSettings().m_continuationAlignBehavior;
|
tew->textDocument()->tabSettings().m_continuationAlignBehavior;
|
||||||
@@ -1885,19 +1747,15 @@ void FakeVimPluginPrivate::editorOpened(IEditor *editor)
|
|||||||
*output = proc.cleanedStdOut();
|
*output = proc.cleanedStdOut();
|
||||||
});
|
});
|
||||||
|
|
||||||
connect(ICore::instance(), &ICore::saveSettingsRequested,
|
|
||||||
this, &FakeVimPluginPrivate::writeSettings);
|
|
||||||
|
|
||||||
|
|
||||||
handler->setCurrentFileName(editor->document()->filePath().toString());
|
handler->setCurrentFileName(editor->document()->filePath().toString());
|
||||||
handler->installEventFilter();
|
handler->installEventFilter();
|
||||||
|
|
||||||
// pop up the bar
|
// pop up the bar
|
||||||
if (fakeVimSettings()->useFakeVim.value()) {
|
if (settings().useFakeVim()) {
|
||||||
resetCommandBuffer();
|
resetCommandBuffer();
|
||||||
handler->setupWidget();
|
handler->setupWidget();
|
||||||
|
|
||||||
if (fakeVimSettings()->relativeNumber.value())
|
if (settings().relativeNumber())
|
||||||
createRelativeNumberWidget(editor);
|
createRelativeNumberWidget(editor);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -1939,8 +1797,8 @@ void FakeVimPluginPrivate::setUseFakeVim(bool on)
|
|||||||
//qDebug() << "SET USE FAKEVIM" << on;
|
//qDebug() << "SET USE FAKEVIM" << on;
|
||||||
Find::setUseFakeVim(on);
|
Find::setUseFakeVim(on);
|
||||||
setUseFakeVimInternal(on);
|
setUseFakeVimInternal(on);
|
||||||
setShowRelativeLineNumbers(fakeVimSettings()->relativeNumber.value());
|
setShowRelativeLineNumbers(settings().relativeNumber());
|
||||||
setCursorBlinking(fakeVimSettings()->blinkingCursor.value());
|
setCursorBlinking(settings().blinkingCursor());
|
||||||
}
|
}
|
||||||
|
|
||||||
void FakeVimPluginPrivate::setUseFakeVimInternal(bool on)
|
void FakeVimPluginPrivate::setUseFakeVimInternal(bool on)
|
||||||
@@ -1968,7 +1826,7 @@ void FakeVimPluginPrivate::setUseFakeVimInternal(bool on)
|
|||||||
|
|
||||||
void FakeVimPluginPrivate::setShowRelativeLineNumbers(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)
|
for (auto it = m_editorToHandler.constBegin(); it != m_editorToHandler.constEnd(); ++it)
|
||||||
createRelativeNumberWidget(it.key());
|
createRelativeNumberWidget(it.key());
|
||||||
}
|
}
|
||||||
@@ -1979,7 +1837,7 @@ void FakeVimPluginPrivate::setCursorBlinking(bool on)
|
|||||||
if (m_savedCursorFlashTime == 0)
|
if (m_savedCursorFlashTime == 0)
|
||||||
m_savedCursorFlashTime = QGuiApplication::styleHints()->cursorFlashTime();
|
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);
|
QGuiApplication::styleHints()->setCursorFlashTime(blink ? m_savedCursorFlashTime : 0);
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -2123,7 +1981,7 @@ void FakeVimPluginPrivate::handleDelayedQuitAll(bool forced)
|
|||||||
|
|
||||||
void FakeVimPluginPrivate::quitFakeVim()
|
void FakeVimPluginPrivate::quitFakeVim()
|
||||||
{
|
{
|
||||||
fakeVimSettings()->useFakeVim.setValue(false);
|
settings().useFakeVim.setValue(false);
|
||||||
}
|
}
|
||||||
|
|
||||||
void FakeVimPluginPrivate::resetCommandBuffer()
|
void FakeVimPluginPrivate::resetCommandBuffer()
|
||||||
|
|||||||
@@ -93,8 +93,8 @@ FossilCommitWidget::FossilCommitWidget() : m_commitPanel(new QWidget)
|
|||||||
m_invalidBranchLabel->setType(InfoLabel::Error);
|
m_invalidBranchLabel->setType(InfoLabel::Error);
|
||||||
|
|
||||||
m_isPrivateCheckBox = new QCheckBox(Tr::tr("Private"));
|
m_isPrivateCheckBox = new QCheckBox(Tr::tr("Private"));
|
||||||
m_isPrivateCheckBox->setToolTip(Tr::tr("Create a private check-in that is never synced.\n"
|
m_isPrivateCheckBox->setToolTip("<html>" + Tr::tr("Create a private check-in that is never synced. "
|
||||||
"Children of private check-ins are automatically private.\n"
|
"Children of private check-ins are automatically private. "
|
||||||
"Private check-ins are not pushed to the remote repository by default."));
|
"Private check-ins are not pushed to the remote repository by default."));
|
||||||
|
|
||||||
m_tagsLineEdit = new QLineEdit;
|
m_tagsLineEdit = new QLineEdit;
|
||||||
|
|||||||
@@ -88,9 +88,9 @@ FossilSettings::FossilSettings()
|
|||||||
logCount.setToolTip(Tr::tr("The number of recent commit log entries to show. "
|
logCount.setToolTip(Tr::tr("The number of recent commit log entries to show. "
|
||||||
"Choose 0 to see all entries."));
|
"Choose 0 to see all entries."));
|
||||||
|
|
||||||
setLayouter([this](QWidget *widget) {
|
setLayouter([this] {
|
||||||
using namespace Layouting;
|
using namespace Layouting;
|
||||||
Column {
|
return Column {
|
||||||
Group {
|
Group {
|
||||||
title(Tr::tr("Configuration")),
|
title(Tr::tr("Configuration")),
|
||||||
Row { binaryPath }
|
Row { binaryPath }
|
||||||
@@ -117,7 +117,7 @@ FossilSettings::FossilSettings()
|
|||||||
},
|
},
|
||||||
},
|
},
|
||||||
st
|
st
|
||||||
}.attachTo(widget);
|
};
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -34,7 +34,7 @@ PullOrPushDialog::PullOrPushDialog(Mode mode, QWidget *parent)
|
|||||||
m_localPathChooser->setPromptDialogFilter(Tr::tr(Constants::FOSSIL_FILE_FILTER));
|
m_localPathChooser->setPromptDialogFilter(Tr::tr(Constants::FOSSIL_FILE_FILTER));
|
||||||
|
|
||||||
m_urlButton = new QRadioButton(Tr::tr("Specify URL:"));
|
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 = new QLineEdit;
|
||||||
m_urlLineEdit->setEnabled(false);
|
m_urlLineEdit->setEnabled(false);
|
||||||
|
|||||||
@@ -86,7 +86,7 @@
|
|||||||
{
|
{
|
||||||
"name": "Repo",
|
"name": "Repo",
|
||||||
"trDisplayName": "Remote repository:",
|
"trDisplayName": "Remote repository:",
|
||||||
"trToolTip": "For example: https://[user[:pass]@]host[:port]/[path]",
|
"trToolTip": "For example: \"https://[user[:pass]@]host[:port]/[path]\".",
|
||||||
"type": "LineEdit",
|
"type": "LineEdit",
|
||||||
"enabled": "%{isCloneRepo}",
|
"enabled": "%{isCloneRepo}",
|
||||||
"mandatory": false
|
"mandatory": false
|
||||||
|
|||||||
@@ -43,8 +43,8 @@ public:
|
|||||||
curlChooser->setCommandVersionArguments({"-V"});
|
curlChooser->setCommandVersionArguments({"-V"});
|
||||||
|
|
||||||
auto portSpinBox = new QSpinBox(this);
|
auto portSpinBox = new QSpinBox(this);
|
||||||
portSpinBox->setValue(p->server.port);
|
|
||||||
portSpinBox->setRange(1, 65535);
|
portSpinBox->setRange(1, 65535);
|
||||||
|
portSpinBox->setValue(p->server.port);
|
||||||
|
|
||||||
auto httpsCheckBox = new QCheckBox(Git::Tr::tr("HTTPS"));
|
auto httpsCheckBox = new QCheckBox(Git::Tr::tr("HTTPS"));
|
||||||
httpsCheckBox->setChecked(p->https);
|
httpsCheckBox->setChecked(p->https);
|
||||||
|
|||||||
@@ -441,7 +441,7 @@ ShowController::ShowController(IDocument *document, const QString &id)
|
|||||||
};
|
};
|
||||||
|
|
||||||
using namespace std::placeholders;
|
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) {
|
for (int i = 0, total = parents.size(); i < total; ++i) {
|
||||||
tasks.append(ProcessTask(std::bind(setupFollow, _1, parents.at(i)),
|
tasks.append(ProcessTask(std::bind(setupFollow, _1, parents.at(i)),
|
||||||
std::bind(onFollowDone, _1, i)));
|
std::bind(onFollowDone, _1, i)));
|
||||||
@@ -465,11 +465,11 @@ ShowController::ShowController(IDocument *document, const QString &id)
|
|||||||
parallel,
|
parallel,
|
||||||
onGroupSetup([this] { setStartupFile(VcsBase::source(this->document()).toString()); }),
|
onGroupSetup([this] { setStartupFile(VcsBase::source(this->document()).toString()); }),
|
||||||
Group {
|
Group {
|
||||||
optional,
|
finishAllAndDone,
|
||||||
ProcessTask(setupDescription, onDescriptionDone),
|
ProcessTask(setupDescription, onDescriptionDone),
|
||||||
Group {
|
Group {
|
||||||
parallel,
|
parallel,
|
||||||
optional,
|
finishAllAndDone,
|
||||||
onGroupSetup(desciptionDetailsSetup),
|
onGroupSetup(desciptionDetailsSetup),
|
||||||
ProcessTask(setupBranches, onBranchesDone, onBranchesError),
|
ProcessTask(setupBranches, onBranchesDone, onBranchesError),
|
||||||
ProcessTask(setupPrecedes, onPrecedesDone, onPrecedesError),
|
ProcessTask(setupPrecedes, onPrecedesDone, onPrecedesError),
|
||||||
@@ -2873,7 +2873,7 @@ bool GitClient::addAndCommit(const FilePath &repositoryDirectory,
|
|||||||
GitPlugin::updateCurrentBranch();
|
GitPlugin::updateCurrentBranch();
|
||||||
return true;
|
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;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -21,13 +21,12 @@
|
|||||||
#include <utils/qtcassert.h>
|
#include <utils/qtcassert.h>
|
||||||
|
|
||||||
#include <QCheckBox>
|
#include <QCheckBox>
|
||||||
#include <QFuture>
|
|
||||||
#include <QHBoxLayout>
|
#include <QHBoxLayout>
|
||||||
#include <QRegularExpressionValidator>
|
#include <QRegularExpressionValidator>
|
||||||
#include <QSettings>
|
#include <QSettings>
|
||||||
#include <QTextStream>
|
|
||||||
|
|
||||||
using namespace Core;
|
using namespace Core;
|
||||||
|
using namespace TextEditor;
|
||||||
using namespace Utils;
|
using namespace Utils;
|
||||||
using namespace VcsBase;
|
using namespace VcsBase;
|
||||||
|
|
||||||
@@ -43,91 +42,106 @@ public:
|
|||||||
QString id() const { return recurseSubmodules ? ref + ".Rec" : ref; }
|
QString id() const { return recurseSubmodules ? ref + ".Rec" : ref; }
|
||||||
};
|
};
|
||||||
|
|
||||||
class GitGrepRunner
|
static QStringView nextLine(QStringView *remainingInput)
|
||||||
{
|
{
|
||||||
using PromiseType = QPromise<SearchResultItems>;
|
const int newLinePos = remainingInput->indexOf('\n');
|
||||||
|
if (newLinePos < 0) {
|
||||||
public:
|
QStringView ret = *remainingInput;
|
||||||
GitGrepRunner(const TextEditor::FileFindParameters ¶meters)
|
*remainingInput = QStringView();
|
||||||
: m_parameters(parameters)
|
return ret;
|
||||||
{
|
|
||||||
m_directory = FilePath::fromString(parameters.additionalParameters.toString());
|
|
||||||
m_vcsBinary = GitClient::instance()->vcsBinary();
|
|
||||||
m_environment = GitClient::instance()->processEnvironment();
|
|
||||||
}
|
}
|
||||||
|
QStringView ret = remainingInput->left(newLinePos);
|
||||||
|
*remainingInput = remainingInput->mid(newLinePos + 1);
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
|
||||||
struct Match
|
struct Match
|
||||||
{
|
{
|
||||||
Match() = default;
|
Match() = default;
|
||||||
Match(int start, int length) :
|
Match(int start, int length) :
|
||||||
matchStart(start), matchLength(length) {}
|
matchStart(start), matchLength(length) {}
|
||||||
|
|
||||||
int matchStart = 0;
|
int matchStart = 0;
|
||||||
int matchLength = 0;
|
int matchLength = 0;
|
||||||
QStringList regexpCapturedTexts;
|
QStringList regexpCapturedTexts;
|
||||||
};
|
};
|
||||||
|
|
||||||
void processLine(const QString &line, SearchResultItems *resultList) const
|
static void processLine(QStringView line, SearchResultItems *resultList,
|
||||||
{
|
const std::optional<QRegularExpression> ®Exp, 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> ®Exp, 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())
|
if (line.isEmpty())
|
||||||
return;
|
continue;
|
||||||
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);
|
|
||||||
|
|
||||||
for (const auto &match : std::as_const(matches)) {
|
processLine(line, &items, regExp, ref, directory);
|
||||||
result.setMainRange(lineNumber, match.matchStart, match.matchLength);
|
|
||||||
result.setUserData(match.regexpCapturedTexts);
|
|
||||||
resultList->append(result);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
return items;
|
||||||
|
}
|
||||||
|
|
||||||
void read(PromiseType &fi, const QString &text)
|
static void runGitGrep(QPromise<SearchResultItems> &promise, const FileFindParameters ¶meters)
|
||||||
{
|
{
|
||||||
SearchResultItems resultList;
|
const FilePath directory = FilePath::fromString(parameters.additionalParameters.toString());
|
||||||
QString t = text;
|
const GitGrepParameters gitParameters
|
||||||
QTextStream stream(&t);
|
= parameters.searchEngineParameters.value<GitGrepParameters>();
|
||||||
while (!stream.atEnd() && !fi.isCanceled())
|
const QString ref = gitParameters.ref.isEmpty() ? QString() : gitParameters.ref + ':';
|
||||||
processLine(stream.readLine(), &resultList);
|
|
||||||
if (!resultList.isEmpty() && !fi.isCanceled())
|
const auto setupProcess = [&](Process &process) {
|
||||||
fi.addResult(resultList);
|
const FilePath vcsBinary = GitClient::instance()->vcsBinary();
|
||||||
}
|
const Environment environment = GitClient::instance()->processEnvironment();
|
||||||
|
|
||||||
void operator()(PromiseType &promise)
|
|
||||||
{
|
|
||||||
QStringList arguments = {
|
QStringList arguments = {
|
||||||
"-c", "color.grep.match=bold red",
|
"-c", "color.grep.match=bold red",
|
||||||
"-c", "color.grep=always",
|
"-c", "color.grep=always",
|
||||||
@@ -135,60 +149,41 @@ public:
|
|||||||
"-c", "color.grep.lineNumber=",
|
"-c", "color.grep.lineNumber=",
|
||||||
"grep", "-zn", "--no-full-name"
|
"grep", "-zn", "--no-full-name"
|
||||||
};
|
};
|
||||||
if (!(m_parameters.flags & FindCaseSensitively))
|
if (!(parameters.flags & FindCaseSensitively))
|
||||||
arguments << "-i";
|
arguments << "-i";
|
||||||
if (m_parameters.flags & FindWholeWords)
|
if (parameters.flags & FindWholeWords)
|
||||||
arguments << "-w";
|
arguments << "-w";
|
||||||
if (m_parameters.flags & FindRegularExpression)
|
if (parameters.flags & FindRegularExpression)
|
||||||
arguments << "-P";
|
arguments << "-P";
|
||||||
else
|
else
|
||||||
arguments << "-F";
|
arguments << "-F";
|
||||||
arguments << "-e" << m_parameters.text;
|
arguments << "-e" << parameters.text;
|
||||||
GitGrepParameters params = m_parameters.searchEngineParameters.value<GitGrepParameters>();
|
if (gitParameters.recurseSubmodules)
|
||||||
if (params.recurseSubmodules)
|
|
||||||
arguments << "--recurse-submodules";
|
arguments << "--recurse-submodules";
|
||||||
if (!params.ref.isEmpty()) {
|
if (!gitParameters.ref.isEmpty()) {
|
||||||
arguments << params.ref;
|
arguments << gitParameters.ref;
|
||||||
m_ref = params.ref + ':';
|
|
||||||
}
|
}
|
||||||
const QStringList filterArgs =
|
const QStringList filterArgs =
|
||||||
m_parameters.nameFilters.isEmpty() ? QStringList("*") // needed for exclusion filters
|
parameters.nameFilters.isEmpty() ? QStringList("*") // needed for exclusion filters
|
||||||
: m_parameters.nameFilters;
|
: parameters.nameFilters;
|
||||||
const QStringList exclusionArgs =
|
const QStringList exclusionArgs =
|
||||||
Utils::transform(m_parameters.exclusionFilters, [](const QString &filter) {
|
Utils::transform(parameters.exclusionFilters, [](const QString &filter) {
|
||||||
return QString(":!" + filter);
|
return QString(":!" + filter);
|
||||||
});
|
});
|
||||||
arguments << "--" << filterArgs << exclusionArgs;
|
arguments << "--" << filterArgs << exclusionArgs;
|
||||||
|
|
||||||
Process process;
|
process.setEnvironment(environment);
|
||||||
process.setEnvironment(m_environment);
|
process.setCommand({vcsBinary, arguments});
|
||||||
process.setCommand({m_vcsBinary, arguments});
|
process.setWorkingDirectory(directory);
|
||||||
process.setWorkingDirectory(m_directory);
|
};
|
||||||
process.setStdOutCallback([this, &promise](const QString &text) { read(promise, text); });
|
|
||||||
process.start();
|
|
||||||
process.waitForFinished();
|
|
||||||
|
|
||||||
switch (process.result()) {
|
const auto outputParser = [&ref, &directory](const QFuture<void> &future, const QString &input,
|
||||||
case ProcessResult::TerminatedAbnormally:
|
const std::optional<QRegularExpression> ®Exp) {
|
||||||
case ProcessResult::StartFailed:
|
return parse(future, input, regExp, ref, directory);
|
||||||
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;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
private:
|
TextEditor::searchInProcessOutput(promise, parameters, setupProcess, outputParser);
|
||||||
FilePath m_vcsBinary;
|
}
|
||||||
FilePath m_directory;
|
|
||||||
QString m_ref;
|
|
||||||
TextEditor::FileFindParameters m_parameters;
|
|
||||||
Environment m_environment;
|
|
||||||
};
|
|
||||||
|
|
||||||
static bool isGitDirectory(const FilePath &path)
|
static bool isGitDirectory(const FilePath &path)
|
||||||
{
|
{
|
||||||
@@ -211,18 +206,16 @@ GitGrep::GitGrep(GitClient *client)
|
|||||||
m_treeLineEdit->setValidator(new QRegularExpressionValidator(refExpression, this));
|
m_treeLineEdit->setValidator(new QRegularExpressionValidator(refExpression, this));
|
||||||
layout->addWidget(m_treeLineEdit);
|
layout->addWidget(m_treeLineEdit);
|
||||||
// asynchronously check git version, add "recurse submodules" option if available
|
// asynchronously check git version, add "recurse submodules" option if available
|
||||||
Utils::onResultReady(client->gitVersion(),
|
Utils::onResultReady(client->gitVersion(), this,
|
||||||
this,
|
|
||||||
[this, pLayout = QPointer<QHBoxLayout>(layout)](unsigned version) {
|
[this, pLayout = QPointer<QHBoxLayout>(layout)](unsigned version) {
|
||||||
if (version >= 0x021300 && pLayout) {
|
if (version >= 0x021300 && pLayout) {
|
||||||
m_recurseSubmodules = new QCheckBox(Tr::tr("Recurse submodules"));
|
m_recurseSubmodules = new QCheckBox(Tr::tr("Recurse submodules"));
|
||||||
pLayout->addWidget(m_recurseSubmodules);
|
pLayout->addWidget(m_recurseSubmodules);
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
TextEditor::FindInFiles *findInFiles = TextEditor::FindInFiles::instance();
|
FindInFiles *findInFiles = FindInFiles::instance();
|
||||||
QTC_ASSERT(findInFiles, return);
|
QTC_ASSERT(findInFiles, return);
|
||||||
connect(findInFiles, &TextEditor::FindInFiles::pathChanged,
|
connect(findInFiles, &FindInFiles::pathChanged, m_widget, [this](const FilePath &path) {
|
||||||
m_widget, [this](const FilePath &path) {
|
|
||||||
setEnabled(isGitDirectory(path));
|
setEnabled(isGitDirectory(path));
|
||||||
});
|
});
|
||||||
connect(this, &SearchEngine::enabledChanged, m_widget, &QWidget::setEnabled);
|
connect(this, &SearchEngine::enabledChanged, m_widget, &QWidget::setEnabled);
|
||||||
@@ -271,14 +264,14 @@ void GitGrep::writeSettings(QSettings *settings) const
|
|||||||
settings->setValue(GitGrepRef, m_treeLineEdit->text());
|
settings->setValue(GitGrepRef, m_treeLineEdit->text());
|
||||||
}
|
}
|
||||||
|
|
||||||
QFuture<SearchResultItems> GitGrep::executeSearch(const TextEditor::FileFindParameters ¶meters,
|
QFuture<SearchResultItems> GitGrep::executeSearch(const FileFindParameters ¶meters,
|
||||||
TextEditor::BaseFileFind * /*baseFileFind*/)
|
BaseFileFind *)
|
||||||
{
|
{
|
||||||
return Utils::asyncRun(GitGrepRunner(parameters));
|
return Utils::asyncRun(runGitGrep, parameters);
|
||||||
}
|
}
|
||||||
|
|
||||||
IEditor *GitGrep::openEditor(const SearchResultItem &item,
|
IEditor *GitGrep::openEditor(const SearchResultItem &item,
|
||||||
const TextEditor::FileFindParameters ¶meters)
|
const FileFindParameters ¶meters)
|
||||||
{
|
{
|
||||||
const GitGrepParameters params = parameters.searchEngineParameters.value<GitGrepParameters>();
|
const GitGrepParameters params = parameters.searchEngineParameters.value<GitGrepParameters>();
|
||||||
const QStringList &itemPath = item.path();
|
const QStringList &itemPath = item.path();
|
||||||
|
|||||||
@@ -9,10 +9,7 @@ QT_BEGIN_NAMESPACE
|
|||||||
class QCheckBox;
|
class QCheckBox;
|
||||||
QT_END_NAMESPACE
|
QT_END_NAMESPACE
|
||||||
|
|
||||||
namespace Utils {
|
namespace Utils { class FancyLineEdit; }
|
||||||
class FancyLineEdit;
|
|
||||||
class SearchResultItem;
|
|
||||||
}
|
|
||||||
|
|
||||||
namespace Git::Internal {
|
namespace Git::Internal {
|
||||||
|
|
||||||
|
|||||||
@@ -90,8 +90,8 @@ GitSettings::GitSettings()
|
|||||||
instantBlame.setSettingsKey("Git Instant");
|
instantBlame.setSettingsKey("Git Instant");
|
||||||
instantBlame.setDefaultValue(true);
|
instantBlame.setDefaultValue(true);
|
||||||
instantBlame.setLabelText(Tr::tr("Add instant blame annotations to editor"));
|
instantBlame.setLabelText(Tr::tr("Add instant blame annotations to editor"));
|
||||||
instantBlame.setToolTip(Tr::tr("Directly annotate each line in the editor "
|
instantBlame.setToolTip(
|
||||||
"when scrolling through the document."));
|
Tr::tr("Annotate the current line in the editor with Git \"blame\" output."));
|
||||||
|
|
||||||
graphLog.setSettingsKey("GraphLog");
|
graphLog.setSettingsKey("GraphLog");
|
||||||
|
|
||||||
|
|||||||
@@ -356,6 +356,7 @@ void Client::setName(const QString &name)
|
|||||||
QString Client::name() const
|
QString Client::name() const
|
||||||
{
|
{
|
||||||
if (d->m_project && !d->m_project->displayName().isEmpty())
|
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 Tr::tr("%1 for %2").arg(d->m_displayName, d->m_project->displayName());
|
||||||
return d->m_displayName;
|
return d->m_displayName;
|
||||||
}
|
}
|
||||||
@@ -555,11 +556,17 @@ Client::State Client::state() const
|
|||||||
QString Client::stateString() const
|
QString Client::stateString() const
|
||||||
{
|
{
|
||||||
switch (d->m_state){
|
switch (d->m_state){
|
||||||
|
//: language client state
|
||||||
case Uninitialized: return Tr::tr("uninitialized");
|
case Uninitialized: return Tr::tr("uninitialized");
|
||||||
|
//: language client state
|
||||||
case InitializeRequested: return Tr::tr("initialize requested");
|
case InitializeRequested: return Tr::tr("initialize requested");
|
||||||
|
//: language client state
|
||||||
case Initialized: return Tr::tr("initialized");
|
case Initialized: return Tr::tr("initialized");
|
||||||
|
//: language client state
|
||||||
case ShutdownRequested: return Tr::tr("shutdown requested");
|
case ShutdownRequested: return Tr::tr("shutdown requested");
|
||||||
|
//: language client state
|
||||||
case Shutdown: return Tr::tr("shut down");
|
case Shutdown: return Tr::tr("shut down");
|
||||||
|
//: language client state
|
||||||
case Error: return Tr::tr("error");
|
case Error: return Tr::tr("error");
|
||||||
}
|
}
|
||||||
return {};
|
return {};
|
||||||
@@ -1970,7 +1977,7 @@ void ClientPrivate::initializeCallback(const InitializeRequest::Response &initRe
|
|||||||
if (std::optional<ResponseError<InitializeError>> error = initResponse.error()) {
|
if (std::optional<ResponseError<InitializeError>> error = initResponse.error()) {
|
||||||
if (std::optional<InitializeError> data = error->data()) {
|
if (std::optional<InitializeError> data = error->data()) {
|
||||||
if (data->retry()) {
|
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(),
|
auto result = QMessageBox::warning(Core::ICore::dialogParent(),
|
||||||
title,
|
title,
|
||||||
error->message(),
|
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();
|
emit q->finished();
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -8,6 +8,7 @@
|
|||||||
#include <languageserverprotocol/progresssupport.h>
|
#include <languageserverprotocol/progresssupport.h>
|
||||||
|
|
||||||
#include <QTime>
|
#include <QTime>
|
||||||
|
#include <QTimer>
|
||||||
|
|
||||||
using namespace LanguageServerProtocol;
|
using namespace LanguageServerProtocol;
|
||||||
|
|
||||||
@@ -81,9 +82,28 @@ void ProgressManager::beginProgress(const ProgressToken &token, const WorkDonePr
|
|||||||
auto interface = new QFutureInterface<void>();
|
auto interface = new QFutureInterface<void>();
|
||||||
interface->reportStarted();
|
interface->reportStarted();
|
||||||
interface->setProgressRange(0, 100); // LSP always reports percentage of the task
|
interface->setProgressRange(0, 100); // LSP always reports percentage of the task
|
||||||
const QString title = m_titles.value(token, begin.title());
|
ProgressItem progressItem;
|
||||||
Core::FutureProgress *progress = Core::ProgressManager::addTask(
|
progressItem.futureInterface = interface;
|
||||||
interface->future(), title, languageClientProgressId(token));
|
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);
|
const std::function<void()> clickHandler = m_clickHandlers.value(token);
|
||||||
if (clickHandler)
|
if (clickHandler)
|
||||||
QObject::connect(progress, &Core::FutureProgress::clicked, 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);
|
QObject::connect(progress, &Core::FutureProgress::canceled, cancelHandler);
|
||||||
else
|
else
|
||||||
progress->setCancelEnabled(false);
|
progress->setCancelEnabled(false);
|
||||||
m_progress[token] = {progress, interface};
|
if (!progressItem.message.isEmpty()) {
|
||||||
if (LOGPROGRESS().isDebugEnabled())
|
progress->setSubtitle(progressItem.message);
|
||||||
m_timer[token].start();
|
progress->setSubtitleVisibleInStatusBar(true);
|
||||||
reportProgress(token, begin);
|
}
|
||||||
|
progressItem.progressInterface = progress;
|
||||||
}
|
}
|
||||||
|
|
||||||
void ProgressManager::reportProgress(const ProgressToken &token,
|
void ProgressManager::reportProgress(const ProgressToken &token,
|
||||||
const WorkDoneProgressReport &report)
|
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) {
|
if (progress.progressInterface) {
|
||||||
const std::optional<QString> &message = report.message();
|
|
||||||
if (message.has_value()) {
|
if (message.has_value()) {
|
||||||
progress.progressInterface->setSubtitle(*message);
|
progress.progressInterface->setSubtitle(*message);
|
||||||
const bool showSubtitle = !message->isEmpty();
|
const bool showSubtitle = !message->isEmpty();
|
||||||
progress.progressInterface->setSubtitleVisibleInStatusBar(showSubtitle);
|
progress.progressInterface->setSubtitleVisibleInStatusBar(showSubtitle);
|
||||||
}
|
}
|
||||||
|
} else if (message.has_value()) {
|
||||||
|
progress.message = *message;
|
||||||
}
|
}
|
||||||
if (progress.futureInterface) {
|
if (progress.futureInterface) {
|
||||||
if (const std::optional<double> &percentage = report.percentage(); percentage.has_value())
|
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)
|
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());
|
const QString &message = end.message().value_or(QString());
|
||||||
if (progress.progressInterface) {
|
if (progress.progressInterface) {
|
||||||
if (!message.isEmpty()) {
|
if (!message.isEmpty()) {
|
||||||
@@ -127,11 +150,11 @@ void ProgressManager::endProgress(const ProgressToken &token, const WorkDoneProg
|
|||||||
}
|
}
|
||||||
progress.progressInterface->setSubtitle(message);
|
progress.progressInterface->setSubtitle(message);
|
||||||
progress.progressInterface->setSubtitleVisibleInStatusBar(!message.isEmpty());
|
progress.progressInterface->setSubtitleVisibleInStatusBar(!message.isEmpty());
|
||||||
auto timer = m_timer.take(token);
|
if (progress.timer.isValid()) {
|
||||||
if (timer.isValid()) {
|
|
||||||
qCDebug(LOGPROGRESS) << QString("%1 took %2")
|
qCDebug(LOGPROGRESS) << QString("%1 took %2")
|
||||||
.arg(progress.progressInterface->title())
|
.arg(progress.progressInterface->title())
|
||||||
.arg(QTime::fromMSecsSinceStartOfDay(timer.elapsed())
|
.arg(QTime::fromMSecsSinceStartOfDay(
|
||||||
|
progress.timer.elapsed())
|
||||||
.toString(Qt::ISODateWithMs));
|
.toString(Qt::ISODateWithMs));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -140,7 +163,8 @@ void ProgressManager::endProgress(const ProgressToken &token, const WorkDoneProg
|
|||||||
|
|
||||||
void ProgressManager::endProgressReport(const ProgressToken &token)
|
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)
|
if (progress.futureInterface)
|
||||||
progress.futureInterface->reportFinished();
|
progress.futureInterface->reportFinished();
|
||||||
delete progress.futureInterface;
|
delete progress.futureInterface;
|
||||||
|
|||||||
@@ -11,6 +11,10 @@
|
|||||||
#include <QFutureInterface>
|
#include <QFutureInterface>
|
||||||
#include <QPointer>
|
#include <QPointer>
|
||||||
|
|
||||||
|
QT_BEGIN_NAMESPACE
|
||||||
|
class QTimer;
|
||||||
|
QT_END_NAMESPACE
|
||||||
|
|
||||||
namespace LanguageServerProtocol {
|
namespace LanguageServerProtocol {
|
||||||
class ProgressParams;
|
class ProgressParams;
|
||||||
class ProgressToken;
|
class ProgressToken;
|
||||||
@@ -46,15 +50,20 @@ private:
|
|||||||
const LanguageServerProtocol::WorkDoneProgressReport &report);
|
const LanguageServerProtocol::WorkDoneProgressReport &report);
|
||||||
void endProgress(const LanguageServerProtocol::ProgressToken &token,
|
void endProgress(const LanguageServerProtocol::ProgressToken &token,
|
||||||
const LanguageServerProtocol::WorkDoneProgressEnd &end);
|
const LanguageServerProtocol::WorkDoneProgressEnd &end);
|
||||||
|
void spawnProgressBar(const LanguageServerProtocol::ProgressToken &token);
|
||||||
|
|
||||||
struct LanguageClientProgress {
|
struct ProgressItem
|
||||||
|
{
|
||||||
QPointer<Core::FutureProgress> progressInterface = nullptr;
|
QPointer<Core::FutureProgress> progressInterface = nullptr;
|
||||||
QFutureInterface<void> *futureInterface = 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, QString> m_titles;
|
||||||
QMap<LanguageServerProtocol::ProgressToken, QElapsedTimer> m_timer;
|
|
||||||
QMap<LanguageServerProtocol::ProgressToken, std::function<void()>> m_clickHandlers;
|
QMap<LanguageServerProtocol::ProgressToken, std::function<void()>> m_clickHandlers;
|
||||||
QMap<LanguageServerProtocol::ProgressToken, std::function<void()>> m_cancelHandlers;
|
QMap<LanguageServerProtocol::ProgressToken, std::function<void()>> m_cancelHandlers;
|
||||||
};
|
};
|
||||||
|
|||||||
@@ -9,7 +9,6 @@ add_qtc_plugin(Macros
|
|||||||
macrolocatorfilter.cpp macrolocatorfilter.h
|
macrolocatorfilter.cpp macrolocatorfilter.h
|
||||||
macromanager.cpp macromanager.h
|
macromanager.cpp macromanager.h
|
||||||
macrooptionspage.cpp macrooptionspage.h
|
macrooptionspage.cpp macrooptionspage.h
|
||||||
macrooptionswidget.cpp macrooptionswidget.h
|
|
||||||
macros.qrc
|
macros.qrc
|
||||||
macrosconstants.h
|
macrosconstants.h
|
||||||
macrosplugin.cpp macrosplugin.h
|
macrosplugin.cpp macrosplugin.h
|
||||||
|
|||||||
@@ -3,15 +3,195 @@
|
|||||||
|
|
||||||
#include "macrooptionspage.h"
|
#include "macrooptionspage.h"
|
||||||
|
|
||||||
|
#include "macro.h"
|
||||||
#include "macromanager.h"
|
#include "macromanager.h"
|
||||||
#include "macrooptionswidget.h"
|
|
||||||
#include "macrosconstants.h"
|
#include "macrosconstants.h"
|
||||||
#include "macrostr.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>
|
#include <texteditor/texteditorconstants.h>
|
||||||
|
|
||||||
namespace Macros {
|
#include <utils/layoutbuilder.h>
|
||||||
namespace Internal {
|
|
||||||
|
#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()
|
MacroOptionsPage::MacroOptionsPage()
|
||||||
{
|
{
|
||||||
@@ -21,5 +201,4 @@ MacroOptionsPage::MacroOptionsPage()
|
|||||||
setWidgetCreator([] { return new MacroOptionsWidget; });
|
setWidgetCreator([] { return new MacroOptionsWidget; });
|
||||||
}
|
}
|
||||||
|
|
||||||
} // Internal
|
} // Macros::Internal
|
||||||
} // Macros
|
|
||||||
|
|||||||
@@ -5,8 +5,7 @@
|
|||||||
|
|
||||||
#include <coreplugin/dialogs/ioptionspage.h>
|
#include <coreplugin/dialogs/ioptionspage.h>
|
||||||
|
|
||||||
namespace Macros {
|
namespace Macros::Internal {
|
||||||
namespace Internal {
|
|
||||||
|
|
||||||
class MacroOptionsPage final : public Core::IOptionsPage
|
class MacroOptionsPage final : public Core::IOptionsPage
|
||||||
{
|
{
|
||||||
@@ -14,5 +13,4 @@ public:
|
|||||||
MacroOptionsPage();
|
MacroOptionsPage();
|
||||||
};
|
};
|
||||||
|
|
||||||
} // namespace Internal
|
} // Macros::Internal
|
||||||
} // namespace Macros
|
|
||||||
|
|||||||
@@ -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
|
|
||||||
@@ -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
|
|
||||||
@@ -29,8 +29,6 @@ QtcPlugin {
|
|||||||
"macromanager.h",
|
"macromanager.h",
|
||||||
"macrooptionspage.cpp",
|
"macrooptionspage.cpp",
|
||||||
"macrooptionspage.h",
|
"macrooptionspage.h",
|
||||||
"macrooptionswidget.cpp",
|
|
||||||
"macrooptionswidget.h",
|
|
||||||
"macros.qrc",
|
"macros.qrc",
|
||||||
"macrosconstants.h",
|
"macrosconstants.h",
|
||||||
"macrosplugin.cpp",
|
"macrosplugin.cpp",
|
||||||
|
|||||||
@@ -24,7 +24,7 @@ add_qtc_plugin(McuSupport
|
|||||||
settingshandler.cpp settingshandler.h
|
settingshandler.cpp settingshandler.h
|
||||||
mcuqmlprojectnode.cpp mcuqmlprojectnode.h
|
mcuqmlprojectnode.cpp mcuqmlprojectnode.h
|
||||||
mcubuildstep.cpp mcubuildstep.h
|
mcubuildstep.cpp mcubuildstep.h
|
||||||
dialogs/mcukitcreationdialog.h dialogs/mcukitcreationdialog.cpp dialogs/mcukitcreationdialog.ui
|
dialogs/mcukitcreationdialog.cpp dialogs/mcukitcreationdialog.h
|
||||||
)
|
)
|
||||||
|
|
||||||
add_subdirectory(test)
|
add_subdirectory(test)
|
||||||
|
|||||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user