diff options
-rw-r--r-- | dist/changelog/changes-10.0.0.md | 237 | ||||
-rw-r--r-- | src/libs/utils/tasktree.cpp | 745 | ||||
-rw-r--r-- | src/plugins/mcusupport/mcuabstractpackage.h | 1 | ||||
-rw-r--r-- | src/plugins/mcusupport/mcupackage.cpp | 5 | ||||
-rw-r--r-- | src/plugins/mcusupport/mcupackage.h | 1 | ||||
-rw-r--r-- | src/plugins/mcusupport/mcusupportoptionspage.cpp | 3 | ||||
-rw-r--r-- | src/plugins/mcusupport/test/packagemock.h | 1 | ||||
-rw-r--r-- | src/tools/cplusplus-ast2png/cplusplus-ast2png.cpp | 6 |
8 files changed, 957 insertions, 42 deletions
diff --git a/dist/changelog/changes-10.0.0.md b/dist/changelog/changes-10.0.0.md new file mode 100644 index 0000000000..a049b07baf --- /dev/null +++ b/dist/changelog/changes-10.0.0.md @@ -0,0 +1,237 @@ +Qt Creator 10 +============= + +Qt Creator version 10 contains bug fixes and new features. + +The most important changes are listed in this document. For a complete list of +changes, see the Git log for the Qt Creator sources that you can check out from +the public Git repository. For example: + + git clone git://code.qt.io/qt-creator/qt-creator.git + git log --cherry-pick --pretty=oneline origin/9.0..v10.0.0 + +General +------- + +* Added support for temporarily dragging progress details out of the way + (QTCREATORBUG-28078) + +Editing +------- + +* Added `Follow Symbol` for `http(s)` string literals (QTCREATORBUG-14967) +* Added environment expansion to file system locator filter (QTCREATORBUG-242) +* Added `Temporarily hide inline annotations` for types of annotations +* Improved cursor visibility with indentation visualization (QTCREATORBUG-28645) +* Fixed editor scrolling when pressing backspace (QTCREATORBUG-28316) +* Fixed performance of rendering many search results (QTCREATORBUG-21056) + +### C++ + +* Added renaming of includes when renaming `.ui` files (QTCREATORBUG-14259) +* Added option for ignoring files for indexing (QTCREATORBUG-28313) +* Added `Tools > C++ > Find Unused Functions`, and `Find Unused C/C++ Functions` + to the project context menu (QTCREATORBUG-6772) +* Added automatic refactoring of C++ code when `.ui` files are renamed + (QTCREATORBUG-1179) +* Fixed text codec when rewriting headers as part of renaming + (QTCREATORBUG-28164) +* Fixed color of whitespace visualization in string literals + (QTCREATORBUG-26693, QTCREATORBUG-28284) +* Fixed `Move Definition` for template functions (QTCREATORBUG-28186) +* Clangd + * Made temporary disabling of global indexing possibly by cancelling in the + progress indicator + * Added support for highlighting angle brackets +* Built-in + * Added support for spaceship operator (QTCREATORBUG-27503) + * Fixed handling of `= default` (QTCREATORBUG-28102) +* Clang Format + * Enabled by default + * Added project setting for `Clang Format` (QTCREATORBUG-28188) + +### Language Server Protocol + +* Added `Restart` action to menu in editor tool bar +* Added `Call Hierarchy` (QTCREATORBUG-11660) + +### QML + +* Added experimental support for QML language server +* Added color preview tooltip (QTCREATORBUG-28446) +* Added option for applying `qmlformat` on file save (QTCREATORBUG-28192, + QTCREATORBUG-26602) +* Added `Follow Symbol` for QRC paths in string literals (QTCREATORBUG-28087) +* Adapted wizard to new features in Qt 6.4 and Qt 6.5 (QTBUG-47996) +* Fixed freeze when closing file (QTCREATORBUG-28206) +* Fixed that `QtObject` was not recognized (QTCREATORBUG-28287, + QTCREATORBUG-28375) + +### Python + +* Added interpreter selector to editor toolbar (PYSIDE-2154) + +Projects +-------- + +* Added `Build > Run Generator` for exporting projects to other build systems + (QTCREATORBUG-28149) +* Added option for browsing remote file system for remote builds and targets +* Added support for opening remote terminal +* Fixed that wizards did not create target directories (QTCREATORBUG-28346) +* Fixed that absolute paths could be shown when relative paths would be + preferable (QTCREATORBUG-288) + +### CMake + +* Added deployment method with `cmake --install` (QTCREATORBUG-25880) +* Added option for using `clang-format` for CMake files + ([clang-format Documentation](https://cmake-format.readthedocs.io/en/latest/)) +* Added option for showing advanced configure items by default +* Moved `Autorun CMake` to global settings +* Changed environment for running CMake to be based on build environment by + default (QTCREATORBUG-28513) +* Fixed that `Package manager auto setup` created dependency of project build to + Qt Creator installation + +### Qbs + +* Updated code model to Qt 6.5 +* Added `Profile` build variant (QTCREATORBUG-27206) +* Fixed that generated files were not made known to the code model + +### Python + +* Removed wizard for dynamically loaded `.ui` projects (QTCREATORBUG-25807) + +### Qt Quick UI Prototype + +* Added support for running on remote Linux devices + +Debugging +--------- + +### C++ + +* Added pretty printers for `variant`, `optional` and `tuple` from `libcpp` + (QTCREATORBUG-25865) +* Fixed highlighting in disassembly view +* Fixed skipping `std::function` details when stepping + +Analyzer +-------- + +### Clang + +* Split `Clang-Tidy and Clazy` into separate `Clang-Tidy` and `Clazy` analyzers + +Version Control Systems +----------------------- + +* Moved support for `Fossil` SCM into mainline repository +* Removed settings for prompting to submit (QTCREATORBUG-22233) +* Added links to file names in diff output (QTCREATORBUG-27309) +* Fixed blame on symbolic links (QTCREATORBUG-20792) +* Fixed saving of files before applying action on chunks (QTCREATORBUG-22506) +* Fixed line ending preservation when reverting chunks (QTCREATORBUG-12690) + +### Git + +* Improved tracking of external changes (QTCREATORBUG-21089) +* Added editor annotation for blame information (instant blame), with setting + (opt-out), and action to show it manually for the current line + (QTCREATORBUG-23299) + +Test Integration +---------------- + +* Improved `Run` and `Debug Test Under Cursor` (QTCREATORBUG-28496) +* Improved number of files that are scanned for tests +* Improved output handling (QTCREATORBUG-28706) +* Made expensive checking for tests in derived `TestCase` objects optional + +Platforms +--------- + +### macOS + +* Changed kits to prefer Xcode toolchain over the wrappers in `/bin` + +### Android + +* Removed service management from manifest editor (QTCREATORBUG-28024) + +### Remote Linux + +* Fixed that opening file dialog unnecessarily queried for password for remote + devices + +### Docker + +* Added support for remote code model via remote Clangd +* Added support for loading and attaching to core dumps from remote devices +* Added support for using Clang Format on remote files +* Added option to enable necessary capabilities for docker devices to allow lldb + debugging +* Fixed issue with space in file paths (QTCREATORBUG-28476) +* Fixed that auto-detection controls were shown for devices registered by the + installer + +Credits for these changes go to: +-------------------------------- +Aleksei German +Alessandro Portale +Alexander Pershin +Ali Kianian +Amr Essam +Andre Hartmann +André Pönitz +Antti Määttä +Artem Sokolovskii +Artur Shepilko +Assam Boudjelthia +BogDan Vatra +Burak Hancerli +Christian Kandeler +Christian Stenger +Cristian Adam +Cristián Maureira-Fredes +David Schulz +Dmitry Bravikov +Eike Ziller +Fabian Kosmale +Fawzi Mohamed +Henning Gruendl +Jaroslaw Kobus +Jussi Witick +Kai Köhne +Knud Dollereder +Knut Petter Svendsen +Leena Miettinen +Łukasz Wojniłowicz +Mahmoud Badri +Marc Mutz +Marco Bubke +Marcus Tillmanns +Mats Honkamaa +Miikka Heikkinen +Mikhail Khachayants +Orgad Shaneh +Oswald Buddenhagen +Philip Van Hoof +Pranta Dastider +Robert Löhning +Sami Shalayel +Samuel Ghinet +Sergey Levin +Sivert Krøvel +Tasuku Suzuki +Thiago Macieira +Thomas Hartmann +Tim Jenssen +Tomáš Juřena +Topi Reinio +Ulf Hermann +Vikas Pachdha +Xavier Besson +Yasser Grimes diff --git a/src/libs/utils/tasktree.cpp b/src/libs/utils/tasktree.cpp index 1cd4fd3f01..f99b20d761 100644 --- a/src/libs/utils/tasktree.cpp +++ b/src/libs/utils/tasktree.cpp @@ -589,46 +589,715 @@ void TaskNode::invokeEndHandler(bool success) /*! \class Utils::TaskTree - - \brief The TaskTree class is responsible for running async task tree structure defined in a + \inheaderfile utils/tasktree.h + \inmodule QtCreator + \ingroup mainclasses + \brief The TaskTree class runs an async task tree structure defined in a declarative way. - The Tasking namespace (similar to Layouting) is designer for building declarative task - tree structure. The examples of tasks that can be used inside TaskTree are e.g. QtcProcess, - FileTransfer, AsyncTask<>. It's extensible, so any possible asynchronous task may be - integrated and used inside TaskTree. TaskTree enables to form sophisticated mixtures of - parallel or sequential flow of tasks in tree form. - - The TaskTree consist of Group root element. The Group can have nested Group elements. - The Group may also contain any number of tasks, e.g. Process, FileTransfer, - AsyncTask<ReturnType>. - - Each Group can contain various other elements describing the processing flow. - - The execute mode elements of a Group specify how direct children of a Group will be executed. - The "sequential" element of a Group means all tasks in a group will be executed in chain, - so after the previous task finished, the next will be started. This is the default Group - behavior. The "parallel" element of a Group means that all tasks in a Group will be started - simultaneously. When having nested Groups hierarchy, we may mix execute modes freely - and each Group will be executed according to its own execute mode. - The "sequential" mode may be very useful in cases when result data from one task is need to - be passed as an input data to the other task - sequential mode guarantees that the next - task will be started only after the previous task has already finished. - - There are many possible "workflow" behaviors for the Group. E.g. "stopOnError", - the default Group workflow behavior, means that whenever any direct child of a Group - finished with error, we immediately stop processing other tasks in this group - (in parallel case) by canceling them and immediately finish the Group with error. - - The user of TaskTree specifies how to setup his tasks (by providing TaskSetupHandlers) - and how to collect output data from the finished tasks (by providing TaskEndHandlers). - The user don't need to create tasks manually - TaskTree will create them when it's needed - and destroy when they are not used anymore. - - Whenever a Group elemenent is being started, the Group's OnGroupSetup handler is being called. - Just after the handler finishes, all Group's children are executed (either in parallel or - in sequence). When all Group's children finished, one of Group's OnGroupDone or OnGroupError - is being executed, depending on results of children execution and Group's workflow policy. + Use the Tasking namespace to build extensible, declarative task tree + structures that contain possibly asynchronous tasks, such as QtcProcess, + FileTransfer, or AsyncTask<ReturnType>. TaskTree structures enable you + to create a sophisticated mixture of a parallel or sequential flow of tasks + in the form of a tree and to run it any time later. + + \section1 Root Element and Tasks + + The TaskTree has a mandatory Group root element, which may contain + any number of tasks of various types, such as Process, FileTransfer, + or AsyncTask<ReturnType>: + + \code + using namespace Utils; + using namespace Tasking; + + const Group root { + Process(...), + Async<int>(...), + Transfer(...) + }; + + TaskTree *taskTree = new TaskTree(root); + connect(taskTree, &TaskTree::done, ...); // a successfully finished handler + connect(taskTree, &TaskTree::errorOccurred, ...); // an erroneously finished handler + taskTree->start(); + \endcode + + The task tree above has a top level element of the Group type that contains + tasks of the type QtcProcess, FileTransfer, and AsyncTask<int>. + After taskTree->start() is called, the tasks are run in a chain, starting + with Process. When Process finishes successfully, the Async<int> task is + started. Finally, when the asynchronous task finishes successfully, the + FileTransfer task is started. + + When the last running task finishes with success, the task tree is considered + to have run successfully and the TaskTree::done() signal is emitted. + When a task finishes with an error, the execution of the task tree is stopped + and the remaining tasks are skipped. The task tree finishes with an error and + sends the TaskTree::errorOccurred() signal. + + \section1 Groups + + The parent of the Group sees it as a single task. Like other tasks, + the group can be started and it can finish with success or an error. + The Group elements can be nested to create a tree structure: + + \code + const Group root { + Group { + parallel, + Process(...), + Async<int>(...) + }, + Transfer(...) + }; + \endcode + + The example above differs from the first example in that the root element has + a subgroup that contains the Process and Async<int> tasks. The subgroup is a + sibling element of the Transfer task in the root. The subgroup contains an + additional \e parallel element that instructs its Group to execute its tasks + in parallel. + + So, when the tree above is started, the Process and Async<int> tasks start + immediately and run in parallel. Since the root group doesn't contain a + \e parallel element, its direct child tasks are run in sequence. Thus, the + Transfer task starts when the whole subgroup finishes. The group is + considered as finished when all its tasks have finished. The order in which + the tasks finish is not relevant. + + So, depending on which task lasts longer (Process or Async<int>), the + following scenarios can take place: + + \table + \header + \li Scenario 1 + \li Scenario 2 + \row + \li Root Group starts + \li Root Group starts + \row + \li Sub Group starts + \li Sub Group starts + \row + \li Process starts + \li Process starts + \row + \li Async<int> starts + \li Async<int> starts + \row + \li ... + \li ... + \row + \li \b {Process finishes} + \li \b {Async<int> finishes} + \row + \li ... + \li ... + \row + \li \b {Async<int> finishes} + \li \b {Process finishes} + \row + \li Sub Group finishes + \li Sub Group finishes + \row + \li Transfer starts + \li Transfer starts + \row + \li ... + \li ... + \row + \li Transfer finishes + \li Transfer finishes + \row + \li Root Group finishes + \li Root Group finishes + \endtable + + The differences between the scenarios are marked with bold. Three dots mean + that an unspecified amount of time passes between previous and next events + (a task or tasks continue to run). No dots between events + means that they occur synchronously. + + The presented scenarios assume that all tasks run successfully. If a task + fails during execution, the task tree finishes with an error. In particular, + when Process finishes with an error while Async<int> is still being executed, + Async<int> is automatically stopped, the subgroup finishes with an error, + Transfer is skipped, and the tree finishes with an error. + + \section1 Task Types + + Each task type is associated with its corresponding task class that executes + the task. For example, a Process task inside a task tree is associated with + the QtcProcess class that executes the process. The associated objects are + automatically created, started, and destructed exclusively by the task tree + at the appropriate time. + + If a root group consists of five sequential Process tasks, and the task tree + executes the group, it creates an instance of QtcProcess for the first + Process task and starts it. If the QtcProcess instance finishes successfully, + the task tree destructs it and creates a new QtcProcess instance for the + second Process, and so on. If the first task finishes with an error, the task + tree stops creating QtcProcess instances, and the root group finishes with an + error. + + The following table shows examples of task types and their corresponding task + classes: + + \table + \header + \li Task Type (Tasking Namespace) + \li Associated Task Class + \li Brief Description + \row + \li Process + \li Utils::QtcProcess + \li Starts processes. + \row + \li Async<ReturnType> + \li Utils::AsyncTask<ReturnType> + \li Starts asynchronous tasks; run in separate thread. + \row + \li Tree + \li Utils::TaskTree + \li Starts a nested task tree. + \row + \li Transfer + \li ProjectExplorer::FileTransfer + \li Starts file transfer between different devices. + \endtable + + \section1 Task Handlers + + Use Task handlers to set up a task for execution and to enable reading + the output data from the task when it finishes with success or an error. + + \section2 Task Start Handler + + When a corresponding task class object is created and before it's started, + the task tree invokes a mandatory user-provided setup handler. The setup + handler should always take a \e reference to the associated task class object: + + \code + const auto onSetup = [](QtcProcess &process) { + process.setCommand({"sleep", {"3"}}); + }; + const Group root { + Process(onSetup) + }; + \endcode + + You can modify the passed QtcProcess in the setup handler, so that the task + tree can start the process according to your configuration. + You do not need to call \e {process.start();} in the setup handler, + as the task tree calls it when needed. The setup handler is mandatory + and must be the first argument of the task's constructor. + + Optionally, the setup handler may return a TaskAction. The returned + TaskAction influences the further start behavior of a given task. The + possible values are: + + \table + \header + \li TaskAction Value + \li Brief Description + \row + \li Continue + \li The task is started normally. This is the default behavior when the + setup handler doesn't return TaskAction (that is, its return type is + void). + \row + \li StopWithDone + \li The task won't be started and it will report success to its parent. + \row + \li StopWithError + \li The task won't be started and it will report an error to its parent. + \endtable + + This is useful for running a task only when a condition is met and the data + needed to evaluate this condition is not known until previously started tasks + finish. This way, the setup handler dynamically decides whether to start the + corresponding task normally or skip it and report success or an error. + For more information about inter-task data exchange, see \l Storage. + + \section2 Task's Done and Error Handlers + + When a running task finishes, the task tree invokes an optionally provided + done or error handler. Both handlers should always take a \e {const reference} + to the associated task class object: + + \code + const auto onSetup = [](QtcProcess &process) { + process.setCommand({"sleep", {"3"}}); + }; + const auto onDone = [](const QtcProcess &process) { + qDebug() << "Success" << process.cleanedStdOut(); + }; + const auto onError = [](const QtcProcess &process) { + qDebug() << "Failure" << process.cleanedStdErr(); + }; + const Group root { + Process(onSetup, onDone, onError) + }; + \endcode + + The done and error handlers may collect output data from QtcProcess, and store it + for further processing or perform additional actions. The done handler is optional. + When used, it must be the second argument of the task constructor. + The error handler must always be the third argument. + You can omit the handlers or substitute the ones that you do not need with curly braces ({}). + + \note If the task setup handler returns StopWithDone or StopWithError, + neither the done nor error handler is invoked. + + \section1 Group Handlers + + Similarly to task handlers, group handlers enable you to set up a group to + execute and to apply more actions when the whole group finishes with + success or an error. + + \section2 Group's Start Handler + + The task tree invokes the group start handler before it starts the child + tasks. The group handler doesn't take any arguments: + + \code + const auto onGroupSetup = [] { + qDebug() << "Entering the group"; + }; + const Group root { + OnGroupSetup(onGroupSetup), + Process(...) + }; + \endcode + + The group setup handler is optional. To define a group setup handler, add an + OnGroupSetup element to a group. The argument of OnGroupSetup is a user + handler. If you add more than one OnGroupSetup element to a group, an assert + is triggered at runtime that includes an error message. + + Like the task start handler, the group start handler may return TaskAction. + The returned TaskAction value affects the start behavior of the + 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 + tasks are started normally. Otherwise, when the start handler returns + TaskAction::StopWithDone or TaskAction::StopWithError, the tasks are not + started (they are skipped) and the group itself reports success or failure, + depending on the returned value, respectively. + + \code + const Group root { + OnGroupSetup([] { qDebug() << "Root setup"; }), + Group { + OnGroupSetup([] { qDebug() << "Group 1 setup"; return TaskAction::Continue; }), + Process(...) // Process 1 + }, + Group { + OnGroupSetup([] { qDebug() << "Group 2 setup"; return TaskAction::StopWithDone; }), + Process(...) // Process 2 + }, + Group { + OnGroupSetup([] { qDebug() << "Group 3 setup"; return TaskAction::StopWithError; }), + Process(...) // Process 3 + }, + Process(...) // Process 4 + }; + \endcode + + In the above example, all subgroups of a root group define their setup handlers. + The following scenario assumes that all started processes finish with success: + + \table + \header + \li Scenario + \li Comment + \row + \li Root Group starts + \li Doesn't return TaskAction, so its tasks are executed. + \row + \li Group 1 starts + \li Returns Continue, so its tasks are executed. + \row + \li Process 1 starts + \li + \row + \li ... + \li ... + \row + \li Process 1 finishes (success) + \li + \row + \li Group 1 finishes (success) + \li + \row + \li Group 2 starts + \li Returns StopWithDone, so Process 2 is skipped and Group 2 reports + success. + \row + \li Group 2 finishes (success) + \li + \row + \li Group 3 starts + \li Returns StopWithError, so Process 3 is skipped and Group 3 reports + an error. + \row + \li Group 3 finishes (error) + \li + \row + \li Root Group finishes (error) + \li Group 3, which is a direct child of the root group, finished with an + error, so the root group stops executing, skips Process 4, which has + not started yet, and reports an error. + \endtable + + \section2 Groups's Done and Error Handlers + + A Group's done or error handler is executed after the successful or failed + execution of its tasks, respectively. The final value reported by the + group depends on its \l {Workflow Policy}. The handlers can apply other + necessary actions. The done and error handlers are defined inside the + OnGroupDone and OnGroupError elements of a group, respectively. They do not + take arguments: + + \code + const Group root { + OnGroupSetup([] { qDebug() << "Root setup"; }), + Process(...), + OnGroupDone([] { qDebug() << "Root finished with success"; }), + OnGroupError([] { qDebug() << "Root finished with error"; }) + }; + \endcode + + The group done and error handlers are optional. If you add more than one + OnGroupDone or OnGroupError each to a group, an assert is triggered at + runtime that includes an error message. + + \note Even if the group setup handler returns StopWithDone or StopWithError, + one of the task's done or error handlers is invoked. This behavior differs + from that of task handlers and might change in the future. + + \section1 Other Group Elements + + A group can contain other elements that describe the processing flow, such as + the execution mode or workflow policy. It can also contain storage elements + that are responsible for collecting and sharing custom common data gathered + during group execution. + + \section2 Execution Mode + + The execution mode element in a Group specifies how the direct child tasks of + the Group are started. + + \table + \header + \li Execution Mode + \li Description + \row + \li sequential + \li Default. When a Group has no execution mode, it runs in the + sequential mode. All the direct child tasks of a group are started + in a chain, so that when one task finishes, the next one starts. + This enables you to pass the results from the previous task + as input to the next task before it starts. This mode guarantees + that the next task is started only after the previous task finishes. + \row + \li parallel + \li All the direct child tasks of a group are started after the group is + started, without waiting for the previous tasks to finish. In this + mode, all tasks run simultaneously. + \row + \li ParallelLimit(int limit) + \li In this mode, a limited number of direct child tasks run simultaneously. + The \e limit defines the maximum number of tasks running in parallel + in a group. When the group is started, the first batch tasks is + started (the number of tasks in batch equals to passed limit, at most), + while the others are kept waiting. When a running task finishes, + the group starts the next remaining one, so that the \e limit + of simultaneously running tasks inside a group isn't exceeded. + This repeats on every child task's finish until all child tasks are started. + This enables you to limit the maximum number of tasks that + run simultaneously, for example if running too many processes might + block the machine for a long time. The value 1 means \e sequential + execution. The value 0 means unlimited and equals \e parallel. + \endtable + + In all execution modes, a group starts tasks in the oder in which they appear. + + If a child of a group is also a group (in a nested tree), the child group + runs its tasks according to its own execution mode. + + \section2 Workflow Policy + + The workflow policy element in a Group specifies how the group should behave + when its direct child tasks finish: + + \table + \header + \li Workflow Policy + \li Description + \row + \li stopOnError + \li Default. If a task finishes with an error, the group: + \list 1 + \li Stops the running tasks (if any - for example, in parallel + mode). + \li Skips executing tasks it has not started (for example, in the + sequential mode). + \li Immediately finishes with an error. + \endlist + If all child tasks finish successfully or the group is empty, the group + finishes with success. + \row + \li continueOnError + \li Similar to stopOnError, but in case any child finishes with + an error, the execution continues until all tasks finish, + and the group reports an error afterwards, even when some other + tasks in group finished with success. + If a task finishes with an error, the group: + \list 1 + \li Continues executing the tasks that are running or have not + started yet. + \li Finishes with an error when all tasks finish. + \endlist + If all tasks finish successfully or the group is empty, the group + finishes with success. + \row + \li stopOnDone + \li If a task finishes with success, the group: + \list 1 + \li Stops running tasks and skips those that it has not started. + \li Immediately finishes with success. + \endlist + If all tasks finish with an error or the group is empty, the group + finishes with an error. + \row + \li continueOnDone + \li Similar to stopOnDone, but in case any child finishes + successfully, the execution continues until all tasks finish, + and the group reports success afterwards, even when some other + tasks in group finished with an error. + If a task finishes with success, the group: + \list 1 + \li Continues executing the tasks that are running or have not + started yet. + \li Finishes with success when all tasks finish. + \endlist + If all tasks finish with an error or the group is empty, the group + finishes with an error. + \row + \li optional + \li The group executes all tasks and ignores their return state. If all + tasks finish or the group is empty, the group finishes with success. + \endtable + + If a child of a group is also a group (in a nested tree), the child group + runs its tasks according to its own workflow policy. + + \section2 Storage + + Use the Storage element to exchange information between tasks. Especially, + in the sequential execution mode, when a task needs data from another task + before it can start. For example, a task tree that copies data by reading + it from a source and writing it to a destination might look as follows: + + \code + static QByteArray load(const FilePath &fileName) { ... } + static void save(const FilePath &fileName, const QByteArray &array) { ... } + + static TaskItem diffRecipe(const FilePath &source, const FilePath &destination) + { + struct CopyStorage { // [1] custom inter-task struct + QByteArray content; // [2] custom inter-task data + }; + + // [3] instance of custom inter-task struct manageable by task tree + const TreeStorage<CopyStorage> storage; + + const auto onLoaderSetup = [source](Async<QByteArray> &async) { + async.setAsyncCallData(&load, source); + }; + // [4] runtime: task tree activates the instance from [5] before invoking handler + const auto onLoaderDone = [storage](const Async<QByteArray> &async) { + storage->content = async.result(); + }; + + // [4] runtime: task tree activates the instance from [5] before invoking handler + const auto onSaverSetup = [storage, destination](Async<void> &async) { + async.setAsyncCallData(&save, destination, storage->content); + }; + const auto onSaverDone = [](const Async<void> &async) { + qDebug() << "Save done successfully"; + }; + + const Group root { + // [5] runtime: task tree creates an instance of CopyStorage when root is entered + Storage(storage), + Async<QByteArray>(onLoaderSetup, onLoaderDone), + Async<void>(onSaverSetup, onSaverDone) + }; + return root; + } + \endcode + + In the example above, the inter-task data consists of a QByteArray content + variable [2] enclosed in a CopyStorage custom struct [1]. If the loader + finishes successfully, it stores the data in a CopyStorage::content + variable. The saver then uses the variable to configure the saving task. + + To enable a task tree to manage the CopyStorage struct, an instance of + TreeStorage<CopyStorage> is created [3]. If a copy of this object is + inserted as group's child task [5], an instance of CopyStorage struct is + created dynamically when the task tree enters this group. When the task + tree leaves this group, the existing instance of CopyStorage struct is + destructed as it's no longer needed. + + If several task trees that hold a copy of the common TreeStorage<CopyStorage> + instance run simultaneously, each task tree contains its own copy of the + CopyStorage struct. + + You can access CopyStorage from any handler in the group with a storage object. + This includes all handlers of all descendant tasks of the group with + a storage object. To access the custom struct in a handler, pass the + copy of the TreeStorage<CopyStorage> object to the handler (for example, in + a lambda capture) [4]. + + When the task tree invokes a handler in a subtree containing the storage [5], + the task tree activates its own CopyStorage instance inside the + TreeStorage<CopyStorage> object. Therefore, the CopyStorage struct may be + accessed only from within the handler body. To access the currently active + CopyStorage from within TreeStorage<CopyStorage>, use the TreeStorage::operator->() + or TreeStorage::activeStorage() method. + + The following list summarizes how to employ a Storage object into the task + tree: + \list 1 + \li Define the custom structure MyStorage with custom data [1], [2] + \li Create an instance of TreeStorage<MyStorage> storage [3] + \li Pass the TreeStorage<MyStorage> instance to handlers [4] + \li Insert the TreeStorage<MyStorage> instance into a group [5] + \endlist + + \note The current implementation assumes that all running task trees + containing copies of the same TreeStorage run in the same thread. Otherwise, + the behavior is undefined. + + \section1 TaskTree + + TaskTree executes the tree structure of asynchronous tasks according to the + recipe described by the Group root element. + + As TaskTree is also an asynchronous task, it can be a part of another TaskTree. + To place a nested TaskTree inside another TaskTree, insert the Tasking::Tree + element into other tree's Group element. + + TaskTree reports progress of completed tasks when running. The progress value + is increased when a task finishes or is skipped or stopped. + When TaskTree is finished and the TaskTree::done() or TaskTree::errorOccurred() + signal is emitted, the current value of the progress equals the maximum + progress value. Maximum progress equals the total number of tasks in a tree. + A nested TaskTree is counted as a single task, and its child tasks are not + counted in the top level tree. Groups themselves are not counted as tasks, + but their tasks are counted. + + To set additional initial data for the running tree, modify the storage + instances in a tree when it creates them by installing a storage setup + handler: + + \code + TreeStorage<CopyStorage> storage; + Group root = ...; // storage placed inside root's group and inside handlers + TaskTree taskTree(root); + auto initStorage = [](CopyStorage *storage){ + storage->content = "initial content"; + }; + taskTree.onStorageSetup(storage, initStorage); + taskTree.start(); + \endcode + + When the running task tree creates a CopyStorage instance, and before any + handler inside a tree is called, the task tree calls the initStorage handler, + to enable setting up initial data of the storage, unique to this particular + run of taskTree. + + Similarly, to collect some additional result data from the running tree, + read it from storage instances in the tree when they are about to be + destroyed. To do this, install a storage done handler: + + \code + TreeStorage<CopyStorage> storage; + Group root = ...; // storage placed inside root's group and inside handlers + TaskTree taskTree(root); + auto collectStorage = [](CopyStorage *storage){ + qDebug() << "final content" << storage->content; + }; + taskTree.onStorageDone(storage, collectStorage); + taskTree.start(); + \endcode + + When the running task tree is about to destroy a CopyStorage instance, the + task tree calls the collectStorage handler, to enable reading the final data + from the storage, unique to this particular run of taskTree. + + \section1 Task Adapters + + To extend a TaskTree with new a task type, implement a simple adapter class + derived from the TaskAdapter class template. The following class is an + adapter for a single shot timer, which may be considered as a new + asynchronous task: + + \code + class TimeoutAdapter : public Utils::Tasking::TaskAdapter<QTimer> + { + public: + TimeoutAdapter() { + task()->setSingleShot(true); + task()->setInterval(1000); + connect(task(), &QTimer::timeout, this, [this] { emit done(true); }); + } + void start() final { task()->start(); } + }; + + QTC_DECLARE_CUSTOM_TASK(Timeout, TimeoutAdapter); + \endcode + + You must derive the custom adapter from the TaskAdapter class template + instantiated with a template parameter of the class implementing a running + task. The code above uses QTimer to run the task. This class appears + later as an argument to the task's handlers. The instance of this class + parameter automatically becomes a member of the TaskAdapter template, and is + accessible through the TaskAdapter::task() method. The constructor + of TimeoutAdapter initially configures the QTimer object and connects + to the QTimer::timeout signal. When the signal is triggered, TimeoutAdapter + emits the done(true) signal to inform the task tree that the task finished + successfully. If it emits done(false), the task finished with an error. + The TaskAdapter::start() method starts the timer. + + To make QTimer accessible inside TaskTree under the \e Timeout name, + register it with QTC_DECLARE_CUSTOM_TASK(Timeout, TimeoutAdapter). Timeout + becomes a new task type inside Utils::Tasking namespace, using TimeoutAdapter. + + The new task type is now registered, and you can use it in TaskTree: + + \code + const auto onTimeoutSetup = [](QTimer &task) { + task.setInterval(2000); + }; + const auto onTimeoutDone = [](const QTimer &task) { + qDebug() << "timeout triggered"; + }; + + const Group root { + Timeout(onTimeoutSetup, onTimeoutDone) + }; + \endcode + + When a task tree containing the root from the above example is started, it + prints a debug message within two seconds and then finishes successfully. + + \note The class implementing the running task should have a default constructor, + and objects of this class should be freely destructible. It should be allowed + to destroy a running object, preferably without waiting for the running task + to finish (that is, safe non-blocking destructor of a running task). */ TaskTree::TaskTree() diff --git a/src/plugins/mcusupport/mcuabstractpackage.h b/src/plugins/mcusupport/mcuabstractpackage.h index 248c91287d..33e9e62bd3 100644 --- a/src/plugins/mcusupport/mcuabstractpackage.h +++ b/src/plugins/mcusupport/mcuabstractpackage.h @@ -47,6 +47,7 @@ public: virtual bool isValidStatus() const = 0; virtual bool writeToSettings() const = 0; + virtual void readFromSettings() = 0; virtual QWidget *widget() = 0; virtual const McuPackageVersionDetector *getVersionDetector() const = 0; diff --git a/src/plugins/mcusupport/mcupackage.cpp b/src/plugins/mcusupport/mcupackage.cpp index 287c89b93e..6feaf728a6 100644 --- a/src/plugins/mcusupport/mcupackage.cpp +++ b/src/plugins/mcusupport/mcupackage.cpp @@ -244,6 +244,11 @@ bool McuPackage::writeToSettings() const return settingsHandler->write(m_settingsKey, m_path, m_defaultPath); } +void McuPackage::readFromSettings() +{ + setPath(settingsHandler->getPath(m_settingsKey, QSettings::UserScope, m_defaultPath)); +} + QWidget *McuPackage::widget() { auto *widget = new QWidget; diff --git a/src/plugins/mcusupport/mcupackage.h b/src/plugins/mcusupport/mcupackage.h index 4cf4606e9f..1bd3b26fb4 100644 --- a/src/plugins/mcusupport/mcupackage.h +++ b/src/plugins/mcusupport/mcupackage.h @@ -66,6 +66,7 @@ public: QString statusText() const override; bool writeToSettings() const override; + void readFromSettings() override; QWidget *widget() override; const McuPackageVersionDetector *getVersionDetector() const override; diff --git a/src/plugins/mcusupport/mcusupportoptionspage.cpp b/src/plugins/mcusupport/mcusupportoptionspage.cpp index 7a8a7d046c..c24785c0db 100644 --- a/src/plugins/mcusupport/mcusupportoptionspage.cpp +++ b/src/plugins/mcusupport/mcusupportoptionspage.cpp @@ -90,6 +90,9 @@ McuSupportOptionsWidget::McuSupportOptionsWidget(McuSupportOptions &options, m_qtForMCUsSdkGroupBox = new QGroupBox(Tr::tr("Qt for MCUs SDK")); m_qtForMCUsSdkGroupBox->setFlat(true); auto *layout = new QVBoxLayout(m_qtForMCUsSdkGroupBox); + // Re-read the qtForMCUs package from settings to discard un-applied changes from previous sessions + m_options.qtForMCUsSdkPackage->readFromSettings(); + layout->addWidget(m_options.qtForMCUsSdkPackage->widget()); mainLayout->addWidget(m_qtForMCUsSdkGroupBox); } diff --git a/src/plugins/mcusupport/test/packagemock.h b/src/plugins/mcusupport/test/packagemock.h index fb4f73601f..1e62fb7764 100644 --- a/src/plugins/mcusupport/test/packagemock.h +++ b/src/plugins/mcusupport/test/packagemock.h @@ -29,6 +29,7 @@ public: MOCK_METHOD(QString, environmentVariableName, (), (const)); MOCK_METHOD(bool, isAddToSystemPath, (), (const)); MOCK_METHOD(bool, writeToSettings, (), (const)); + MOCK_METHOD(void, readFromSettings, ()); MOCK_METHOD(QStringList, versions, (), (const)); MOCK_METHOD(QWidget *, widget, ()); diff --git a/src/tools/cplusplus-ast2png/cplusplus-ast2png.cpp b/src/tools/cplusplus-ast2png/cplusplus-ast2png.cpp index 36fb7533e5..5fe89323a9 100644 --- a/src/tools/cplusplus-ast2png/cplusplus-ast2png.cpp +++ b/src/tools/cplusplus-ast2png/cplusplus-ast2png.cpp @@ -511,11 +511,9 @@ int main(int argc, char *argv[]) } // Process options & arguments - const bool helpRequested = args.contains(QLatin1String("-h")) - || args.contains(QLatin1String("-help")); - if (helpRequested) { + if (args.contains(QLatin1String("-h")) || args.contains(QLatin1String("-help"))) { printUsage(); - return helpRequested ? EXIT_SUCCESS : EXIT_FAILURE; + return EXIT_SUCCESS; } if (args.contains(QLatin1String("-v"))) { |