forked from qt-creator/qt-creator
Merge remote-tracking branch 'origin/11.0'
Change-Id: Icb3ed8a1aaf31e8201a61d04221bfcb23a78562a
This commit is contained in:
31
dist/changelog/changes-11.0.0.md
vendored
31
dist/changelog/changes-11.0.0.md
vendored
@@ -42,7 +42,7 @@ To use an external terminal, deselect the `Use internal terminal` check box in
|
|||||||
|
|
||||||
### Copilot
|
### Copilot
|
||||||
|
|
||||||
The experimental Copilot plugin integrates
|
The Copilot plugin (disabled by default) integrates
|
||||||
[GitHub Copilot](https://github.com/features/copilot), which uses OpenAI to
|
[GitHub Copilot](https://github.com/features/copilot), which uses OpenAI to
|
||||||
suggest code in the `Edit` mode.
|
suggest code in the `Edit` mode.
|
||||||
|
|
||||||
@@ -87,6 +87,8 @@ General
|
|||||||
([QTCREATORBUG-26128](https://bugreports.qt.io/browse/QTCREATORBUG-26128),
|
([QTCREATORBUG-26128](https://bugreports.qt.io/browse/QTCREATORBUG-26128),
|
||||||
[QTCREATORBUG-27006](https://bugreports.qt.io/browse/QTCREATORBUG-27006),
|
[QTCREATORBUG-27006](https://bugreports.qt.io/browse/QTCREATORBUG-27006),
|
||||||
[QTCREATORBUG-27506](https://bugreports.qt.io/browse/QTCREATORBUG-27506))
|
[QTCREATORBUG-27506](https://bugreports.qt.io/browse/QTCREATORBUG-27506))
|
||||||
|
* Fixed a crash with a large number of search hits from Silver Searcher
|
||||||
|
([QTCREATORBUG-29130](https://bugreports.qt.io/browse/QTCREATORBUG-29130))
|
||||||
* Locator
|
* Locator
|
||||||
* Improved performance
|
* Improved performance
|
||||||
* Added the creation of directories to the `Files in File System` filter
|
* Added the creation of directories to the `Files in File System` filter
|
||||||
@@ -101,6 +103,8 @@ Editing
|
|||||||
([QTCREATORBUG-19651](https://bugreports.qt.io/browse/QTCREATORBUG-19651))
|
([QTCREATORBUG-19651](https://bugreports.qt.io/browse/QTCREATORBUG-19651))
|
||||||
* Fixed an issue of copy and paste with multiple cursors
|
* Fixed an issue of copy and paste with multiple cursors
|
||||||
([QTCREATORBUG-29117](https://bugreports.qt.io/browse/QTCREATORBUG-29117))
|
([QTCREATORBUG-29117](https://bugreports.qt.io/browse/QTCREATORBUG-29117))
|
||||||
|
* Fixed the handling of pre-edit text for input methods
|
||||||
|
([QTCREATORBUG-29134](https://bugreports.qt.io/browse/QTCREATORBUG-29134))
|
||||||
|
|
||||||
### C++
|
### C++
|
||||||
|
|
||||||
@@ -111,12 +115,22 @@ Editing
|
|||||||
* Extended the `Add Class Member` refactoring action to create class
|
* Extended the `Add Class Member` refactoring action to create class
|
||||||
members from assignments
|
members from assignments
|
||||||
([QTCREATORBUG-1918](https://bugreports.qt.io/browse/QTCREATORBUG-1918))
|
([QTCREATORBUG-1918](https://bugreports.qt.io/browse/QTCREATORBUG-1918))
|
||||||
|
* Fixed that generated functions did not have a `const` qualifier when
|
||||||
|
required
|
||||||
|
([QTCREATORBUG-29274](https://bugreports.qt.io/browse/QTCREATORBUG-29274))
|
||||||
* Fixed that locator showed both the declaration and the definition of symbols
|
* Fixed that locator showed both the declaration and the definition of symbols
|
||||||
([QTCREATORBUG-13894](https://bugreports.qt.io/browse/QTCREATORBUG-13894))
|
([QTCREATORBUG-13894](https://bugreports.qt.io/browse/QTCREATORBUG-13894))
|
||||||
* Fixed the handling of C++20 keywords and concepts
|
* Fixed the handling of C++20 keywords and concepts
|
||||||
|
* Clangd
|
||||||
|
* Fixed that the index could be outdated after VCS operations
|
||||||
|
* Fixed the highlighting of labels
|
||||||
|
([QTCREATORBUG-27338](https://bugreports.qt.io/browse/QTCREATORBUG-27338))
|
||||||
* Built-in
|
* Built-in
|
||||||
* Fixed support for `if`-statements with initializer
|
* Fixed support for `if`-statements with initializer
|
||||||
([QTCREATORBUG-29182](https://bugreports.qt.io/browse/QTCREATORBUG-29182))
|
([QTCREATORBUG-29182](https://bugreports.qt.io/browse/QTCREATORBUG-29182))
|
||||||
|
* Clang Format
|
||||||
|
* Fixed the conversion of tab indentation settings to Clang Format
|
||||||
|
([QTCREATORBUG-29185](https://bugreports.qt.io/browse/QTCREATORBUG-29185))
|
||||||
|
|
||||||
### Language Server Protocol
|
### Language Server Protocol
|
||||||
|
|
||||||
@@ -135,12 +149,16 @@ Editing
|
|||||||
([QTCREATORBUG-29123](https://bugreports.qt.io/browse/QTCREATORBUG-29123))
|
([QTCREATORBUG-29123](https://bugreports.qt.io/browse/QTCREATORBUG-29123))
|
||||||
* Fixed the completion for Qt Quick Controls
|
* Fixed the completion for Qt Quick Controls
|
||||||
([QTCREATORBUG-28648](https://bugreports.qt.io/browse/QTCREATORBUG-28648))
|
([QTCREATORBUG-28648](https://bugreports.qt.io/browse/QTCREATORBUG-28648))
|
||||||
|
* Fixed that `qmllint` issues were not shown in the `Issues` view
|
||||||
|
([QTCREATORBUG-28720](https://bugreports.qt.io/browse/QTCREATORBUG-28720))
|
||||||
|
|
||||||
### Python
|
### Python
|
||||||
|
|
||||||
* Added the option to create a virtual environment (`venv`) to the Python
|
* Added the option to create a virtual environment (`venv`) to the Python
|
||||||
interpreter selector and the wizard
|
interpreter selector and the wizard
|
||||||
([PYSIDE-2152](https://bugreports.qt.io/browse/PYSIDE-2152))
|
([PYSIDE-2152](https://bugreports.qt.io/browse/PYSIDE-2152))
|
||||||
|
* Fixed that too many progress indicators could be created
|
||||||
|
([QTCREATORBUG-29224](https://bugreports.qt.io/browse/QTCREATORBUG-29224))
|
||||||
|
|
||||||
([Documentation](https://doc-snapshots.qt.io/qtcreator-11.0/creator-python-development.html))
|
([Documentation](https://doc-snapshots.qt.io/qtcreator-11.0/creator-python-development.html))
|
||||||
|
|
||||||
@@ -168,6 +186,7 @@ Projects
|
|||||||
[QTCREATORBUG-29006](https://bugreports.qt.io/browse/QTCREATORBUG-29006))
|
[QTCREATORBUG-29006](https://bugreports.qt.io/browse/QTCREATORBUG-29006))
|
||||||
* Added `Build > Reload CMake Presets` to reload CMake presets after making
|
* Added `Build > Reload CMake Presets` to reload CMake presets after making
|
||||||
changes to them
|
changes to them
|
||||||
|
* Added support for `block()` and `endblock()`
|
||||||
* Fixed that CMake Presets were not visible in `Projects` view
|
* Fixed that CMake Presets were not visible in `Projects` view
|
||||||
([QTCREATORBUG-28966](https://bugreports.qt.io/browse/QTCREATORBUG-28966))
|
([QTCREATORBUG-28966](https://bugreports.qt.io/browse/QTCREATORBUG-28966))
|
||||||
* Fixed issues with detecting a configured Qt version when importing a build
|
* Fixed issues with detecting a configured Qt version when importing a build
|
||||||
@@ -184,11 +203,17 @@ Debugging
|
|||||||
* Improved the UI for enabling and disabling debuggers in `Projects > Run >
|
* Improved the UI for enabling and disabling debuggers in `Projects > Run >
|
||||||
Debugger settings`
|
Debugger settings`
|
||||||
([QTCREATORBUG-28627](https://bugreports.qt.io/browse/QTCREATORBUG-28627))
|
([QTCREATORBUG-28627](https://bugreports.qt.io/browse/QTCREATORBUG-28627))
|
||||||
|
* Fixed the automatic source mapping for Qt versions from an installer
|
||||||
|
([QTCREATORBUG-28950](https://bugreports.qt.io/browse/QTCREATORBUG-28950))
|
||||||
|
* Fixed pretty printer for `std::string` for recent `libc++`
|
||||||
|
([QTCREATORBUG-29230](https://bugreports.qt.io/browse/QTCREATORBUG-29230))
|
||||||
|
|
||||||
### C++
|
### C++
|
||||||
|
|
||||||
* Added an option for the default number of array elements to show
|
* Added an option for the default number of array elements to show
|
||||||
(`Preferences > Debugger > Locals & Expressions > Default array size`)
|
(`Preferences > Debugger > Locals & Expressions > Default array size`)
|
||||||
|
* Fixed debugging in a terminal as the root user
|
||||||
|
([QTCREATORBUG-27519](https://bugreports.qt.io/browse/QTCREATORBUG-27519))
|
||||||
* CDB
|
* CDB
|
||||||
* Added automatic source file mapping for Qt packages
|
* Added automatic source file mapping for Qt packages
|
||||||
* Fixed the variables view on remote Windows devices
|
* Fixed the variables view on remote Windows devices
|
||||||
|
|||||||
BIN
doc/qtcreator/images/qtquick-debugger-settings.webp
Normal file
BIN
doc/qtcreator/images/qtquick-debugger-settings.webp
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 3.4 KiB |
Binary file not shown.
|
Before Width: | Height: | Size: 2.5 KiB |
@@ -42,9 +42,11 @@
|
|||||||
\section2 Debugging Qt Quick UI Projects
|
\section2 Debugging Qt Quick UI Projects
|
||||||
\endif
|
\endif
|
||||||
|
|
||||||
To debug Qt Quick UI projects (.qmlproject), select the
|
To debug Qt Quick UI projects (.qmlproject), select \uicontrol Automatic
|
||||||
\uicontrol {Enable QML} check box in \uicontrol {Debugger settings}
|
or \uicontrol Enabled in \uicontrol{Run Settings} >
|
||||||
in \uicontrol Projects mode \uicontrol {Run Settings}.
|
\uicontrol {Debugger Settings} > \uicontrol {QML debugger}.
|
||||||
|
|
||||||
|
\image qtquick-debugger-settings.webp {Debugger settings section in Run Settings}
|
||||||
|
|
||||||
\if defined(qtcreator)
|
\if defined(qtcreator)
|
||||||
\section2 Debugging Qt Quick Applications
|
\section2 Debugging Qt Quick Applications
|
||||||
@@ -65,9 +67,13 @@
|
|||||||
functions. Therefore, you must make sure that the port is properly
|
functions. Therefore, you must make sure that the port is properly
|
||||||
protected by a firewall.
|
protected by a firewall.
|
||||||
|
|
||||||
\li In \uicontrol {Run Settings} > \uicontrol {Debugger settings}, select
|
\li In \uicontrol {Run Settings} > \uicontrol {Debugger settings} >
|
||||||
the \uicontrol {Enable QML} check box to enable QML debugging for
|
\uicontrol {QML debugger}, select \uicontrol Automatic or
|
||||||
running applications.
|
\uicontrol Enabled to enable QML debugging for running applications.
|
||||||
|
|
||||||
|
To debug both the C++ and QML parts of your application at the same
|
||||||
|
time, also select \uicontrol Automatic or \uicontrol Enabled in
|
||||||
|
\uicontrol {C++ debugger}.
|
||||||
|
|
||||||
\li Select \uicontrol Build > \uicontrol {Rebuild Project} to clean and
|
\li Select \uicontrol Build > \uicontrol {Rebuild Project} to clean and
|
||||||
rebuild the project.
|
rebuild the project.
|
||||||
@@ -119,17 +125,8 @@
|
|||||||
For example, for qmake the global setting only affects build configurations
|
For example, for qmake the global setting only affects build configurations
|
||||||
that are automatically created when enabling a kit. Also, CMake ignores the
|
that are automatically created when enabling a kit. Also, CMake ignores the
|
||||||
global setting.
|
global setting.
|
||||||
|
|
||||||
\section1 Mixed C++/QML Debugging
|
|
||||||
|
|
||||||
To debug both the C++ and QML parts of your application at the same time,
|
|
||||||
select the \uicontrol {Enable C++} and \uicontrol {Enable QML} checkboxes for both
|
|
||||||
languages in the \uicontrol {Debugger Settings} section in the project
|
|
||||||
\uicontrol{Run Settings}.
|
|
||||||
\endif
|
\endif
|
||||||
|
|
||||||
\image qtquick-debugging-settings.png {Debugger settings section in Run Settings}
|
|
||||||
|
|
||||||
\section1 Starting QML Debugging
|
\section1 Starting QML Debugging
|
||||||
|
|
||||||
To start the application, choose \uicontrol Debug > \uicontrol {Start Debugging}
|
To start the application, choose \uicontrol Debug > \uicontrol {Start Debugging}
|
||||||
|
|||||||
@@ -81,7 +81,7 @@
|
|||||||
|
|
||||||
\li \l {Using GitHub Copilot}
|
\li \l {Using GitHub Copilot}
|
||||||
|
|
||||||
The experimental Copilot plugin integrates
|
The Copilot plugin (disabled by default) integrates
|
||||||
\l{https://github.com/features/copilot}{GitHub Copilot} into \QC.
|
\l{https://github.com/features/copilot}{GitHub Copilot} into \QC.
|
||||||
You can view suggestions from Copilot in the code editor.
|
You can view suggestions from Copilot in the code editor.
|
||||||
|
|
||||||
|
|||||||
@@ -8,7 +8,7 @@
|
|||||||
|
|
||||||
\title Using GitHub Copilot
|
\title Using GitHub Copilot
|
||||||
|
|
||||||
The experimental Copilot plugin integrates
|
The Copilot plugin (disabled by default) integrates
|
||||||
\l{https://github.com/features/copilot}{GitHub Copilot} into \QC.
|
\l{https://github.com/features/copilot}{GitHub Copilot} into \QC.
|
||||||
You can view suggestions from Copilot in the \uicontrol Edit mode.
|
You can view suggestions from Copilot in the \uicontrol Edit mode.
|
||||||
|
|
||||||
|
|||||||
@@ -1,4 +1,4 @@
|
|||||||
// Copyright (C) 2022 The Qt Company Ltd.
|
// Copyright (C) 2023 The Qt Company Ltd.
|
||||||
// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GFDL-1.3-no-invariants-only
|
// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GFDL-1.3-no-invariants-only
|
||||||
|
|
||||||
/*!
|
/*!
|
||||||
@@ -6,10 +6,11 @@
|
|||||||
|
|
||||||
\section1 Enabling Debugging
|
\section1 Enabling Debugging
|
||||||
|
|
||||||
\image qtquick-debugging-settings.png "Debugger Settings"
|
\image qtquick-debugger-settings.webp "Debugger Settings"
|
||||||
|
|
||||||
To select the languages to debug, select the \uicontrol {Enable C++} and
|
To select the languages to debug, select \uicontrol Automatic
|
||||||
\uicontrol {Enable QML} check boxes.
|
or \uicontrol Enabled in \uicontrol {Debugger Settings} >
|
||||||
|
\uicontrol {C++ debugger} and \uicontrol {QML debugger}.
|
||||||
|
|
||||||
\note Opening a socket at a well-known port presents a security risk. Anyone
|
\note Opening a socket at a well-known port presents a security risk. Anyone
|
||||||
on the Internet could connect to the application that you are debugging and
|
on the Internet could connect to the application that you are debugging and
|
||||||
@@ -28,6 +29,11 @@
|
|||||||
|
|
||||||
However, you can usually leave this field empty.
|
However, you can usually leave this field empty.
|
||||||
|
|
||||||
|
\note To create a build configuration that supports debugging for a
|
||||||
|
Qt Quick application project, you also need to \l {Using Default Values}
|
||||||
|
{enable QML debugging} either globally or in the \uicontrol {Build Settings}
|
||||||
|
of the project.
|
||||||
|
|
||||||
For more information about debugging, see \l{Debugging}.
|
For more information about debugging, see \l{Debugging}.
|
||||||
|
|
||||||
//! [run settings debugger]
|
//! [run settings debugger]
|
||||||
|
|||||||
@@ -16,7 +16,7 @@ headerdirs = . \
|
|||||||
../src \
|
../src \
|
||||||
../../../src/libs/aggregation \
|
../../../src/libs/aggregation \
|
||||||
../../../src/libs/extensionsystem \
|
../../../src/libs/extensionsystem \
|
||||||
../../../src/libs/solutions/tasking \
|
../../../src/libs/solutions \
|
||||||
../../../src/libs/utils \
|
../../../src/libs/utils \
|
||||||
../../../src/plugins/coreplugin
|
../../../src/plugins/coreplugin
|
||||||
|
|
||||||
@@ -24,7 +24,7 @@ sourcedirs = . \
|
|||||||
../src \
|
../src \
|
||||||
../../../src/libs/aggregation \
|
../../../src/libs/aggregation \
|
||||||
../../../src/libs/extensionsystem \
|
../../../src/libs/extensionsystem \
|
||||||
../../../src/libs/solutions/tasking \
|
../../../src/libs/solutions \
|
||||||
../../../src/libs/utils \
|
../../../src/libs/utils \
|
||||||
../../../src/plugins/coreplugin
|
../../../src/plugins/coreplugin
|
||||||
|
|
||||||
@@ -42,7 +42,8 @@ sources.fileextensions = "*.cpp *.qdoc"
|
|||||||
|
|
||||||
imagedirs = ../images \
|
imagedirs = ../images \
|
||||||
../../config/images \
|
../../config/images \
|
||||||
../../qtcreator/images
|
../../qtcreator/images \
|
||||||
|
../../../src/libs/solutions
|
||||||
exampledirs = ../examples
|
exampledirs = ../examples
|
||||||
|
|
||||||
depends += qtwidgets \
|
depends += qtwidgets \
|
||||||
|
|||||||
@@ -119,6 +119,11 @@
|
|||||||
\li Solution Name
|
\li Solution Name
|
||||||
\li Description
|
\li Description
|
||||||
|
|
||||||
|
\row
|
||||||
|
\li \l{Spinner Solution}{Spinner}
|
||||||
|
\li Renders a circular, endlessly animated progress indicator,
|
||||||
|
which may be attached to any widget as an overlay.
|
||||||
|
|
||||||
\row
|
\row
|
||||||
\li \l{Tasking Solution}{Tasking}
|
\li \l{Tasking Solution}{Tasking}
|
||||||
\li Enables you to build extensible, declarative task tree structures
|
\li Enables you to build extensible, declarative task tree structures
|
||||||
|
|||||||
@@ -1,6 +1,7 @@
|
|||||||
# Copyright (C) 2016 The Qt Company Ltd.
|
# Copyright (C) 2016 The Qt Company Ltd.
|
||||||
# SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only WITH Qt-GPL-exception-1.0
|
# SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only WITH Qt-GPL-exception-1.0
|
||||||
|
|
||||||
|
import argparse
|
||||||
import os
|
import os
|
||||||
import locale
|
import locale
|
||||||
import shutil
|
import shutil
|
||||||
@@ -196,13 +197,13 @@ def is_not_debug(path, filenames):
|
|||||||
files = [fn for fn in filenames if os.path.isfile(os.path.join(path, fn))]
|
files = [fn for fn in filenames if os.path.isfile(os.path.join(path, fn))]
|
||||||
return [fn for fn in files if not is_debug_file(os.path.join(path, fn))]
|
return [fn for fn in files if not is_debug_file(os.path.join(path, fn))]
|
||||||
|
|
||||||
def codesign_call():
|
def codesign_call(identity=None, flags=None):
|
||||||
signing_identity = os.environ.get('SIGNING_IDENTITY')
|
signing_identity = identity or os.environ.get('SIGNING_IDENTITY')
|
||||||
if not signing_identity:
|
if not signing_identity:
|
||||||
return None
|
return None
|
||||||
codesign_call = ['codesign', '-o', 'runtime', '--force', '-s', signing_identity,
|
codesign_call = ['codesign', '-o', 'runtime', '--force', '-s', signing_identity,
|
||||||
'-v']
|
'-v']
|
||||||
signing_flags = os.environ.get('SIGNING_FLAGS')
|
signing_flags = flags or os.environ.get('SIGNING_FLAGS')
|
||||||
if signing_flags:
|
if signing_flags:
|
||||||
codesign_call.extend(signing_flags.split())
|
codesign_call.extend(signing_flags.split())
|
||||||
return codesign_call
|
return codesign_call
|
||||||
@@ -228,8 +229,8 @@ def conditional_sign_recursive(path, filter):
|
|||||||
if is_mac_platform():
|
if is_mac_platform():
|
||||||
os_walk(path, filter, lambda fp: codesign_executable(fp))
|
os_walk(path, filter, lambda fp: codesign_executable(fp))
|
||||||
|
|
||||||
def codesign(app_path):
|
def codesign(app_path, identity=None, flags=None):
|
||||||
codesign = codesign_call()
|
codesign = codesign_call(identity, flags)
|
||||||
if not codesign or not is_mac_platform():
|
if not codesign or not is_mac_platform():
|
||||||
return
|
return
|
||||||
# sign all executables in Resources
|
# sign all executables in Resources
|
||||||
@@ -243,3 +244,20 @@ def codesign(app_path):
|
|||||||
entitlements_path = os.path.join(os.path.dirname(os.path.realpath(__file__)), '..', 'dist',
|
entitlements_path = os.path.join(os.path.dirname(os.path.realpath(__file__)), '..', 'dist',
|
||||||
'installer', 'mac', 'entitlements.plist')
|
'installer', 'mac', 'entitlements.plist')
|
||||||
subprocess.check_call(codesign + ['--deep', app_path, '--entitlements', entitlements_path])
|
subprocess.check_call(codesign + ['--deep', app_path, '--entitlements', entitlements_path])
|
||||||
|
|
||||||
|
def codesign_main(args):
|
||||||
|
codesign(args.app_bundle, args.identity, args.flags)
|
||||||
|
|
||||||
|
def main():
|
||||||
|
parser = argparse.ArgumentParser(description='Qt Creator build tools')
|
||||||
|
subparsers = parser.add_subparsers(title='subcommands', required=True)
|
||||||
|
parser_codesign = subparsers.add_parser('codesign', description='Codesign macOS app bundle')
|
||||||
|
parser_codesign.add_argument('app_bundle')
|
||||||
|
parser_codesign.add_argument('-s', '--identity', help='Codesign identity')
|
||||||
|
parser_codesign.add_argument('--flags', help='Additional flags')
|
||||||
|
parser_codesign.set_defaults(func=codesign_main)
|
||||||
|
args = parser.parse_args()
|
||||||
|
args.func(args)
|
||||||
|
|
||||||
|
if __name__ == '__main__':
|
||||||
|
main()
|
||||||
|
|||||||
@@ -1509,9 +1509,10 @@ class CliDumper(Dumper):
|
|||||||
self.setupDumpers({})
|
self.setupDumpers({})
|
||||||
|
|
||||||
def put(self, line):
|
def put(self, line):
|
||||||
if self.output.endswith('\n'):
|
if self.output:
|
||||||
self.output = self.output[0:-1]
|
if self.output[-1].endswith('\n'):
|
||||||
self.output += line
|
self.output[-1] = self.output[-1][0:-1]
|
||||||
|
self.output.append(line)
|
||||||
|
|
||||||
def putNumChild(self, numchild):
|
def putNumChild(self, numchild):
|
||||||
pass
|
pass
|
||||||
|
|||||||
@@ -504,6 +504,21 @@ int main(int argc, char **argv)
|
|||||||
{{"LD_PRELOAD", "", Utils::EnvironmentItem::Unset}});
|
{{"LD_PRELOAD", "", Utils::EnvironmentItem::Unset}});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
auto restoreEnvVarFromSquish = [](const QByteArray &squishVar, const QString &var) {
|
||||||
|
if (qEnvironmentVariableIsSet(squishVar)) {
|
||||||
|
Utils::Environment::modifySystemEnvironment(
|
||||||
|
{{var, "", Utils::EnvironmentItem::Unset}});
|
||||||
|
const QString content = qEnvironmentVariable(squishVar);
|
||||||
|
if (!content.isEmpty()) {
|
||||||
|
Utils::Environment::modifySystemEnvironment(
|
||||||
|
{{var, content, Utils::EnvironmentItem::Prepend}});
|
||||||
|
}
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
restoreEnvVarFromSquish("SQUISH_SHELL_ORIG_DYLD_LIBRARY_PATH", "DYLD_LIBRARY_PATH");
|
||||||
|
restoreEnvVarFromSquish("SQUISH_ORIG_DYLD_FRAMEWORK_PATH", "DYLD_FRAMEWORK_PATH");
|
||||||
|
|
||||||
if (options.userLibraryPath) {
|
if (options.userLibraryPath) {
|
||||||
if ((*options.userLibraryPath).isEmpty()) {
|
if ((*options.userLibraryPath).isEmpty()) {
|
||||||
Utils::Environment::modifySystemEnvironment(
|
Utils::Environment::modifySystemEnvironment(
|
||||||
|
|||||||
@@ -370,7 +370,7 @@ QByteArray LibraryInfo::calculateFingerprint() const
|
|||||||
{
|
{
|
||||||
QCryptographicHash hash(QCryptographicHash::Sha1);
|
QCryptographicHash hash(QCryptographicHash::Sha1);
|
||||||
auto addData = [&hash](auto p, size_t len) {
|
auto addData = [&hash](auto p, size_t len) {
|
||||||
hash.addData(QByteArrayView(reinterpret_cast<const char *>(p), len));
|
hash.addData(reinterpret_cast<const char *>(p), len);
|
||||||
};
|
};
|
||||||
|
|
||||||
addData(&_status, sizeof(_status));
|
addData(&_status, sizeof(_status));
|
||||||
|
|||||||
@@ -1 +1,2 @@
|
|||||||
|
add_subdirectory(spinner)
|
||||||
add_subdirectory(tasking)
|
add_subdirectory(tasking)
|
||||||
|
|||||||
@@ -2,6 +2,7 @@ Project {
|
|||||||
name: "Solutions"
|
name: "Solutions"
|
||||||
|
|
||||||
references: [
|
references: [
|
||||||
|
"spinner/spinner.qbs",
|
||||||
"tasking/tasking.qbs",
|
"tasking/tasking.qbs",
|
||||||
].concat(project.additionalLibs)
|
].concat(project.additionalLibs)
|
||||||
}
|
}
|
||||||
|
|||||||
9
src/libs/solutions/spinner/CMakeLists.txt
Normal file
9
src/libs/solutions/spinner/CMakeLists.txt
Normal file
@@ -0,0 +1,9 @@
|
|||||||
|
add_qtc_library(Spinner OBJECT
|
||||||
|
# Never add dependencies to non-Qt libraries for this library
|
||||||
|
DEPENDS Qt::Core Qt::Widgets
|
||||||
|
PUBLIC_DEFINES SPINNER_LIBRARY
|
||||||
|
SOURCES
|
||||||
|
spinner.cpp spinner.h
|
||||||
|
spinner.qrc
|
||||||
|
spinner_global.h
|
||||||
|
)
|
||||||
BIN
src/libs/solutions/spinner/icons/spinner_large.png
Normal file
BIN
src/libs/solutions/spinner/icons/spinner_large.png
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 1.3 KiB |
BIN
src/libs/solutions/spinner/icons/spinner_medium.png
Normal file
BIN
src/libs/solutions/spinner/icons/spinner_medium.png
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 765 B |
BIN
src/libs/solutions/spinner/icons/spinner_small.png
Normal file
BIN
src/libs/solutions/spinner/icons/spinner_small.png
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 315 B |
249
src/libs/solutions/spinner/spinner.cpp
Normal file
249
src/libs/solutions/spinner/spinner.cpp
Normal file
@@ -0,0 +1,249 @@
|
|||||||
|
// Copyright (C) 2023 The Qt Company Ltd.
|
||||||
|
// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only WITH Qt-GPL-exception-1.0
|
||||||
|
|
||||||
|
#include "spinner.h"
|
||||||
|
|
||||||
|
#include <QEvent>
|
||||||
|
#include <QPainter>
|
||||||
|
#include <QTimer>
|
||||||
|
#include <QWidget>
|
||||||
|
|
||||||
|
namespace SpinnerSolution {
|
||||||
|
|
||||||
|
class OverlayWidget : public QWidget
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
using PaintFunction = std::function<void(QWidget *, QPainter &, QPaintEvent *)>;
|
||||||
|
|
||||||
|
explicit OverlayWidget(QWidget *parent = nullptr)
|
||||||
|
{
|
||||||
|
setAttribute(Qt::WA_TransparentForMouseEvents);
|
||||||
|
if (parent)
|
||||||
|
attachToWidget(parent);
|
||||||
|
}
|
||||||
|
|
||||||
|
void attachToWidget(QWidget *parent)
|
||||||
|
{
|
||||||
|
if (parentWidget())
|
||||||
|
parentWidget()->removeEventFilter(this);
|
||||||
|
setParent(parent);
|
||||||
|
if (parent) {
|
||||||
|
parent->installEventFilter(this);
|
||||||
|
resizeToParent();
|
||||||
|
raise();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
void setPaintFunction(const PaintFunction &paint) { m_paint = paint; }
|
||||||
|
|
||||||
|
protected:
|
||||||
|
bool eventFilter(QObject *obj, QEvent *ev) override
|
||||||
|
{
|
||||||
|
if (obj == parent() && ev->type() == QEvent::Resize)
|
||||||
|
resizeToParent();
|
||||||
|
return QWidget::eventFilter(obj, ev);
|
||||||
|
}
|
||||||
|
|
||||||
|
void paintEvent(QPaintEvent *ev) override
|
||||||
|
{
|
||||||
|
if (m_paint) {
|
||||||
|
QPainter p(this);
|
||||||
|
m_paint(this, p, ev);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private:
|
||||||
|
void resizeToParent() { setGeometry(QRect({}, parentWidget()->size())); }
|
||||||
|
|
||||||
|
PaintFunction m_paint;
|
||||||
|
};
|
||||||
|
|
||||||
|
class SpinnerPainter
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
using UpdateCallback = std::function<void()>;
|
||||||
|
|
||||||
|
SpinnerPainter(SpinnerSize size);
|
||||||
|
|
||||||
|
void setSize(SpinnerSize size);
|
||||||
|
|
||||||
|
void setUpdateCallback(const UpdateCallback &cb) { m_callback = cb; }
|
||||||
|
|
||||||
|
QSize size() const { return m_pixmap.size() / m_pixmap.devicePixelRatio(); }
|
||||||
|
void paint(QPainter &painter, const QRect &rect) const;
|
||||||
|
void startAnimation() { m_timer.start(); }
|
||||||
|
void stopAnimation() { m_timer.stop(); }
|
||||||
|
|
||||||
|
protected:
|
||||||
|
void nextAnimationStep() { m_rotation = (m_rotation + m_rotationStep + 360) % 360; }
|
||||||
|
|
||||||
|
private:
|
||||||
|
SpinnerSize m_size = SpinnerSize::Small;
|
||||||
|
int m_rotationStep = 45;
|
||||||
|
int m_rotation = 0;
|
||||||
|
QTimer m_timer;
|
||||||
|
QPixmap m_pixmap;
|
||||||
|
UpdateCallback m_callback;
|
||||||
|
};
|
||||||
|
|
||||||
|
static QString imageFileNameForSpinnerSize(SpinnerSize size)
|
||||||
|
{
|
||||||
|
switch (size) {
|
||||||
|
case SpinnerSize::Large:
|
||||||
|
return ":/icons/spinner_large.png";
|
||||||
|
case SpinnerSize::Medium:
|
||||||
|
return ":/icons/spinner_medium.png";
|
||||||
|
case SpinnerSize::Small:
|
||||||
|
return ":/icons/spinner_small.png";
|
||||||
|
}
|
||||||
|
return {};
|
||||||
|
}
|
||||||
|
|
||||||
|
SpinnerPainter::SpinnerPainter(SpinnerSize size)
|
||||||
|
{
|
||||||
|
m_timer.setSingleShot(false);
|
||||||
|
QObject::connect(&m_timer, &QTimer::timeout, &m_timer, [this] {
|
||||||
|
nextAnimationStep();
|
||||||
|
if (m_callback)
|
||||||
|
m_callback();
|
||||||
|
});
|
||||||
|
setSize(size);
|
||||||
|
}
|
||||||
|
|
||||||
|
void SpinnerPainter::setSize(SpinnerSize size)
|
||||||
|
{
|
||||||
|
m_size = size;
|
||||||
|
m_rotationStep = size == SpinnerSize::Small ? 45 : 30;
|
||||||
|
m_timer.setInterval(size == SpinnerSize::Small ? 100 : 80);
|
||||||
|
m_pixmap = QPixmap(imageFileNameForSpinnerSize(size));
|
||||||
|
}
|
||||||
|
|
||||||
|
void SpinnerPainter::paint(QPainter &painter, const QRect &rect) const
|
||||||
|
{
|
||||||
|
painter.save();
|
||||||
|
painter.setRenderHint(QPainter::SmoothPixmapTransform);
|
||||||
|
QPoint translate(rect.x() + rect.width() / 2, rect.y() + rect.height() / 2);
|
||||||
|
QTransform t;
|
||||||
|
t.translate(translate.x(), translate.y());
|
||||||
|
t.rotate(m_rotation);
|
||||||
|
t.translate(-translate.x(), -translate.y());
|
||||||
|
painter.setTransform(t);
|
||||||
|
QSize pixmapUserSize(m_pixmap.size() / m_pixmap.devicePixelRatio());
|
||||||
|
painter.drawPixmap(QPoint(rect.x() + ((rect.width() - pixmapUserSize.width()) / 2),
|
||||||
|
rect.y() + ((rect.height() - pixmapUserSize.height()) / 2)),
|
||||||
|
m_pixmap);
|
||||||
|
painter.restore();
|
||||||
|
}
|
||||||
|
|
||||||
|
class SpinnerWidget : public OverlayWidget
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
explicit SpinnerWidget(SpinnerSize size, QWidget *parent = nullptr)
|
||||||
|
: OverlayWidget(parent)
|
||||||
|
, m_paint(size)
|
||||||
|
{
|
||||||
|
setPaintFunction(
|
||||||
|
[this](QWidget *w, QPainter &p, QPaintEvent *) { m_paint.paint(p, w->rect()); });
|
||||||
|
m_paint.setUpdateCallback([this] { update(); });
|
||||||
|
updateGeometry();
|
||||||
|
}
|
||||||
|
|
||||||
|
void setSize(SpinnerSize size)
|
||||||
|
{
|
||||||
|
m_paint.setSize(size);
|
||||||
|
updateGeometry();
|
||||||
|
}
|
||||||
|
QSize sizeHint() const final { return m_paint.size(); }
|
||||||
|
|
||||||
|
protected:
|
||||||
|
void showEvent(QShowEvent *) final { m_paint.startAnimation(); }
|
||||||
|
void hideEvent(QHideEvent *) final { m_paint.stopAnimation(); }
|
||||||
|
|
||||||
|
private:
|
||||||
|
SpinnerPainter m_paint;
|
||||||
|
};
|
||||||
|
|
||||||
|
/*!
|
||||||
|
\module SpinnerSolution
|
||||||
|
\title Spinner Solution
|
||||||
|
\ingroup solutions-modules
|
||||||
|
\brief Contains a Spinner solution.
|
||||||
|
|
||||||
|
The Spinner solution depends on Qt only, and doesn't depend on any \QC specific code.
|
||||||
|
*/
|
||||||
|
|
||||||
|
/*!
|
||||||
|
\namespace SpinnerSolution
|
||||||
|
\inmodule SpinnerSolution
|
||||||
|
\brief The SpinnerSolution namespace encloses the Spinner class.
|
||||||
|
*/
|
||||||
|
|
||||||
|
/*!
|
||||||
|
\enum SpinnerSolution::SpinnerSize
|
||||||
|
|
||||||
|
This enum describes the possible spinner sizes.
|
||||||
|
|
||||||
|
\value Small \inlineimage spinner/icons/spinner_small.png
|
||||||
|
\value Medium \inlineimage spinner/icons/spinner_medium.png
|
||||||
|
\value Large \inlineimage spinner/icons/spinner_large.png
|
||||||
|
*/
|
||||||
|
|
||||||
|
/*!
|
||||||
|
\class SpinnerSolution::Spinner
|
||||||
|
\inheaderfile solutions/spinner/spinner.h
|
||||||
|
\inmodule SpinnerSolution
|
||||||
|
\brief The Spinner class renders a circular, endlessly animated progress indicator,
|
||||||
|
that may be attached to any widget as an overlay.
|
||||||
|
*/
|
||||||
|
|
||||||
|
/*!
|
||||||
|
Creates a spinner overlay with a given \a size for the passed \a parent widget.
|
||||||
|
|
||||||
|
The \a parent widget takes the ownership of the created spinner.
|
||||||
|
*/
|
||||||
|
Spinner::Spinner(SpinnerSize size, QWidget *parent)
|
||||||
|
: QObject(parent)
|
||||||
|
, m_widget(new SpinnerWidget(size, parent)) {}
|
||||||
|
|
||||||
|
/*!
|
||||||
|
Sets the size of the spinner to the given \a size.
|
||||||
|
*/
|
||||||
|
void Spinner::setSize(SpinnerSize size)
|
||||||
|
{
|
||||||
|
m_widget->setSize(size);
|
||||||
|
}
|
||||||
|
|
||||||
|
/*!
|
||||||
|
Shows the animated spinner as an overlay for the parent widget
|
||||||
|
set previously in the constructor.
|
||||||
|
*/
|
||||||
|
void Spinner::show()
|
||||||
|
{
|
||||||
|
m_widget->show();
|
||||||
|
}
|
||||||
|
|
||||||
|
/*!
|
||||||
|
Hides the spinner.
|
||||||
|
*/
|
||||||
|
void Spinner::hide()
|
||||||
|
{
|
||||||
|
m_widget->hide();
|
||||||
|
}
|
||||||
|
|
||||||
|
/*!
|
||||||
|
Returns \c true if the spinner is visible; otherwise, returns \c false.
|
||||||
|
*/
|
||||||
|
bool Spinner::isVisible() const
|
||||||
|
{
|
||||||
|
return m_widget->isVisible();
|
||||||
|
}
|
||||||
|
|
||||||
|
/*!
|
||||||
|
Shows or hides the spinner depending on the value of \a visible.
|
||||||
|
By default, the spinner is visible.
|
||||||
|
*/
|
||||||
|
void Spinner::setVisible(bool visible)
|
||||||
|
{
|
||||||
|
m_widget->setVisible(visible);
|
||||||
|
}
|
||||||
|
|
||||||
|
} // namespace SpinnerSolution
|
||||||
37
src/libs/solutions/spinner/spinner.h
Normal file
37
src/libs/solutions/spinner/spinner.h
Normal file
@@ -0,0 +1,37 @@
|
|||||||
|
// Copyright (C) 2023 The Qt Company Ltd.
|
||||||
|
// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only WITH Qt-GPL-exception-1.0
|
||||||
|
|
||||||
|
#ifndef SPINNER_H
|
||||||
|
#define SPINNER_H
|
||||||
|
|
||||||
|
#include "spinner_global.h"
|
||||||
|
|
||||||
|
#include <QObject>
|
||||||
|
|
||||||
|
namespace SpinnerSolution {
|
||||||
|
|
||||||
|
Q_NAMESPACE_EXPORT(SPINNER_EXPORT)
|
||||||
|
|
||||||
|
enum class SpinnerSize { Small, Medium, Large };
|
||||||
|
Q_ENUM_NS(SpinnerSize);
|
||||||
|
|
||||||
|
// TODO: SpinnerOverlay and SpinnerWidget?
|
||||||
|
|
||||||
|
class SPINNER_EXPORT Spinner : public QObject
|
||||||
|
{
|
||||||
|
Q_OBJECT
|
||||||
|
public:
|
||||||
|
explicit Spinner(SpinnerSize size, QWidget *parent = nullptr);
|
||||||
|
void setSize(SpinnerSize size);
|
||||||
|
void show();
|
||||||
|
void hide();
|
||||||
|
bool isVisible() const;
|
||||||
|
void setVisible(bool visible);
|
||||||
|
|
||||||
|
private:
|
||||||
|
class SpinnerWidget *m_widget = nullptr;
|
||||||
|
};
|
||||||
|
|
||||||
|
} // namespace SpinnerSolution
|
||||||
|
|
||||||
|
#endif // SPINNER_H
|
||||||
13
src/libs/solutions/spinner/spinner.qbs
Normal file
13
src/libs/solutions/spinner/spinner.qbs
Normal file
@@ -0,0 +1,13 @@
|
|||||||
|
QtcLibrary {
|
||||||
|
name: "Spinner"
|
||||||
|
Depends { name: "Qt"; submodules: ["core", "widgets"] }
|
||||||
|
cpp.defines: base.concat("SPINNER_LIBRARY")
|
||||||
|
|
||||||
|
files: [
|
||||||
|
"spinner.cpp",
|
||||||
|
"spinner.h",
|
||||||
|
"spinner.qrc",
|
||||||
|
"spinner_global.h",
|
||||||
|
]
|
||||||
|
}
|
||||||
|
|
||||||
7
src/libs/solutions/spinner/spinner.qrc
Normal file
7
src/libs/solutions/spinner/spinner.qrc
Normal file
@@ -0,0 +1,7 @@
|
|||||||
|
<RCC>
|
||||||
|
<qresource prefix="/" >
|
||||||
|
<file>icons/spinner_large.png</file>
|
||||||
|
<file>icons/spinner_medium.png</file>
|
||||||
|
<file>icons/spinner_small.png</file>
|
||||||
|
</qresource>
|
||||||
|
</RCC>
|
||||||
14
src/libs/solutions/spinner/spinner_global.h
Normal file
14
src/libs/solutions/spinner/spinner_global.h
Normal file
@@ -0,0 +1,14 @@
|
|||||||
|
// 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 <qglobal.h>
|
||||||
|
|
||||||
|
#if defined(SPINNER_LIBRARY)
|
||||||
|
# define SPINNER_EXPORT Q_DECL_EXPORT
|
||||||
|
#elif defined(SPINNER_STATIC_LIBRARY)
|
||||||
|
# define SPINNER_EXPORT
|
||||||
|
#else
|
||||||
|
# define SPINNER_EXPORT Q_DECL_IMPORT
|
||||||
|
#endif
|
||||||
@@ -83,14 +83,14 @@ public:
|
|||||||
"It is possible that no barrier was added to the tree, "
|
"It is possible that no barrier was added to the tree, "
|
||||||
"or the storage is not reachable from where it is referenced. "
|
"or the storage is not reachable from where it is referenced. "
|
||||||
"The WaitForBarrier task will finish with error. ");
|
"The WaitForBarrier task will finish with error. ");
|
||||||
return TaskAction::StopWithError;
|
return SetupResult::StopWithError;
|
||||||
}
|
}
|
||||||
Barrier *activeSharedBarrier = activeBarrier->barrier();
|
Barrier *activeSharedBarrier = activeBarrier->barrier();
|
||||||
const std::optional<bool> result = activeSharedBarrier->result();
|
const std::optional<bool> result = activeSharedBarrier->result();
|
||||||
if (result.has_value())
|
if (result.has_value())
|
||||||
return result.value() ? TaskAction::StopWithDone : TaskAction::StopWithError;
|
return result.value() ? SetupResult::StopWithDone : SetupResult::StopWithError;
|
||||||
QObject::connect(activeSharedBarrier, &Barrier::done, &barrier, &Barrier::stopWithResult);
|
QObject::connect(activeSharedBarrier, &Barrier::done, &barrier, &Barrier::stopWithResult);
|
||||||
return TaskAction::Continue;
|
return SetupResult::Continue;
|
||||||
}) {}
|
}) {}
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|||||||
@@ -57,6 +57,107 @@ private:
|
|||||||
\brief The Tasking namespace encloses all classes and global functions of the Tasking solution.
|
\brief The Tasking namespace encloses all classes and global functions of the Tasking solution.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
|
/*!
|
||||||
|
\class Tasking::TaskInterface
|
||||||
|
\inheaderfile solutions/tasking/tasktree.h
|
||||||
|
\inmodule TaskingSolution
|
||||||
|
\brief TaskInterface is the abstract base class for implementing custom task adapters.
|
||||||
|
|
||||||
|
To implement a custom task adapter, derive your adapter from the
|
||||||
|
\c TaskAdapter<Task> class template. TaskAdapter automatically creates and destroys
|
||||||
|
the custom task instance and associates the adapter with a given \c Task type.
|
||||||
|
*/
|
||||||
|
|
||||||
|
/*!
|
||||||
|
\fn virtual void TaskInterface::start()
|
||||||
|
|
||||||
|
This method is called by the running TaskTree for starting the \c Task instance.
|
||||||
|
Reimplement this method in \c TaskAdapter<Task>'s subclass in order to start the
|
||||||
|
associated task.
|
||||||
|
|
||||||
|
Use TaskAdapter::task() to access the associated \c Task instance.
|
||||||
|
|
||||||
|
\sa done(), TaskAdapter::task()
|
||||||
|
*/
|
||||||
|
|
||||||
|
/*!
|
||||||
|
\fn void TaskInterface::done(bool success)
|
||||||
|
|
||||||
|
Emit this signal from the \c TaskAdapter<Task>'s subclass, when the \c Task is finished.
|
||||||
|
Pass \c true as a \a success argument when the task finishes with success;
|
||||||
|
otherwise, when an error occurs, pass \c false.
|
||||||
|
*/
|
||||||
|
|
||||||
|
/*!
|
||||||
|
\class Tasking::TaskAdapter
|
||||||
|
\inheaderfile solutions/tasking/tasktree.h
|
||||||
|
\inmodule TaskingSolution
|
||||||
|
\brief A class template for implementing custom task adapters.
|
||||||
|
|
||||||
|
The TaskAdapter class template is responsible for creating a task of the \c Task type,
|
||||||
|
starting it, and reporting success or an error when the task is finished.
|
||||||
|
It also associates the adapter with a given \c Task type.
|
||||||
|
|
||||||
|
Reimplement this class with the actual \c Task type to adapt the task's interface
|
||||||
|
into the general TaskTree's interface for managing the \c Task instances.
|
||||||
|
|
||||||
|
Each subclass needs to provide a public default constructor,
|
||||||
|
implement the start() method, and emit the done() signal when the task is finished.
|
||||||
|
Use task() to access the associated \c Task instance.
|
||||||
|
|
||||||
|
For more information on implementing the custom task adapters, refer to \l {Task Adapters}.
|
||||||
|
|
||||||
|
\sa start(), done(), task()
|
||||||
|
*/
|
||||||
|
|
||||||
|
/*!
|
||||||
|
\typealias TaskAdapter::Type
|
||||||
|
|
||||||
|
Type alias for the \c Task type.
|
||||||
|
*/
|
||||||
|
|
||||||
|
/*!
|
||||||
|
\fn template <typename Task> TaskAdapter<Task>::TaskAdapter<Task>()
|
||||||
|
|
||||||
|
Creates a task adapter for the given \c Task type. Internally, it creates
|
||||||
|
an instance of \c Task, which is accessible via the task() method.
|
||||||
|
|
||||||
|
\sa task()
|
||||||
|
*/
|
||||||
|
|
||||||
|
/*!
|
||||||
|
\fn template <typename Task> Task *TaskAdapter<Task>::task()
|
||||||
|
|
||||||
|
Returns the pointer to the associated \c Task instance.
|
||||||
|
*/
|
||||||
|
|
||||||
|
/*!
|
||||||
|
\fn template <typename Task> Task *TaskAdapter<Task>::task() const
|
||||||
|
\overload
|
||||||
|
|
||||||
|
Returns the const pointer to the associated \c Task instance.
|
||||||
|
*/
|
||||||
|
|
||||||
|
/*!
|
||||||
|
\macro TASKING_DECLARE_TASK(CustomTaskName, TaskAdapterClass)
|
||||||
|
\relates Tasking
|
||||||
|
|
||||||
|
Registers the new custom task type under a \a CustomTaskName name inside the
|
||||||
|
Tasking namespace for the passed \a TaskAdapterClass adapter class.
|
||||||
|
|
||||||
|
For more information on implementing the custom task adapters, refer to \l {Task Adapters}.
|
||||||
|
*/
|
||||||
|
|
||||||
|
/*!
|
||||||
|
\macro TASKING_DECLARE_TEMPLATE_TASK(CustomTaskName, TaskAdapterClass)
|
||||||
|
\relates Tasking
|
||||||
|
|
||||||
|
Registers the new custom task template type under a \a CustomTaskName name inside the
|
||||||
|
Tasking namespace for the passed \a TaskAdapterClass adapter class template.
|
||||||
|
|
||||||
|
For more information on implementing the custom task adapters, refer to \l {Task Adapters}.
|
||||||
|
*/
|
||||||
|
|
||||||
/*!
|
/*!
|
||||||
\class Tasking::GroupItem
|
\class Tasking::GroupItem
|
||||||
\inheaderfile solutions/tasking/tasktree.h
|
\inheaderfile solutions/tasking/tasktree.h
|
||||||
@@ -236,25 +337,27 @@ private:
|
|||||||
*/
|
*/
|
||||||
|
|
||||||
/*!
|
/*!
|
||||||
\enum Tasking::TaskAction
|
\enum Tasking::SetupResult
|
||||||
|
|
||||||
This enum is optionally returned from the group's or task's setup handler function.
|
This enum is optionally returned from the group's or task's setup handler function.
|
||||||
It instructs the running task tree on how to proceed after the setup handler's execution
|
It instructs the running task tree on how to proceed after the setup handler's execution
|
||||||
finished.
|
finished.
|
||||||
\value Continue
|
\value Continue
|
||||||
Default. The group's or task's execution continues nomally.
|
Default. The group's or task's execution continues normally.
|
||||||
When a group's or task's setup handler returns void, it's assumed that
|
When a group's or task's setup handler returns void, it's assumed that
|
||||||
it returned Continue.
|
it returned Continue.
|
||||||
\value StopWithDone
|
\value StopWithDone
|
||||||
The group's or task's execution stops immediately with success.
|
The group's or task's execution stops immediately with success.
|
||||||
When returned from the group's setup handler, all child tasks are skipped,
|
When returned from the group's setup handler, all child tasks are skipped,
|
||||||
and the group's onGroupDone() handler is invoked (if provided).
|
and the group's onGroupDone() handler is invoked (if provided).
|
||||||
|
The group reports success to its parent. The group's workflow policy is ignored.
|
||||||
When returned from the task's setup handler, the task isn't started,
|
When returned from the task's setup handler, the task isn't started,
|
||||||
its done handler isn't invoked, and the task reports success to its parent.
|
its done handler isn't invoked, and the task reports success to its parent.
|
||||||
\value StopWithError
|
\value StopWithError
|
||||||
The group's or task's execution stops immediately with an error.
|
The group's or task's execution stops immediately with an error.
|
||||||
When returned from the group's setup handler, all child tasks are skipped,
|
When returned from the group's setup handler, all child tasks are skipped,
|
||||||
and the group's onGroupError() handler is invoked (if provided).
|
and the group's onGroupError() handler is invoked (if provided).
|
||||||
|
The group reports an error to its parent. The group's workflow policy is ignored.
|
||||||
When returned from the task's setup handler, the task isn't started,
|
When returned from the task's setup handler, the task isn't started,
|
||||||
its error handler isn't invoked, and the task reports an error to its parent.
|
its error handler isn't invoked, and the task reports an error to its parent.
|
||||||
*/
|
*/
|
||||||
@@ -262,21 +365,21 @@ private:
|
|||||||
/*!
|
/*!
|
||||||
\typealias GroupItem::GroupSetupHandler
|
\typealias GroupItem::GroupSetupHandler
|
||||||
|
|
||||||
Type alias for \c std::function<TaskAction()>.
|
Type alias for \c std::function<SetupResult()>.
|
||||||
|
|
||||||
The GroupSetupHandler is used when constructing the onGroupSetup() element.
|
The GroupSetupHandler is used when constructing the onGroupSetup() element.
|
||||||
Any function with the above signature, when passed as a group setup handler,
|
Any function with the above signature, when passed as a group setup handler,
|
||||||
will be called by the running task tree when the group execution starts.
|
will be called by the running task tree when the group execution starts.
|
||||||
|
|
||||||
The return value of the handler instructs the running group on how to proceed
|
The return value of the handler instructs the running group on how to proceed
|
||||||
after the handler's invocation is finished. The default return value of TaskAction::Continue
|
after the handler's invocation is finished. The default return value of SetupResult::Continue
|
||||||
instructs the group to continue running, i.e. to start executing its child tasks.
|
instructs the group to continue running, i.e. to start executing its child tasks.
|
||||||
The return value of TaskAction::StopWithDone or TaskAction::StopWithError
|
The return value of SetupResult::StopWithDone or SetupResult::StopWithError
|
||||||
instructs the group to skip the child tasks' execution and finish immediately with
|
instructs the group to skip the child tasks' execution and finish immediately with
|
||||||
success or an error, respectively.
|
success or an error, respectively.
|
||||||
|
|
||||||
When the return type is either TaskAction::StopWithDone
|
When the return type is either SetupResult::StopWithDone
|
||||||
of TaskAction::StopWithError, the group's done or error handler (if provided)
|
of SetupResult::StopWithError, the group's done or error handler (if provided)
|
||||||
is called synchronously immediately afterwards.
|
is called synchronously immediately afterwards.
|
||||||
|
|
||||||
\note Even if the group setup handler returns StopWithDone or StopWithError,
|
\note Even if the group setup handler returns StopWithDone or StopWithError,
|
||||||
@@ -285,7 +388,7 @@ private:
|
|||||||
|
|
||||||
The onGroupSetup() accepts also functions in the shortened form of \c std::function<void()>,
|
The onGroupSetup() accepts also functions in the shortened form of \c std::function<void()>,
|
||||||
i.e. the return value is void. In this case it's assumed that the return value
|
i.e. the return value is void. In this case it's assumed that the return value
|
||||||
is TaskAction::Continue by default.
|
is SetupResult::Continue by default.
|
||||||
|
|
||||||
\sa onGroupSetup()
|
\sa onGroupSetup()
|
||||||
*/
|
*/
|
||||||
@@ -293,7 +396,7 @@ private:
|
|||||||
/*!
|
/*!
|
||||||
\typealias GroupItem::GroupEndHandler
|
\typealias GroupItem::GroupEndHandler
|
||||||
|
|
||||||
Type alias for \c std::function\<void()\>.
|
Type alias for \c std::function<void()>.
|
||||||
|
|
||||||
The GroupEndHandler is used when constructing the onGroupDone() and onGroupError() elements.
|
The GroupEndHandler is used when constructing the onGroupDone() and onGroupError() elements.
|
||||||
Any function with the above signature, when passed as a group done or error handler,
|
Any function with the above signature, when passed as a group done or error handler,
|
||||||
@@ -309,7 +412,7 @@ private:
|
|||||||
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<SetupResult()> or \c std::function<void()>
|
||||||
type. For more information on possible argument type, refer to
|
type. For more information on possible argument type, refer to
|
||||||
\l {GroupItem::GroupSetupHandler}.
|
\l {GroupItem::GroupSetupHandler}.
|
||||||
|
|
||||||
@@ -430,9 +533,9 @@ const GroupItem stopOnFinished = workflowPolicy(WorkflowPolicy::StopOnFinished);
|
|||||||
const GroupItem finishAllAndDone = workflowPolicy(WorkflowPolicy::FinishAllAndDone);
|
const GroupItem finishAllAndDone = workflowPolicy(WorkflowPolicy::FinishAllAndDone);
|
||||||
const GroupItem finishAllAndError = workflowPolicy(WorkflowPolicy::FinishAllAndError);
|
const GroupItem finishAllAndError = workflowPolicy(WorkflowPolicy::FinishAllAndError);
|
||||||
|
|
||||||
static TaskAction toTaskAction(bool success)
|
static SetupResult toSetupResult(bool success)
|
||||||
{
|
{
|
||||||
return success ? TaskAction::StopWithDone : TaskAction::StopWithError;
|
return success ? SetupResult::StopWithDone : SetupResult::StopWithError;
|
||||||
}
|
}
|
||||||
|
|
||||||
bool TreeStorageBase::isValid() const
|
bool TreeStorageBase::isValid() const
|
||||||
@@ -658,10 +761,10 @@ public:
|
|||||||
TaskContainer(TaskTreePrivate *taskTreePrivate, const GroupItem &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();
|
SetupResult start();
|
||||||
TaskAction continueStart(TaskAction startAction, int nextChild);
|
SetupResult continueStart(SetupResult startAction, int nextChild);
|
||||||
TaskAction startChildren(int nextChild);
|
SetupResult startChildren(int nextChild);
|
||||||
TaskAction childDone(bool success);
|
SetupResult childDone(bool success);
|
||||||
void stop();
|
void stop();
|
||||||
void invokeEndHandler();
|
void invokeEndHandler();
|
||||||
bool isRunning() const { return m_runtimeData.has_value(); }
|
bool isRunning() const { return m_runtimeData.has_value(); }
|
||||||
@@ -716,7 +819,7 @@ public:
|
|||||||
|
|
||||||
// If returned value != Continue, childDone() needs to be called in parent container (in caller)
|
// If returned value != Continue, childDone() needs to be called in parent container (in caller)
|
||||||
// in order to unwind properly.
|
// in order to unwind properly.
|
||||||
TaskAction start();
|
SetupResult start();
|
||||||
void stop();
|
void stop();
|
||||||
void invokeEndHandler(bool success);
|
void invokeEndHandler(bool success);
|
||||||
bool isRunning() const { return m_task || m_container.isRunning(); }
|
bool isRunning() const { return m_task || m_container.isRunning(); }
|
||||||
@@ -945,31 +1048,34 @@ int TaskContainer::RuntimeData::currentLimit() const
|
|||||||
? qMin(m_doneCount + m_constData.m_parallelLimit, childCount) : childCount;
|
? qMin(m_doneCount + m_constData.m_parallelLimit, childCount) : childCount;
|
||||||
}
|
}
|
||||||
|
|
||||||
TaskAction TaskContainer::start()
|
SetupResult TaskContainer::start()
|
||||||
{
|
{
|
||||||
QTC_CHECK(!isRunning());
|
QTC_CHECK(!isRunning());
|
||||||
m_runtimeData.emplace(m_constData);
|
m_runtimeData.emplace(m_constData);
|
||||||
|
|
||||||
TaskAction startAction = TaskAction::Continue;
|
SetupResult startAction = SetupResult::Continue;
|
||||||
if (m_constData.m_groupHandler.m_setupHandler) {
|
if (m_constData.m_groupHandler.m_setupHandler) {
|
||||||
startAction = invokeHandler(this, m_constData.m_groupHandler.m_setupHandler);
|
startAction = invokeHandler(this, m_constData.m_groupHandler.m_setupHandler);
|
||||||
if (startAction != TaskAction::Continue)
|
if (startAction != SetupResult::Continue) {
|
||||||
m_constData.m_taskTreePrivate->advanceProgress(m_constData.m_taskCount);
|
m_constData.m_taskTreePrivate->advanceProgress(m_constData.m_taskCount);
|
||||||
|
// Non-Continue SetupResult takes precedence over the workflow policy.
|
||||||
|
m_runtimeData->m_successBit = startAction == SetupResult::StopWithDone;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
if (startAction == TaskAction::Continue) {
|
if (startAction == SetupResult::Continue) {
|
||||||
if (m_constData.m_children.isEmpty())
|
if (m_constData.m_children.isEmpty())
|
||||||
startAction = toTaskAction(m_runtimeData->m_successBit);
|
startAction = toSetupResult(m_runtimeData->m_successBit);
|
||||||
}
|
}
|
||||||
return continueStart(startAction, 0);
|
return continueStart(startAction, 0);
|
||||||
}
|
}
|
||||||
|
|
||||||
TaskAction TaskContainer::continueStart(TaskAction startAction, int nextChild)
|
SetupResult TaskContainer::continueStart(SetupResult startAction, int nextChild)
|
||||||
{
|
{
|
||||||
const TaskAction groupAction = startAction == TaskAction::Continue ? startChildren(nextChild)
|
const SetupResult groupAction = startAction == SetupResult::Continue ? startChildren(nextChild)
|
||||||
: startAction;
|
: startAction;
|
||||||
QTC_CHECK(isRunning()); // TODO: superfluous
|
QTC_CHECK(isRunning()); // TODO: superfluous
|
||||||
if (groupAction != TaskAction::Continue) {
|
if (groupAction != SetupResult::Continue) {
|
||||||
const bool success = m_runtimeData->updateSuccessBit(groupAction == TaskAction::StopWithDone);
|
const bool success = m_runtimeData->updateSuccessBit(groupAction == SetupResult::StopWithDone);
|
||||||
invokeEndHandler();
|
invokeEndHandler();
|
||||||
if (TaskContainer *parentContainer = m_constData.m_parentContainer) {
|
if (TaskContainer *parentContainer = m_constData.m_parentContainer) {
|
||||||
QTC_CHECK(parentContainer->isRunning());
|
QTC_CHECK(parentContainer->isRunning());
|
||||||
@@ -984,7 +1090,7 @@ TaskAction TaskContainer::continueStart(TaskAction startAction, int nextChild)
|
|||||||
return groupAction;
|
return groupAction;
|
||||||
}
|
}
|
||||||
|
|
||||||
TaskAction TaskContainer::startChildren(int nextChild)
|
SetupResult TaskContainer::startChildren(int nextChild)
|
||||||
{
|
{
|
||||||
QTC_CHECK(isRunning());
|
QTC_CHECK(isRunning());
|
||||||
GuardLocker locker(m_runtimeData->m_startGuard);
|
GuardLocker locker(m_runtimeData->m_startGuard);
|
||||||
@@ -993,12 +1099,12 @@ TaskAction TaskContainer::startChildren(int nextChild)
|
|||||||
if (i >= limit)
|
if (i >= limit)
|
||||||
break;
|
break;
|
||||||
|
|
||||||
const TaskAction startAction = m_constData.m_children.at(i)->start();
|
const SetupResult startAction = m_constData.m_children.at(i)->start();
|
||||||
if (startAction == TaskAction::Continue)
|
if (startAction == SetupResult::Continue)
|
||||||
continue;
|
continue;
|
||||||
|
|
||||||
const TaskAction finalizeAction = childDone(startAction == TaskAction::StopWithDone);
|
const SetupResult finalizeAction = childDone(startAction == SetupResult::StopWithDone);
|
||||||
if (finalizeAction == TaskAction::Continue)
|
if (finalizeAction == SetupResult::Continue)
|
||||||
continue;
|
continue;
|
||||||
|
|
||||||
int skippedTaskCount = 0;
|
int skippedTaskCount = 0;
|
||||||
@@ -1008,10 +1114,10 @@ TaskAction TaskContainer::startChildren(int nextChild)
|
|||||||
m_constData.m_taskTreePrivate->advanceProgress(skippedTaskCount);
|
m_constData.m_taskTreePrivate->advanceProgress(skippedTaskCount);
|
||||||
return finalizeAction;
|
return finalizeAction;
|
||||||
}
|
}
|
||||||
return TaskAction::Continue;
|
return SetupResult::Continue;
|
||||||
}
|
}
|
||||||
|
|
||||||
TaskAction TaskContainer::childDone(bool success)
|
SetupResult TaskContainer::childDone(bool success)
|
||||||
{
|
{
|
||||||
QTC_CHECK(isRunning());
|
QTC_CHECK(isRunning());
|
||||||
const int limit = m_runtimeData->currentLimit(); // Read before bumping m_doneCount and stop()
|
const int limit = m_runtimeData->currentLimit(); // Read before bumping m_doneCount and stop()
|
||||||
@@ -1023,9 +1129,9 @@ TaskAction TaskContainer::childDone(bool success)
|
|||||||
|
|
||||||
++m_runtimeData->m_doneCount;
|
++m_runtimeData->m_doneCount;
|
||||||
const bool updatedSuccess = m_runtimeData->updateSuccessBit(success);
|
const bool updatedSuccess = m_runtimeData->updateSuccessBit(success);
|
||||||
const TaskAction startAction
|
const SetupResult startAction
|
||||||
= (shouldStop || m_runtimeData->m_doneCount == m_constData.m_children.size())
|
= (shouldStop || m_runtimeData->m_doneCount == m_constData.m_children.size())
|
||||||
? toTaskAction(updatedSuccess) : TaskAction::Continue;
|
? toSetupResult(updatedSuccess) : SetupResult::Continue;
|
||||||
|
|
||||||
if (isStarting())
|
if (isStarting())
|
||||||
return startAction;
|
return startAction;
|
||||||
@@ -1059,30 +1165,30 @@ void TaskContainer::invokeEndHandler()
|
|||||||
m_runtimeData.reset();
|
m_runtimeData.reset();
|
||||||
}
|
}
|
||||||
|
|
||||||
TaskAction TaskNode::start()
|
SetupResult TaskNode::start()
|
||||||
{
|
{
|
||||||
QTC_CHECK(!isRunning());
|
QTC_CHECK(!isRunning());
|
||||||
if (!isTask())
|
if (!isTask())
|
||||||
return m_container.start();
|
return m_container.start();
|
||||||
|
|
||||||
m_task.reset(m_taskHandler.m_createHandler());
|
m_task.reset(m_taskHandler.m_createHandler());
|
||||||
const TaskAction startAction = m_taskHandler.m_setupHandler
|
const SetupResult startAction = m_taskHandler.m_setupHandler
|
||||||
? invokeHandler(parentContainer(), m_taskHandler.m_setupHandler, *m_task.get())
|
? invokeHandler(parentContainer(), m_taskHandler.m_setupHandler, *m_task.get())
|
||||||
: TaskAction::Continue;
|
: SetupResult::Continue;
|
||||||
if (startAction != TaskAction::Continue) {
|
if (startAction != SetupResult::Continue) {
|
||||||
m_container.m_constData.m_taskTreePrivate->advanceProgress(1);
|
m_container.m_constData.m_taskTreePrivate->advanceProgress(1);
|
||||||
m_task.reset();
|
m_task.reset();
|
||||||
return startAction;
|
return startAction;
|
||||||
}
|
}
|
||||||
const std::shared_ptr<TaskAction> unwindAction
|
const std::shared_ptr<SetupResult> unwindAction
|
||||||
= std::make_shared<TaskAction>(TaskAction::Continue);
|
= std::make_shared<SetupResult>(SetupResult::Continue);
|
||||||
QObject::connect(m_task.get(), &TaskInterface::done, taskTree(), [=](bool success) {
|
QObject::connect(m_task.get(), &TaskInterface::done, taskTree(), [=](bool success) {
|
||||||
invokeEndHandler(success);
|
invokeEndHandler(success);
|
||||||
QObject::disconnect(m_task.get(), &TaskInterface::done, taskTree(), nullptr);
|
QObject::disconnect(m_task.get(), &TaskInterface::done, taskTree(), nullptr);
|
||||||
m_task.release()->deleteLater();
|
m_task.release()->deleteLater();
|
||||||
QTC_ASSERT(parentContainer() && parentContainer()->isRunning(), return);
|
QTC_ASSERT(parentContainer() && parentContainer()->isRunning(), return);
|
||||||
if (parentContainer()->isStarting())
|
if (parentContainer()->isStarting())
|
||||||
*unwindAction = toTaskAction(success);
|
*unwindAction = toSetupResult(success);
|
||||||
else
|
else
|
||||||
parentContainer()->childDone(success);
|
parentContainer()->childDone(success);
|
||||||
});
|
});
|
||||||
@@ -1321,18 +1427,18 @@ void TaskNode::invokeEndHandler(bool success)
|
|||||||
as the task tree calls it when needed. The setup handler is optional. When used,
|
as the task tree calls it when needed. The setup handler is optional. When used,
|
||||||
it must be the first argument of the task's constructor.
|
it must be the first argument of the task's constructor.
|
||||||
|
|
||||||
Optionally, the setup handler may return a TaskAction. The returned
|
Optionally, the setup handler may return a SetupResult. The returned
|
||||||
TaskAction influences the further start behavior of a given task. The
|
SetupResult influences the further start behavior of a given task. The
|
||||||
possible values are:
|
possible values are:
|
||||||
|
|
||||||
\table
|
\table
|
||||||
\header
|
\header
|
||||||
\li TaskAction Value
|
\li SetupResult Value
|
||||||
\li Brief Description
|
\li Brief Description
|
||||||
\row
|
\row
|
||||||
\li Continue
|
\li Continue
|
||||||
\li The task will be started normally. This is the default behavior when the
|
\li The task will be started normally. This is the default behavior when the
|
||||||
setup handler doesn't return TaskAction (that is, its return type is
|
setup handler doesn't return SetupResult (that is, its return type is
|
||||||
void).
|
void).
|
||||||
\row
|
\row
|
||||||
\li StopWithDone
|
\li StopWithDone
|
||||||
@@ -1404,12 +1510,12 @@ void TaskNode::invokeEndHandler(bool success)
|
|||||||
handler. If you add more than one onGroupSetup() element to a group, an assert
|
handler. If you add more than one onGroupSetup() element to a group, an assert
|
||||||
is triggered at runtime that includes an error message.
|
is triggered at runtime that includes an error message.
|
||||||
|
|
||||||
Like the task's start handler, the group start handler may return TaskAction.
|
Like the task's start handler, the group start handler may return SetupResult.
|
||||||
The returned TaskAction value affects the start behavior of the
|
The returned SetupResult value affects the start behavior of the
|
||||||
whole group. If you do not specify a group start handler or its return type
|
whole group. If you do not specify a group start handler or its return type
|
||||||
is void, the default group's action is TaskAction::Continue, so that all
|
is void, the default group's action is SetupResult::Continue, so that all
|
||||||
tasks are started normally. Otherwise, when the start handler returns
|
tasks are started normally. Otherwise, when the start handler returns
|
||||||
TaskAction::StopWithDone or TaskAction::StopWithError, the tasks are not
|
SetupResult::StopWithDone or SetupResult::StopWithError, the tasks are not
|
||||||
started (they are skipped) and the group itself reports success or failure,
|
started (they are skipped) and the group itself reports success or failure,
|
||||||
depending on the returned value, respectively.
|
depending on the returned value, respectively.
|
||||||
|
|
||||||
@@ -1417,15 +1523,15 @@ void TaskNode::invokeEndHandler(bool success)
|
|||||||
const Group root {
|
const Group root {
|
||||||
onGroupSetup([] { qDebug() << "Root setup"; }),
|
onGroupSetup([] { qDebug() << "Root setup"; }),
|
||||||
Group {
|
Group {
|
||||||
onGroupSetup([] { qDebug() << "Group 1 setup"; return TaskAction::Continue; }),
|
onGroupSetup([] { qDebug() << "Group 1 setup"; return SetupResult::Continue; }),
|
||||||
ProcessTask(...) // Process 1
|
ProcessTask(...) // Process 1
|
||||||
},
|
},
|
||||||
Group {
|
Group {
|
||||||
onGroupSetup([] { qDebug() << "Group 2 setup"; return TaskAction::StopWithDone; }),
|
onGroupSetup([] { qDebug() << "Group 2 setup"; return SetupResult::StopWithDone; }),
|
||||||
ProcessTask(...) // Process 2
|
ProcessTask(...) // Process 2
|
||||||
},
|
},
|
||||||
Group {
|
Group {
|
||||||
onGroupSetup([] { qDebug() << "Group 3 setup"; return TaskAction::StopWithError; }),
|
onGroupSetup([] { qDebug() << "Group 3 setup"; return SetupResult::StopWithError; }),
|
||||||
ProcessTask(...) // Process 3
|
ProcessTask(...) // Process 3
|
||||||
},
|
},
|
||||||
ProcessTask(...) // Process 4
|
ProcessTask(...) // Process 4
|
||||||
@@ -1441,7 +1547,7 @@ void TaskNode::invokeEndHandler(bool success)
|
|||||||
\li Comment
|
\li Comment
|
||||||
\row
|
\row
|
||||||
\li Root Group starts
|
\li Root Group starts
|
||||||
\li Doesn't return TaskAction, so its tasks are executed.
|
\li Doesn't return SetupResult, so its tasks are executed.
|
||||||
\row
|
\row
|
||||||
\li Group 1 starts
|
\li Group 1 starts
|
||||||
\li Returns Continue, so its tasks are executed.
|
\li Returns Continue, so its tasks are executed.
|
||||||
@@ -1833,7 +1939,7 @@ void TaskTree::setRecipe(const Group &recipe)
|
|||||||
Otherwise, the task tree is started.
|
Otherwise, the task tree is started.
|
||||||
|
|
||||||
The started task tree may finish synchronously,
|
The started task tree may finish synchronously,
|
||||||
for example when the main group's start handler returns TaskAction::StopWithError.
|
for example when the main group's start handler returns SetupResult::StopWithError.
|
||||||
For this reason, the connections to the done and errorOccurred signals should be
|
For this reason, the connections to the done and errorOccurred signals should be
|
||||||
established before calling start. Use isRunning() in order to detect whether
|
established before calling start. Use isRunning() in order to detect whether
|
||||||
the task tree is still running after a call to start().
|
the task tree is still running after a call to start().
|
||||||
|
|||||||
@@ -26,12 +26,14 @@ class TASKING_EXPORT TaskInterface : public QObject
|
|||||||
{
|
{
|
||||||
Q_OBJECT
|
Q_OBJECT
|
||||||
|
|
||||||
public:
|
|
||||||
TaskInterface() = default;
|
|
||||||
virtual void start() = 0;
|
|
||||||
|
|
||||||
signals:
|
signals:
|
||||||
void done(bool success);
|
void done(bool success);
|
||||||
|
|
||||||
|
private:
|
||||||
|
template <typename Task> friend class TaskAdapter;
|
||||||
|
friend class TaskNode;
|
||||||
|
TaskInterface() = default;
|
||||||
|
virtual void start() = 0;
|
||||||
};
|
};
|
||||||
|
|
||||||
class TASKING_EXPORT TreeStorageBase
|
class TASKING_EXPORT TreeStorageBase
|
||||||
@@ -115,13 +117,13 @@ enum class WorkflowPolicy {
|
|||||||
};
|
};
|
||||||
Q_ENUM_NS(WorkflowPolicy);
|
Q_ENUM_NS(WorkflowPolicy);
|
||||||
|
|
||||||
enum class TaskAction
|
enum class SetupResult
|
||||||
{
|
{
|
||||||
Continue,
|
Continue,
|
||||||
StopWithDone,
|
StopWithDone,
|
||||||
StopWithError
|
StopWithError
|
||||||
};
|
};
|
||||||
Q_ENUM_NS(TaskAction);
|
Q_ENUM_NS(SetupResult);
|
||||||
|
|
||||||
class TASKING_EXPORT GroupItem
|
class TASKING_EXPORT GroupItem
|
||||||
{
|
{
|
||||||
@@ -129,11 +131,11 @@ public:
|
|||||||
// Internal, provided by QTC_DECLARE_CUSTOM_TASK
|
// Internal, provided by QTC_DECLARE_CUSTOM_TASK
|
||||||
using TaskCreateHandler = std::function<TaskInterface *(void)>;
|
using TaskCreateHandler = std::function<TaskInterface *(void)>;
|
||||||
// Called prior to task start, just after createHandler
|
// Called prior to task start, just after createHandler
|
||||||
using TaskSetupHandler = std::function<TaskAction(TaskInterface &)>;
|
using TaskSetupHandler = std::function<SetupResult(TaskInterface &)>;
|
||||||
// Called on task done / error
|
// Called on task done / error
|
||||||
using TaskEndHandler = std::function<void(const TaskInterface &)>;
|
using TaskEndHandler = std::function<void(const TaskInterface &)>;
|
||||||
// Called when group entered
|
// Called when group entered
|
||||||
using GroupSetupHandler = std::function<TaskAction()>;
|
using GroupSetupHandler = std::function<SetupResult()>;
|
||||||
// Called when group done / error
|
// Called when group done / error
|
||||||
using GroupEndHandler = std::function<void()>;
|
using GroupEndHandler = std::function<void()>;
|
||||||
|
|
||||||
@@ -228,17 +230,17 @@ private:
|
|||||||
static GroupSetupHandler wrapGroupSetup(SetupHandler &&handler)
|
static GroupSetupHandler wrapGroupSetup(SetupHandler &&handler)
|
||||||
{
|
{
|
||||||
static constexpr bool isDynamic
|
static constexpr bool isDynamic
|
||||||
= std::is_same_v<TaskAction, std::invoke_result_t<std::decay_t<SetupHandler>>>;
|
= std::is_same_v<SetupResult, std::invoke_result_t<std::decay_t<SetupHandler>>>;
|
||||||
constexpr bool isVoid
|
constexpr bool isVoid
|
||||||
= std::is_same_v<void, std::invoke_result_t<std::decay_t<SetupHandler>>>;
|
= std::is_same_v<void, std::invoke_result_t<std::decay_t<SetupHandler>>>;
|
||||||
static_assert(isDynamic || isVoid,
|
static_assert(isDynamic || isVoid,
|
||||||
"Group setup handler needs to take no arguments and has to return "
|
"Group setup handler needs to take no arguments and has to return "
|
||||||
"void or TaskAction. The passed handler doesn't fulfill these requirements.");
|
"void or SetupResult. The passed handler doesn't fulfill these requirements.");
|
||||||
return [=] {
|
return [=] {
|
||||||
if constexpr (isDynamic)
|
if constexpr (isDynamic)
|
||||||
return std::invoke(handler);
|
return std::invoke(handler);
|
||||||
std::invoke(handler);
|
std::invoke(handler);
|
||||||
return TaskAction::Continue;
|
return SetupResult::Continue;
|
||||||
};
|
};
|
||||||
};
|
};
|
||||||
};
|
};
|
||||||
@@ -290,22 +292,24 @@ private:
|
|||||||
static_assert(isBool || isVoid,
|
static_assert(isBool || isVoid,
|
||||||
"Sync element: The synchronous function has to return void or bool.");
|
"Sync element: The synchronous function has to return void or bool.");
|
||||||
if constexpr (isBool) {
|
if constexpr (isBool) {
|
||||||
return {onGroupSetup([function] { return function() ? TaskAction::StopWithDone
|
return {onGroupSetup([function] { return function() ? SetupResult::StopWithDone
|
||||||
: TaskAction::StopWithError; })};
|
: SetupResult::StopWithError; })};
|
||||||
}
|
}
|
||||||
return {onGroupSetup([function] { function(); return TaskAction::StopWithDone; })};
|
return {onGroupSetup([function] { function(); return SetupResult::StopWithDone; })};
|
||||||
};
|
};
|
||||||
};
|
};
|
||||||
|
|
||||||
template <typename Task>
|
template <typename Task>
|
||||||
class TaskAdapter : public TaskInterface
|
class TaskAdapter : public TaskInterface
|
||||||
{
|
{
|
||||||
public:
|
protected:
|
||||||
using Type = Task;
|
using Type = Task;
|
||||||
TaskAdapter() = default;
|
TaskAdapter() = default;
|
||||||
Task *task() { return &m_task; }
|
Task *task() { return &m_task; }
|
||||||
const Task *task() const { return &m_task; }
|
const Task *task() const { return &m_task; }
|
||||||
|
|
||||||
private:
|
private:
|
||||||
|
template <typename Adapter> friend class CustomTask;
|
||||||
Task m_task;
|
Task m_task;
|
||||||
};
|
};
|
||||||
|
|
||||||
@@ -344,19 +348,19 @@ public:
|
|||||||
private:
|
private:
|
||||||
template<typename SetupFunction>
|
template<typename SetupFunction>
|
||||||
static GroupItem::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<SetupResult,
|
||||||
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,
|
||||||
std::invoke_result_t<std::decay_t<SetupFunction>, typename Adapter::Type &>>;
|
std::invoke_result_t<std::decay_t<SetupFunction>, typename Adapter::Type &>>;
|
||||||
static_assert(isDynamic || isVoid,
|
static_assert(isDynamic || isVoid,
|
||||||
"Task setup handler needs to take (Task &) as an argument and has to return "
|
"Task setup handler needs to take (Task &) as an argument and has to return "
|
||||||
"void or TaskAction. The passed handler doesn't fulfill these requirements.");
|
"void or SetupResult. The passed handler doesn't fulfill these requirements.");
|
||||||
return [=](TaskInterface &taskInterface) {
|
return [=](TaskInterface &taskInterface) {
|
||||||
Adapter &adapter = static_cast<Adapter &>(taskInterface);
|
Adapter &adapter = static_cast<Adapter &>(taskInterface);
|
||||||
if constexpr (isDynamic)
|
if constexpr (isDynamic)
|
||||||
return std::invoke(function, *adapter.task());
|
return std::invoke(function, *adapter.task());
|
||||||
std::invoke(function, *adapter.task());
|
std::invoke(function, *adapter.task());
|
||||||
return TaskAction::Continue;
|
return SetupResult::Continue;
|
||||||
};
|
};
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|||||||
@@ -1474,8 +1474,13 @@ void BoolAspect::addToLayout(Layouting::LayoutItem &parent)
|
|||||||
d->m_button = createSubWidget<QCheckBox>();
|
d->m_button = createSubWidget<QCheckBox>();
|
||||||
}
|
}
|
||||||
switch (d->m_labelPlacement) {
|
switch (d->m_labelPlacement) {
|
||||||
|
case LabelPlacement::AtCheckBoxWithoutDummyLabel:
|
||||||
|
d->m_button->setText(labelText());
|
||||||
|
parent.addItem(d->m_button.data());
|
||||||
|
break;
|
||||||
case LabelPlacement::AtCheckBox:
|
case LabelPlacement::AtCheckBox:
|
||||||
d->m_button->setText(labelText());
|
d->m_button->setText(labelText());
|
||||||
|
parent.addItem(empty());
|
||||||
parent.addItem(d->m_button.data());
|
parent.addItem(d->m_button.data());
|
||||||
break;
|
break;
|
||||||
case LabelPlacement::InExtraLabel:
|
case LabelPlacement::InExtraLabel:
|
||||||
|
|||||||
@@ -237,7 +237,7 @@ public:
|
|||||||
bool defaultValue() const;
|
bool defaultValue() const;
|
||||||
void setDefaultValue(bool val);
|
void setDefaultValue(bool val);
|
||||||
|
|
||||||
enum class LabelPlacement { AtCheckBox, InExtraLabel };
|
enum class LabelPlacement { AtCheckBox, AtCheckBoxWithoutDummyLabel, InExtraLabel };
|
||||||
void setLabel(const QString &labelText,
|
void setLabel(const QString &labelText,
|
||||||
LabelPlacement labelPlacement = LabelPlacement::InExtraLabel);
|
LabelPlacement labelPlacement = LabelPlacement::InExtraLabel);
|
||||||
void setLabelPlacement(LabelPlacement labelPlacement);
|
void setLabelPlacement(LabelPlacement labelPlacement);
|
||||||
|
|||||||
@@ -1444,16 +1444,15 @@ CommandLine CommandLine::fromUserInput(const QString &cmdline, MacroExpander *ex
|
|||||||
|
|
||||||
QString input = cmdline.trimmed();
|
QString input = cmdline.trimmed();
|
||||||
|
|
||||||
QStringList result = ProcessArgs::splitArgs(cmdline, HostOsInfo::hostOs());
|
if (expander)
|
||||||
|
input = expander->expand(input);
|
||||||
|
|
||||||
|
const QStringList result = ProcessArgs::splitArgs(input, HostOsInfo::hostOs());
|
||||||
|
|
||||||
if (result.isEmpty())
|
if (result.isEmpty())
|
||||||
return {};
|
return {};
|
||||||
|
|
||||||
auto cmd = CommandLine(FilePath::fromUserInput(result.value(0)), result.mid(1));
|
return {FilePath::fromUserInput(result.value(0)), result.mid(1)};
|
||||||
if (expander)
|
|
||||||
cmd.m_arguments = expander->expand(cmd.m_arguments);
|
|
||||||
|
|
||||||
return cmd;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void CommandLine::addArg(const QString &arg)
|
void CommandLine::addArg(const QString &arg)
|
||||||
|
|||||||
@@ -229,6 +229,7 @@ struct ResultItem
|
|||||||
int space = -1;
|
int space = -1;
|
||||||
int stretch = -1;
|
int stretch = -1;
|
||||||
int span = 1;
|
int span = 1;
|
||||||
|
bool empty = false;
|
||||||
};
|
};
|
||||||
|
|
||||||
struct Slice
|
struct Slice
|
||||||
@@ -287,6 +288,8 @@ static void addItemToBoxLayout(QBoxLayout *layout, const ResultItem &item)
|
|||||||
layout->addSpacing(item.space);
|
layout->addSpacing(item.space);
|
||||||
} else if (!item.text.isEmpty()) {
|
} else if (!item.text.isEmpty()) {
|
||||||
layout->addWidget(createLabel(item.text));
|
layout->addWidget(createLabel(item.text));
|
||||||
|
} else if (item.empty) {
|
||||||
|
// Nothing to do, but no reason to warn, either.
|
||||||
} else {
|
} else {
|
||||||
QTC_CHECK(false);
|
QTC_CHECK(false);
|
||||||
}
|
}
|
||||||
@@ -654,8 +657,8 @@ LayoutItem empty()
|
|||||||
LayoutItem item;
|
LayoutItem item;
|
||||||
item.onAdd = [](LayoutBuilder &builder) {
|
item.onAdd = [](LayoutBuilder &builder) {
|
||||||
ResultItem ri;
|
ResultItem ri;
|
||||||
ri.span = 1;
|
ri.empty = true;
|
||||||
builder.stack.last().pendingItems.append(ResultItem());
|
builder.stack.last().pendingItems.append(ri);
|
||||||
};
|
};
|
||||||
return item;
|
return item;
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -91,7 +91,7 @@ static CreateAvdInfo createAvdCommand(const AndroidConfig &config, const CreateA
|
|||||||
proc.setCommand(avdManager);
|
proc.setCommand(avdManager);
|
||||||
proc.start();
|
proc.start();
|
||||||
if (!proc.waitForStarted()) {
|
if (!proc.waitForStarted()) {
|
||||||
result.error = Tr::tr("Could not start process \"%1\"").arg(avdManager.toUserOutput());
|
result.error = Tr::tr("Could not start process \"%1\".").arg(avdManager.toUserOutput());
|
||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
QTC_CHECK(proc.isRunning());
|
QTC_CHECK(proc.isRunning());
|
||||||
|
|||||||
@@ -389,7 +389,7 @@ FilePath AndroidQmlPreviewWorker::createQmlrcFile(const FilePath &workFolder,
|
|||||||
rccProcess.setCommand({rccBinary, args});
|
rccProcess.setCommand({rccBinary, args});
|
||||||
rccProcess.start();
|
rccProcess.start();
|
||||||
if (!rccProcess.waitForStarted()) {
|
if (!rccProcess.waitForStarted()) {
|
||||||
appendMessage(Tr::tr("Could not create file for %1 \"%2\"").
|
appendMessage(Tr::tr("Could not create file for %1 \"%2\".").
|
||||||
arg(apkInfo()->name, rccProcess.commandLine().toUserOutput()),
|
arg(apkInfo()->name, rccProcess.commandLine().toUserOutput()),
|
||||||
StdErrFormat);
|
StdErrFormat);
|
||||||
qrcPath.removeFile();
|
qrcPath.removeFile();
|
||||||
@@ -400,7 +400,7 @@ FilePath AndroidQmlPreviewWorker::createQmlrcFile(const FilePath &workFolder,
|
|||||||
if (!rccProcess.readDataFromProcess(&stdOut, &stdErr)) {
|
if (!rccProcess.readDataFromProcess(&stdOut, &stdErr)) {
|
||||||
rccProcess.stop();
|
rccProcess.stop();
|
||||||
rccProcess.waitForFinished();
|
rccProcess.waitForFinished();
|
||||||
appendMessage(Tr::tr("A timeout occurred running \"%1\"").
|
appendMessage(Tr::tr("A timeout occurred running \"%1\".").
|
||||||
arg(rccProcess.commandLine().toUserOutput()), StdErrFormat);
|
arg(rccProcess.commandLine().toUserOutput()), StdErrFormat);
|
||||||
qrcPath.removeFile();
|
qrcPath.removeFile();
|
||||||
return {};
|
return {};
|
||||||
@@ -412,7 +412,7 @@ FilePath AndroidQmlPreviewWorker::createQmlrcFile(const FilePath &workFolder,
|
|||||||
appendMessage(QString::fromLocal8Bit(stdErr), StdErrFormat);
|
appendMessage(QString::fromLocal8Bit(stdErr), StdErrFormat);
|
||||||
|
|
||||||
if (rccProcess.exitStatus() != QProcess::NormalExit) {
|
if (rccProcess.exitStatus() != QProcess::NormalExit) {
|
||||||
appendMessage(Tr::tr("Crash while creating file for %1 \"%2\"").
|
appendMessage(Tr::tr("Crash while creating file for %1 \"%2\".").
|
||||||
arg(apkInfo()->name, rccProcess.commandLine().toUserOutput()),
|
arg(apkInfo()->name, rccProcess.commandLine().toUserOutput()),
|
||||||
StdErrFormat);
|
StdErrFormat);
|
||||||
qrcPath.removeFile();
|
qrcPath.removeFile();
|
||||||
|
|||||||
@@ -158,20 +158,20 @@ void AndroidSdkDownloader::downloadAndExtractSdk()
|
|||||||
m_progressDialog->setRange(0, 0);
|
m_progressDialog->setRange(0, 0);
|
||||||
m_progressDialog->setLabelText(Tr::tr("Unarchiving SDK Tools package..."));
|
m_progressDialog->setLabelText(Tr::tr("Unarchiving SDK Tools package..."));
|
||||||
if (!*storage)
|
if (!*storage)
|
||||||
return TaskAction::StopWithError;
|
return SetupResult::StopWithError;
|
||||||
const FilePath sdkFileName = **storage;
|
const FilePath sdkFileName = **storage;
|
||||||
if (!verifyFileIntegrity(sdkFileName, m_androidConfig.getSdkToolsSha256())) {
|
if (!verifyFileIntegrity(sdkFileName, m_androidConfig.getSdkToolsSha256())) {
|
||||||
logError(Tr::tr("Verifying the integrity of the downloaded file has failed."));
|
logError(Tr::tr("Verifying the integrity of the downloaded file has failed."));
|
||||||
return TaskAction::StopWithError;
|
return SetupResult::StopWithError;
|
||||||
}
|
}
|
||||||
const auto sourceAndCommand = Unarchiver::sourceAndCommand(sdkFileName);
|
const auto sourceAndCommand = Unarchiver::sourceAndCommand(sdkFileName);
|
||||||
if (!sourceAndCommand) {
|
if (!sourceAndCommand) {
|
||||||
logError(sourceAndCommand.error());
|
logError(sourceAndCommand.error());
|
||||||
return TaskAction::StopWithError;
|
return SetupResult::StopWithError;
|
||||||
}
|
}
|
||||||
unarchiver.setSourceAndCommand(*sourceAndCommand);
|
unarchiver.setSourceAndCommand(*sourceAndCommand);
|
||||||
unarchiver.setDestDir(sdkFileName.parentDir());
|
unarchiver.setDestDir(sdkFileName.parentDir());
|
||||||
return TaskAction::Continue;
|
return SetupResult::Continue;
|
||||||
};
|
};
|
||||||
const auto onUnarchiverDone = [this, storage](const Unarchiver &) {
|
const auto onUnarchiverDone = [this, storage](const Unarchiver &) {
|
||||||
m_androidConfig.setTemporarySdkToolsPath(
|
m_androidConfig.setTemporarySdkToolsPath(
|
||||||
|
|||||||
@@ -102,8 +102,13 @@ QStringList BoostTestConfiguration::argumentsForTestRunner(QStringList *omitted)
|
|||||||
arguments << "--detect_memory_leaks=0";
|
arguments << "--detect_memory_leaks=0";
|
||||||
|
|
||||||
// TODO improve the test case gathering and arguments building to avoid too long command lines
|
// TODO improve the test case gathering and arguments building to avoid too long command lines
|
||||||
for (const QString &test : testCases())
|
if (isDebugRunMode()) { // debugger has its own quoting
|
||||||
arguments << "-t" << test;
|
for (const QString &test : testCases())
|
||||||
|
arguments << "-t" << test;
|
||||||
|
} else {
|
||||||
|
for (const QString &test : testCases())
|
||||||
|
arguments << "-t" << "\"" + test + "\"";
|
||||||
|
}
|
||||||
|
|
||||||
if (TestSettings::instance()->processArgs()) {
|
if (TestSettings::instance()->processArgs()) {
|
||||||
arguments << filterInterfering(runnable().command.arguments().split(
|
arguments << filterInterfering(runnable().command.arguments().split(
|
||||||
|
|||||||
@@ -31,12 +31,6 @@ BoostTestOutputReader::BoostTestOutputReader(Process *testApplication,
|
|||||||
, m_logLevel(log)
|
, m_logLevel(log)
|
||||||
, m_reportLevel(report)
|
, m_reportLevel(report)
|
||||||
{
|
{
|
||||||
if (!testApplication)
|
|
||||||
return;
|
|
||||||
|
|
||||||
connect(testApplication, &Process::done, this, [this, testApplication] {
|
|
||||||
onDone(testApplication->exitCode());
|
|
||||||
});
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// content of "error:..." / "info:..." / ... messages
|
// content of "error:..." / "info:..." / ... messages
|
||||||
@@ -147,7 +141,7 @@ void BoostTestOutputReader::handleMessageMatch(const QRegularExpressionMatch &ma
|
|||||||
if (m_currentTest != match.captured(11) && m_currentTest.isEmpty())
|
if (m_currentTest != match.captured(11) && m_currentTest.isEmpty())
|
||||||
m_currentTest = match.captured(11);
|
m_currentTest = match.captured(11);
|
||||||
m_result = ResultType::TestEnd;
|
m_result = ResultType::TestEnd;
|
||||||
m_description = Tr::tr("Test execution took %1").arg(match.captured(12));
|
m_description = Tr::tr("Test execution took %1.").arg(match.captured(12));
|
||||||
} else if (type == "suite") {
|
} else if (type == "suite") {
|
||||||
if (!m_currentSuite.isEmpty()) {
|
if (!m_currentSuite.isEmpty()) {
|
||||||
int index = m_currentSuite.lastIndexOf('/');
|
int index = m_currentSuite.lastIndexOf('/');
|
||||||
@@ -163,7 +157,7 @@ void BoostTestOutputReader::handleMessageMatch(const QRegularExpressionMatch &ma
|
|||||||
}
|
}
|
||||||
m_currentTest.clear();
|
m_currentTest.clear();
|
||||||
m_result = ResultType::TestEnd;
|
m_result = ResultType::TestEnd;
|
||||||
m_description = Tr::tr("Test suite execution took %1").arg(match.captured(12));
|
m_description = Tr::tr("Test suite execution took %1.").arg(match.captured(12));
|
||||||
}
|
}
|
||||||
} else if (content.startsWith("Test case ")) {
|
} else if (content.startsWith("Test case ")) {
|
||||||
m_currentTest = match.captured(4);
|
m_currentTest = match.captured(4);
|
||||||
@@ -247,7 +241,7 @@ void BoostTestOutputReader::processOutputLine(const QByteArray &outputLine)
|
|||||||
} else {
|
} else {
|
||||||
QTC_CHECK(m_currentModule == match.captured(3));
|
QTC_CHECK(m_currentModule == match.captured(3));
|
||||||
BoostTestResult result(id(), m_currentModule, m_projectFile);
|
BoostTestResult result(id(), m_currentModule, m_projectFile);
|
||||||
result.setDescription(Tr::tr("Test module execution took %1").arg(match.captured(4)));
|
result.setDescription(Tr::tr("Test module execution took %1.").arg(match.captured(4)));
|
||||||
result.setResult(ResultType::TestEnd);
|
result.setResult(ResultType::TestEnd);
|
||||||
reportResult(result);
|
reportResult(result);
|
||||||
|
|
||||||
@@ -394,17 +388,17 @@ void BoostTestOutputReader::onDone(int exitCode)
|
|||||||
if (m_logLevel == LogLevel::Nothing && m_reportLevel == ReportLevel::No) {
|
if (m_logLevel == LogLevel::Nothing && m_reportLevel == ReportLevel::No) {
|
||||||
switch (exitCode) {
|
switch (exitCode) {
|
||||||
case 0:
|
case 0:
|
||||||
reportNoOutputFinish(Tr::tr("Running tests exited with %1").arg("boost::exit_success."),
|
reportNoOutputFinish(Tr::tr("Running tests exited with %1.").arg("boost::exit_success"),
|
||||||
ResultType::Pass);
|
ResultType::Pass);
|
||||||
break;
|
break;
|
||||||
case 200:
|
case 200:
|
||||||
reportNoOutputFinish(
|
reportNoOutputFinish(
|
||||||
Tr::tr("Running tests exited with %1").arg("boost::exit_test_exception."),
|
Tr::tr("Running tests exited with %1.").arg("boost::exit_test_exception"),
|
||||||
ResultType::MessageFatal);
|
ResultType::MessageFatal);
|
||||||
break;
|
break;
|
||||||
case 201:
|
case 201:
|
||||||
reportNoOutputFinish(Tr::tr("Running tests exited with %1")
|
reportNoOutputFinish(Tr::tr("Running tests exited with %1.")
|
||||||
.arg("boost::exit_test_failure."), ResultType::Fail);
|
.arg("boost::exit_test_failure"), ResultType::Fail);
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
} else if (exitCode != 0 && exitCode != 201 && !m_description.isEmpty()) {
|
} else if (exitCode != 0 && exitCode != 201 && !m_description.isEmpty()) {
|
||||||
|
|||||||
@@ -23,7 +23,7 @@ protected:
|
|||||||
TestResult createDefaultResult() const override;
|
TestResult createDefaultResult() const override;
|
||||||
|
|
||||||
private:
|
private:
|
||||||
void onDone(int exitCode);
|
void onDone(int exitCode) override;
|
||||||
void sendCompleteInformation();
|
void sendCompleteInformation();
|
||||||
void handleMessageMatch(const QRegularExpressionMatch &match);
|
void handleMessageMatch(const QRegularExpressionMatch &match);
|
||||||
void reportNoOutputFinish(const QString &description, ResultType type);
|
void reportNoOutputFinish(const QString &description, ResultType type);
|
||||||
|
|||||||
@@ -90,7 +90,7 @@ void CTestOutputReader::processOutputLine(const QByteArray &outputLine)
|
|||||||
m_project = match.captured(1);
|
m_project = match.captured(1);
|
||||||
TestResult testResult = createDefaultResult();
|
TestResult testResult = createDefaultResult();
|
||||||
testResult.setResult(ResultType::TestStart);
|
testResult.setResult(ResultType::TestStart);
|
||||||
testResult.setDescription(Tr::tr("Running tests for %1").arg(m_project));
|
testResult.setDescription(Tr::tr("Running tests for \"%1\".").arg(m_project));
|
||||||
reportResult(testResult);
|
reportResult(testResult);
|
||||||
} else if (ExactMatch match = testCase1.match(line)) {
|
} else if (ExactMatch match = testCase1.match(line)) {
|
||||||
int current = match.captured("current").toInt();
|
int current = match.captured("current").toInt();
|
||||||
|
|||||||
@@ -23,18 +23,6 @@ GTestOutputReader::GTestOutputReader(Process *testApplication,
|
|||||||
: TestOutputReader(testApplication, buildDirectory)
|
: TestOutputReader(testApplication, buildDirectory)
|
||||||
, m_projectFile(projectFile)
|
, m_projectFile(projectFile)
|
||||||
{
|
{
|
||||||
if (testApplication) {
|
|
||||||
connect(testApplication, &Process::done, this, [this, testApplication] {
|
|
||||||
const int exitCode = testApplication->exitCode();
|
|
||||||
if (exitCode == 1 && !m_description.isEmpty()) {
|
|
||||||
createAndReportResult(Tr::tr("Running tests failed.\n %1\nExecutable: %2")
|
|
||||||
.arg(m_description).arg(id()), ResultType::MessageFatal);
|
|
||||||
}
|
|
||||||
// on Windows abort() will result in normal termination, but exit code will be set to 3
|
|
||||||
if (HostOsInfo::isWindowsHost() && exitCode == 3)
|
|
||||||
reportCrash();
|
|
||||||
});
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void GTestOutputReader::processOutputLine(const QByteArray &outputLine)
|
void GTestOutputReader::processOutputLine(const QByteArray &outputLine)
|
||||||
@@ -81,7 +69,7 @@ void GTestOutputReader::processOutputLine(const QByteArray &outputLine)
|
|||||||
if (ExactMatch match = testEnds.match(line)) {
|
if (ExactMatch match = testEnds.match(line)) {
|
||||||
TestResult testResult = createDefaultResult();
|
TestResult testResult = createDefaultResult();
|
||||||
testResult.setResult(ResultType::TestEnd);
|
testResult.setResult(ResultType::TestEnd);
|
||||||
testResult.setDescription(Tr::tr("Test execution took %1").arg(match.captured(2)));
|
testResult.setDescription(Tr::tr("Test execution took %1.").arg(match.captured(2)));
|
||||||
reportResult(testResult);
|
reportResult(testResult);
|
||||||
m_currentTestSuite.clear();
|
m_currentTestSuite.clear();
|
||||||
m_currentTestCase.clear();
|
m_currentTestCase.clear();
|
||||||
@@ -182,6 +170,17 @@ TestResult GTestOutputReader::createDefaultResult() const
|
|||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void GTestOutputReader::onDone(int exitCode)
|
||||||
|
{
|
||||||
|
if (exitCode == 1 && !m_description.isEmpty()) {
|
||||||
|
createAndReportResult(Tr::tr("Running tests failed.\n %1\nExecutable: %2")
|
||||||
|
.arg(m_description).arg(id()), ResultType::MessageFatal);
|
||||||
|
}
|
||||||
|
// on Windows abort() will result in normal termination, but exit code will be set to 3
|
||||||
|
if (HostOsInfo::isWindowsHost() && exitCode == 3)
|
||||||
|
reportCrash();
|
||||||
|
}
|
||||||
|
|
||||||
void GTestOutputReader::setCurrentTestCase(const QString &testCase)
|
void GTestOutputReader::setCurrentTestCase(const QString &testCase)
|
||||||
{
|
{
|
||||||
m_currentTestCase = testCase;
|
m_currentTestCase = testCase;
|
||||||
|
|||||||
@@ -19,6 +19,7 @@ protected:
|
|||||||
TestResult createDefaultResult() const override;
|
TestResult createDefaultResult() const override;
|
||||||
|
|
||||||
private:
|
private:
|
||||||
|
void onDone(int exitCode) override;
|
||||||
void setCurrentTestCase(const QString &testCase);
|
void setCurrentTestCase(const QString &testCase);
|
||||||
void setCurrentTestSuite(const QString &testSuite);
|
void setCurrentTestSuite(const QString &testSuite);
|
||||||
void handleDescriptionAndReportResult(const TestResult &testResult);
|
void handleDescriptionAndReportResult(const TestResult &testResult);
|
||||||
|
|||||||
@@ -28,6 +28,8 @@ public:
|
|||||||
void setId(const QString &id) { m_id = id; }
|
void setId(const QString &id) { m_id = id; }
|
||||||
QString id() const { return m_id; }
|
QString id() const { return m_id; }
|
||||||
|
|
||||||
|
virtual void onDone(int exitCode) { Q_UNUSED(exitCode) }
|
||||||
|
|
||||||
void resetCommandlineColor();
|
void resetCommandlineColor();
|
||||||
signals:
|
signals:
|
||||||
void newResult(const TestResult &result);
|
void newResult(const TestResult &result);
|
||||||
|
|||||||
@@ -355,13 +355,13 @@ void TestRunner::runTestsHelper()
|
|||||||
|
|
||||||
const auto onSetup = [this, config] {
|
const auto onSetup = [this, config] {
|
||||||
if (!config->project())
|
if (!config->project())
|
||||||
return TaskAction::StopWithDone;
|
return SetupResult::StopWithDone;
|
||||||
if (config->testExecutable().isEmpty()) {
|
if (config->testExecutable().isEmpty()) {
|
||||||
reportResult(ResultType::MessageFatal,
|
reportResult(ResultType::MessageFatal,
|
||||||
Tr::tr("Executable path is empty. (%1)").arg(config->displayName()));
|
Tr::tr("Executable path is empty. (%1)").arg(config->displayName()));
|
||||||
return TaskAction::StopWithDone;
|
return SetupResult::StopWithDone;
|
||||||
}
|
}
|
||||||
return TaskAction::Continue;
|
return SetupResult::Continue;
|
||||||
};
|
};
|
||||||
const auto onProcessSetup = [this, config, storage](Process &process) {
|
const auto onProcessSetup = [this, config, storage](Process &process) {
|
||||||
TestStorage *testStorage = storage.activeStorage();
|
TestStorage *testStorage = storage.activeStorage();
|
||||||
@@ -419,6 +419,9 @@ void TestRunner::runTestsHelper()
|
|||||||
+ processInformation(&process) + rcInfo(config));
|
+ processInformation(&process) + rcInfo(config));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (testStorage->m_outputReader)
|
||||||
|
testStorage->m_outputReader->onDone(process.exitCode());
|
||||||
|
|
||||||
if (process.exitStatus() == QProcess::CrashExit) {
|
if (process.exitStatus() == QProcess::CrashExit) {
|
||||||
if (testStorage->m_outputReader)
|
if (testStorage->m_outputReader)
|
||||||
testStorage->m_outputReader->reportCrash();
|
testStorage->m_outputReader->reportCrash();
|
||||||
|
|||||||
@@ -11,6 +11,7 @@
|
|||||||
#include <utils/utilsicons.h>
|
#include <utils/utilsicons.h>
|
||||||
|
|
||||||
#include <QFormLayout>
|
#include <QFormLayout>
|
||||||
|
#include <QGridLayout>
|
||||||
#include <QLabel>
|
#include <QLabel>
|
||||||
#include <QScrollArea>
|
#include <QScrollArea>
|
||||||
#include <QStackedWidget>
|
#include <QStackedWidget>
|
||||||
@@ -28,7 +29,8 @@ public:
|
|||||||
private:
|
private:
|
||||||
QLabel *m_project = nullptr;
|
QLabel *m_project = nullptr;
|
||||||
QLabel *m_loc = nullptr;
|
QLabel *m_loc = nullptr;
|
||||||
QFormLayout *m_formLayout = nullptr;
|
QLabel *m_timestamp = nullptr;
|
||||||
|
QGridLayout *m_gridLayout = nullptr;
|
||||||
};
|
};
|
||||||
|
|
||||||
DashboardWidget::DashboardWidget(QWidget *parent)
|
DashboardWidget::DashboardWidget(QWidget *parent)
|
||||||
@@ -41,58 +43,98 @@ DashboardWidget::DashboardWidget(QWidget *parent)
|
|||||||
projectLayout->addRow(Tr::tr("Project:"), m_project);
|
projectLayout->addRow(Tr::tr("Project:"), m_project);
|
||||||
m_loc = new QLabel(this);
|
m_loc = new QLabel(this);
|
||||||
projectLayout->addRow(Tr::tr("Lines of code:"), m_loc);
|
projectLayout->addRow(Tr::tr("Lines of code:"), m_loc);
|
||||||
|
m_timestamp = new QLabel(this);
|
||||||
|
projectLayout->addRow(Tr::tr("Analysis timestamp:"), m_timestamp);
|
||||||
layout->addLayout(projectLayout);
|
layout->addLayout(projectLayout);
|
||||||
m_formLayout = new QFormLayout;
|
layout->addSpacing(10);
|
||||||
layout->addLayout(m_formLayout);
|
auto row = new QHBoxLayout;
|
||||||
|
m_gridLayout = new QGridLayout;
|
||||||
|
row->addLayout(m_gridLayout);
|
||||||
|
row->addStretch(1);
|
||||||
|
layout->addLayout(row);
|
||||||
|
layout->addStretch(1);
|
||||||
setWidget(widget);
|
setWidget(widget);
|
||||||
setVerticalScrollBarPolicy(Qt::ScrollBarAsNeeded);
|
setVerticalScrollBarPolicy(Qt::ScrollBarAsNeeded);
|
||||||
setWidgetResizable(true);
|
setWidgetResizable(true);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static QPixmap trendIcon(int added, int removed)
|
||||||
|
{
|
||||||
|
static const QPixmap unchanged = Utils::Icons::NEXT.pixmap();
|
||||||
|
static const QPixmap increased = Utils::Icon(
|
||||||
|
{ {":/utils/images/arrowup.png", Utils::Theme::IconsErrorColor} }).pixmap();
|
||||||
|
static const QPixmap decreased = Utils::Icon(
|
||||||
|
{ {":/utils/images/arrowdown.png", Utils::Theme::IconsRunColor} }).pixmap();
|
||||||
|
if (added == removed)
|
||||||
|
return unchanged;
|
||||||
|
return added < removed ? decreased : increased;
|
||||||
|
}
|
||||||
|
|
||||||
void DashboardWidget::updateUi()
|
void DashboardWidget::updateUi()
|
||||||
{
|
{
|
||||||
const ProjectInfo &info = AxivionPlugin::projectInfo();
|
const ProjectInfo &info = AxivionPlugin::projectInfo();
|
||||||
m_project->setText(info.name);
|
m_project->setText(info.name);
|
||||||
m_loc->setText({});
|
m_loc->setText({});
|
||||||
while (m_formLayout->rowCount())
|
m_timestamp->setText({});
|
||||||
m_formLayout->removeRow(0);
|
QLayoutItem *child;
|
||||||
|
while ((child = m_gridLayout->takeAt(0)) != nullptr) {
|
||||||
|
delete child->widget();
|
||||||
|
delete child;
|
||||||
|
}
|
||||||
|
|
||||||
if (info.versions.isEmpty())
|
if (info.versions.isEmpty())
|
||||||
return;
|
return;
|
||||||
|
|
||||||
const ResultVersion &last = info.versions.last();
|
const ResultVersion &last = info.versions.last();
|
||||||
m_loc->setText(QString::number(last.linesOfCode));
|
m_loc->setText(QString::number(last.linesOfCode));
|
||||||
|
const QDateTime timeStamp = QDateTime::fromString(last.timeStamp, Qt::ISODate);
|
||||||
|
m_timestamp->setText(timeStamp.isValid() ? timeStamp.toString("yyyy-MM-dd HH::mm::ss")
|
||||||
|
: Tr::tr("unknown"));
|
||||||
|
|
||||||
const QString tmpl("%1 %2 +%3 / -%4");
|
|
||||||
auto apply = [&tmpl](int t, int a, int r){
|
|
||||||
QChar tr = (a == r ? '=' : (a < r ? '^' : 'v'));
|
|
||||||
return tmpl.arg(t, 10, 10, QLatin1Char(' ')).arg(tr).arg(a, 5, 10, QLatin1Char(' '))
|
|
||||||
.arg(r, 5, 10, QLatin1Char(' '));
|
|
||||||
};
|
|
||||||
const QList<IssueKind> &issueKinds = info.issueKinds;
|
const QList<IssueKind> &issueKinds = info.issueKinds;
|
||||||
auto toolTip = [issueKinds](const QString &prefix){
|
auto toolTip = [issueKinds](const QString &prefix){
|
||||||
for (const IssueKind &kind : issueKinds) {
|
for (const IssueKind &kind : issueKinds) {
|
||||||
if (kind.prefix == prefix)
|
if (kind.prefix == prefix)
|
||||||
return kind.nicePlural;
|
return kind.nicePlural;
|
||||||
}
|
}
|
||||||
return QString();
|
return prefix;
|
||||||
};
|
};
|
||||||
int allTotal = 0, allAdded = 0, allRemoved = 0;
|
auto addValuesWidgets = [this, &toolTip](const IssueCount &issueCount, int row){
|
||||||
|
const QString currentToolTip = toolTip(issueCount.issueKind);
|
||||||
|
QLabel *label = new QLabel(issueCount.issueKind, this);
|
||||||
|
label->setToolTip(currentToolTip);
|
||||||
|
m_gridLayout->addWidget(label, row, 0);
|
||||||
|
label = new QLabel(QString::number(issueCount.total), this);
|
||||||
|
label->setToolTip(currentToolTip);
|
||||||
|
label->setAlignment(Qt::AlignRight);
|
||||||
|
m_gridLayout->addWidget(label, row, 1);
|
||||||
|
label = new QLabel(this);
|
||||||
|
label->setPixmap(trendIcon(issueCount.added, issueCount.removed));
|
||||||
|
label->setToolTip(currentToolTip);
|
||||||
|
m_gridLayout->addWidget(label, row, 2);
|
||||||
|
label = new QLabel('+' + QString::number(issueCount.added));
|
||||||
|
label->setAlignment(Qt::AlignRight);
|
||||||
|
label->setToolTip(currentToolTip);
|
||||||
|
m_gridLayout->addWidget(label, row, 3);
|
||||||
|
label = new QLabel("/");
|
||||||
|
label->setToolTip(currentToolTip);
|
||||||
|
m_gridLayout->addWidget(label, row, 4);
|
||||||
|
label = new QLabel('-' + QString::number(issueCount.removed));
|
||||||
|
label->setAlignment(Qt::AlignRight);
|
||||||
|
label->setToolTip(currentToolTip);
|
||||||
|
m_gridLayout->addWidget(label, row, 5);
|
||||||
|
};
|
||||||
|
int allTotal = 0, allAdded = 0, allRemoved = 0, row = 0;
|
||||||
for (auto issueCount : std::as_const(last.issueCounts)) {
|
for (auto issueCount : std::as_const(last.issueCounts)) {
|
||||||
allTotal += issueCount.total;
|
allTotal += issueCount.total;
|
||||||
allAdded += issueCount.added;
|
allAdded += issueCount.added;
|
||||||
allRemoved += issueCount.removed;
|
allRemoved += issueCount.removed;
|
||||||
const QString txt = apply(issueCount.total, issueCount.added, issueCount.removed);
|
addValuesWidgets(issueCount, row);
|
||||||
const QString currentToolTip = toolTip(issueCount.issueKind);
|
++row;
|
||||||
QLabel *label = new QLabel(issueCount.issueKind, this);
|
|
||||||
label->setToolTip(currentToolTip);
|
|
||||||
QLabel *values = new QLabel(txt, this);
|
|
||||||
values->setToolTip(currentToolTip);
|
|
||||||
m_formLayout->addRow(label, values);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
QLabel *label = new QLabel(apply(allTotal, allAdded, allRemoved), this);
|
const IssueCount total{{}, Tr::tr("Total:"), allTotal, allAdded, allRemoved};
|
||||||
m_formLayout->addRow(Tr::tr("Total:"), label);
|
addValuesWidgets(total, row);
|
||||||
}
|
}
|
||||||
|
|
||||||
AxivionOutputPane::AxivionOutputPane(QObject *parent)
|
AxivionOutputPane::AxivionOutputPane(QObject *parent)
|
||||||
|
|||||||
@@ -43,7 +43,7 @@ Group QdbStopApplicationStep::deployRecipe()
|
|||||||
const auto device = DeviceKitAspect::device(target()->kit());
|
const auto device = DeviceKitAspect::device(target()->kit());
|
||||||
if (!device) {
|
if (!device) {
|
||||||
addErrorMessage(Tr::tr("No device to stop the application on."));
|
addErrorMessage(Tr::tr("No device to stop the application on."));
|
||||||
return TaskAction::StopWithError;
|
return SetupResult::StopWithError;
|
||||||
}
|
}
|
||||||
QTC_CHECK(device);
|
QTC_CHECK(device);
|
||||||
process.setCommand({device->filePath(Constants::AppcontrollerFilepath), {"--stop"}});
|
process.setCommand({device->filePath(Constants::AppcontrollerFilepath), {"--stop"}});
|
||||||
@@ -52,7 +52,7 @@ Group QdbStopApplicationStep::deployRecipe()
|
|||||||
connect(proc, &Process::readyReadStandardOutput, this, [this, proc] {
|
connect(proc, &Process::readyReadStandardOutput, this, [this, proc] {
|
||||||
handleStdOutData(proc->readAllStandardOutput());
|
handleStdOutData(proc->readAllStandardOutput());
|
||||||
});
|
});
|
||||||
return TaskAction::Continue;
|
return SetupResult::Continue;
|
||||||
};
|
};
|
||||||
const auto doneHandler = [this](const Process &) {
|
const auto doneHandler = [this](const Process &) {
|
||||||
addProgressMessage(Tr::tr("Stopped the running application."));
|
addProgressMessage(Tr::tr("Stopped the running application."));
|
||||||
|
|||||||
@@ -128,23 +128,23 @@ GroupItem clangToolTask(const AnalyzeInputData &input,
|
|||||||
|
|
||||||
const auto onSetup = [=] {
|
const auto onSetup = [=] {
|
||||||
if (setupHandler && !setupHandler())
|
if (setupHandler && !setupHandler())
|
||||||
return TaskAction::StopWithError;
|
return SetupResult::StopWithError;
|
||||||
|
|
||||||
ClangToolStorage *data = storage.activeStorage();
|
ClangToolStorage *data = storage.activeStorage();
|
||||||
data->name = clangToolName(input.tool);
|
data->name = clangToolName(input.tool);
|
||||||
data->executable = toolExecutable(input.tool);
|
data->executable = toolExecutable(input.tool);
|
||||||
if (!data->executable.isExecutableFile()) {
|
if (!data->executable.isExecutableFile()) {
|
||||||
qWarning() << "Can't start:" << data->executable << "as" << data->name;
|
qWarning() << "Can't start:" << data->executable << "as" << data->name;
|
||||||
return TaskAction::StopWithError;
|
return SetupResult::StopWithError;
|
||||||
}
|
}
|
||||||
|
|
||||||
QTC_CHECK(!input.unit.arguments.contains(QLatin1String("-o")));
|
QTC_CHECK(!input.unit.arguments.contains(QLatin1String("-o")));
|
||||||
QTC_CHECK(!input.unit.arguments.contains(input.unit.file.nativePath()));
|
QTC_CHECK(!input.unit.arguments.contains(input.unit.file.nativePath()));
|
||||||
QTC_ASSERT(input.unit.file.exists(), return TaskAction::StopWithError);
|
QTC_ASSERT(input.unit.file.exists(), return SetupResult::StopWithError);
|
||||||
data->outputFilePath = createOutputFilePath(input.outputDirPath, input.unit.file);
|
data->outputFilePath = createOutputFilePath(input.outputDirPath, input.unit.file);
|
||||||
QTC_ASSERT(!data->outputFilePath.isEmpty(), return TaskAction::StopWithError);
|
QTC_ASSERT(!data->outputFilePath.isEmpty(), return SetupResult::StopWithError);
|
||||||
|
|
||||||
return TaskAction::Continue;
|
return SetupResult::Continue;
|
||||||
};
|
};
|
||||||
const auto onProcessSetup = [=](Process &process) {
|
const auto onProcessSetup = [=](Process &process) {
|
||||||
process.setEnvironment(input.environment);
|
process.setEnvironment(input.environment);
|
||||||
|
|||||||
@@ -12,6 +12,10 @@
|
|||||||
#include "cmakeprojectmanagertr.h"
|
#include "cmakeprojectmanagertr.h"
|
||||||
#include "cmaketool.h"
|
#include "cmaketool.h"
|
||||||
|
|
||||||
|
#include <android/androidconstants.h>
|
||||||
|
|
||||||
|
#include <ios/iosconstants.h>
|
||||||
|
|
||||||
#include <coreplugin/find/itemviewfind.h>
|
#include <coreplugin/find/itemviewfind.h>
|
||||||
#include <projectexplorer/buildsteplist.h>
|
#include <projectexplorer/buildsteplist.h>
|
||||||
#include <projectexplorer/devicesupport/idevice.h>
|
#include <projectexplorer/devicesupport/idevice.h>
|
||||||
@@ -173,13 +177,15 @@ static QString initialStagingDir(Kit *kit)
|
|||||||
return QString::fromUtf8("/tmp/Qt-Creator-staging-" + ba);
|
return QString::fromUtf8("/tmp/Qt-Creator-staging-" + ba);
|
||||||
}
|
}
|
||||||
|
|
||||||
static bool buildAndRunOnSameDevice(Kit *kit)
|
static bool supportsStageForInstallation(const Kit *kit)
|
||||||
{
|
{
|
||||||
IDeviceConstPtr runDevice = DeviceKitAspect::device(kit);
|
IDeviceConstPtr runDevice = DeviceKitAspect::device(kit);
|
||||||
IDeviceConstPtr buildDevice = BuildDeviceKitAspect::device(kit);
|
IDeviceConstPtr buildDevice = BuildDeviceKitAspect::device(kit);
|
||||||
QTC_ASSERT(runDevice, return false);
|
QTC_ASSERT(runDevice, return false);
|
||||||
QTC_ASSERT(buildDevice, return false);
|
QTC_ASSERT(buildDevice, return false);
|
||||||
return runDevice->id() == buildDevice->id();
|
return runDevice->id() != buildDevice->id()
|
||||||
|
&& runDevice->type() != Android::Constants::ANDROID_DEVICE_TYPE
|
||||||
|
&& runDevice->type() != Ios::Constants::IOS_DEVICE_TYPE;
|
||||||
}
|
}
|
||||||
|
|
||||||
CMakeBuildStep::CMakeBuildStep(BuildStepList *bsl, Id id) :
|
CMakeBuildStep::CMakeBuildStep(BuildStepList *bsl, Id id) :
|
||||||
@@ -198,7 +204,7 @@ CMakeBuildStep::CMakeBuildStep(BuildStepList *bsl, Id id) :
|
|||||||
m_useStaging = addAspect<BoolAspect>();
|
m_useStaging = addAspect<BoolAspect>();
|
||||||
m_useStaging->setSettingsKey(USE_STAGING_KEY);
|
m_useStaging->setSettingsKey(USE_STAGING_KEY);
|
||||||
m_useStaging->setLabel(Tr::tr("Stage for installation"), BoolAspect::LabelPlacement::AtCheckBox);
|
m_useStaging->setLabel(Tr::tr("Stage for installation"), BoolAspect::LabelPlacement::AtCheckBox);
|
||||||
m_useStaging->setDefaultValue(!buildAndRunOnSameDevice(kit()));
|
m_useStaging->setDefaultValue(supportsStageForInstallation(kit()));
|
||||||
|
|
||||||
m_stagingDir = addAspect<FilePathAspect>();
|
m_stagingDir = addAspect<FilePathAspect>();
|
||||||
m_stagingDir->setSettingsKey(STAGING_DIR_KEY);
|
m_stagingDir->setSettingsKey(STAGING_DIR_KEY);
|
||||||
|
|||||||
@@ -30,6 +30,8 @@ AuthWidget::AuthWidget(QWidget *parent)
|
|||||||
m_progressIndicator->setVisible(false);
|
m_progressIndicator->setVisible(false);
|
||||||
m_statusLabel = new QLabel();
|
m_statusLabel = new QLabel();
|
||||||
m_statusLabel->setVisible(false);
|
m_statusLabel->setVisible(false);
|
||||||
|
m_statusLabel->setTextInteractionFlags(Qt::TextInteractionFlag::TextSelectableByMouse
|
||||||
|
| Qt::TextInteractionFlag::TextSelectableByKeyboard);
|
||||||
|
|
||||||
// clang-format off
|
// clang-format off
|
||||||
Column {
|
Column {
|
||||||
|
|||||||
@@ -12,6 +12,8 @@ const char COPILOT_TOGGLE[] = "Copilot.Toggle";
|
|||||||
const char COPILOT_ENABLE[] = "Copilot.Enable";
|
const char COPILOT_ENABLE[] = "Copilot.Enable";
|
||||||
const char COPILOT_DISABLE[] = "Copilot.Disable";
|
const char COPILOT_DISABLE[] = "Copilot.Disable";
|
||||||
const char COPILOT_REQUEST_SUGGESTION[] = "Copilot.RequestSuggestion";
|
const char COPILOT_REQUEST_SUGGESTION[] = "Copilot.RequestSuggestion";
|
||||||
|
const char COPILOT_NEXT_SUGGESTION[] = "Copilot.NextSuggestion";
|
||||||
|
const char COPILOT_PREVIOUS_SUGGESTION[] = "Copilot.PreviousSuggestion";
|
||||||
|
|
||||||
const char COPILOT_GENERAL_OPTIONS_ID[] = "Copilot.General";
|
const char COPILOT_GENERAL_OPTIONS_ID[] = "Copilot.General";
|
||||||
const char COPILOT_GENERAL_OPTIONS_CATEGORY[] = "ZY.Copilot";
|
const char COPILOT_GENERAL_OPTIONS_CATEGORY[] = "ZY.Copilot";
|
||||||
|
|||||||
@@ -41,16 +41,15 @@ public:
|
|||||||
});
|
});
|
||||||
|
|
||||||
// clang-format off
|
// clang-format off
|
||||||
helpLabel->setText(Tr::tr(R"(
|
helpLabel->setText(Tr::tr(
|
||||||
The Copilot plugin requires node.js and the Copilot neovim plugin.
|
"The Copilot plugin requires node.js and the Copilot neovim plugin. "
|
||||||
If you install the neovim plugin as described in the
|
"If you install the neovim plugin as described in %1, "
|
||||||
[README.md](https://github.com/github/copilot.vim),
|
"the plugin will find the agent.js file automatically.\n\n"
|
||||||
the plugin will find the agent.js file automatically.
|
"Otherwise you need to specify the path to the %2 "
|
||||||
|
"file from the Copilot neovim plugin.",
|
||||||
Otherwise you need to specify the path to the
|
"Markdown text for the copilot instruction label").arg(
|
||||||
[agent.js](https://github.com/github/copilot.vim/tree/release/copilot/dist)
|
"[README.md](https://github.com/github/copilot.vim)",
|
||||||
file from the Copilot neovim plugin.
|
"[agent.js](https://github.com/github/copilot.vim/tree/release/copilot/dist)"));
|
||||||
)", "Markdown text for the copilot instruction label"));
|
|
||||||
|
|
||||||
Column {
|
Column {
|
||||||
authWidget, br,
|
authWidget, br,
|
||||||
|
|||||||
@@ -9,6 +9,7 @@
|
|||||||
#include "copilotoptionspage.h"
|
#include "copilotoptionspage.h"
|
||||||
#include "copilotprojectpanel.h"
|
#include "copilotprojectpanel.h"
|
||||||
#include "copilotsettings.h"
|
#include "copilotsettings.h"
|
||||||
|
#include "copilotsuggestion.h"
|
||||||
#include "copilottr.h"
|
#include "copilottr.h"
|
||||||
|
|
||||||
#include <coreplugin/actionmanager/actionmanager.h>
|
#include <coreplugin/actionmanager/actionmanager.h>
|
||||||
@@ -20,6 +21,7 @@
|
|||||||
|
|
||||||
#include <projectexplorer/projectpanelfactory.h>
|
#include <projectexplorer/projectpanelfactory.h>
|
||||||
|
|
||||||
|
#include <texteditor/textdocumentlayout.h>
|
||||||
#include <texteditor/texteditor.h>
|
#include <texteditor/texteditor.h>
|
||||||
|
|
||||||
#include <QAction>
|
#include <QAction>
|
||||||
@@ -32,6 +34,28 @@ using namespace ProjectExplorer;
|
|||||||
namespace Copilot {
|
namespace Copilot {
|
||||||
namespace Internal {
|
namespace Internal {
|
||||||
|
|
||||||
|
enum Direction { Previous, Next };
|
||||||
|
void cycleSuggestion(TextEditor::TextEditorWidget *editor, Direction direction)
|
||||||
|
{
|
||||||
|
QTextBlock block = editor->textCursor().block();
|
||||||
|
if (auto *suggestion = dynamic_cast<CopilotSuggestion *>(
|
||||||
|
TextEditor::TextDocumentLayout::suggestion(block))) {
|
||||||
|
int index = suggestion->currentCompletion();
|
||||||
|
if (direction == Previous)
|
||||||
|
--index;
|
||||||
|
else
|
||||||
|
++index;
|
||||||
|
if (index < 0)
|
||||||
|
index = suggestion->completions().count() - 1;
|
||||||
|
else if (index >= suggestion->completions().count())
|
||||||
|
index = 0;
|
||||||
|
suggestion->reset();
|
||||||
|
editor->insertSuggestion(std::make_unique<CopilotSuggestion>(suggestion->completions(),
|
||||||
|
editor->document(),
|
||||||
|
index));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
void CopilotPlugin::initialize()
|
void CopilotPlugin::initialize()
|
||||||
{
|
{
|
||||||
CopilotSettings::instance().readSettings(ICore::settings());
|
CopilotSettings::instance().readSettings(ICore::settings());
|
||||||
@@ -57,6 +81,30 @@ void CopilotPlugin::initialize()
|
|||||||
|
|
||||||
ActionManager::registerAction(requestAction, Constants::COPILOT_REQUEST_SUGGESTION);
|
ActionManager::registerAction(requestAction, Constants::COPILOT_REQUEST_SUGGESTION);
|
||||||
|
|
||||||
|
QAction *nextSuggestionAction = new QAction(this);
|
||||||
|
nextSuggestionAction->setText(Tr::tr("Show next Copilot Suggestion"));
|
||||||
|
nextSuggestionAction->setToolTip(Tr::tr(
|
||||||
|
"Cycles through the received Copilot Suggestions showing the next available Suggestion."));
|
||||||
|
|
||||||
|
connect(nextSuggestionAction, &QAction::triggered, this, [] {
|
||||||
|
if (auto editor = TextEditor::TextEditorWidget::currentTextEditorWidget())
|
||||||
|
cycleSuggestion(editor, Next);
|
||||||
|
});
|
||||||
|
|
||||||
|
ActionManager::registerAction(nextSuggestionAction, Constants::COPILOT_NEXT_SUGGESTION);
|
||||||
|
|
||||||
|
QAction *previousSuggestionAction = new QAction(this);
|
||||||
|
previousSuggestionAction->setText(Tr::tr("Show previos Copilot Suggestion"));
|
||||||
|
previousSuggestionAction->setToolTip(Tr::tr("Cycles through the received Copilot Suggestions "
|
||||||
|
"showing the previous available Suggestion."));
|
||||||
|
|
||||||
|
connect(previousSuggestionAction, &QAction::triggered, this, [] {
|
||||||
|
if (auto editor = TextEditor::TextEditorWidget::currentTextEditorWidget())
|
||||||
|
cycleSuggestion(editor, Previous);
|
||||||
|
});
|
||||||
|
|
||||||
|
ActionManager::registerAction(previousSuggestionAction, Constants::COPILOT_PREVIOUS_SUGGESTION);
|
||||||
|
|
||||||
QAction *disableAction = new QAction(this);
|
QAction *disableAction = new QAction(this);
|
||||||
disableAction->setText(Tr::tr("Disable Copilot"));
|
disableAction->setText(Tr::tr("Disable Copilot"));
|
||||||
disableAction->setToolTip(Tr::tr("Disable Copilot."));
|
disableAction->setToolTip(Tr::tr("Disable Copilot."));
|
||||||
|
|||||||
@@ -190,11 +190,11 @@ LocatorMatcherTasks ActionsFilter::matchers()
|
|||||||
collectEntriesForCommands();
|
collectEntriesForCommands();
|
||||||
if (storage->input().simplified().isEmpty()) {
|
if (storage->input().simplified().isEmpty()) {
|
||||||
storage->reportOutput(m_entries);
|
storage->reportOutput(m_entries);
|
||||||
return TaskAction::StopWithDone;
|
return SetupResult::StopWithDone;
|
||||||
}
|
}
|
||||||
async.setFutureSynchronizer(ExtensionSystem::PluginManager::futureSynchronizer());
|
async.setFutureSynchronizer(ExtensionSystem::PluginManager::futureSynchronizer());
|
||||||
async.setConcurrentCallData(matches, *storage, m_entries);
|
async.setConcurrentCallData(matches, *storage, m_entries);
|
||||||
return TaskAction::Continue;
|
return SetupResult::Continue;
|
||||||
};
|
};
|
||||||
|
|
||||||
return {{AsyncTask<void>(onSetup), storage}};
|
return {{AsyncTask<void>(onSetup), storage}};
|
||||||
|
|||||||
@@ -82,9 +82,9 @@ DirectoryFilter::DirectoryFilter(Id id)
|
|||||||
using namespace Tasking;
|
using namespace Tasking;
|
||||||
const auto groupSetup = [this] {
|
const auto groupSetup = [this] {
|
||||||
if (!m_directories.isEmpty())
|
if (!m_directories.isEmpty())
|
||||||
return TaskAction::Continue; // Async task will run
|
return SetupResult::Continue; // Async task will run
|
||||||
m_cache.setFilePaths({});
|
m_cache.setFilePaths({});
|
||||||
return TaskAction::StopWithDone; // Group stops, skips async task
|
return SetupResult::StopWithDone; // Group stops, skips async task
|
||||||
};
|
};
|
||||||
const auto asyncSetup = [this](Async<FilePaths> &async) {
|
const auto asyncSetup = [this](Async<FilePaths> &async) {
|
||||||
async.setConcurrentCallData(&refresh, m_directories, m_filters, m_exclusionFilters,
|
async.setConcurrentCallData(&refresh, m_directories, m_filters, m_exclusionFilters,
|
||||||
|
|||||||
@@ -1503,16 +1503,16 @@ LocatorMatcherTask LocatorFileCache::matcher() const
|
|||||||
const auto onSetup = [storage, weak](Async<LocatorFileCachePrivate> &async) {
|
const auto onSetup = [storage, weak](Async<LocatorFileCachePrivate> &async) {
|
||||||
auto that = weak.lock();
|
auto that = weak.lock();
|
||||||
if (!that) // LocatorMatcher is running after *this LocatorFileCache was destructed.
|
if (!that) // LocatorMatcher is running after *this LocatorFileCache was destructed.
|
||||||
return TaskAction::StopWithDone;
|
return SetupResult::StopWithDone;
|
||||||
|
|
||||||
if (!that->ensureValidated())
|
if (!that->ensureValidated())
|
||||||
return TaskAction::StopWithDone; // The cache is invalid and
|
return SetupResult::StopWithDone; // The cache is invalid and
|
||||||
// no provider is set or it returned empty generator
|
// no provider is set or it returned empty generator
|
||||||
that->bumpExecutionId();
|
that->bumpExecutionId();
|
||||||
|
|
||||||
async.setFutureSynchronizer(ExtensionSystem::PluginManager::futureSynchronizer());
|
async.setFutureSynchronizer(ExtensionSystem::PluginManager::futureSynchronizer());
|
||||||
async.setConcurrentCallData(&filter, *storage, *that);
|
async.setConcurrentCallData(&filter, *storage, *that);
|
||||||
return TaskAction::Continue;
|
return SetupResult::Continue;
|
||||||
};
|
};
|
||||||
const auto onDone = [weak](const Async<LocatorFileCachePrivate> &async) {
|
const auto onDone = [weak](const Async<LocatorFileCachePrivate> &async) {
|
||||||
auto that = weak.lock();
|
auto that = weak.lock();
|
||||||
|
|||||||
@@ -372,7 +372,7 @@ LocatorMatcherTasks JavaScriptFilter::matchers()
|
|||||||
|
|
||||||
const auto onSetup = [storage, engine] {
|
const auto onSetup = [storage, engine] {
|
||||||
if (!engine)
|
if (!engine)
|
||||||
return TaskAction::StopWithError;
|
return SetupResult::StopWithError;
|
||||||
if (storage->input().trimmed().isEmpty()) {
|
if (storage->input().trimmed().isEmpty()) {
|
||||||
LocatorFilterEntry entry;
|
LocatorFilterEntry entry;
|
||||||
entry.displayName = Tr::tr("Reset Engine");
|
entry.displayName = Tr::tr("Reset Engine");
|
||||||
@@ -385,9 +385,9 @@ LocatorMatcherTasks JavaScriptFilter::matchers()
|
|||||||
return AcceptResult();
|
return AcceptResult();
|
||||||
};
|
};
|
||||||
storage->reportOutput({entry});
|
storage->reportOutput({entry});
|
||||||
return TaskAction::StopWithDone;
|
return SetupResult::StopWithDone;
|
||||||
}
|
}
|
||||||
return TaskAction::Continue;
|
return SetupResult::Continue;
|
||||||
};
|
};
|
||||||
|
|
||||||
const auto onJavaScriptSetup = [storage, engine](JavaScriptRequest &request) {
|
const auto onJavaScriptSetup = [storage, engine](JavaScriptRequest &request) {
|
||||||
|
|||||||
@@ -179,7 +179,7 @@ LocatorMatcherTasks SpotlightLocatorFilter::matchers()
|
|||||||
const Link link = Link::fromString(storage->input(), true);
|
const Link link = Link::fromString(storage->input(), true);
|
||||||
const FilePath input = link.targetFilePath;
|
const FilePath input = link.targetFilePath;
|
||||||
if (input.isEmpty())
|
if (input.isEmpty())
|
||||||
return TaskAction::StopWithDone;
|
return SetupResult::StopWithDone;
|
||||||
|
|
||||||
// only pass the file name part to allow searches like "somepath/*foo"
|
// only pass the file name part to allow searches like "somepath/*foo"
|
||||||
const std::unique_ptr<MacroExpander> expander(createMacroExpander(input.fileName()));
|
const std::unique_ptr<MacroExpander> expander(createMacroExpander(input.fileName()));
|
||||||
@@ -189,7 +189,7 @@ LocatorMatcherTasks SpotlightLocatorFilter::matchers()
|
|||||||
CommandLine::Raw);
|
CommandLine::Raw);
|
||||||
async.setFutureSynchronizer(ExtensionSystem::PluginManager::futureSynchronizer());
|
async.setFutureSynchronizer(ExtensionSystem::PluginManager::futureSynchronizer());
|
||||||
async.setConcurrentCallData(matches, *storage, cmd);
|
async.setConcurrentCallData(matches, *storage, cmd);
|
||||||
return TaskAction::Continue;
|
return SetupResult::Continue;
|
||||||
};
|
};
|
||||||
|
|
||||||
return {{AsyncTask<void>(onSetup), storage}};
|
return {{AsyncTask<void>(onSetup), storage}};
|
||||||
|
|||||||
@@ -236,11 +236,11 @@ public:
|
|||||||
|
|
||||||
const auto onCheckerSetup = [this](Async<ArchiveIssue> &async) {
|
const auto onCheckerSetup = [this](Async<ArchiveIssue> &async) {
|
||||||
if (!m_tempDir)
|
if (!m_tempDir)
|
||||||
return TaskAction::StopWithError;
|
return SetupResult::StopWithError;
|
||||||
|
|
||||||
async.setConcurrentCallData(checkContents, m_tempDir->path());
|
async.setConcurrentCallData(checkContents, m_tempDir->path());
|
||||||
async.setFutureSynchronizer(PluginManager::futureSynchronizer());
|
async.setFutureSynchronizer(PluginManager::futureSynchronizer());
|
||||||
return TaskAction::Continue;
|
return SetupResult::Continue;
|
||||||
};
|
};
|
||||||
const auto onCheckerDone = [this](const Async<ArchiveIssue> &async) {
|
const auto onCheckerDone = [this](const Async<ArchiveIssue> &async) {
|
||||||
m_isComplete = !async.isResultAvailable();
|
m_isComplete = !async.isResultAvailable();
|
||||||
|
|||||||
@@ -310,12 +310,12 @@ FileListDiffController::FileListDiffController(IDocument *document, const QStrin
|
|||||||
|
|
||||||
const auto setupStaged = [this, stagedFiles](Process &process) {
|
const auto setupStaged = [this, stagedFiles](Process &process) {
|
||||||
if (stagedFiles.isEmpty())
|
if (stagedFiles.isEmpty())
|
||||||
return TaskAction::StopWithError;
|
return SetupResult::StopWithError;
|
||||||
process.setCodec(VcsBaseEditor::getCodec(workingDirectory(), stagedFiles));
|
process.setCodec(VcsBaseEditor::getCodec(workingDirectory(), stagedFiles));
|
||||||
setupCommand(process, addConfigurationArguments(
|
setupCommand(process, addConfigurationArguments(
|
||||||
QStringList({"diff", "--cached", "--"}) + stagedFiles));
|
QStringList({"diff", "--cached", "--"}) + stagedFiles));
|
||||||
VcsOutputWindow::appendCommand(process.workingDirectory(), process.commandLine());
|
VcsOutputWindow::appendCommand(process.workingDirectory(), process.commandLine());
|
||||||
return TaskAction::Continue;
|
return SetupResult::Continue;
|
||||||
};
|
};
|
||||||
const auto onStagedDone = [storage](const Process &process) {
|
const auto onStagedDone = [storage](const Process &process) {
|
||||||
storage->m_stagedOutput = process.cleanedStdOut();
|
storage->m_stagedOutput = process.cleanedStdOut();
|
||||||
@@ -323,12 +323,12 @@ FileListDiffController::FileListDiffController(IDocument *document, const QStrin
|
|||||||
|
|
||||||
const auto setupUnstaged = [this, unstagedFiles](Process &process) {
|
const auto setupUnstaged = [this, unstagedFiles](Process &process) {
|
||||||
if (unstagedFiles.isEmpty())
|
if (unstagedFiles.isEmpty())
|
||||||
return TaskAction::StopWithError;
|
return SetupResult::StopWithError;
|
||||||
process.setCodec(VcsBaseEditor::getCodec(workingDirectory(), unstagedFiles));
|
process.setCodec(VcsBaseEditor::getCodec(workingDirectory(), unstagedFiles));
|
||||||
setupCommand(process, addConfigurationArguments(
|
setupCommand(process, addConfigurationArguments(
|
||||||
QStringList({"diff", "--"}) + unstagedFiles));
|
QStringList({"diff", "--"}) + unstagedFiles));
|
||||||
VcsOutputWindow::appendCommand(process.workingDirectory(), process.commandLine());
|
VcsOutputWindow::appendCommand(process.workingDirectory(), process.commandLine());
|
||||||
return TaskAction::Continue;
|
return SetupResult::Continue;
|
||||||
};
|
};
|
||||||
const auto onUnstagedDone = [storage](const Process &process) {
|
const auto onUnstagedDone = [storage](const Process &process) {
|
||||||
storage->m_unstagedOutput = process.cleanedStdOut();
|
storage->m_unstagedOutput = process.cleanedStdOut();
|
||||||
@@ -421,8 +421,8 @@ ShowController::ShowController(IDocument *document, const QString &id)
|
|||||||
|
|
||||||
const auto desciptionDetailsSetup = [storage] {
|
const auto desciptionDetailsSetup = [storage] {
|
||||||
if (!storage->m_postProcessDescription)
|
if (!storage->m_postProcessDescription)
|
||||||
return TaskAction::StopWithDone;
|
return SetupResult::StopWithDone;
|
||||||
return TaskAction::Continue;
|
return SetupResult::Continue;
|
||||||
};
|
};
|
||||||
|
|
||||||
const auto setupBranches = [this, storage](Process &process) {
|
const auto setupBranches = [this, storage](Process &process) {
|
||||||
|
|||||||
@@ -1698,27 +1698,35 @@ void ClientPrivate::log(const ShowMessageParams &message)
|
|||||||
LanguageClientValue<MessageActionItem> ClientPrivate::showMessageBox(
|
LanguageClientValue<MessageActionItem> ClientPrivate::showMessageBox(
|
||||||
const ShowMessageRequestParams &message)
|
const ShowMessageRequestParams &message)
|
||||||
{
|
{
|
||||||
auto box = new QMessageBox();
|
QMessageBox box;
|
||||||
box->setText(message.toString());
|
box.setText(message.toString());
|
||||||
box->setAttribute(Qt::WA_DeleteOnClose);
|
|
||||||
switch (message.type()) {
|
switch (message.type()) {
|
||||||
case Error: box->setIcon(QMessageBox::Critical); break;
|
case Error:
|
||||||
case Warning: box->setIcon(QMessageBox::Warning); break;
|
box.setIcon(QMessageBox::Critical);
|
||||||
case Info: box->setIcon(QMessageBox::Information); break;
|
break;
|
||||||
case Log: box->setIcon(QMessageBox::NoIcon); break;
|
case Warning:
|
||||||
|
box.setIcon(QMessageBox::Warning);
|
||||||
|
break;
|
||||||
|
case Info:
|
||||||
|
box.setIcon(QMessageBox::Information);
|
||||||
|
break;
|
||||||
|
case Log:
|
||||||
|
box.setIcon(QMessageBox::NoIcon);
|
||||||
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
QHash<QAbstractButton *, MessageActionItem> itemForButton;
|
QHash<QAbstractButton *, MessageActionItem> itemForButton;
|
||||||
if (const std::optional<QList<MessageActionItem>> actions = message.actions()) {
|
if (const std::optional<QList<MessageActionItem>> actions = message.actions()) {
|
||||||
auto button = box->addButton(QMessageBox::Close);
|
|
||||||
connect(button, &QPushButton::clicked, box, &QMessageBox::reject);
|
|
||||||
for (const MessageActionItem &action : *actions) {
|
for (const MessageActionItem &action : *actions) {
|
||||||
connect(button, &QPushButton::clicked, box, &QMessageBox::accept);
|
auto button = box.addButton(action.title(), QMessageBox::ActionRole);
|
||||||
|
connect(button, &QPushButton::clicked, &box, &QMessageBox::accept);
|
||||||
itemForButton.insert(button, action);
|
itemForButton.insert(button, action);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if (box->exec() == QDialog::Rejected)
|
|
||||||
|
if (box.exec() == QDialog::Rejected || itemForButton.isEmpty())
|
||||||
return {};
|
return {};
|
||||||
const MessageActionItem &item = itemForButton.value(box->clickedButton());
|
const MessageActionItem &item = itemForButton.value(box.clickedButton());
|
||||||
return item.isValid() ? LanguageClientValue<MessageActionItem>(item)
|
return item.isValid() ? LanguageClientValue<MessageActionItem>(item)
|
||||||
: LanguageClientValue<MessageActionItem>();
|
: LanguageClientValue<MessageActionItem>();
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -69,10 +69,10 @@ LocatorMatcherTask locatorMatcher(Client *client, int maxResultCount,
|
|||||||
const auto onFilterSetup = [storage, resultStorage, client, filter](Async<void> &async) {
|
const auto onFilterSetup = [storage, resultStorage, client, filter](Async<void> &async) {
|
||||||
const QList<SymbolInformation> results = *resultStorage;
|
const QList<SymbolInformation> results = *resultStorage;
|
||||||
if (results.isEmpty())
|
if (results.isEmpty())
|
||||||
return TaskAction::StopWithDone;
|
return SetupResult::StopWithDone;
|
||||||
async.setFutureSynchronizer(ExtensionSystem::PluginManager::futureSynchronizer());
|
async.setFutureSynchronizer(ExtensionSystem::PluginManager::futureSynchronizer());
|
||||||
async.setConcurrentCallData(filterResults, *storage, client, results, filter);
|
async.setConcurrentCallData(filterResults, *storage, client, results, filter);
|
||||||
return TaskAction::Continue;
|
return SetupResult::Continue;
|
||||||
};
|
};
|
||||||
|
|
||||||
const Group root {
|
const Group root {
|
||||||
|
|||||||
@@ -1,5 +1,5 @@
|
|||||||
add_qtc_plugin(McuSupport
|
add_qtc_plugin(McuSupport
|
||||||
DEPENDS Qt::Core
|
DEPENDS Qt::Core QmlJS
|
||||||
PLUGIN_DEPENDS Core BareMetal ProjectExplorer Debugger CMakeProjectManager QtSupport
|
PLUGIN_DEPENDS Core BareMetal ProjectExplorer Debugger CMakeProjectManager QtSupport
|
||||||
SOURCES
|
SOURCES
|
||||||
mcukitinformation.cpp mcukitinformation.h
|
mcukitinformation.cpp mcukitinformation.h
|
||||||
|
|||||||
@@ -18,6 +18,7 @@
|
|||||||
#include "test/unittest.h"
|
#include "test/unittest.h"
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
#include <coreplugin/actionmanager/actionmanager.h>
|
||||||
#include <coreplugin/coreconstants.h>
|
#include <coreplugin/coreconstants.h>
|
||||||
#include <coreplugin/icontext.h>
|
#include <coreplugin/icontext.h>
|
||||||
#include <coreplugin/icore.h>
|
#include <coreplugin/icore.h>
|
||||||
@@ -34,9 +35,14 @@
|
|||||||
|
|
||||||
#include <cmakeprojectmanager/cmakeprojectconstants.h>
|
#include <cmakeprojectmanager/cmakeprojectconstants.h>
|
||||||
|
|
||||||
|
#include <qmljs/qmljsmodelmanagerinterface.h>
|
||||||
|
#include <qmljstools/qmljstoolsconstants.h>
|
||||||
|
|
||||||
#include <utils/filepath.h>
|
#include <utils/filepath.h>
|
||||||
#include <utils/infobar.h>
|
#include <utils/infobar.h>
|
||||||
|
|
||||||
|
#include <QAction>
|
||||||
|
#include <QDateTime>
|
||||||
#include <QTimer>
|
#include <QTimer>
|
||||||
|
|
||||||
using namespace Core;
|
using namespace Core;
|
||||||
@@ -119,6 +125,41 @@ void McuSupportPlugin::initialize()
|
|||||||
&ProjectManager::projectFinishedParsing,
|
&ProjectManager::projectFinishedParsing,
|
||||||
updateMCUProjectTree);
|
updateMCUProjectTree);
|
||||||
|
|
||||||
|
// Temporary fix for CodeModel/Checker race condition
|
||||||
|
// Remove after https://bugreports.qt.io/browse/QTCREATORBUG-29269 is closed
|
||||||
|
connect(QmlJS::ModelManagerInterface::instance(),
|
||||||
|
&QmlJS::ModelManagerInterface::documentUpdated,
|
||||||
|
[lasttime = QTime::currentTime()](QmlJS::Document::Ptr doc) mutable {
|
||||||
|
// Prevent inifinite recall loop
|
||||||
|
auto currenttime = QTime::currentTime();
|
||||||
|
if (lasttime.msecsTo(currenttime) < 1000) {
|
||||||
|
lasttime = currenttime;
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
lasttime = currenttime;
|
||||||
|
|
||||||
|
if (!doc)
|
||||||
|
return;
|
||||||
|
//Reset code model only for QtMCUs documents
|
||||||
|
const Project *project = ProjectManager::projectForFile(doc->path());
|
||||||
|
if (!project)
|
||||||
|
return;
|
||||||
|
const QList<Target *> targets = project->targets();
|
||||||
|
bool isMcuDocument
|
||||||
|
= std::any_of(std::begin(targets), std::end(targets), [](const Target *target) {
|
||||||
|
if (!target || !target->kit()
|
||||||
|
|| !target->kit()->hasValue(Constants::KIT_MCUTARGET_KITVERSION_KEY))
|
||||||
|
return false;
|
||||||
|
return true;
|
||||||
|
});
|
||||||
|
if (!isMcuDocument)
|
||||||
|
return;
|
||||||
|
|
||||||
|
Core::ActionManager::command(QmlJSTools::Constants::RESET_CODEMODEL)
|
||||||
|
->action()
|
||||||
|
->trigger();
|
||||||
|
});
|
||||||
|
|
||||||
dd->m_options.registerQchFiles();
|
dd->m_options.registerQchFiles();
|
||||||
dd->m_options.registerExamples();
|
dd->m_options.registerExamples();
|
||||||
ProjectExplorer::JsonWizardFactory::addWizardPath(":/mcusupport/wizards/");
|
ProjectExplorer::JsonWizardFactory::addWizardPath(":/mcusupport/wizards/");
|
||||||
|
|||||||
@@ -70,6 +70,7 @@ public:
|
|||||||
{
|
{
|
||||||
if (m_widget)
|
if (m_widget)
|
||||||
return m_widget->displayIcon();
|
return m_widget->displayIcon();
|
||||||
|
QTC_ASSERT(m_kit, return {});
|
||||||
return m_kit->displayIcon();
|
return m_kit->displayIcon();
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -77,6 +78,7 @@ public:
|
|||||||
{
|
{
|
||||||
if (m_widget)
|
if (m_widget)
|
||||||
return m_widget->displayName();
|
return m_widget->displayName();
|
||||||
|
QTC_ASSERT(m_kit, return {});
|
||||||
return m_kit->displayName();
|
return m_kit->displayName();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -68,7 +68,7 @@ void TerminalAspect::addToLayout(LayoutItem &parent)
|
|||||||
m_checkBox = createSubWidget<QCheckBox>(Tr::tr("Run in terminal"));
|
m_checkBox = createSubWidget<QCheckBox>(Tr::tr("Run in terminal"));
|
||||||
m_checkBox->setChecked(m_useTerminal);
|
m_checkBox->setChecked(m_useTerminal);
|
||||||
m_checkBox->setEnabled(isEnabled());
|
m_checkBox->setEnabled(isEnabled());
|
||||||
parent.addItems({{}, m_checkBox.data()});
|
parent.addItems({empty(), m_checkBox.data()});
|
||||||
connect(m_checkBox.data(), &QAbstractButton::clicked, this, [this] {
|
connect(m_checkBox.data(), &QAbstractButton::clicked, this, [this] {
|
||||||
m_userSet = true;
|
m_userSet = true;
|
||||||
m_useTerminal = m_checkBox->isChecked();
|
m_useTerminal = m_checkBox->isChecked();
|
||||||
|
|||||||
@@ -671,7 +671,6 @@ TaskView::TaskView()
|
|||||||
void TaskView::resizeColumns()
|
void TaskView::resizeColumns()
|
||||||
{
|
{
|
||||||
setColumnWidth(0, width() * 0.85);
|
setColumnWidth(0, width() * 0.85);
|
||||||
setColumnWidth(1, width() * 0.15);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void TaskView::resizeEvent(QResizeEvent *e)
|
void TaskView::resizeEvent(QResizeEvent *e)
|
||||||
|
|||||||
@@ -149,10 +149,10 @@ GroupItem QnxDeployQtLibrariesDialogPrivate::removeDirTask()
|
|||||||
{
|
{
|
||||||
const auto setupHandler = [this](Process &process) {
|
const auto setupHandler = [this](Process &process) {
|
||||||
if (m_checkResult != CheckResult::RemoveDir)
|
if (m_checkResult != CheckResult::RemoveDir)
|
||||||
return TaskAction::StopWithDone;
|
return SetupResult::StopWithDone;
|
||||||
m_deployLogWindow->appendPlainText(Tr::tr("Removing \"%1\"").arg(fullRemoteDirectory()));
|
m_deployLogWindow->appendPlainText(Tr::tr("Removing \"%1\"").arg(fullRemoteDirectory()));
|
||||||
process.setCommand({m_device->filePath("rm"), {"-rf", fullRemoteDirectory()}});
|
process.setCommand({m_device->filePath("rm"), {"-rf", fullRemoteDirectory()}});
|
||||||
return TaskAction::Continue;
|
return SetupResult::Continue;
|
||||||
};
|
};
|
||||||
const auto errorHandler = [this](const Process &process) {
|
const auto errorHandler = [this](const Process &process) {
|
||||||
QTC_ASSERT(process.exitCode() == 0, return);
|
QTC_ASSERT(process.exitCode() == 0, return);
|
||||||
@@ -167,7 +167,7 @@ GroupItem QnxDeployQtLibrariesDialogPrivate::uploadTask()
|
|||||||
const auto setupHandler = [this](FileTransfer &transfer) {
|
const auto setupHandler = [this](FileTransfer &transfer) {
|
||||||
if (m_deployableFiles.isEmpty()) {
|
if (m_deployableFiles.isEmpty()) {
|
||||||
emitProgressMessage(Tr::tr("No files need to be uploaded."));
|
emitProgressMessage(Tr::tr("No files need to be uploaded."));
|
||||||
return TaskAction::StopWithDone;
|
return SetupResult::StopWithDone;
|
||||||
}
|
}
|
||||||
emitProgressMessage(Tr::tr("%n file(s) need to be uploaded.", "",
|
emitProgressMessage(Tr::tr("%n file(s) need to be uploaded.", "",
|
||||||
m_deployableFiles.size()));
|
m_deployableFiles.size()));
|
||||||
@@ -177,18 +177,18 @@ GroupItem QnxDeployQtLibrariesDialogPrivate::uploadTask()
|
|||||||
const QString message = Tr::tr("Local file \"%1\" does not exist.")
|
const QString message = Tr::tr("Local file \"%1\" does not exist.")
|
||||||
.arg(file.localFilePath().toUserOutput());
|
.arg(file.localFilePath().toUserOutput());
|
||||||
emitErrorMessage(message);
|
emitErrorMessage(message);
|
||||||
return TaskAction::StopWithError;
|
return SetupResult::StopWithError;
|
||||||
}
|
}
|
||||||
files.append({file.localFilePath(), m_device->filePath(file.remoteFilePath())});
|
files.append({file.localFilePath(), m_device->filePath(file.remoteFilePath())});
|
||||||
}
|
}
|
||||||
if (files.isEmpty()) {
|
if (files.isEmpty()) {
|
||||||
emitProgressMessage(Tr::tr("No files need to be uploaded."));
|
emitProgressMessage(Tr::tr("No files need to be uploaded."));
|
||||||
return TaskAction::StopWithDone;
|
return SetupResult::StopWithDone;
|
||||||
}
|
}
|
||||||
transfer.setFilesToTransfer(files);
|
transfer.setFilesToTransfer(files);
|
||||||
QObject::connect(&transfer, &FileTransfer::progress,
|
QObject::connect(&transfer, &FileTransfer::progress,
|
||||||
this, &QnxDeployQtLibrariesDialogPrivate::emitProgressMessage);
|
this, &QnxDeployQtLibrariesDialogPrivate::emitProgressMessage);
|
||||||
return TaskAction::Continue;
|
return SetupResult::Continue;
|
||||||
};
|
};
|
||||||
const auto errorHandler = [this](const FileTransfer &transfer) {
|
const auto errorHandler = [this](const FileTransfer &transfer) {
|
||||||
emitErrorMessage(transfer.resultData().m_errorString);
|
emitErrorMessage(transfer.resultData().m_errorString);
|
||||||
@@ -238,7 +238,7 @@ Group QnxDeployQtLibrariesDialogPrivate::deployRecipe()
|
|||||||
const auto setupHandler = [this] {
|
const auto setupHandler = [this] {
|
||||||
if (!m_device) {
|
if (!m_device) {
|
||||||
emitErrorMessage(Tr::tr("No device configuration set."));
|
emitErrorMessage(Tr::tr("No device configuration set."));
|
||||||
return TaskAction::StopWithError;
|
return SetupResult::StopWithError;
|
||||||
}
|
}
|
||||||
QList<DeployableFile> collected;
|
QList<DeployableFile> collected;
|
||||||
for (int i = 0; i < m_deployableFiles.count(); ++i)
|
for (int i = 0; i < m_deployableFiles.count(); ++i)
|
||||||
@@ -247,18 +247,18 @@ Group QnxDeployQtLibrariesDialogPrivate::deployRecipe()
|
|||||||
QTC_CHECK(collected.size() >= m_deployableFiles.size());
|
QTC_CHECK(collected.size() >= m_deployableFiles.size());
|
||||||
m_deployableFiles = collected;
|
m_deployableFiles = collected;
|
||||||
if (!m_deployableFiles.isEmpty())
|
if (!m_deployableFiles.isEmpty())
|
||||||
return TaskAction::Continue;
|
return SetupResult::Continue;
|
||||||
|
|
||||||
emitProgressMessage(Tr::tr("No deployment action necessary. Skipping."));
|
emitProgressMessage(Tr::tr("No deployment action necessary. Skipping."));
|
||||||
return TaskAction::StopWithDone;
|
return SetupResult::StopWithDone;
|
||||||
};
|
};
|
||||||
const auto doneHandler = [this] {
|
const auto doneHandler = [this] {
|
||||||
emitProgressMessage(Tr::tr("All files successfully deployed."));
|
emitProgressMessage(Tr::tr("All files successfully deployed."));
|
||||||
};
|
};
|
||||||
const auto subGroupSetupHandler = [this] {
|
const auto subGroupSetupHandler = [this] {
|
||||||
if (m_checkResult == CheckResult::Abort)
|
if (m_checkResult == CheckResult::Abort)
|
||||||
return TaskAction::StopWithError;
|
return SetupResult::StopWithError;
|
||||||
return TaskAction::Continue;
|
return SetupResult::Continue;
|
||||||
};
|
};
|
||||||
const Group root {
|
const Group root {
|
||||||
onGroupSetup(setupHandler),
|
onGroupSetup(setupHandler),
|
||||||
|
|||||||
@@ -19,12 +19,13 @@ using namespace ProjectExplorer;
|
|||||||
namespace QtSupport {
|
namespace QtSupport {
|
||||||
|
|
||||||
// opt. drive letter + filename: (2 brackets)
|
// opt. drive letter + filename: (2 brackets)
|
||||||
#define FILE_PATTERN R"(^(?<file>(?:[A-Za-z]:)?[^:\(]+\.[^:\(]+))"
|
#define FILE_PATTERN R"((?<file>(?:[A-Za-z]:)?[^:\(]+\.[^:\(]+))"
|
||||||
|
|
||||||
QtParser::QtParser() :
|
QtParser::QtParser() :
|
||||||
m_mocRegExp(FILE_PATTERN R"([:\(](?<line>\d+)?(?::(?<column>\d+))?\)?:\s(?<level>[Ww]arning|[Ee]rror|[Nn]ote):\s(?<description>.+?)$)"),
|
m_mocRegExp("^" FILE_PATTERN R"([:\(](?<line>\d+)?(?::(?<column>\d+))?\)?:\s(?<level>[Ww]arning|[Ee]rror|[Nn]ote):\s(?<description>.+?)$)"),
|
||||||
m_uicRegExp(FILE_PATTERN R"(: Warning:\s(?<msg>.+?)$)"),
|
m_uicRegExp("^" FILE_PATTERN R"(: Warning:\s(?<msg>.+?)$)"),
|
||||||
m_translationRegExp(R"(^(?<level>[Ww]arning|[Ee]rror):\s+(?<description>.*?) in '(?<file>.*?)'$)")
|
m_translationRegExp(R"(^(?<level>[Ww]arning|[Ee]rror):\s+(?<description>.*?) in '(?<file>.*?)'$)"),
|
||||||
|
m_qmlToolsRegExp(R"(^(?<level>Warning|Error):\s*)" FILE_PATTERN R"([:\(](?<line>\d+)?(?::(?<column>\d+))?\)?:\s(?<description>.+?)$)")
|
||||||
{
|
{
|
||||||
setObjectName(QLatin1String("QtParser"));
|
setObjectName(QLatin1String("QtParser"));
|
||||||
}
|
}
|
||||||
@@ -89,19 +90,22 @@ Utils::OutputLineParser::Result QtParser::handleLine(const QString &line, Utils:
|
|||||||
scheduleTask(task, 1);
|
scheduleTask(task, 1);
|
||||||
return {Status::Done, linkSpecs};
|
return {Status::Done, linkSpecs};
|
||||||
}
|
}
|
||||||
|
match = m_qmlToolsRegExp.match(line);
|
||||||
if (lne.startsWith(QLatin1String("Error:"))) {
|
if (match.hasMatch()) {
|
||||||
constexpr int matchLength = 6;
|
const Task::TaskType type = match.captured("level") == "Error" ? Task::Error
|
||||||
CompileTask task(Task::TaskType::Error, line.mid(matchLength).trimmed());
|
: Task::Warning;
|
||||||
|
const Utils::FilePath file
|
||||||
|
= absoluteFilePath(Utils::FilePath::fromUserInput(match.captured("file")));
|
||||||
|
bool ok;
|
||||||
|
int lineno = match.captured("line").toInt(&ok);
|
||||||
|
if (!ok)
|
||||||
|
lineno = -1;
|
||||||
|
LinkSpecs linkSpecs;
|
||||||
|
addLinkSpecForAbsoluteFilePath(linkSpecs, file, lineno, match, "file");
|
||||||
|
CompileTask task(type, match.captured("description"), file, lineno,
|
||||||
|
match.captured("column").toInt());
|
||||||
scheduleTask(task, 1);
|
scheduleTask(task, 1);
|
||||||
return Status::Done;
|
return {Status::Done, linkSpecs};
|
||||||
}
|
|
||||||
|
|
||||||
if (lne.startsWith(QLatin1String("Warning:"))) {
|
|
||||||
constexpr int matchLength = 8;
|
|
||||||
CompileTask task(Task::TaskType::Warning, line.mid(matchLength).trimmed());
|
|
||||||
scheduleTask(task, 1);
|
|
||||||
return Status::Done;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
return Status::NotHandled;
|
return Status::NotHandled;
|
||||||
@@ -220,15 +224,22 @@ void QtSupportPlugin::testQtOutputParser_data()
|
|||||||
QLatin1String("dropping duplicate messages"),
|
QLatin1String("dropping duplicate messages"),
|
||||||
Utils::FilePath::fromUserInput(QLatin1String("/some/place/qtcreator_fr.qm")), -1))
|
Utils::FilePath::fromUserInput(QLatin1String("/some/place/qtcreator_fr.qm")), -1))
|
||||||
<< QString();
|
<< QString();
|
||||||
QTest::newRow("qmlsc warning") // QTCREATORBUG-28720
|
QTest::newRow("qmlsc/qmllint warning") // QTCREATORBUG-28720
|
||||||
<< QString::fromUtf8("Warning: Main.qml:4:1: Warnings occurred while importing module "
|
<< QString::fromLatin1("Warning: Main.qml:4:1: Warnings occurred while importing module "
|
||||||
"\"QtQuick.Controls\": [import]\"")
|
"\"QtQuick.Controls\": [import]\"")
|
||||||
<< OutputParserTester::STDERR << QString() << QString()
|
<< OutputParserTester::STDERR << QString() << QString()
|
||||||
<< (Tasks() << CompileTask(Task::Warning,
|
<< (Tasks() << CompileTask(Task::Warning,
|
||||||
QString::fromUtf8(
|
"Warnings occurred while importing module \"QtQuick.Controls\": [import]\"",
|
||||||
"Main.qml:4:1: Warnings occurred while importing module "
|
Utils::FilePath::fromUserInput("Main.qml"), 4, 1))
|
||||||
"\"QtQuick.Controls\": [import]\"")))
|
<< QString();
|
||||||
<< QString();
|
QTest::newRow("qmlsc/qmllint error") // QTCREATORBUG-28720
|
||||||
|
<< QString::fromLatin1("Error: E:/foo/PerfProfilerFlameGraphView.qml:10:5: "
|
||||||
|
"Could not compile binding for model: Cannot resolve property type for binding on model")
|
||||||
|
<< OutputParserTester::STDERR << QString() << QString()
|
||||||
|
<< (Tasks() << CompileTask(Task::Error,
|
||||||
|
"Could not compile binding for model: Cannot resolve property type for binding on model",
|
||||||
|
Utils::FilePath::fromUserInput("E:/foo/PerfProfilerFlameGraphView.qml"), 10, 5))
|
||||||
|
<< QString();
|
||||||
}
|
}
|
||||||
|
|
||||||
void QtSupportPlugin::testQtOutputParser()
|
void QtSupportPlugin::testQtOutputParser()
|
||||||
|
|||||||
@@ -25,6 +25,7 @@ private:
|
|||||||
QRegularExpression m_mocRegExp;
|
QRegularExpression m_mocRegExp;
|
||||||
QRegularExpression m_uicRegExp;
|
QRegularExpression m_uicRegExp;
|
||||||
QRegularExpression m_translationRegExp;
|
QRegularExpression m_translationRegExp;
|
||||||
|
const QRegularExpression m_qmlToolsRegExp;
|
||||||
};
|
};
|
||||||
|
|
||||||
} // namespace QtSupport
|
} // namespace QtSupport
|
||||||
|
|||||||
@@ -194,7 +194,7 @@ GroupItem GenericDirectUploadStep::uploadTask(const TreeStorage<UploadStorage> &
|
|||||||
const auto setupHandler = [this, storage](FileTransfer &transfer) {
|
const auto setupHandler = [this, storage](FileTransfer &transfer) {
|
||||||
if (storage->filesToUpload.isEmpty()) {
|
if (storage->filesToUpload.isEmpty()) {
|
||||||
addProgressMessage(Tr::tr("No files need to be uploaded."));
|
addProgressMessage(Tr::tr("No files need to be uploaded."));
|
||||||
return TaskAction::StopWithDone;
|
return SetupResult::StopWithDone;
|
||||||
}
|
}
|
||||||
addProgressMessage(Tr::tr("%n file(s) need to be uploaded.", "",
|
addProgressMessage(Tr::tr("%n file(s) need to be uploaded.", "",
|
||||||
storage->filesToUpload.size()));
|
storage->filesToUpload.size()));
|
||||||
@@ -208,19 +208,19 @@ GroupItem GenericDirectUploadStep::uploadTask(const TreeStorage<UploadStorage> &
|
|||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
addErrorMessage(message);
|
addErrorMessage(message);
|
||||||
return TaskAction::StopWithError;
|
return SetupResult::StopWithError;
|
||||||
}
|
}
|
||||||
files.append({file.localFilePath(),
|
files.append({file.localFilePath(),
|
||||||
deviceConfiguration()->filePath(file.remoteFilePath())});
|
deviceConfiguration()->filePath(file.remoteFilePath())});
|
||||||
}
|
}
|
||||||
if (files.isEmpty()) {
|
if (files.isEmpty()) {
|
||||||
addProgressMessage(Tr::tr("No files need to be uploaded."));
|
addProgressMessage(Tr::tr("No files need to be uploaded."));
|
||||||
return TaskAction::StopWithDone;
|
return SetupResult::StopWithDone;
|
||||||
}
|
}
|
||||||
transfer.setFilesToTransfer(files);
|
transfer.setFilesToTransfer(files);
|
||||||
QObject::connect(&transfer, &FileTransfer::progress,
|
QObject::connect(&transfer, &FileTransfer::progress,
|
||||||
this, &GenericDirectUploadStep::addProgressMessage);
|
this, &GenericDirectUploadStep::addProgressMessage);
|
||||||
return TaskAction::Continue;
|
return SetupResult::Continue;
|
||||||
};
|
};
|
||||||
const auto errorHandler = [this](const FileTransfer &transfer) {
|
const auto errorHandler = [this](const FileTransfer &transfer) {
|
||||||
addErrorMessage(transfer.resultData().m_errorString);
|
addErrorMessage(transfer.resultData().m_errorString);
|
||||||
|
|||||||
@@ -167,13 +167,13 @@ SubversionDiffEditorController::SubversionDiffEditorController(IDocument *docume
|
|||||||
|
|
||||||
const auto setupDescription = [this](Process &process) {
|
const auto setupDescription = [this](Process &process) {
|
||||||
if (m_changeNumber == 0)
|
if (m_changeNumber == 0)
|
||||||
return TaskAction::StopWithDone;
|
return SetupResult::StopWithDone;
|
||||||
setupCommand(process, {"log", "-r", QString::number(m_changeNumber)});
|
setupCommand(process, {"log", "-r", QString::number(m_changeNumber)});
|
||||||
CommandLine command = process.commandLine();
|
CommandLine command = process.commandLine();
|
||||||
command << SubversionClient::AddAuthOptions();
|
command << SubversionClient::AddAuthOptions();
|
||||||
process.setCommand(command);
|
process.setCommand(command);
|
||||||
setDescription(Tr::tr("Waiting for data..."));
|
setDescription(Tr::tr("Waiting for data..."));
|
||||||
return TaskAction::Continue;
|
return SetupResult::Continue;
|
||||||
};
|
};
|
||||||
const auto onDescriptionDone = [this](const Process &process) {
|
const auto onDescriptionDone = [this](const Process &process) {
|
||||||
setDescription(process.cleanedStdOut());
|
setDescription(process.cleanedStdOut());
|
||||||
|
|||||||
@@ -227,7 +227,7 @@ void tst_Tasking::testTree_data()
|
|||||||
};
|
};
|
||||||
};
|
};
|
||||||
|
|
||||||
const auto setupDynamicTask = [storage](int taskId, TaskAction action) {
|
const auto setupDynamicTask = [storage](int taskId, SetupResult action) {
|
||||||
return [storage, taskId, action](TaskObject &) {
|
return [storage, taskId, action](TaskObject &) {
|
||||||
storage->m_log.append({taskId, Handler::Setup});
|
storage->m_log.append({taskId, Handler::Setup});
|
||||||
return action;
|
return action;
|
||||||
@@ -274,7 +274,7 @@ void tst_Tasking::testTree_data()
|
|||||||
};
|
};
|
||||||
|
|
||||||
const auto createDynamicTask = [storage, setupDynamicTask, setupDone, setupError](
|
const auto createDynamicTask = [storage, setupDynamicTask, setupDone, setupError](
|
||||||
int taskId, TaskAction action) {
|
int taskId, SetupResult action) {
|
||||||
return TestTask(setupDynamicTask(taskId, action), setupDone(taskId), setupError(taskId));
|
return TestTask(setupDynamicTask(taskId, action), setupDone(taskId), setupError(taskId));
|
||||||
};
|
};
|
||||||
|
|
||||||
@@ -302,35 +302,74 @@ void tst_Tasking::testTree_data()
|
|||||||
};
|
};
|
||||||
const Group root2 {
|
const Group root2 {
|
||||||
Storage(storage),
|
Storage(storage),
|
||||||
onGroupSetup([] { return TaskAction::Continue; }),
|
onGroupSetup([] { return SetupResult::Continue; }),
|
||||||
groupDone(0),
|
groupDone(0),
|
||||||
groupError(0)
|
groupError(0)
|
||||||
};
|
};
|
||||||
const Group root3 {
|
const Group root3 {
|
||||||
Storage(storage),
|
Storage(storage),
|
||||||
onGroupSetup([] { return TaskAction::StopWithDone; }),
|
onGroupSetup([] { return SetupResult::StopWithDone; }),
|
||||||
groupDone(0),
|
groupDone(0),
|
||||||
groupError(0)
|
groupError(0)
|
||||||
};
|
};
|
||||||
const Group root4 {
|
const Group root4 {
|
||||||
Storage(storage),
|
Storage(storage),
|
||||||
onGroupSetup([] { return TaskAction::StopWithError; }),
|
onGroupSetup([] { return SetupResult::StopWithError; }),
|
||||||
groupDone(0),
|
groupDone(0),
|
||||||
groupError(0)
|
groupError(0)
|
||||||
};
|
};
|
||||||
|
|
||||||
const Log logDone {{0, Handler::GroupDone}};
|
const Log logDone {{0, Handler::GroupDone}};
|
||||||
const Log logError {{0, Handler::GroupError}};
|
const Log logError {{0, Handler::GroupError}};
|
||||||
|
|
||||||
QTest::newRow("Empty") << TestData{storage, root1, logDone, 0, OnDone::Success};
|
QTest::newRow("Empty") << TestData{storage, root1, logDone, 0, OnDone::Success};
|
||||||
QTest::newRow("EmptyContinue") << TestData{storage, root2, logDone, 0, OnDone::Success};
|
QTest::newRow("EmptyContinue") << TestData{storage, root2, logDone, 0, OnDone::Success};
|
||||||
QTest::newRow("EmptyDone") << TestData{storage, root3, logDone, 0, OnDone::Success};
|
QTest::newRow("EmptyDone") << TestData{storage, root3, logDone, 0, OnDone::Success};
|
||||||
QTest::newRow("EmptyError") << TestData{storage, root4, logError, 0, OnDone::Failure};
|
QTest::newRow("EmptyError") << TestData{storage, root4, logError, 0, OnDone::Failure};
|
||||||
}
|
}
|
||||||
|
|
||||||
|
{
|
||||||
|
const auto setupGroup = [=](SetupResult setupResult, WorkflowPolicy policy) {
|
||||||
|
return Group {
|
||||||
|
Storage(storage),
|
||||||
|
workflowPolicy(policy),
|
||||||
|
onGroupSetup([setupResult] { return setupResult; }),
|
||||||
|
groupDone(0),
|
||||||
|
groupError(0)
|
||||||
|
};
|
||||||
|
};
|
||||||
|
|
||||||
|
const auto doneData = [storage, setupGroup](WorkflowPolicy policy) {
|
||||||
|
return TestData{storage, setupGroup(SetupResult::StopWithDone, policy),
|
||||||
|
Log{{0, Handler::GroupDone}}, 0, OnDone::Success};
|
||||||
|
};
|
||||||
|
const auto errorData = [storage, setupGroup](WorkflowPolicy policy) {
|
||||||
|
return TestData{storage, setupGroup(SetupResult::StopWithError, policy),
|
||||||
|
Log{{0, Handler::GroupError}}, 0, OnDone::Failure};
|
||||||
|
};
|
||||||
|
|
||||||
|
QTest::newRow("DoneAndStopOnError") << doneData(WorkflowPolicy::StopOnError);
|
||||||
|
QTest::newRow("DoneAndContinueOnError") << doneData(WorkflowPolicy::ContinueOnError);
|
||||||
|
QTest::newRow("DoneAndStopOnDone") << doneData(WorkflowPolicy::StopOnDone);
|
||||||
|
QTest::newRow("DoneAndContinueOnDone") << doneData(WorkflowPolicy::ContinueOnDone);
|
||||||
|
QTest::newRow("DoneAndStopOnFinished") << doneData(WorkflowPolicy::StopOnFinished);
|
||||||
|
QTest::newRow("DoneAndFinishAllAndDone") << doneData(WorkflowPolicy::FinishAllAndDone);
|
||||||
|
QTest::newRow("DoneAndFinishAllAndError") << doneData(WorkflowPolicy::FinishAllAndError);
|
||||||
|
|
||||||
|
QTest::newRow("ErrorAndStopOnError") << errorData(WorkflowPolicy::StopOnError);
|
||||||
|
QTest::newRow("ErrorAndContinueOnError") << errorData(WorkflowPolicy::ContinueOnError);
|
||||||
|
QTest::newRow("ErrorAndStopOnDone") << errorData(WorkflowPolicy::StopOnDone);
|
||||||
|
QTest::newRow("ErrorAndContinueOnDone") << errorData(WorkflowPolicy::ContinueOnDone);
|
||||||
|
QTest::newRow("ErrorAndStopOnFinished") << errorData(WorkflowPolicy::StopOnFinished);
|
||||||
|
QTest::newRow("ErrorAndFinishAllAndDone") << errorData(WorkflowPolicy::FinishAllAndDone);
|
||||||
|
QTest::newRow("ErrorAndFinishAllAndError") << errorData(WorkflowPolicy::FinishAllAndError);
|
||||||
|
}
|
||||||
|
|
||||||
{
|
{
|
||||||
const Group root {
|
const Group root {
|
||||||
Storage(storage),
|
Storage(storage),
|
||||||
createDynamicTask(1, TaskAction::StopWithDone),
|
createDynamicTask(1, SetupResult::StopWithDone),
|
||||||
createDynamicTask(2, TaskAction::StopWithDone)
|
createDynamicTask(2, SetupResult::StopWithDone)
|
||||||
};
|
};
|
||||||
const Log log {{1, Handler::Setup}, {2, Handler::Setup}};
|
const Log log {{1, Handler::Setup}, {2, Handler::Setup}};
|
||||||
QTest::newRow("DynamicTaskDone") << TestData{storage, root, log, 2, OnDone::Success};
|
QTest::newRow("DynamicTaskDone") << TestData{storage, root, log, 2, OnDone::Success};
|
||||||
@@ -339,8 +378,8 @@ void tst_Tasking::testTree_data()
|
|||||||
{
|
{
|
||||||
const Group root {
|
const Group root {
|
||||||
Storage(storage),
|
Storage(storage),
|
||||||
createDynamicTask(1, TaskAction::StopWithError),
|
createDynamicTask(1, SetupResult::StopWithError),
|
||||||
createDynamicTask(2, TaskAction::StopWithError)
|
createDynamicTask(2, SetupResult::StopWithError)
|
||||||
};
|
};
|
||||||
const Log log {{1, Handler::Setup}};
|
const Log log {{1, Handler::Setup}};
|
||||||
QTest::newRow("DynamicTaskError") << TestData{storage, root, log, 2, OnDone::Failure};
|
QTest::newRow("DynamicTaskError") << TestData{storage, root, log, 2, OnDone::Failure};
|
||||||
@@ -349,10 +388,10 @@ void tst_Tasking::testTree_data()
|
|||||||
{
|
{
|
||||||
const Group root {
|
const Group root {
|
||||||
Storage(storage),
|
Storage(storage),
|
||||||
createDynamicTask(1, TaskAction::Continue),
|
createDynamicTask(1, SetupResult::Continue),
|
||||||
createDynamicTask(2, TaskAction::Continue),
|
createDynamicTask(2, SetupResult::Continue),
|
||||||
createDynamicTask(3, TaskAction::StopWithError),
|
createDynamicTask(3, SetupResult::StopWithError),
|
||||||
createDynamicTask(4, TaskAction::Continue)
|
createDynamicTask(4, SetupResult::Continue)
|
||||||
};
|
};
|
||||||
const Log log {
|
const Log log {
|
||||||
{1, Handler::Setup},
|
{1, Handler::Setup},
|
||||||
@@ -368,10 +407,10 @@ void tst_Tasking::testTree_data()
|
|||||||
const Group root {
|
const Group root {
|
||||||
parallel,
|
parallel,
|
||||||
Storage(storage),
|
Storage(storage),
|
||||||
createDynamicTask(1, TaskAction::Continue),
|
createDynamicTask(1, SetupResult::Continue),
|
||||||
createDynamicTask(2, TaskAction::Continue),
|
createDynamicTask(2, SetupResult::Continue),
|
||||||
createDynamicTask(3, TaskAction::StopWithError),
|
createDynamicTask(3, SetupResult::StopWithError),
|
||||||
createDynamicTask(4, TaskAction::Continue)
|
createDynamicTask(4, SetupResult::Continue)
|
||||||
};
|
};
|
||||||
const Log log {
|
const Log log {
|
||||||
{1, Handler::Setup},
|
{1, Handler::Setup},
|
||||||
@@ -387,12 +426,12 @@ void tst_Tasking::testTree_data()
|
|||||||
const Group root {
|
const Group root {
|
||||||
parallel,
|
parallel,
|
||||||
Storage(storage),
|
Storage(storage),
|
||||||
createDynamicTask(1, TaskAction::Continue),
|
createDynamicTask(1, SetupResult::Continue),
|
||||||
createDynamicTask(2, TaskAction::Continue),
|
createDynamicTask(2, SetupResult::Continue),
|
||||||
Group {
|
Group {
|
||||||
createDynamicTask(3, TaskAction::StopWithError)
|
createDynamicTask(3, SetupResult::StopWithError)
|
||||||
},
|
},
|
||||||
createDynamicTask(4, TaskAction::Continue)
|
createDynamicTask(4, SetupResult::Continue)
|
||||||
};
|
};
|
||||||
const Log log {
|
const Log log {
|
||||||
{1, Handler::Setup},
|
{1, Handler::Setup},
|
||||||
@@ -408,16 +447,16 @@ void tst_Tasking::testTree_data()
|
|||||||
const Group root {
|
const Group root {
|
||||||
parallel,
|
parallel,
|
||||||
Storage(storage),
|
Storage(storage),
|
||||||
createDynamicTask(1, TaskAction::Continue),
|
createDynamicTask(1, SetupResult::Continue),
|
||||||
createDynamicTask(2, TaskAction::Continue),
|
createDynamicTask(2, SetupResult::Continue),
|
||||||
Group {
|
Group {
|
||||||
onGroupSetup([storage] {
|
onGroupSetup([storage] {
|
||||||
storage->m_log.append({0, Handler::GroupSetup});
|
storage->m_log.append({0, Handler::GroupSetup});
|
||||||
return TaskAction::StopWithError;
|
return SetupResult::StopWithError;
|
||||||
}),
|
}),
|
||||||
createDynamicTask(3, TaskAction::Continue)
|
createDynamicTask(3, SetupResult::Continue)
|
||||||
},
|
},
|
||||||
createDynamicTask(4, TaskAction::Continue)
|
createDynamicTask(4, SetupResult::Continue)
|
||||||
};
|
};
|
||||||
const Log log {
|
const Log log {
|
||||||
{1, Handler::Setup},
|
{1, Handler::Setup},
|
||||||
@@ -1280,14 +1319,14 @@ void tst_Tasking::testTree_data()
|
|||||||
|
|
||||||
{
|
{
|
||||||
const auto createRoot = [storage, createSuccessTask, groupDone, groupError](
|
const auto createRoot = [storage, createSuccessTask, groupDone, groupError](
|
||||||
TaskAction taskAction) {
|
SetupResult setupResult) {
|
||||||
return Group {
|
return Group {
|
||||||
Storage(storage),
|
Storage(storage),
|
||||||
Group {
|
Group {
|
||||||
createSuccessTask(1)
|
createSuccessTask(1)
|
||||||
},
|
},
|
||||||
Group {
|
Group {
|
||||||
onGroupSetup([=] { return taskAction; }),
|
onGroupSetup([=] { return setupResult; }),
|
||||||
createSuccessTask(2),
|
createSuccessTask(2),
|
||||||
createSuccessTask(3),
|
createSuccessTask(3),
|
||||||
createSuccessTask(4)
|
createSuccessTask(4)
|
||||||
@@ -1297,7 +1336,7 @@ void tst_Tasking::testTree_data()
|
|||||||
};
|
};
|
||||||
};
|
};
|
||||||
|
|
||||||
const Group root1 = createRoot(TaskAction::StopWithDone);
|
const Group root1 = createRoot(SetupResult::StopWithDone);
|
||||||
const Log log1 {
|
const Log log1 {
|
||||||
{1, Handler::Setup},
|
{1, Handler::Setup},
|
||||||
{1, Handler::Done},
|
{1, Handler::Done},
|
||||||
@@ -1305,7 +1344,7 @@ void tst_Tasking::testTree_data()
|
|||||||
};
|
};
|
||||||
QTest::newRow("DynamicSetupDone") << TestData{storage, root1, log1, 4, OnDone::Success};
|
QTest::newRow("DynamicSetupDone") << TestData{storage, root1, log1, 4, OnDone::Success};
|
||||||
|
|
||||||
const Group root2 = createRoot(TaskAction::StopWithError);
|
const Group root2 = createRoot(SetupResult::StopWithError);
|
||||||
const Log log2 {
|
const Log log2 {
|
||||||
{1, Handler::Setup},
|
{1, Handler::Setup},
|
||||||
{1, Handler::Done},
|
{1, Handler::Done},
|
||||||
@@ -1313,7 +1352,7 @@ void tst_Tasking::testTree_data()
|
|||||||
};
|
};
|
||||||
QTest::newRow("DynamicSetupError") << TestData{storage, root2, log2, 4, OnDone::Failure};
|
QTest::newRow("DynamicSetupError") << TestData{storage, root2, log2, 4, OnDone::Failure};
|
||||||
|
|
||||||
const Group root3 = createRoot(TaskAction::Continue);
|
const Group root3 = createRoot(SetupResult::Continue);
|
||||||
const Log log3 {
|
const Log log3 {
|
||||||
{1, Handler::Setup},
|
{1, Handler::Setup},
|
||||||
{1, Handler::Done},
|
{1, Handler::Done},
|
||||||
@@ -1380,7 +1419,7 @@ void tst_Tasking::testTree_data()
|
|||||||
},
|
},
|
||||||
Group {
|
Group {
|
||||||
groupSetup(3),
|
groupSetup(3),
|
||||||
createDynamicTask(3, TaskAction::StopWithDone)
|
createDynamicTask(3, SetupResult::StopWithDone)
|
||||||
},
|
},
|
||||||
Group {
|
Group {
|
||||||
groupSetup(4),
|
groupSetup(4),
|
||||||
@@ -1424,7 +1463,7 @@ void tst_Tasking::testTree_data()
|
|||||||
},
|
},
|
||||||
Group {
|
Group {
|
||||||
groupSetup(3),
|
groupSetup(3),
|
||||||
createDynamicTask(3, TaskAction::StopWithError)
|
createDynamicTask(3, SetupResult::StopWithError)
|
||||||
},
|
},
|
||||||
Group {
|
Group {
|
||||||
groupSetup(4),
|
groupSetup(4),
|
||||||
@@ -1463,7 +1502,7 @@ void tst_Tasking::testTree_data()
|
|||||||
},
|
},
|
||||||
Group {
|
Group {
|
||||||
groupSetup(3),
|
groupSetup(3),
|
||||||
createDynamicTask(3, TaskAction::StopWithError)
|
createDynamicTask(3, SetupResult::StopWithError)
|
||||||
},
|
},
|
||||||
Group {
|
Group {
|
||||||
groupSetup(4),
|
groupSetup(4),
|
||||||
@@ -1508,7 +1547,7 @@ void tst_Tasking::testTree_data()
|
|||||||
},
|
},
|
||||||
Group {
|
Group {
|
||||||
groupSetup(3),
|
groupSetup(3),
|
||||||
createDynamicTask(3, TaskAction::StopWithError)
|
createDynamicTask(3, SetupResult::StopWithError)
|
||||||
},
|
},
|
||||||
Group {
|
Group {
|
||||||
groupSetup(4),
|
groupSetup(4),
|
||||||
@@ -1605,7 +1644,7 @@ void tst_Tasking::testTree_data()
|
|||||||
},
|
},
|
||||||
Group {
|
Group {
|
||||||
groupSetup(3),
|
groupSetup(3),
|
||||||
Group { createDynamicTask(3, TaskAction::StopWithDone) }
|
Group { createDynamicTask(3, SetupResult::StopWithDone) }
|
||||||
},
|
},
|
||||||
Group {
|
Group {
|
||||||
groupSetup(4),
|
groupSetup(4),
|
||||||
@@ -1650,7 +1689,7 @@ void tst_Tasking::testTree_data()
|
|||||||
},
|
},
|
||||||
Group {
|
Group {
|
||||||
groupSetup(3),
|
groupSetup(3),
|
||||||
Group { createDynamicTask(3, TaskAction::StopWithError) }
|
Group { createDynamicTask(3, SetupResult::StopWithError) }
|
||||||
},
|
},
|
||||||
Group {
|
Group {
|
||||||
groupSetup(4),
|
groupSetup(4),
|
||||||
|
|||||||
@@ -196,8 +196,7 @@ private slots:
|
|||||||
|
|
||||||
QTest::newRow("simple") << "command %{hello}"
|
QTest::newRow("simple") << "command %{hello}"
|
||||||
<< "command"
|
<< "command"
|
||||||
<< (HostOsInfo::isWindowsHost() ? "\"hello world\""
|
<< "hello world";
|
||||||
: "'hello world'");
|
|
||||||
|
|
||||||
QTest::newRow("simple-quoted")
|
QTest::newRow("simple-quoted")
|
||||||
<< "command \"%{hello}\""
|
<< "command \"%{hello}\""
|
||||||
@@ -226,15 +225,11 @@ private slots:
|
|||||||
CommandLine cmd = CommandLine::fromUserInput(input, &expander);
|
CommandLine cmd = CommandLine::fromUserInput(input, &expander);
|
||||||
QCOMPARE(cmd.executable().toUserOutput(), expectedExecutable);
|
QCOMPARE(cmd.executable().toUserOutput(), expectedExecutable);
|
||||||
|
|
||||||
// TODO: Fix (macro) escaping on windows
|
if (HostOsInfo::isWindowsHost()) {
|
||||||
if (HostOsInfo::isWindowsHost())
|
|
||||||
QEXPECT_FAIL("simple", "Windows does not correctly quote macro arguments", Continue);
|
|
||||||
if (HostOsInfo::isWindowsHost())
|
|
||||||
QEXPECT_FAIL("simple-quoted", "Windows removes quotes from macro arguments", Continue);
|
|
||||||
if (HostOsInfo::isWindowsHost())
|
|
||||||
QEXPECT_FAIL("convert-to-quote-win",
|
QEXPECT_FAIL("convert-to-quote-win",
|
||||||
"Windows should convert single to double quotes",
|
"Windows should convert single to double quotes",
|
||||||
Continue);
|
Continue);
|
||||||
|
}
|
||||||
|
|
||||||
QCOMPARE(cmd.arguments(), expectedArguments);
|
QCOMPARE(cmd.arguments(), expectedArguments);
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -16,6 +16,7 @@ add_subdirectory(proparser)
|
|||||||
# add_subdirectory(qt4projectmanager)
|
# add_subdirectory(qt4projectmanager)
|
||||||
# add_subdirectory(search)
|
# add_subdirectory(search)
|
||||||
add_subdirectory(shootout)
|
add_subdirectory(shootout)
|
||||||
|
add_subdirectory(spinner)
|
||||||
add_subdirectory(subdirfileiterator)
|
add_subdirectory(subdirfileiterator)
|
||||||
add_subdirectory(tasking)
|
add_subdirectory(tasking)
|
||||||
add_subdirectory(widgets)
|
add_subdirectory(widgets)
|
||||||
|
|||||||
23
tests/manual/docker/Dockerfile-qt-6-fedora-37-build
Normal file
23
tests/manual/docker/Dockerfile-qt-6-fedora-37-build
Normal file
@@ -0,0 +1,23 @@
|
|||||||
|
|
||||||
|
FROM fedora:37
|
||||||
|
|
||||||
|
RUN yum update
|
||||||
|
|
||||||
|
RUN yum -y install \
|
||||||
|
yum-utils \
|
||||||
|
qt-creator \
|
||||||
|
gdb \
|
||||||
|
git \
|
||||||
|
vim \
|
||||||
|
cmake \
|
||||||
|
qt \
|
||||||
|
qt-devel \
|
||||||
|
qt6-qtbase-devel \
|
||||||
|
qt6-qtdeclarative-devel \
|
||||||
|
qt6-qtquicktimeline-devel \
|
||||||
|
qt6-qtquick3d-devel \
|
||||||
|
ninja-build \
|
||||||
|
valgrind \
|
||||||
|
xclock
|
||||||
|
|
||||||
|
# && rm -rf /var/lib/apt/lists/*
|
||||||
@@ -3,3 +3,4 @@
|
|||||||
docker build -t qt-5-ubuntu-20.04-build -f Dockerfile-qt-5-ubuntu-20.04-build .
|
docker build -t qt-5-ubuntu-20.04-build -f Dockerfile-qt-5-ubuntu-20.04-build .
|
||||||
docker build -t qt-5-ubuntu-20.04-run -f Dockerfile-qt-5-ubuntu-20.04-run .
|
docker build -t qt-5-ubuntu-20.04-run -f Dockerfile-qt-5-ubuntu-20.04-run .
|
||||||
docker build -t qt-5-ubuntu-20.04-clang-lldb-build -f Dockerfile-qt-5-ubuntu-20.04-clang-lldb-build .
|
docker build -t qt-5-ubuntu-20.04-clang-lldb-build -f Dockerfile-qt-5-ubuntu-20.04-clang-lldb-build .
|
||||||
|
docker build -t qt-6-fedora-37-build -f Dockerfile-qt-6-fedora-37-build .
|
||||||
|
|||||||
@@ -13,6 +13,7 @@ Project {
|
|||||||
"pluginview/pluginview.qbs",
|
"pluginview/pluginview.qbs",
|
||||||
"proparser/testreader.qbs",
|
"proparser/testreader.qbs",
|
||||||
"shootout/shootout.qbs",
|
"shootout/shootout.qbs",
|
||||||
|
"spinner/spinner.qbs",
|
||||||
"subdirfileiterator/subdirfileiterator.qbs",
|
"subdirfileiterator/subdirfileiterator.qbs",
|
||||||
"tasking/demo/demo.qbs",
|
"tasking/demo/demo.qbs",
|
||||||
"tasking/imagescaling/imagescaling.qbs",
|
"tasking/imagescaling/imagescaling.qbs",
|
||||||
|
|||||||
6
tests/manual/spinner/CMakeLists.txt
Normal file
6
tests/manual/spinner/CMakeLists.txt
Normal file
@@ -0,0 +1,6 @@
|
|||||||
|
add_qtc_test(tst_spinner
|
||||||
|
MANUALTEST
|
||||||
|
DEPENDS Spinner Qt::Widgets
|
||||||
|
SOURCES
|
||||||
|
main.cpp
|
||||||
|
)
|
||||||
167
tests/manual/spinner/main.cpp
Normal file
167
tests/manual/spinner/main.cpp
Normal file
@@ -0,0 +1,167 @@
|
|||||||
|
// Copyright (C) 2023 The Qt Company Ltd.
|
||||||
|
// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR BSD-3-Clause
|
||||||
|
|
||||||
|
#include <spinner/spinner.h>
|
||||||
|
|
||||||
|
#include <QApplication>
|
||||||
|
#include <QBoxLayout>
|
||||||
|
#include <QCalendarWidget>
|
||||||
|
#include <QGroupBox>
|
||||||
|
#include <QLabel>
|
||||||
|
#include <QMetaEnum>
|
||||||
|
#include <QTextEdit>
|
||||||
|
#include <QToolButton>
|
||||||
|
|
||||||
|
using namespace SpinnerSolution;
|
||||||
|
|
||||||
|
enum class State {
|
||||||
|
NotRunning,
|
||||||
|
Running
|
||||||
|
};
|
||||||
|
|
||||||
|
static QString colorButtonStyleSheet(const QColor &bgColor)
|
||||||
|
{
|
||||||
|
QString rc("border-width: 2px; border-radius: 2px; border-color: black; ");
|
||||||
|
rc += bgColor.isValid() ? "border-style: solid; background:" + bgColor.name() + ";"
|
||||||
|
: QString("border-style: dotted;");
|
||||||
|
return rc;
|
||||||
|
}
|
||||||
|
|
||||||
|
static QColor stateToColor(State state)
|
||||||
|
{
|
||||||
|
switch (state) {
|
||||||
|
case State::NotRunning: return Qt::gray;
|
||||||
|
case State::Running: return Qt::yellow;
|
||||||
|
}
|
||||||
|
return {};
|
||||||
|
}
|
||||||
|
|
||||||
|
class StateIndicator : public QLabel
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
StateIndicator(QWidget *parent = nullptr)
|
||||||
|
: QLabel(parent)
|
||||||
|
{
|
||||||
|
setFixedSize(30, 30);
|
||||||
|
m_spinner = new Spinner(SpinnerSize::Small, this);
|
||||||
|
m_spinner->hide();
|
||||||
|
updateState();
|
||||||
|
}
|
||||||
|
|
||||||
|
void setState(State state)
|
||||||
|
{
|
||||||
|
if (m_state == state)
|
||||||
|
return;
|
||||||
|
m_state = state;
|
||||||
|
updateState();
|
||||||
|
}
|
||||||
|
|
||||||
|
private:
|
||||||
|
void updateState()
|
||||||
|
{
|
||||||
|
setStyleSheet(colorButtonStyleSheet(stateToColor(m_state)));
|
||||||
|
if (m_state == State::Running)
|
||||||
|
m_spinner->show();
|
||||||
|
else
|
||||||
|
m_spinner->hide();
|
||||||
|
}
|
||||||
|
State m_state = State::NotRunning;
|
||||||
|
Spinner *m_spinner = nullptr;
|
||||||
|
};
|
||||||
|
|
||||||
|
class StateWidget : public QWidget
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
StateWidget() : m_stateIndicator(new StateIndicator(this)) {
|
||||||
|
QBoxLayout *layout = new QHBoxLayout(this);
|
||||||
|
layout->setContentsMargins(0, 0, 0, 0);
|
||||||
|
layout->addWidget(m_stateIndicator);
|
||||||
|
setSizePolicy(QSizePolicy::Fixed, QSizePolicy::Fixed);
|
||||||
|
}
|
||||||
|
void setState(State state) { m_stateIndicator->setState(state); }
|
||||||
|
|
||||||
|
protected:
|
||||||
|
StateIndicator *m_stateIndicator = nullptr;
|
||||||
|
};
|
||||||
|
|
||||||
|
QGroupBox *createGroupBox(SpinnerSize size, QWidget *widget)
|
||||||
|
{
|
||||||
|
const QMetaEnum spinnerSize = QMetaEnum::fromType<SpinnerSize>();
|
||||||
|
QGroupBox *groupBox = new QGroupBox(spinnerSize.valueToKey(int(size)));
|
||||||
|
|
||||||
|
StateWidget *stateWidget = new StateWidget;
|
||||||
|
QToolButton *startButton = new QToolButton;
|
||||||
|
startButton->setText("Start");
|
||||||
|
QToolButton *stopButton = new QToolButton;
|
||||||
|
stopButton->setText("Stop");
|
||||||
|
|
||||||
|
QVBoxLayout *mainLayout = new QVBoxLayout(groupBox);
|
||||||
|
QHBoxLayout *topLayout = new QHBoxLayout();
|
||||||
|
topLayout->addWidget(stateWidget);
|
||||||
|
topLayout->addWidget(startButton);
|
||||||
|
topLayout->addWidget(stopButton);
|
||||||
|
topLayout->addStretch();
|
||||||
|
mainLayout->addLayout(topLayout);
|
||||||
|
mainLayout->addWidget(widget);
|
||||||
|
|
||||||
|
Spinner *spinner = new Spinner(size, widget);
|
||||||
|
spinner->hide(); // TODO: make the default hidden?
|
||||||
|
|
||||||
|
QObject::connect(startButton, &QAbstractButton::clicked, groupBox, [=] {
|
||||||
|
stateWidget->setState(State::Running);
|
||||||
|
spinner->show();
|
||||||
|
widget->setEnabled(false);
|
||||||
|
});
|
||||||
|
QObject::connect(stopButton, &QAbstractButton::clicked, groupBox, [=] {
|
||||||
|
stateWidget->setState(State::NotRunning);
|
||||||
|
spinner->hide();
|
||||||
|
widget->setEnabled(true);
|
||||||
|
});
|
||||||
|
return groupBox;
|
||||||
|
}
|
||||||
|
|
||||||
|
static QWidget *hr()
|
||||||
|
{
|
||||||
|
auto frame = new QFrame;
|
||||||
|
frame->setFrameShape(QFrame::HLine);
|
||||||
|
frame->setFrameShadow(QFrame::Sunken);
|
||||||
|
return frame;
|
||||||
|
}
|
||||||
|
|
||||||
|
static QString pangram(int count)
|
||||||
|
{
|
||||||
|
return QStringList(count, "The quick brown fox jumps over the lazy dog.").join(' ');
|
||||||
|
}
|
||||||
|
|
||||||
|
int main(int argc, char *argv[])
|
||||||
|
{
|
||||||
|
QApplication app(argc, argv);
|
||||||
|
|
||||||
|
QWidget mainWidget;
|
||||||
|
mainWidget.setWindowTitle("Spinner Example");
|
||||||
|
|
||||||
|
QVBoxLayout *mainLayout = new QVBoxLayout(&mainWidget);
|
||||||
|
|
||||||
|
QLabel *smallWidget = new QLabel;
|
||||||
|
smallWidget->setFixedWidth(30);
|
||||||
|
QGroupBox *smallGroupBox = createGroupBox(SpinnerSize::Small, smallWidget);
|
||||||
|
mainLayout->addWidget(smallGroupBox);
|
||||||
|
|
||||||
|
mainLayout->addWidget(hr());
|
||||||
|
|
||||||
|
QCalendarWidget *mediumWidget = new QCalendarWidget;
|
||||||
|
mediumWidget->setSizePolicy(QSizePolicy::Fixed, QSizePolicy::Fixed);
|
||||||
|
QGroupBox *mediumGroupBox = createGroupBox(SpinnerSize::Medium, mediumWidget);
|
||||||
|
mainLayout->addWidget(mediumGroupBox);
|
||||||
|
|
||||||
|
mainLayout->addWidget(hr());
|
||||||
|
|
||||||
|
QTextEdit *largeWidget = new QTextEdit;
|
||||||
|
largeWidget->setText(pangram(25));
|
||||||
|
QGroupBox *largeGroupBox = createGroupBox(SpinnerSize::Large, largeWidget);
|
||||||
|
mainLayout->addWidget(largeGroupBox);
|
||||||
|
|
||||||
|
mainWidget.show();
|
||||||
|
|
||||||
|
return app.exec();
|
||||||
|
}
|
||||||
13
tests/manual/spinner/spinner.qbs
Normal file
13
tests/manual/spinner/spinner.qbs
Normal file
@@ -0,0 +1,13 @@
|
|||||||
|
import qbs.FileInfo
|
||||||
|
|
||||||
|
QtcManualtest {
|
||||||
|
name: "Spinner example"
|
||||||
|
type: ["application"]
|
||||||
|
|
||||||
|
Depends { name: "Qt"; submodules: ["widgets"] }
|
||||||
|
Depends { name: "Spinner" }
|
||||||
|
|
||||||
|
files: [
|
||||||
|
"main.cpp",
|
||||||
|
]
|
||||||
|
}
|
||||||
Reference in New Issue
Block a user