Merge remote-tracking branch 'origin/11.0'

Conflicts:
	cmake/QtCreatorIDEBranding.cmake
	qbs/modules/qtc/qtc.qbs

Change-Id: Ide0650d70d5dbd32a5492c8db24089925251af12
This commit is contained in:
Eike Ziller
2023-06-12 12:33:26 +02:00
68 changed files with 1125 additions and 863 deletions

View File

@@ -10,21 +10,83 @@ the public Git repository. For example:
git clone git://code.qt.io/qt-creator/qt-creator.git git clone git://code.qt.io/qt-creator/qt-creator.git
git log --cherry-pick --pretty=oneline origin/10.0..v11.0.0 git log --cherry-pick --pretty=oneline origin/10.0..v11.0.0
What's new?
------------
* Markdown editor with preview
([QTCREATORBUG-27883](https://bugreports.qt.io/browse/QTCREATORBUG-27883))
* Internal terminal
([QTCREATORBUG-8511](https://bugreports.qt.io/browse/QTCREATORBUG-8511))
* Experimental support for GitHub Copilot
* Experimental support for the `vcpkg` C/C++ package manager
* Experimental support for the Axivion static analyzer
### Markdown
You can open markdown (.md) files for editing or select `File > New File >
General > Markdown File` to create a new file.
([Documentation](https://doc-snapshots.qt.io/qtcreator-11.0/creator-markdown-editor.html))
### Terminal
When you select the `Run in Terminal` check box and run an application or the
`Open Terminal` button to open a terminal, the default terminal opens in the
`Terminal` output view. It supports multiple tabs, as well as various
shells, colors, and fonts.
To use an external terminal, deselect the `Use internal terminal` check box in
`Preferences > Terminal`.
([Documentation](https://doc-snapshots.qt.io/qtcreator-11.0/creator-output-panes.html#terminal))
### Copilot
The experimental Copilot plugin integrates
[GitHub Copilot](https://github.com/features/copilot), which uses OpenAI to
suggest code in the `Edit` mode.
To set Copilot preferences, select `Preferences > Copilot`.
([Documentation](https://doc-snapshots.qt.io/qtcreator-11.0/creator-copilot.html))
### vcpkg
The experimental vcpkg plugin integrates the [vcpgk](https://vcpkg.io)
package manager for downloading and managing libraries.
Select the `vcpkg` installation location in `Preferences > CMake > Vcpkg > Path`.
To create a new `vcpkg.json` package manifest file, select `File > New File >
vcpkg`. The file is automatically added to the CMakeLists.txt file for the
project.
Edit manifest files in the manifest editor. To search for packages to add to the
file, select the `Search Package` button on the manifest editor toolbar.
([Documentation](https://doc-snapshots.qt.io/qtcreator-11.0/creator-vcpkg.html))
### Axivion
After you configure access to the [Axivion](https://www.axivion.com) Dashboard
and link a project to an Axivion project in the project settings, Qt Creator
shows annotations of the latest run in the editors and allows you to view some
details on the issues.
([Documentation](https://doc-snapshots.qt.io/qtcreator-11.0/creator-axivion.html))
General General
------- -------
* Added a `Terminal` view (QTCREATORBUG-8511) * Added a more spacious `Relaxed` toolbar style to `Preferences > Environment >
([Documentation](https://doc-snapshots.qt.io/qtcreator-11.0/creator-output-panes.html#terminal)) Interface`
* Opt-out via `Preferences` > `Terminal` preferences
* Added support for
* different shells, colors, fonts, and multiple tabs
* opening file paths in Qt Creator with `Ctrl+click` (`Cmd+click` on
macOS)
* Added a more spacious "relaxed" toolbar style `Environment > Interface`
* Added a pin button to progress details instead of automatically resetting * Added a pin button to progress details instead of automatically resetting
their position (QTCREATORBUG-28829) their position
([QTCREATORBUG-28829](https://bugreports.qt.io/browse/QTCREATORBUG-28829))
* Improved the selection and navigation in the `Issues` view * Improved the selection and navigation in the `Issues` view
(QTCREATORBUG-26128, QTCREATORBUG-27006, QTCREATORBUG-27506) ([QTCREATORBUG-26128](https://bugreports.qt.io/browse/QTCREATORBUG-26128),
[QTCREATORBUG-27006](https://bugreports.qt.io/browse/QTCREATORBUG-27006),
[QTCREATORBUG-27506](https://bugreports.qt.io/browse/QTCREATORBUG-27506))
* 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
@@ -35,78 +97,79 @@ Editing
------- -------
* Improved the performance of the multi-cursor support * Improved the performance of the multi-cursor support
* Fixed the saving of hardlinked files (QTCREATORBUG-19651) * Fixed the saving of hardlinked files
* Fixed an issue of copy and paste with multiple cursors (QTCREATORBUG-29117) ([QTCREATORBUG-19651](https://bugreports.qt.io/browse/QTCREATORBUG-19651))
* Fixed an issue of copy and paste with multiple cursors
([QTCREATORBUG-29117](https://bugreports.qt.io/browse/QTCREATORBUG-29117))
### C++ ### C++
* Improved the style of forward declarations in the outline (QTCREATORBUG-312) * Improved the style of forward declarations in the outline
([QTCREATORBUG-312](https://bugreports.qt.io/browse/QTCREATORBUG-312))
* Added highlighting for typed string literals and user-defined literals * Added highlighting for typed string literals and user-defined literals
(QTCREATORBUG-28869) ([QTCREATORBUG-28869](https://bugreports.qt.io/browse/QTCREATORBUG-28869))
* Added the option to create class members from assignments (QTCREATORBUG-1918) * Added the option to create class members from assignments
([QTCREATORBUG-1918](https://bugreports.qt.io/browse/QTCREATORBUG-1918))
* 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) ([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
* Built-in * Built-in
* Fixed support for `if`-statements with initializer (QTCREATORBUG-29182) * Fixed support for `if`-statements with initializer
([QTCREATORBUG-29182](https://bugreports.qt.io/browse/QTCREATORBUG-29182))
### Language Server Protocol ### Language Server Protocol
* Added experimental support for GitHub Copilot * Added missing actions for opening the `Call Hierarchy`
([GitHub documentation](https://github.com/features/copilot)) ([QTCREATORBUG-28839](https://bugreports.qt.io/browse/QTCREATORBUG-28839),
([Qt Creator documentation](https://doc-snapshots.qt.io/qtcreator-11.0/creator-copilot.html)) [QTCREATORBUG-28842](https://bugreports.qt.io/browse/QTCREATORBUG-28842))
* Added missing actions for opening the `Call Hierarchy` (QTCREATORBUG-28839,
QTCREATORBUG-28842)
### QML ### QML
* Fixed the reformatting in the presence of JavaScript directives and function * Fixed the reformatting in the presence of JavaScript directives and function
return type annotations (QTCREATORBUG-29001, QTCREATORBUG-29046) return type annotations
* Fixed that reformatting changed `of` to `in` (QTCREATORBUG-29123) ([QTCREATORBUG-29001](https://bugreports.qt.io/browse/QTCREATORBUG-29001),
* Fixed the completion for Qt Quick Controls (QTCREATORBUG-28648) [QTCREATORBUG-29046](https://bugreports.qt.io/browse/QTCREATORBUG-29046))
* Fixed that reformatting changed `of` to `in`
([QTCREATORBUG-29123](https://bugreports.qt.io/browse/QTCREATORBUG-29123))
* Fixed the completion for Qt Quick Controls
([QTCREATORBUG-28648](https://bugreports.qt.io/browse/QTCREATORBUG-28648))
### 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 (PYSIDE-2152) interpreter selector and the wizard
([PYSIDE-2152](https://bugreports.qt.io/browse/PYSIDE-2152))
### Markdown
* Added a Markdown editor with preview (QTCREATORBUG-27883)
* Added a wizard for Markdown files (QTCREATORBUG-29056)
Projects Projects
-------- --------
* Made it possible to add devices without going through the wizard * Made it possible to add devices without going through the wizard
* Added support for moving files to a different directory when renaming * Added support for moving files to a different directory when renaming
(QTCREATORBUG-15981) ([QTCREATORBUG-15981](https://bugreports.qt.io/browse/QTCREATORBUG-15981))
### CMake ### CMake
* Implemented adding files to the project (QTCREATORBUG-25922, * Implemented adding files to the project
QTCREATORBUG-26006, QTCREATORBUG-27213, QTCREATORBUG-27538, ([QTCREATORBUG-25922](https://bugreports.qt.io/browse/QTCREATORBUG-25922),
QTCREATORBUG-28493, QTCREATORBUG-28904, QTCREATORBUG-28985, [QTCREATORBUG-26006](https://bugreports.qt.io/browse/QTCREATORBUG-26006),
QTCREATORBUG-29006) [QTCREATORBUG-27213](https://bugreports.qt.io/browse/QTCREATORBUG-27213),
[QTCREATORBUG-27538](https://bugreports.qt.io/browse/QTCREATORBUG-27538),
[QTCREATORBUG-28493](https://bugreports.qt.io/browse/QTCREATORBUG-28493),
[QTCREATORBUG-28904](https://bugreports.qt.io/browse/QTCREATORBUG-28904),
[QTCREATORBUG-28985](https://bugreports.qt.io/browse/QTCREATORBUG-28985),
[QTCREATORBUG-29006](https://bugreports.qt.io/browse/QTCREATORBUG-29006))
* Fixed issues with detecting a configured Qt version when importing a build * Fixed issues with detecting a configured Qt version when importing a build
(QTCREATORBUG-29075) ([QTCREATORBUG-29075](https://bugreports.qt.io/browse/QTCREATORBUG-29075))
### Python ### Python
* Added an option for the interpreter to the wizards * Added an option for the interpreter to the wizards
### vcpkg
* Added experimental support for `vcpkg`
([vcpgk documentation](https://vcpkg.io/en/))
* Added an option for the `vcpkg` installation location
* Added a search dialog for packages
* Added a wizard and an editor for `vcpkg.json` files
Debugging Debugging
--------- ---------
* Improved the UI for enabling and disabling debuggers (QTCREATORBUG-28627) * Improved the UI for enabling and disabling debuggers
([QTCREATORBUG-28627](https://bugreports.qt.io/browse/QTCREATORBUG-28627))
### C++ ### C++
@@ -114,16 +177,20 @@ Debugging
(`Preferences > Debugger > Locals & Expressions > Default array size`) (`Preferences > Debugger > Locals & Expressions > Default array size`)
* 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 (QTCREATORBUG-29000) * Fixed the variables view on remote Windows devices
([QTCREATORBUG-29000](https://bugreports.qt.io/browse/QTCREATORBUG-29000))
* LLDB * LLDB
* Fixed that long lines in the application output were broken into multiple * Fixed that long lines in the application output were broken into multiple
lines (QTCREATORBUG-29098) lines
([QTCREATORBUG-29098](https://bugreports.qt.io/browse/QTCREATORBUG-29098))
### Qt Quick ### Qt Quick
* Improved the auto-detection if QML debugging is required (QTCREATORBUG-28627) * Improved the auto-detection if QML debugging is required
([QTCREATORBUG-28627](https://bugreports.qt.io/browse/QTCREATORBUG-28627))
* Added an option for disabling static analyzer messages to * Added an option for disabling static analyzer messages to
`Qt Quick > QML/JS Editing` (QTCREATORBUG-29095) `Qt Quick > QML/JS Editing`
([QTCREATORBUG-29095](https://bugreports.qt.io/browse/QTCREATORBUG-29095))
Analyzer Analyzer
-------- --------
@@ -131,11 +198,8 @@ Analyzer
### Clang ### Clang
* Fixed that a `.clang-tidy` file in the project directory was not used by * Fixed that a `.clang-tidy` file in the project directory was not used by
default (QTCREATORBUG-28852) default
([QTCREATORBUG-28852](https://bugreports.qt.io/browse/QTCREATORBUG-28852))
### Axivion
* Added experimental support
Version Control Systems Version Control Systems
----------------------- -----------------------
@@ -143,7 +207,8 @@ Version Control Systems
### Git ### Git
* Instant Blame * Instant Blame
* Improved the performance (QTCREATORBUG-29151) * Improved the performance
([QTCREATORBUG-29151](https://bugreports.qt.io/browse/QTCREATORBUG-29151))
* Fixed that it did not show at the end of the document * Fixed that it did not show at the end of the document
Platforms Platforms
@@ -151,7 +216,8 @@ Platforms
### Android ### Android
* Fixed an issue with building library targets (QTCREATORBUG-26980) * Fixed an issue with building library targets
([QTCREATORBUG-26980](https://bugreports.qt.io/browse/QTCREATORBUG-26980))
### Remote Linux ### Remote Linux
@@ -159,14 +225,16 @@ Platforms
### Docker ### Docker
* Added support for `qmake` based projects (QTCREATORBUG-29140) * Added support for `qmake` based projects
([QTCREATORBUG-29140](https://bugreports.qt.io/browse/QTCREATORBUG-29140))
* Fixed issues after deleting the Docker image for a registered Docker device * Fixed issues after deleting the Docker image for a registered Docker device
(QTCREATORBUG-28880) ([QTCREATORBUG-28880](https://bugreports.qt.io/browse/QTCREATORBUG-28880))
### QNX ### QNX
* Added `slog2info` as a requirement for devices * Added `slog2info` as a requirement for devices
* Fixed the support for remote working directories (QTCREATORBUG-28900) * Fixed the support for remote working directories
([QTCREATORBUG-28900](https://bugreports.qt.io/browse/QTCREATORBUG-28900))
Credits for these changes go to: Credits for these changes go to:
-------------------------------- --------------------------------

Binary file not shown.

Before

Width:  |  Height:  |  Size: 21 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 14 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 10 KiB

After

Width:  |  Height:  |  Size: 13 KiB

View File

@@ -33,9 +33,15 @@
\section1 Adding Boot2Qt Devices \section1 Adding Boot2Qt Devices
If \QC does not automatically detect a device you connected with USB, you can If \QC does not automatically detect a device you connected with USB, select
use a wizard to create either a network connection or a USB connection to \uicontrol Edit > \uicontrol Preferences > \uicontrol Devices >
it. \uicontrol Devices > \uicontrol Add > \uicontrol {Boot2Qt Device} to create
either a network connection or a USB connection to it.
\image qtcreator-boot2qt-device-configurations.webp {Devices tab in Preferences}
To add a device without using a wizard, select \uicontrol {Boot2Qt Device} in
the pull-down menu of the \uicontrol Add button.
\note On Ubuntu Linux, the development user account must have access to the \note On Ubuntu Linux, the development user account must have access to the
plugged-in devices. To grant them access to the device via USB, create a new plugged-in devices. To grant them access to the device via USB, create a new
@@ -46,8 +52,6 @@
You can edit the settings later in \uicontrol Edit > \uicontrol Preferences > You can edit the settings later in \uicontrol Edit > \uicontrol Preferences >
\uicontrol Devices > \uicontrol Devices. \uicontrol Devices > \uicontrol Devices.
\image qtcreator-boot2qt-device-configurations.png {Devices dialog}
To reboot the selected device, select \uicontrol {Reboot Device}. To reboot the selected device, select \uicontrol {Reboot Device}.
To restore the default application to the device, select To restore the default application to the device, select
@@ -122,6 +126,10 @@
parameters that have sensible default values. One of parameters that have sensible default values. One of
these is the SSH port number, which is available in these is the SSH port number, which is available in
the variable \c %{Device:SshPort}. the variable \c %{Device:SshPort}.
To add a device without using the wizard, select
\uicontrol {Boot2Qt Device} in the pull-down menu of the
\uicontrol Add button.
\endlist \endlist
\li Select \uicontrol Edit > \uicontrol Preferences > \uicontrol Kits > \li Select \uicontrol Edit > \uicontrol Preferences > \uicontrol Kits >
\uicontrol Add to add a kit for building applications for the \uicontrol Add to add a kit for building applications for the

View File

@@ -107,6 +107,9 @@
All of these parameters can be edited later, as well as additional ones that the All of these parameters can be edited later, as well as additional ones that the
wizard does not show because there are sensible default values. wizard does not show because there are sensible default values.
To add a device without using the wizard, select
\uicontrol {Add Remote Linux Device} in the pull-down
menu of the \uicontrol Add button.
\li Select \uicontrol Edit > \uicontrol Preferences > \uicontrol Kits > \li Select \uicontrol Edit > \uicontrol Preferences > \uicontrol Kits >
\uicontrol Add to add a kit for building for the device. Select the \uicontrol Add to add a kit for building for the device. Select the

View File

@@ -1,3 +1,5 @@
{ {
"files": ["%{SrcFileName}"] "files": [
"%{SrcFileName}"
]
} }

View File

@@ -1,3 +1,6 @@
{ {
"files": ["%{SrcFileName}", "%{QmlFileName}"] "files": [
"%{SrcFileName}",
"%{QmlFileName}"
]
} }

View File

@@ -1,3 +1,6 @@
{ {
"files": ["%{SrcFileName}", "form.ui"] "files": [
"%{SrcFileName}",
"form.ui"
]
} }

View File

@@ -252,7 +252,7 @@ private:
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 executions 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 TaskAction::Continue
@@ -1123,7 +1123,7 @@ void TaskNode::invokeEndHandler(bool success)
Use the Tasking namespace to build extensible, declarative task tree Use the Tasking namespace to build extensible, declarative task tree
structures that contain possibly asynchronous tasks, such as Process, structures that contain possibly asynchronous tasks, such as Process,
FileTransfer, or Async<ReturnType>. TaskTree structures enable you FileTransfer, or ConcurrentCall<ReturnType>. TaskTree structures enable you
to create a sophisticated mixture of a parallel or sequential flow of tasks 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. in the form of a tree and to run it any time later.
@@ -1131,14 +1131,14 @@ void TaskNode::invokeEndHandler(bool success)
The TaskTree has a mandatory Group root element, which may contain The TaskTree has a mandatory Group root element, which may contain
any number of tasks of various types, such as ProcessTask, FileTransferTask, any number of tasks of various types, such as ProcessTask, FileTransferTask,
or AsyncTask<ReturnType>: or ConcurrentCallTask<ReturnType>:
\code \code
using namespace Tasking; using namespace Tasking;
const Group root { const Group root {
ProcessTask(...), ProcessTask(...),
AsyncTask<int>(...), ConcurrentCallTask<int>(...),
FileTransferTask(...) FileTransferTask(...)
}; };
@@ -1149,10 +1149,10 @@ void TaskNode::invokeEndHandler(bool success)
\endcode \endcode
The task tree above has a top level element of the Group type that contains The task tree above has a top level element of the Group type that contains
tasks of the type ProcessTask, FileTransferTask, and AsyncTask<int>. tasks of the type ProcessTask, FileTransferTask, and ConcurrentCallTask<int>.
After taskTree->start() is called, the tasks are run in a chain, starting After taskTree->start() is called, the tasks are run in a chain, starting
with ProcessTask. When the ProcessTask finishes successfully, the AsyncTask<int> task is with ProcessTask. When the ProcessTask finishes successfully, the ConcurrentCallTask<int>
started. Finally, when the asynchronous task finishes successfully, the task is started. Finally, when the asynchronous task finishes successfully, the
FileTransferTask task is started. FileTransferTask task is started.
When the last running task finishes with success, the task tree is considered When the last running task finishes with success, the task tree is considered
@@ -1172,26 +1172,26 @@ void TaskNode::invokeEndHandler(bool success)
Group { Group {
parallel, parallel,
ProcessTask(...), ProcessTask(...),
AsyncTask<int>(...) ConcurrentCallTask<int>(...)
}, },
FileTransferTask(...) FileTransferTask(...)
}; };
\endcode \endcode
The example above differs from the first example in that the root element has The example above differs from the first example in that the root element has
a subgroup that contains the ProcessTask and AsyncTask<int>. The subgroup is a a subgroup that contains the ProcessTask and ConcurrentCallTask<int>. The subgroup is a
sibling element of the FileTransferTask in the root. The subgroup contains an sibling element of the FileTransferTask in the root. The subgroup contains an
additional \e parallel element that instructs its Group to execute its tasks additional \e parallel element that instructs its Group to execute its tasks
in parallel. in parallel.
So, when the tree above is started, the ProcessTask and AsyncTask<int> start So, when the tree above is started, the ProcessTask and ConcurrentCallTask<int> start
immediately and run in parallel. Since the root group doesn't contain a 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 \e parallel element, its direct child tasks are run in sequence. Thus, the
FileTransferTask starts when the whole subgroup finishes. The group is FileTransferTask starts when the whole subgroup finishes. The group is
considered as finished when all its tasks have finished. The order in which considered as finished when all its tasks have finished. The order in which
the tasks finish is not relevant. the tasks finish is not relevant.
So, depending on which task lasts longer (ProcessTask or AsyncTask<int>), the So, depending on which task lasts longer (ProcessTask or ConcurrentCallTask<int>), the
following scenarios can take place: following scenarios can take place:
\table \table
@@ -1208,19 +1208,19 @@ void TaskNode::invokeEndHandler(bool success)
\li ProcessTask starts \li ProcessTask starts
\li ProcessTask starts \li ProcessTask starts
\row \row
\li AsyncTask<int> starts \li ConcurrentCallTask<int> starts
\li AsyncTask<int> starts \li ConcurrentCallTask<int> starts
\row \row
\li ... \li ...
\li ... \li ...
\row \row
\li \b {ProcessTask finishes} \li \b {ProcessTask finishes}
\li \b {AsyncTask<int> finishes} \li \b {ConcurrentCallTask<int> finishes}
\row \row
\li ... \li ...
\li ... \li ...
\row \row
\li \b {AsyncTask<int> finishes} \li \b {ConcurrentCallTask<int> finishes}
\li \b {ProcessTask finishes} \li \b {ProcessTask finishes}
\row \row
\li Sub Group finishes \li Sub Group finishes
@@ -1246,8 +1246,8 @@ void TaskNode::invokeEndHandler(bool success)
The presented scenarios assume that all tasks run successfully. If a task The presented scenarios assume that all tasks run successfully. If a task
fails during execution, the task tree finishes with an error. In particular, fails during execution, the task tree finishes with an error. In particular,
when ProcessTask finishes with an error while AsyncTask<int> is still being executed, when ProcessTask finishes with an error while ConcurrentCallTask<int> is still being executed,
the AsyncTask<int> is automatically stopped, the subgroup finishes with an error, the ConcurrentCallTask<int> is automatically stopped, the subgroup finishes with an error,
the FileTransferTask is skipped, and the tree finishes with an error. the FileTransferTask is skipped, and the tree finishes with an error.
\section1 Task Types \section1 Task Types
@@ -1277,11 +1277,11 @@ void TaskNode::invokeEndHandler(bool success)
\row \row
\li ProcessTask \li ProcessTask
\li Utils::Process \li Utils::Process
\li Starts processes. \li Starts process.
\row \row
\li AsyncTask<ReturnType> \li ConcurrentCallTask<ReturnType>
\li Utils::Async<ReturnType> \li Tasking::ConcurrentCall<ReturnType>
\li Starts asynchronous tasks; run in separate thread. \li Starts asynchronous task, runs in separate thread.
\row \row
\li TaskTreeTask \li TaskTreeTask
\li Utils::TaskTree \li Utils::TaskTree
@@ -1540,7 +1540,7 @@ void TaskNode::invokeEndHandler(bool success)
static QByteArray load(const QString &fileName) { ... } static QByteArray load(const QString &fileName) { ... }
static void save(const QString &fileName, const QByteArray &array) { ... } static void save(const QString &fileName, const QByteArray &array) { ... }
static GroupItem copyRecipe(const QString &source, const QString &destination) static Group copyRecipe(const QString &source, const QString &destination)
{ {
struct CopyStorage { // [1] custom inter-task struct struct CopyStorage { // [1] custom inter-task struct
QByteArray content; // [2] custom inter-task data QByteArray content; // [2] custom inter-task data
@@ -1549,28 +1549,28 @@ void TaskNode::invokeEndHandler(bool success)
// [3] instance of custom inter-task struct manageable by task tree // [3] instance of custom inter-task struct manageable by task tree
const TreeStorage<CopyStorage> storage; const TreeStorage<CopyStorage> storage;
const auto onLoaderSetup = [source](Async<QByteArray> &async) { const auto onLoaderSetup = [source](ConcurrentCall<QByteArray> &async) {
async.setConcurrentCallData(&load, source); async.setConcurrentCallData(&load, source);
}; };
// [4] runtime: task tree activates the instance from [7] before invoking handler // [4] runtime: task tree activates the instance from [7] before invoking handler
const auto onLoaderDone = [storage](const Async<QByteArray> &async) { const auto onLoaderDone = [storage](const ConcurrentCall<QByteArray> &async) {
storage->content = async.result(); // [5] loader stores the result in storage storage->content = async.result(); // [5] loader stores the result in storage
}; };
// [4] runtime: task tree activates the instance from [7] before invoking handler // [4] runtime: task tree activates the instance from [7] before invoking handler
const auto onSaverSetup = [storage, destination](Async<void> &async) { const auto onSaverSetup = [storage, destination](ConcurrentCall<void> &async) {
const QByteArray content = storage->content; // [6] saver takes data from storage const QByteArray content = storage->content; // [6] saver takes data from storage
async.setConcurrentCallData(&save, destination, content); async.setConcurrentCallData(&save, destination, content);
}; };
const auto onSaverDone = [](const Async<void> &async) { const auto onSaverDone = [](const ConcurrentCall<void> &async) {
qDebug() << "Save done successfully"; qDebug() << "Save done successfully";
}; };
const Group root { const Group root {
// [7] runtime: task tree creates an instance of CopyStorage when root is entered // [7] runtime: task tree creates an instance of CopyStorage when root is entered
Storage(storage), Storage(storage),
AsyncTask<QByteArray>(onLoaderSetup, onLoaderDone), ConcurrentCallTask<QByteArray>(onLoaderSetup, onLoaderDone),
AsyncTask<void>(onSaverSetup, onSaverDone) ConcurrentCallTask<void>(onSaverSetup, onSaverDone)
}; };
return root; return root;
} }
@@ -1650,7 +1650,7 @@ void TaskNode::invokeEndHandler(bool success)
\code \code
TreeStorage<CopyStorage> storage; TreeStorage<CopyStorage> storage;
Group root = ...; // storage placed inside root's group and inside handlers const Group root = ...; // storage placed inside root's group and inside handlers
TaskTree taskTree(root); TaskTree taskTree(root);
auto initStorage = [](CopyStorage *storage){ auto initStorage = [](CopyStorage *storage){
storage->content = "initial content"; storage->content = "initial content";
@@ -1670,7 +1670,7 @@ void TaskNode::invokeEndHandler(bool success)
\code \code
TreeStorage<CopyStorage> storage; TreeStorage<CopyStorage> storage;
Group root = ...; // storage placed inside root's group and inside handlers const Group root = ...; // storage placed inside root's group and inside handlers
TaskTree taskTree(root); TaskTree taskTree(root);
auto collectStorage = [](CopyStorage *storage){ auto collectStorage = [](CopyStorage *storage){
qDebug() << "final content" << storage->content; qDebug() << "final content" << storage->content;
@@ -1758,7 +1758,7 @@ TaskTree::TaskTree(const Group &recipe) : TaskTree()
TaskTree::~TaskTree() TaskTree::~TaskTree()
{ {
QTC_ASSERT(!d->m_guard.isLocked(), qWarning("Deleting TaskTree instance directly from " QTC_ASSERT(!d->m_guard.isLocked(), qWarning("Deleting TaskTree instance directly from "
"one of its handlers will lead to crash!")); "one of its handlers will lead to a crash!"));
// TODO: delete storages explicitly here? // TODO: delete storages explicitly here?
delete d; delete d;
} }

View File

@@ -2346,16 +2346,12 @@ void IntegersAspect::setDefaultValue(const QList<int> &value)
A text display does not have a real value. A text display does not have a real value.
*/ */
TextDisplay::TextDisplay(AspectContainer *container)
: BaseAspect(container), d(new Internal::TextDisplayPrivate)
{}
/*! /*!
Constructs a text display showing the \a message with an icon representing Constructs a text display showing the \a message with an icon representing
type \a type. type \a type.
*/ */
TextDisplay::TextDisplay(const QString &message, InfoLabel::InfoType type) TextDisplay::TextDisplay(AspectContainer *container, const QString &message, InfoLabel::InfoType type)
: d(new Internal::TextDisplayPrivate) : BaseAspect(container), d(new Internal::TextDisplayPrivate)
{ {
d->m_message = message; d->m_message = message;
d->m_type = type; d->m_type = type;

View File

@@ -610,8 +610,8 @@ class QTCREATOR_UTILS_EXPORT TextDisplay : public BaseAspect
Q_OBJECT Q_OBJECT
public: public:
explicit TextDisplay(AspectContainer *container); explicit TextDisplay(AspectContainer *container,
TextDisplay(const QString &message = {}, const QString &message = {},
InfoLabel::InfoType type = InfoLabel::None); InfoLabel::InfoType type = InfoLabel::None);
~TextDisplay() override; ~TextDisplay() override;

View File

@@ -545,11 +545,11 @@ IconButton::IconButton(QWidget *parent)
void IconButton::paintEvent(QPaintEvent *) void IconButton::paintEvent(QPaintEvent *)
{ {
QWindow *window = this->window()->windowHandle(); const qreal pixelRatio = window()->windowHandle()->devicePixelRatio();
const QPixmap iconPixmap = icon().pixmap(window, sizeHint(), const QPixmap iconPixmap = icon().pixmap(sizeHint(), pixelRatio,
isEnabled() ? QIcon::Normal : QIcon::Disabled); isEnabled() ? QIcon::Normal : QIcon::Disabled);
QStylePainter painter(this); QStylePainter painter(this);
QRect pixmapRect(QPoint(), iconPixmap.size() / window->devicePixelRatio()); QRect pixmapRect(QPoint(), iconPixmap.size() / pixelRatio);
pixmapRect.moveCenter(rect().center()); pixmapRect.moveCenter(rect().center());
if (m_autoHide) if (m_autoHide)

View File

@@ -65,7 +65,7 @@ QString JsonValue::kindToString(JsonValue::Kind kind)
JsonValue *JsonValue::build(const QVariant &variant, JsonMemoryPool *pool) JsonValue *JsonValue::build(const QVariant &variant, JsonMemoryPool *pool)
{ {
switch (variant.type()) { switch (variant.typeId()) {
case QVariant::List: { case QVariant::List: {
auto newValue = new (pool) JsonArrayValue; auto newValue = new (pool) JsonArrayValue;

View File

@@ -216,6 +216,13 @@ void DefaultImpl::start()
return; return;
if (!ensureProgramExists(program)) if (!ensureProgramExists(program))
return; return;
if (m_setup.m_runAsRoot && !HostOsInfo::isWindowsHost()) {
arguments.prepend(program);
arguments.prepend("-A");
program = "sudo";
}
s_start.measureAndRun(&DefaultImpl::doDefaultStart, this, program, arguments); s_start.measureAndRun(&DefaultImpl::doDefaultStart, this, program, arguments);
} }
@@ -766,15 +773,6 @@ public:
m_blockingInterface->setParent(this); m_blockingInterface->setParent(this);
} }
CommandLine fullCommandLine() const
{
if (!m_setup.m_runAsRoot || HostOsInfo::isWindowsHost())
return m_setup.m_commandLine;
CommandLine rootCommand("sudo", {"-A"});
rootCommand.addCommandLineAsArgs(m_setup.m_commandLine);
return rootCommand;
}
Process *q; Process *q;
std::unique_ptr<ProcessBlockingInterface> m_blockingInterface; std::unique_ptr<ProcessBlockingInterface> m_blockingInterface;
std::unique_ptr<ProcessInterface> m_process; std::unique_ptr<ProcessInterface> m_process;
@@ -1217,7 +1215,6 @@ void Process::start()
d->setProcessInterface(processImpl); d->setProcessInterface(processImpl);
d->m_state = QProcess::Starting; d->m_state = QProcess::Starting;
d->m_process->m_setup = d->m_setup; d->m_process->m_setup = d->m_setup;
d->m_process->m_setup.m_commandLine = d->fullCommandLine();
d->emitGuardedSignal(&Process::starting); d->emitGuardedSignal(&Process::starting);
d->m_process->start(); d->m_process->start();
} }

View File

@@ -10,8 +10,10 @@
#include <QTime> #include <QTime>
#include <QWidget> #include <QWidget>
QT_BEGIN_NAMESPACE
class QPainter; class QPainter;
class QStyleOption; class QStyleOption;
QT_END_NAMESPACE
namespace Utils { namespace Utils {
/* /*

View File

@@ -385,6 +385,22 @@ void TerminalInterface::start()
ProcessSetupData stubSetupData = m_setup; ProcessSetupData stubSetupData = m_setup;
stubSetupData.m_commandLine = cmd; stubSetupData.m_commandLine = cmd;
if (m_setup.m_runAsRoot && !HostOsInfo::isWindowsHost()) {
CommandLine rootCommand(FilePath("sudo").searchInPath(), {"-A"});
rootCommand.addCommandLineAsArgs(cmd);
const FilePath askPassPath = FilePath::fromUserInput(QCoreApplication::applicationDirPath())
.pathAppended(QLatin1String(RELATIVE_LIBEXEC_PATH))
.pathAppended(QLatin1String("qtc-askpass"));
if (askPassPath.exists())
stubSetupData.m_environment.setFallback("SUDO_ASKPASS", askPassPath.toUserOutput());
stubSetupData.m_commandLine = rootCommand;
} else {
stubSetupData.m_commandLine = cmd;
}
QMetaObject::invokeMethod( QMetaObject::invokeMethod(
d->stubCreator, d->stubCreator,
[stubSetupData, this] { d->stubCreator->startStubProcess(stubSetupData); }, [stubSetupData, this] { d->stubCreator->startStubProcess(stubSetupData); },

View File

@@ -7,9 +7,12 @@
#include <QScrollBar> #include <QScrollBar>
QT_BEGIN_NAMESPACE
class QAbstractScrollArea; class QAbstractScrollArea;
QT_END_NAMESPACE
namespace Utils { namespace Utils {
class ScrollAreaPrivate; class ScrollAreaPrivate;
class ScrollBarPrivate; class ScrollBarPrivate;

View File

@@ -191,7 +191,7 @@ void AndroidConfig::load(const QSettings &settings)
{ {
// user settings // user settings
QVariant emulatorArgs = settings.value(EmulatorArgsKey, QString("-netdelay none -netspeed full")); QVariant emulatorArgs = settings.value(EmulatorArgsKey, QString("-netdelay none -netspeed full"));
if (emulatorArgs.type() == QVariant::StringList) // Changed in 8.0 from QStringList to QString. if (emulatorArgs.typeId() == QVariant::StringList) // Changed in 8.0 from QStringList to QString.
emulatorArgs = ProcessArgs::joinArgs(emulatorArgs.toStringList()); emulatorArgs = ProcessArgs::joinArgs(emulatorArgs.toStringList());
m_emulatorArgs = emulatorArgs.toString(); m_emulatorArgs = emulatorArgs.toString();
m_sdkLocation = FilePath::fromUserInput(settings.value(SDKLocationKey).toString()).cleanPath(); m_sdkLocation = FilePath::fromUserInput(settings.value(SDKLocationKey).toString()).cleanPath();

View File

@@ -488,21 +488,40 @@ void AndroidManifestEditorWidget::focusInEvent(QFocusEvent *event)
} }
} }
static bool checkDocument(const QDomDocument &doc, QDomDocument::ParseResult *result)
{
QDomElement manifest = doc.documentElement();
if (manifest.tagName() != QLatin1String("manifest")) {
result->errorMessage = ::Android::Tr::tr("The structure of the Android manifest file "
"is corrupted. Expected a top level 'manifest' node.");
result->errorLine = -1;
result->errorColumn = -1;
return false;
}
if (manifest.firstChildElement(QLatin1String("application")).firstChildElement(QLatin1String("activity")).isNull()) {
// missing either application or activity element
result->errorMessage = ::Android::Tr::tr("The structure of the Android manifest file "
"is corrupted. Expected an 'application' and 'activity' sub node.");
result->errorLine = -1;
result->errorColumn = -1;
return false;
}
return true;
}
void AndroidManifestEditorWidget::updateAfterFileLoad() void AndroidManifestEditorWidget::updateAfterFileLoad()
{ {
QString error;
int errorLine;
int errorColumn;
QDomDocument doc; QDomDocument doc;
if (doc.setContent(m_textEditorWidget->toPlainText(), &error, &errorLine, &errorColumn)) { QDomDocument::ParseResult result = doc.setContent(m_textEditorWidget->toPlainText());
if (checkDocument(doc, &error, &errorLine, &errorColumn)) { if (result) {
if (checkDocument(doc, &result)) {
if (activePage() != Source) if (activePage() != Source)
syncToWidgets(doc); syncToWidgets(doc);
return; return;
} }
} }
// some error occurred // some error occurred
updateInfoBar(error, errorLine, errorColumn); updateInfoBar(result.errorMessage, result.errorLine, result.errorColumn);
setActivePage(Source); setActivePage(Source);
} }
@@ -591,39 +610,19 @@ TextEditor::TextEditorWidget *AndroidManifestEditorWidget::textEditorWidget() co
bool AndroidManifestEditorWidget::syncToWidgets() bool AndroidManifestEditorWidget::syncToWidgets()
{ {
QDomDocument doc; QDomDocument doc;
QString errorMessage; QDomDocument::ParseResult result = doc.setContent(m_textEditorWidget->toPlainText());
int errorLine, errorColumn; if (result) {
if (doc.setContent(m_textEditorWidget->toPlainText(), &errorMessage, &errorLine, &errorColumn)) { if (checkDocument(doc, &result)) {
if (checkDocument(doc, &errorMessage, &errorLine, &errorColumn)) {
hideInfoBar(); hideInfoBar();
syncToWidgets(doc); syncToWidgets(doc);
return true; return true;
} }
} }
updateInfoBar(errorMessage, errorLine, errorColumn); updateInfoBar(result.errorMessage, result.errorLine, result.errorColumn);
return false; return false;
} }
bool AndroidManifestEditorWidget::checkDocument(const QDomDocument &doc, QString *errorMessage,
int *errorLine, int *errorColumn)
{
QDomElement manifest = doc.documentElement();
if (manifest.tagName() != QLatin1String("manifest")) {
*errorMessage = ::Android::Tr::tr("The structure of the Android manifest file is corrupted. Expected a top level 'manifest' node.");
*errorLine = -1;
*errorColumn = -1;
return false;
} else if (manifest.firstChildElement(QLatin1String("application")).firstChildElement(QLatin1String("activity")).isNull()) {
// missing either application or activity element
*errorMessage = ::Android::Tr::tr("The structure of the Android manifest file is corrupted. Expected an 'application' and 'activity' sub node.");
*errorLine = -1;
*errorColumn = -1;
return false;
}
return true;
}
void AndroidManifestEditorWidget::startParseCheck() void AndroidManifestEditorWidget::startParseCheck()
{ {
m_timerParseCheck.start(); m_timerParseCheck.start();
@@ -641,16 +640,15 @@ void AndroidManifestEditorWidget::updateInfoBar()
return; return;
} }
QDomDocument doc; QDomDocument doc;
int errorLine, errorColumn; QDomDocument::ParseResult result = doc.setContent(m_textEditorWidget->toPlainText());
QString errorMessage; if (result) {
if (doc.setContent(m_textEditorWidget->toPlainText(), &errorMessage, &errorLine, &errorColumn)) { if (checkDocument(doc, &result)) {
if (checkDocument(doc, &errorMessage, &errorLine, &errorColumn)) {
hideInfoBar(); hideInfoBar();
return; return;
} }
} }
updateInfoBar(errorMessage, errorLine, errorColumn); updateInfoBar(result.errorMessage, result.errorLine, result.errorColumn);
} }
void AndroidManifestEditorWidget::updateSdkVersions() void AndroidManifestEditorWidget::updateSdkVersions()
@@ -888,9 +886,9 @@ void AndroidManifestEditorWidget::syncToEditor()
m_dirty = false; m_dirty = false;
} }
namespace { static QXmlStreamAttributes modifyXmlStreamAttributes(
QXmlStreamAttributes modifyXmlStreamAttributes(const QXmlStreamAttributes &input, const QStringList &keys, const QXmlStreamAttributes &input, const QStringList &keys,
const QStringList &values, const QStringList &remove = QStringList()) const QStringList &values, const QStringList &remove = {})
{ {
Q_ASSERT(keys.size() == values.size()); Q_ASSERT(keys.size() == values.size());
QXmlStreamAttributes result; QXmlStreamAttributes result;
@@ -903,8 +901,7 @@ QXmlStreamAttributes modifyXmlStreamAttributes(const QXmlStreamAttributes &input
if (index == -1) if (index == -1)
result.push_back(attribute); result.push_back(attribute);
else else
result.push_back(QXmlStreamAttribute(name, result.push_back(QXmlStreamAttribute(name, values.at(index)));
values.at(index)));
} }
for (int i = 0; i < keys.size(); ++i) { for (int i = 0; i < keys.size(); ++i) {
@@ -913,7 +910,6 @@ QXmlStreamAttributes modifyXmlStreamAttributes(const QXmlStreamAttributes &input
} }
return result; return result;
} }
} // end namespace
void AndroidManifestEditorWidget::parseManifest(QXmlStreamReader &reader, QXmlStreamWriter &writer) void AndroidManifestEditorWidget::parseManifest(QXmlStreamReader &reader, QXmlStreamWriter &writer)
{ {

View File

@@ -14,14 +14,11 @@
QT_BEGIN_NAMESPACE QT_BEGIN_NAMESPACE
class QCheckBox; class QCheckBox;
class QDomDocument; class QDomDocument;
class QDomElement;
class QComboBox; class QComboBox;
class QPushButton; class QPushButton;
class QLabel; class QLabel;
class QLineEdit; class QLineEdit;
class QListView; class QListView;
class QSpinBox;
class QToolButton;
class QXmlStreamReader; class QXmlStreamReader;
class QXmlStreamWriter; class QXmlStreamWriter;
QT_END_NAMESPACE QT_END_NAMESPACE
@@ -108,9 +105,6 @@ private:
void syncToEditor(); void syncToEditor();
void updateAfterFileLoad(); void updateAfterFileLoad();
bool checkDocument(const QDomDocument &doc, QString *errorMessage,
int *errorLine, int *errorColumn);
void updateInfoBar(const QString &errorMessage, int line, int column); void updateInfoBar(const QString &errorMessage, int line, int column);
void hideInfoBar(); void hideInfoBar();

View File

@@ -280,7 +280,7 @@ AndroidRunnerWorker::AndroidRunnerWorker(RunWorker *runner, const QString &packa
m_beforeStartAdbCommands.append(QString("shell %1").arg(shellCmd)); m_beforeStartAdbCommands.append(QString("shell %1").arg(shellCmd));
if (auto aspect = runControl->aspect(Constants::ANDROID_POSTFINISHSHELLCMDLIST)) { if (auto aspect = runControl->aspect(Constants::ANDROID_POSTFINISHSHELLCMDLIST)) {
QTC_CHECK(aspect->value.type() == QVariant::String); QTC_CHECK(aspect->value.typeId() == QVariant::String);
const QStringList commands = aspect->value.toString().split('\n', Qt::SkipEmptyParts); const QStringList commands = aspect->value.toString().split('\n', Qt::SkipEmptyParts);
for (const QString &shellCmd : commands) for (const QString &shellCmd : commands)
m_afterFinishAdbCommands.append(QString("shell %1").arg(shellCmd)); m_afterFinishAdbCommands.append(QString("shell %1").arg(shellCmd));

View File

@@ -455,7 +455,7 @@ void TestRunner::runTestsHelper()
connect(m_taskTree.get(), &TaskTree::errorOccurred, this, &TestRunner::onFinished); connect(m_taskTree.get(), &TaskTree::errorOccurred, this, &TestRunner::onFinished);
auto progress = new TaskProgress(m_taskTree.get()); auto progress = new TaskProgress(m_taskTree.get());
progress->setDisplayName(tr("Running Tests")); progress->setDisplayName(Tr::tr("Running Tests"));
progress->setAutoStopOnCancel(false); progress->setAutoStopOnCancel(false);
progress->setHalfLifeTimePerTask(10000); // 10 seconds progress->setHalfLifeTimePerTask(10000); // 10 seconds
connect(progress, &TaskProgress::canceled, this, [this, progress] { connect(progress, &TaskProgress::canceled, this, [this, progress] {

View File

@@ -77,10 +77,10 @@ void ArtisticStyleSettings::createDocumentationFile() const
if (process.result() != ProcessResult::FinishedWithSuccess) if (process.result() != ProcessResult::FinishedWithSuccess)
return; return;
if (!documentationFilePath.exists())
documentationFilePath.parentDir().ensureWritableDir();
QFile file(documentationFilePath.toFSPathString()); QFile file(documentationFilePath.toFSPathString());
const QFileInfo fi(file);
if (!fi.exists())
fi.dir().mkpath(fi.absolutePath());
if (!file.open(QIODevice::WriteOnly | QIODevice::Truncate | QIODevice::Text)) if (!file.open(QIODevice::WriteOnly | QIODevice::Truncate | QIODevice::Text))
return; return;

View File

@@ -33,6 +33,7 @@
#include <QVersionNumber> #include <QVersionNumber>
using namespace TextEditor; using namespace TextEditor;
using namespace Utils;
namespace Beautifier::Internal { namespace Beautifier::Internal {
@@ -72,7 +73,7 @@ void Uncrustify::updateActions(Core::IEditor *editor)
void Uncrustify::formatFile() void Uncrustify::formatFile()
{ {
const QString cfgFileName = configurationFile(); const FilePath cfgFileName = configurationFile();
if (cfgFileName.isEmpty()) { if (cfgFileName.isEmpty()) {
BeautifierPlugin::showError(BeautifierPlugin::msgCannotGetConfigurationFile( BeautifierPlugin::showError(BeautifierPlugin::msgCannotGetConfigurationFile(
Tr::tr(Constants::UNCRUSTIFY_DISPLAY_NAME))); Tr::tr(Constants::UNCRUSTIFY_DISPLAY_NAME)));
@@ -83,7 +84,7 @@ void Uncrustify::formatFile()
void Uncrustify::formatSelectedText() void Uncrustify::formatSelectedText()
{ {
const QString cfgFileName = configurationFile(); const FilePath cfgFileName = configurationFile();
if (cfgFileName.isEmpty()) { if (cfgFileName.isEmpty()) {
BeautifierPlugin::showError(BeautifierPlugin::msgCannotGetConfigurationFile( BeautifierPlugin::showError(BeautifierPlugin::msgCannotGetConfigurationFile(
Tr::tr(Constants::UNCRUSTIFY_DISPLAY_NAME))); Tr::tr(Constants::UNCRUSTIFY_DISPLAY_NAME)));
@@ -112,42 +113,41 @@ void Uncrustify::formatSelectedText()
} }
} }
QString Uncrustify::configurationFile() const FilePath Uncrustify::configurationFile() const
{ {
if (m_settings.useCustomStyle()) if (m_settings.useCustomStyle())
return m_settings.styleFileName(m_settings.customStyle()); return FilePath::fromUserInput(m_settings.styleFileName(m_settings.customStyle()));
if (m_settings.useOtherFiles()) { if (m_settings.useOtherFiles()) {
if (const ProjectExplorer::Project *project using namespace ProjectExplorer;
= ProjectExplorer::ProjectTree::currentProject()) { if (const Project *project = ProjectTree::currentProject()) {
const Utils::FilePaths files = project->files( const FilePaths files = project->files([](const Node *n) {
[](const ProjectExplorer::Node *n) { return n->filePath().endsWith("cfg"); }); const FilePath fp = n->filePath();
for (const Utils::FilePath &file : files) { return fp.fileName() == "uncrustify.cfg" && fp.isReadableFile();
const QFileInfo fi = file.toFileInfo(); });
if (fi.isReadable() && fi.fileName() == "uncrustify.cfg") if (!files.isEmpty())
return file.toString(); return files.first();
}
} }
} }
if (m_settings.useSpecificConfigFile()) { if (m_settings.useSpecificConfigFile()) {
const Utils::FilePath file = m_settings.specificConfigFile(); const FilePath file = m_settings.specificConfigFile();
if (file.exists()) if (file.exists())
return file.toString();
}
if (m_settings.useHomeFile()) {
const QString file = QDir::home().filePath("uncrustify.cfg");
if (QFile::exists(file))
return file; return file;
} }
return QString(); if (m_settings.useHomeFile()) {
const FilePath file = FileUtils::homePath() / "uncrustify.cfg";
if (file.exists())
return file;
}
return {};
} }
Command Uncrustify::command() const Command Uncrustify::command() const
{ {
const QString cfgFile = configurationFile(); const FilePath cfgFile = configurationFile();
return cfgFile.isEmpty() ? Command() : command(cfgFile, false); return cfgFile.isEmpty() ? Command() : command(cfgFile, false);
} }
@@ -156,7 +156,7 @@ bool Uncrustify::isApplicable(const Core::IDocument *document) const
return m_settings.isApplicable(document); return m_settings.isApplicable(document);
} }
Command Uncrustify::command(const QString &cfgFile, bool fragment) const Command Uncrustify::command(const FilePath &cfgFile, bool fragment) const
{ {
Command command; Command command;
command.setExecutable(m_settings.command()); command.setExecutable(m_settings.command());
@@ -173,7 +173,7 @@ Command Uncrustify::command(const QString &cfgFile, bool fragment) const
if (fragment) if (fragment)
command.addOption("--frag"); command.addOption("--frag");
command.addOption("-c"); command.addOption("-c");
command.addOption(cfgFile); command.addOption(cfgFile.path());
return command; return command;
} }

View File

@@ -22,8 +22,8 @@ public:
private: private:
void formatFile(); void formatFile();
void formatSelectedText(); void formatSelectedText();
QString configurationFile() const; Utils::FilePath configurationFile() const;
TextEditor::Command command(const QString &cfgFile, bool fragment = false) const; TextEditor::Command command(const Utils::FilePath &cfgFile, bool fragment = false) const;
QAction *m_formatFile = nullptr; QAction *m_formatFile = nullptr;
QAction *m_formatRange = nullptr; QAction *m_formatRange = nullptr;

View File

@@ -207,7 +207,7 @@ void ClangFormatConfigWidget::createStyleFileIfNeeded(bool isGlobal)
if (configFile.exists()) if (configFile.exists())
return; return;
QDir().mkpath(path.toString()); path.ensureWritableDir();
if (!isGlobal) { if (!isGlobal) {
FilePath possibleProjectConfig = d->project->rootProjectDirectory() FilePath possibleProjectConfig = d->project->rootProjectDirectory()
/ Constants::SETTINGS_FILE_NAME; / Constants::SETTINGS_FILE_NAME;
@@ -218,11 +218,8 @@ void ClangFormatConfigWidget::createStyleFileIfNeeded(bool isGlobal)
} }
} }
std::fstream newStyleFile(configFile.toString().toStdString(), std::fstream::out); const std::string config = clang::format::configurationAsText(constructStyle());
if (newStyleFile.is_open()) { configFile.writeFileContents(QByteArray::fromStdString(config));
newStyleFile << clang::format::configurationAsText(constructStyle());
newStyleFile.close();
}
} }
void ClangFormatConfigWidget::showOrHideWidgets() void ClangFormatConfigWidget::showOrHideWidgets()

View File

@@ -1465,8 +1465,10 @@ void MainWindow::changeLog()
return; return;
const FilePath file = versionedFiles.at(index).second; const FilePath file = versionedFiles.at(index).second;
QString contents = QString::fromUtf8(file.fileContents().value_or(QByteArray())); QString contents = QString::fromUtf8(file.fileContents().value_or(QByteArray()));
static const QRegularExpression bugexpr("(QT(CREATOR)?BUG-[0-9]+)"); // (?<![[\/]) == don't replace if it is preceded by "[" or "/"
contents.replace(bugexpr, "[\\1](https://bugreports.qt.io/browse/\\1)"); // i.e. if it already is part of a link
static const QRegularExpression bugexpr(R"((?<![[\/])((QT(CREATOR)?BUG|PYSIDE)-\d+))");
contents.replace(bugexpr, R"([\1](https://bugreports.qt.io/browse/\1))");
static const QRegularExpression docexpr("https://doc[.]qt[.]io/qtcreator/([.a-zA-Z/_-]*)"); static const QRegularExpression docexpr("https://doc[.]qt[.]io/qtcreator/([.a-zA-Z/_-]*)");
QList<QRegularExpressionMatch> matches; QList<QRegularExpressionMatch> matches;
for (const QRegularExpressionMatch &m : docexpr.globalMatch(contents)) for (const QRegularExpressionMatch &m : docexpr.globalMatch(contents))

View File

@@ -42,12 +42,12 @@ ProjectInfo::ConstPtr ProjectInfoGenerator::generate(const QPromise<ProjectInfo:
}); });
}; };
if (m_cToolchainMissing) { if (m_cToolchainMissing) {
showWarning(Tr::tr( showWarning(
"The project contains C source files, but the currently active kit " ::CppEditor::Tr::tr("The project contains C source files, but the currently active kit "
"has no C compiler. The code model will not be fully functional.")); "has no C compiler. The code model will not be fully functional."));
} }
if (m_cxxToolchainMissing) { if (m_cxxToolchainMissing) {
showWarning(Tr::tr( showWarning(::CppEditor::Tr::tr(
"The project contains C++ source files, but the currently active kit " "The project contains C++ source files, but the currently active kit "
"has no C++ compiler. The code model will not be fully functional.")); "has no C++ compiler. The code model will not be fully functional."));
} }

View File

@@ -1107,7 +1107,7 @@ QVariant BreakpointItem::data(int column, int role) const
return QVariant(); return QVariant();
} }
void BreakpointItem::addToCommand(DebuggerCommand *cmd) const void BreakpointItem::addToCommand(DebuggerCommand *cmd, BreakpointPathUsage defaultPathUsage) const
{ {
QTC_ASSERT(m_globalBreakpoint, return); QTC_ASSERT(m_globalBreakpoint, return);
const BreakpointParameters &requested = requestedParameters(); const BreakpointParameters &requested = requestedParameters();
@@ -1120,10 +1120,19 @@ void BreakpointItem::addToCommand(DebuggerCommand *cmd) const
cmd->arg("function", requested.functionName); cmd->arg("function", requested.functionName);
cmd->arg("oneshot", requested.oneShot); cmd->arg("oneshot", requested.oneShot);
cmd->arg("enabled", requested.enabled); cmd->arg("enabled", requested.enabled);
cmd->arg("file", requested.fileName.path());
cmd->arg("line", requested.textPosition.line); cmd->arg("line", requested.textPosition.line);
cmd->arg("address", requested.address); cmd->arg("address", requested.address);
cmd->arg("expression", requested.expression); cmd->arg("expression", requested.expression);
BreakpointPathUsage pathUsage = (requested.pathUsage
== BreakpointPathUsage::BreakpointPathUsageEngineDefault)
? defaultPathUsage
: requested.pathUsage;
cmd->arg("file",
pathUsage == BreakpointPathUsage::BreakpointUseFullPath
? requested.fileName.path()
: requested.fileName.fileName());
} }
void BreakpointItem::updateFromGdbOutput(const GdbMi &bkpt, const FilePath &fileRoot) void BreakpointItem::updateFromGdbOutput(const GdbMi &bkpt, const FilePath &fileRoot)

View File

@@ -107,7 +107,9 @@ public:
int markerLineNumber() const; int markerLineNumber() const;
const BreakpointParameters &requestedParameters() const; const BreakpointParameters &requestedParameters() const;
void addToCommand(DebuggerCommand *cmd) const; void addToCommand(DebuggerCommand *cmd,
BreakpointPathUsage defaultPathUsage
= BreakpointPathUsage::BreakpointUseFullPath) const;
void updateFromGdbOutput(const GdbMi &bkpt, const Utils::FilePath &fileRoot); void updateFromGdbOutput(const GdbMi &bkpt, const Utils::FilePath &fileRoot);
int modelId() const; int modelId() const;

View File

@@ -8,6 +8,7 @@
#include <coreplugin/icore.h> #include <coreplugin/icore.h>
#include <projectexplorer/runconfiguration.h> #include <projectexplorer/runconfiguration.h>
#include <projectexplorer/runconfigurationaspects.h>
#include <utils/environment.h> #include <utils/environment.h>
#include <utils/hostosinfo.h> #include <utils/hostosinfo.h>
@@ -172,9 +173,18 @@ void TerminalRunner::start()
QTC_ASSERT(!m_stubProc, reportFailure({}); return); QTC_ASSERT(!m_stubProc, reportFailure({}); return);
Runnable stub = m_stubRunnable(); Runnable stub = m_stubRunnable();
bool runAsRoot = false;
if (auto runAsRootAspect = runControl()->aspect<RunAsRootAspect>())
runAsRoot = runAsRootAspect->value;
m_stubProc = new Process(this); m_stubProc = new Process(this);
m_stubProc->setTerminalMode(TerminalMode::Debug); m_stubProc->setTerminalMode(TerminalMode::Debug);
if (runAsRoot) {
m_stubProc->setRunAsRoot(runAsRoot);
RunControl::provideAskPassEntry(stub.environment);
}
connect(m_stubProc, &Process::started, connect(m_stubProc, &Process::started,
this, &TerminalRunner::stubStarted); this, &TerminalRunner::stubStarted);
connect(m_stubProc, &Process::done, connect(m_stubProc, &Process::done,

View File

@@ -647,7 +647,7 @@ ActionContainer *FormEditorData::createPreviewStyleMenu(QActionGroup *actionGrou
QString name = menuId; QString name = menuId;
name += dot; name += dot;
const QVariant data = a->data(); const QVariant data = a->data();
const bool isDeviceProfile = data.type() == QVariant::Int; const bool isDeviceProfile = data.typeId() == QVariant::Int;
if (isDeviceProfile) { if (isDeviceProfile) {
name += deviceProfilePrefix; name += deviceProfilePrefix;
name += dot; name += dot;

View File

@@ -50,6 +50,39 @@ public:
BuildConsoleBuildStep(BuildStepList *buildStepList, Id id); BuildConsoleBuildStep(BuildStepList *buildStepList, Id id);
void setupOutputFormatter(OutputFormatter *formatter) final; void setupOutputFormatter(OutputFormatter *formatter) final;
TextDisplay t1{this, "<b>" + Tr::tr("Target and Configuration")};
CommandBuilderAspect commandBuilder{this};
TextDisplay t2{this, "<i>" + Tr::tr("Enter the appropriate arguments to your build command.")};
TextDisplay t3{this, "<i>" + Tr::tr("Make sure the build command's multi-job "
"parameter value is large enough "
"(such as -j200 for the JOM or Make build tools)")};
BoolAspect keepJobNum{this};
TextDisplay t4{this, "<b>" + Tr::tr("IncrediBuild Distribution Control")};
FilePathAspect profileXml{this};
BoolAspect avoidLocal{this};
IntegerAspect maxCpu{this};
SelectionAspect maxWinVer{this};
SelectionAspect minWinVer{this};
TextDisplay t5{this, "<b>" + Tr::tr("Output and Logging")};
StringAspect title{this};
FilePathAspect monFile{this};
BoolAspect suppressStdOut{this};
FilePathAspect logFile{this};
BoolAspect showCmd{this};
BoolAspect showAgents{this};
BoolAspect showTime{this};
BoolAspect hideHeader{this};
SelectionAspect logLevel{this};
TextDisplay t6{this, "<b>" + Tr::tr("Miscellaneous")};
StringAspect setEnv{this};
BoolAspect stopOnError{this};
StringAspect additionalArguments{this};
BoolAspect openMonitor{this};
}; };
BuildConsoleBuildStep::BuildConsoleBuildStep(BuildStepList *buildStepList, Id id) BuildConsoleBuildStep::BuildConsoleBuildStep(BuildStepList *buildStepList, Id id)
@@ -57,32 +90,20 @@ BuildConsoleBuildStep::BuildConsoleBuildStep(BuildStepList *buildStepList, Id id
{ {
setDisplayName(Tr::tr("IncrediBuild for Windows")); setDisplayName(Tr::tr("IncrediBuild for Windows"));
addAspect<TextDisplay>("<b>" + Tr::tr("Target and Configuration")); commandBuilder.setSettingsKey("IncrediBuild.BuildConsole.CommandBuilder");
auto commandBuilder = addAspect<CommandBuilderAspect>(this); keepJobNum.setSettingsKey("IncrediBuild.BuildConsole.KeepJobNum");
commandBuilder->setSettingsKey("IncrediBuild.BuildConsole.CommandBuilder"); keepJobNum.setLabel(Tr::tr("Keep original jobs number:"));
keepJobNum.setToolTip(Tr::tr("Forces IncrediBuild to not override the -j command line switch, "
addAspect<TextDisplay>("<i>" + Tr::tr("Enter the appropriate arguments to your build command."));
addAspect<TextDisplay>("<i>" + Tr::tr("Make sure the build command's multi-job "
"parameter value is large enough "
"(such as -j200 for the JOM or Make build tools)"));
auto keepJobNum = addAspect<BoolAspect>();
keepJobNum->setSettingsKey("IncrediBuild.BuildConsole.KeepJobNum");
keepJobNum->setLabel(Tr::tr("Keep original jobs number:"));
keepJobNum->setToolTip(Tr::tr("Forces IncrediBuild to not override the -j command line switch, "
"that controls the number of parallel spawned tasks. The default " "that controls the number of parallel spawned tasks. The default "
"IncrediBuild behavior is to set it to 200.")); "IncrediBuild behavior is to set it to 200."));
addAspect<TextDisplay>("<b>" + Tr::tr("IncrediBuild Distribution Control")); profileXml.setSettingsKey("IncrediBuild.BuildConsole.ProfileXml");
profileXml.setLabelText(Tr::tr("Profile.xml:"));
auto profileXml = addAspect<FilePathAspect>(); profileXml.setExpectedKind(PathChooser::Kind::File);
profileXml->setSettingsKey("IncrediBuild.BuildConsole.ProfileXml"); profileXml.setBaseFileName(PathChooser::homePath());
profileXml->setLabelText(Tr::tr("Profile.xml:")); profileXml.setHistoryCompleter("IncrediBuild.BuildConsole.ProfileXml.History");
profileXml->setExpectedKind(PathChooser::Kind::File); profileXml.setToolTip(Tr::tr("Defines how Automatic "
profileXml->setBaseFileName(PathChooser::homePath());
profileXml->setHistoryCompleter("IncrediBuild.BuildConsole.ProfileXml.History");
profileXml->setToolTip(Tr::tr("Defines how Automatic "
"Interception Interface should handle the various processes " "Interception Interface should handle the various processes "
"involved in a distributed job. It is not necessary for " "involved in a distributed job. It is not necessary for "
"\"Visual Studio\" or \"Make and Build tools\" builds, " "\"Visual Studio\" or \"Make and Build tools\" builds, "
@@ -91,199 +112,176 @@ BuildConsoleBuildStep::BuildConsoleBuildStep(BuildStepList *buildStepList, Id id
"those packages. It is required to configure distributable " "those packages. It is required to configure distributable "
"processes in \"Dev Tools\" builds.")); "processes in \"Dev Tools\" builds."));
auto avoidLocal = addAspect<BoolAspect>(); avoidLocal.setSettingsKey("IncrediBuild.BuildConsole.AvoidLocal");
avoidLocal->setSettingsKey("IncrediBuild.BuildConsole.AvoidLocal"); avoidLocal.setLabel(Tr::tr("Avoid local task execution:"));
avoidLocal->setLabel(Tr::tr("Avoid local task execution:")); avoidLocal.setToolTip(Tr::tr("Overrides the Agent Settings dialog Avoid task execution on local "
avoidLocal->setToolTip(Tr::tr("Overrides the Agent Settings dialog Avoid task execution on local "
"machine when possible option. This allows to free more resources " "machine when possible option. This allows to free more resources "
"on the initiator machine and could be beneficial to distribution " "on the initiator machine and could be beneficial to distribution "
"in scenarios where the initiating machine is bottlenecking the " "in scenarios where the initiating machine is bottlenecking the "
"build with High CPU usage.")); "build with High CPU usage."));
auto maxCpu = addAspect<IntegerAspect>(); maxCpu.setSettingsKey("IncrediBuild.BuildConsole.MaxCpu");
maxCpu->setSettingsKey("IncrediBuild.BuildConsole.MaxCpu"); maxCpu.setToolTip(Tr::tr("Determines the maximum number of CPU cores that can be used in a "
maxCpu->setToolTip(Tr::tr("Determines the maximum number of CPU cores that can be used in a "
"build, regardless of the number of available Agents. " "build, regardless of the number of available Agents. "
"It takes into account both local and remote cores, even if the " "It takes into account both local and remote cores, even if the "
"Avoid Task Execution on Local Machine option is selected.")); "Avoid Task Execution on Local Machine option is selected."));
maxCpu->setLabel(Tr::tr("Maximum CPUs to utilize in the build:")); maxCpu.setLabel(Tr::tr("Maximum CPUs to utilize in the build:"));
maxCpu->setRange(0, 65536); maxCpu.setRange(0, 65536);
auto maxWinVer = addAspect<SelectionAspect>(); maxWinVer.setSettingsKey("IncrediBuild.BuildConsole.MaxWinVer");
maxWinVer->setSettingsKey("IncrediBuild.BuildConsole.MaxWinVer"); maxWinVer.setDisplayName(Tr::tr("Newest allowed helper machine OS:"));
maxWinVer->setDisplayName(Tr::tr("Newest allowed helper machine OS:")); maxWinVer.setDisplayStyle(SelectionAspect::DisplayStyle::ComboBox);
maxWinVer->setDisplayStyle(SelectionAspect::DisplayStyle::ComboBox); maxWinVer.setToolTip(Tr::tr("Specifies the newest operating system installed on a helper "
maxWinVer->setToolTip(Tr::tr("Specifies the newest operating system installed on a helper "
"machine to be allowed to participate as helper in the build.")); "machine to be allowed to participate as helper in the build."));
for (const QString &version : supportedWindowsVersions()) for (const QString &version : supportedWindowsVersions())
maxWinVer->addOption(version); maxWinVer.addOption(version);
auto minWinVer = addAspect<SelectionAspect>(); minWinVer.setSettingsKey("IncrediBuild.BuildConsole.MinWinVer");
minWinVer->setSettingsKey("IncrediBuild.BuildConsole.MinWinVer"); minWinVer.setDisplayName(Tr::tr("Oldest allowed helper machine OS:"));
minWinVer->setDisplayName(Tr::tr("Oldest allowed helper machine OS:")); minWinVer.setDisplayStyle(SelectionAspect::DisplayStyle::ComboBox);
minWinVer->setDisplayStyle(SelectionAspect::DisplayStyle::ComboBox); minWinVer.setToolTip(Tr::tr("Specifies the oldest operating system installed on a helper "
minWinVer->setToolTip(Tr::tr("Specifies the oldest operating system installed on a helper "
"machine to be allowed to participate as helper in the build.")); "machine to be allowed to participate as helper in the build."));
for (const QString &version : supportedWindowsVersions()) for (const QString &version : supportedWindowsVersions())
minWinVer->addOption(version); minWinVer.addOption(version);
addAspect<TextDisplay>("<b>" + Tr::tr("Output and Logging")); title.setSettingsKey("IncrediBuild.BuildConsole.Title");
title.setLabelText(Tr::tr("Build title:"));
auto title = addAspect<StringAspect>(); title.setDisplayStyle(StringAspect::LineEditDisplay);
title->setSettingsKey("IncrediBuild.BuildConsole.Title"); title.setToolTip(Tr::tr("Specifies a custom header line which will be displayed in the "
title->setLabelText(Tr::tr("Build title:"));
title->setDisplayStyle(StringAspect::LineEditDisplay);
title->setToolTip(Tr::tr("Specifies a custom header line which will be displayed in the "
"beginning of the build output text. This title will also be used " "beginning of the build output text. This title will also be used "
"for the Build History and Build Monitor displays.")); "for the Build History and Build Monitor displays."));
auto monFile = addAspect<FilePathAspect>(); monFile.setSettingsKey("IncrediBuild.BuildConsole.MonFile");
monFile->setSettingsKey("IncrediBuild.BuildConsole.MonFile"); monFile.setLabelText(Tr::tr("Save IncrediBuild monitor file:"));
monFile->setLabelText(Tr::tr("Save IncrediBuild monitor file:")); monFile.setExpectedKind(PathChooser::Kind::Any);
monFile->setExpectedKind(PathChooser::Kind::Any); monFile.setBaseFileName(PathChooser::homePath());
monFile->setBaseFileName(PathChooser::homePath()); monFile.setHistoryCompleter(QLatin1String("IncrediBuild.BuildConsole.MonFile.History"));
monFile->setHistoryCompleter(QLatin1String("IncrediBuild.BuildConsole.MonFile.History")); monFile.setToolTip(Tr::tr("Writes a copy of the build progress file (.ib_mon) to the specified "
monFile->setToolTip(Tr::tr("Writes a copy of the build progress file (.ib_mon) to the specified "
"location. If only a folder name is given, a generated GUID will serve " "location. If only a folder name is given, a generated GUID will serve "
"as the file name. The full path of the saved Build Monitor will be " "as the file name. The full path of the saved Build Monitor will be "
"written to the end of the build output.")); "written to the end of the build output."));
auto suppressStdOut = addAspect<BoolAspect>(); suppressStdOut.setSettingsKey("IncrediBuild.BuildConsole.SuppressStdOut");
suppressStdOut->setSettingsKey("IncrediBuild.BuildConsole.SuppressStdOut"); suppressStdOut.setLabel(Tr::tr("Suppress STDOUT:"));
suppressStdOut->setLabel(Tr::tr("Suppress STDOUT:")); suppressStdOut.setToolTip(Tr::tr("Does not write anything to the standard output."));
suppressStdOut->setToolTip(Tr::tr("Does not write anything to the standard output."));
auto logFile = addAspect<FilePathAspect>(); logFile.setSettingsKey("IncrediBuild.BuildConsole.LogFile");
logFile->setSettingsKey("IncrediBuild.BuildConsole.LogFile"); logFile.setLabelText(Tr::tr("Output Log file:"));
logFile->setLabelText(Tr::tr("Output Log file:")); logFile.setExpectedKind(PathChooser::Kind::SaveFile);
logFile->setExpectedKind(PathChooser::Kind::SaveFile); logFile.setBaseFileName(PathChooser::homePath());
logFile->setBaseFileName(PathChooser::homePath()); logFile.setHistoryCompleter(QLatin1String("IncrediBuild.BuildConsole.LogFile.History"));
logFile->setHistoryCompleter(QLatin1String("IncrediBuild.BuildConsole.LogFile.History")); logFile.setToolTip(Tr::tr("Writes build output to a file."));
logFile->setToolTip(Tr::tr("Writes build output to a file."));
auto showCmd = addAspect<BoolAspect>(); showCmd.setSettingsKey("IncrediBuild.BuildConsole.ShowCmd");
showCmd->setSettingsKey("IncrediBuild.BuildConsole.ShowCmd"); showCmd.setLabel(Tr::tr("Show Commands in output:"));
showCmd->setLabel(Tr::tr("Show Commands in output:")); showCmd.setToolTip(Tr::tr("Shows, for each file built, the command-line used by IncrediBuild "
showCmd->setToolTip(Tr::tr("Shows, for each file built, the command-line used by IncrediBuild "
"to build the file.")); "to build the file."));
auto showAgents = addAspect<BoolAspect>(); showAgents.setSettingsKey("IncrediBuild.BuildConsole.ShowAgents");
showAgents->setSettingsKey("IncrediBuild.BuildConsole.ShowAgents"); showAgents.setLabel(Tr::tr("Show Agents in output:"));
showAgents->setLabel(Tr::tr("Show Agents in output:")); showAgents.setToolTip(Tr::tr("Shows the Agent used to build each file."));
showAgents->setToolTip(Tr::tr("Shows the Agent used to build each file."));
auto showTime = addAspect<BoolAspect>(); showTime.setSettingsKey("IncrediBuild.BuildConsole.ShowTime");
showTime->setSettingsKey("IncrediBuild.BuildConsole.ShowTime"); showTime.setLabel(Tr::tr("Show Time in output:"));
showTime->setLabel(Tr::tr("Show Time in output:")); showTime.setToolTip(Tr::tr("Shows the Start and Finish time for each file built."));
showTime->setToolTip(Tr::tr("Shows the Start and Finish time for each file built."));
auto hideHeader = addAspect<BoolAspect>(); hideHeader.setSettingsKey("IncrediBuild.BuildConsole.HideHeader");
hideHeader->setSettingsKey("IncrediBuild.BuildConsole.HideHeader"); hideHeader.setLabel(Tr::tr("Hide IncrediBuild Header in output:"));
hideHeader->setLabel(Tr::tr("Hide IncrediBuild Header in output:")); hideHeader.setToolTip(Tr::tr("Suppresses IncrediBuild's header in the build output"));
hideHeader->setToolTip(Tr::tr("Suppresses IncrediBuild's header in the build output"));
auto logLevel = addAspect<SelectionAspect>(); logLevel.setSettingsKey("IncrediBuild.BuildConsole.LogLevel");
logLevel->setSettingsKey("IncrediBuild.BuildConsole.LogLevel"); logLevel.setDisplayName(Tr::tr("Internal IncrediBuild logging level:"));
logLevel->setDisplayName(Tr::tr("Internal IncrediBuild logging level:")); logLevel.setDisplayStyle(SelectionAspect::DisplayStyle::ComboBox);
logLevel->setDisplayStyle(SelectionAspect::DisplayStyle::ComboBox); logLevel.addOption(QString());
logLevel->addOption(QString()); logLevel.addOption("Minimal");
logLevel->addOption("Minimal"); logLevel.addOption("Extended");
logLevel->addOption("Extended"); logLevel.addOption("Detailed");
logLevel->addOption("Detailed"); logLevel.setToolTip(Tr::tr("Overrides the internal Incredibuild logging level for this build. "
logLevel->setToolTip(Tr::tr("Overrides the internal Incredibuild logging level for this build. "
"Does not affect output or any user accessible logging. Used mainly " "Does not affect output or any user accessible logging. Used mainly "
"to troubleshoot issues with the help of IncrediBuild support")); "to troubleshoot issues with the help of IncrediBuild support"));
addAspect<TextDisplay>("<b>" + Tr::tr("Miscellaneous")); setEnv.setSettingsKey("IncrediBuild.BuildConsole.SetEnv");
setEnv.setLabelText(Tr::tr("Set an Environment Variable:"));
setEnv.setDisplayStyle(StringAspect::LineEditDisplay);
setEnv.setToolTip(Tr::tr("Sets or overrides environment variables for the context of the build."));
auto setEnv = addAspect<StringAspect>(); stopOnError.setSettingsKey("IncrediBuild.BuildConsole.StopOnError");
setEnv->setSettingsKey("IncrediBuild.BuildConsole.SetEnv"); stopOnError.setLabel(Tr::tr("Stop on errors:"));
setEnv->setLabelText(Tr::tr("Set an Environment Variable:")); stopOnError.setToolTip(Tr::tr("When specified, the execution will stop as soon as an error "
setEnv->setDisplayStyle(StringAspect::LineEditDisplay);
setEnv->setToolTip(Tr::tr("Sets or overrides environment variables for the context of the build."));
auto stopOnError = addAspect<BoolAspect>();
stopOnError->setSettingsKey("IncrediBuild.BuildConsole.StopOnError");
stopOnError->setLabel(Tr::tr("Stop on errors:"));
stopOnError->setToolTip(Tr::tr("When specified, the execution will stop as soon as an error "
"is encountered. This is the default behavior in " "is encountered. This is the default behavior in "
"\"Visual Studio\" builds, but not the default for " "\"Visual Studio\" builds, but not the default for "
"\"Make and Build tools\" or \"Dev Tools\" builds")); "\"Make and Build tools\" or \"Dev Tools\" builds"));
auto additionalArguments = addAspect<StringAspect>(); additionalArguments.setSettingsKey("IncrediBuild.BuildConsole.AdditionalArguments");
additionalArguments->setSettingsKey("IncrediBuild.BuildConsole.AdditionalArguments"); additionalArguments.setLabelText(Tr::tr("Additional Arguments:"));
additionalArguments->setLabelText(Tr::tr("Additional Arguments:")); additionalArguments.setDisplayStyle(StringAspect::LineEditDisplay);
additionalArguments->setDisplayStyle(StringAspect::LineEditDisplay); additionalArguments.setToolTip(Tr::tr("Add additional buildconsole arguments manually. "
additionalArguments->setToolTip(Tr::tr("Add additional buildconsole arguments manually. "
"The value of this field will be concatenated to the " "The value of this field will be concatenated to the "
"final buildconsole command line")); "final buildconsole command line"));
auto openMonitor = addAspect<BoolAspect>(); openMonitor.setSettingsKey("IncrediBuild.BuildConsole.OpenMonitor");
openMonitor->setSettingsKey("IncrediBuild.BuildConsole.OpenMonitor"); openMonitor.setLabel(Tr::tr("Open Build Monitor:"));
openMonitor->setLabel(Tr::tr("Open Build Monitor:")); openMonitor.setToolTip(Tr::tr("Opens Build Monitor once the build starts."));
openMonitor->setToolTip(Tr::tr("Opens Build Monitor once the build starts."));
setCommandLineProvider([=] { setCommandLineProvider([this] {
QStringList args; CommandLine cmd("BuildConsole.exe");
QString cmd("/Command= %1"); cmd.addArgs(QString("/Command=%1").arg(commandBuilder.fullCommandFlag(keepJobNum())), CommandLine::Raw);
cmd = cmd.arg(commandBuilder->fullCommandFlag(keepJobNum->value()));
args.append(cmd);
if (!profileXml->value().isEmpty()) if (!profileXml().isEmpty())
args.append("/Profile=" + profileXml->value()); cmd.addArg(QString("/Profile=%1").arg(profileXml().path()));
args.append(QString("/AvoidLocal=%1").arg(avoidLocal->value() ? QString("ON") : QString("OFF"))); cmd.addArg(QString("/AvoidLocal=%1").arg(avoidLocal() ? QString("ON") : QString("OFF")));
if (maxCpu->value() > 0) if (maxCpu() > 0)
args.append(QString("/MaxCPUs=%1").arg(maxCpu->value())); cmd.addArg(QString("/MaxCPUs=%1").arg(maxCpu()));
if (!maxWinVer->stringValue().isEmpty()) if (!maxWinVer.stringValue().isEmpty())
args.append(QString("/MaxWinVer=%1").arg(normalizeWinVerArgument(maxWinVer->stringValue()))); cmd.addArg(QString("/MaxWinVer=%1").arg(normalizeWinVerArgument(maxWinVer.stringValue())));
if (!minWinVer->stringValue().isEmpty()) if (!minWinVer.stringValue().isEmpty())
args.append(QString("/MinWinVer=%1").arg(normalizeWinVerArgument(minWinVer->stringValue()))); cmd.addArg(QString("/MinWinVer=%1").arg(normalizeWinVerArgument(minWinVer.stringValue())));
if (!title->value().isEmpty()) if (!title().isEmpty())
args.append(QString("/Title=" + title->value())); cmd.addArg("/Title=" + title());
if (!monFile->value().isEmpty()) if (!monFile().isEmpty())
args.append(QString("/Mon=" + monFile->value())); cmd.addArg("/Mon=" + monFile().path());
if (suppressStdOut->value()) if (suppressStdOut())
args.append("/Silent"); cmd.addArg("/Silent");
if (!logFile->value().isEmpty()) if (!logFile().isEmpty())
args.append(QString("/Log=" + logFile->value())); cmd.addArg("/Log=" + logFile().path());
if (showCmd->value()) if (showCmd())
args.append("/ShowCmd"); cmd.addArg("/ShowCmd");
if (showAgents->value()) if (showAgents())
args.append("/ShowAgent"); cmd.addArg("/ShowAgent");
if (showAgents->value()) if (showAgents())
args.append("/ShowTime"); cmd.addArg("/ShowTime");
if (hideHeader->value()) if (hideHeader())
args.append("/NoLogo"); cmd.addArg("/NoLogo");
if (!logLevel->stringValue().isEmpty()) if (!logLevel.stringValue().isEmpty())
args.append(QString("/LogLevel=" + logLevel->stringValue())); cmd.addArg("/LogLevel=" + logLevel.stringValue());
if (!setEnv->value().isEmpty()) if (!setEnv().isEmpty())
args.append(QString("/SetEnv=" + setEnv->value())); cmd.addArg("/SetEnv=" + setEnv());
if (stopOnError->value()) if (stopOnError())
args.append("/StopOnErrors"); cmd.addArg("/StopOnErrors");
if (!additionalArguments->value().isEmpty()) if (!additionalArguments().isEmpty())
args.append(additionalArguments->value()); cmd.addArgs(additionalArguments(), CommandLine::Raw);
if (openMonitor->value()) if (openMonitor())
args.append("/OpenMonitor"); cmd.addArg("/OpenMonitor");
return CommandLine("BuildConsole.exe", args); return cmd;
}); });
} }

View File

@@ -28,6 +28,21 @@ public:
IBConsoleBuildStep(BuildStepList *buildStepList, Id id); IBConsoleBuildStep(BuildStepList *buildStepList, Id id);
void setupOutputFormatter(OutputFormatter *formatter) final; void setupOutputFormatter(OutputFormatter *formatter) final;
TextDisplay t1{this, "<b>" + Tr::tr("Target and Configuration")};
CommandBuilderAspect commandBuilder{this};
BoolAspect keepJobNum{this};
TextDisplay t2{this, "<i>" + Tr::tr("Enter the appropriate arguments to your build command.")};
TextDisplay t3{this, "<i>" + Tr::tr("Make sure the build command's "
"multi-job parameter value is large enough (such as "
"-j200 for the JOM or Make build tools)")};
TextDisplay t4{this, "<b>" + Tr::tr("IncrediBuild Distribution Control")};
IntegerAspect nice{this};
BoolAspect forceRemote{this};
BoolAspect alternate{this};
}; };
IBConsoleBuildStep::IBConsoleBuildStep(BuildStepList *buildStepList, Id id) IBConsoleBuildStep::IBConsoleBuildStep(BuildStepList *buildStepList, Id id)
@@ -35,52 +50,38 @@ IBConsoleBuildStep::IBConsoleBuildStep(BuildStepList *buildStepList, Id id)
{ {
setDisplayName(Tr::tr("IncrediBuild for Linux")); setDisplayName(Tr::tr("IncrediBuild for Linux"));
addAspect<TextDisplay>("<b>" + Tr::tr("Target and Configuration")); commandBuilder.setSettingsKey("IncrediBuild.IBConsole.CommandBuilder");
auto commandBuilder = addAspect<CommandBuilderAspect>(this); keepJobNum.setSettingsKey("IncrediBuild.IBConsole.KeepJobNum");
commandBuilder->setSettingsKey("IncrediBuild.IBConsole.CommandBuilder"); keepJobNum.setLabel(Tr::tr("Keep original jobs number:"));
keepJobNum.setToolTip(Tr::tr("Forces IncrediBuild to not override the -j command line switch, "
addAspect<TextDisplay>("<i>" + Tr::tr("Enter the appropriate arguments to your build command."));
addAspect<TextDisplay>("<i>" + Tr::tr("Make sure the build command's "
"multi-job parameter value is large enough (such as "
"-j200 for the JOM or Make build tools)"));
auto keepJobNum = addAspect<BoolAspect>();
keepJobNum->setSettingsKey("IncrediBuild.IBConsole.KeepJobNum");
keepJobNum->setLabel(Tr::tr("Keep original jobs number:"));
keepJobNum->setToolTip(Tr::tr("Forces IncrediBuild to not override the -j command line switch, "
"that controls the number of parallel spawned tasks. The default " "that controls the number of parallel spawned tasks. The default "
"IncrediBuild behavior is to set it to 200.")); "IncrediBuild behavior is to set it to 200."));
addAspect<TextDisplay>("<b>" + Tr::tr("IncrediBuild Distribution Control")); nice.setSettingsKey("IncrediBuild.IBConsole.Nice");
nice.setToolTip(Tr::tr("Specify nice value. Nice Value should be numeric and between -20 and 19"));
nice.setLabel(Tr::tr("Nice value:"));
nice.setRange(-20, 19);
auto nice = addAspect<IntegerAspect>(); forceRemote.setSettingsKey("IncrediBuild.IBConsole.Alternate");
nice->setSettingsKey("IncrediBuild.IBConsole.Nice"); forceRemote.setLabel(Tr::tr("Force remote:"));
nice->setToolTip(Tr::tr("Specify nice value. Nice Value should be numeric and between -20 and 19"));
nice->setLabel(Tr::tr("Nice value:"));
nice->setRange(-20, 19);
auto forceRemote = addAspect<BoolAspect>(); alternate.setSettingsKey("IncrediBuild.IBConsole.ForceRemote");
forceRemote->setSettingsKey("IncrediBuild.IBConsole.Alternate"); alternate.setLabel(Tr::tr("Alternate tasks preference:"));
forceRemote->setLabel(Tr::tr("Force remote:"));
auto alternate = addAspect<BoolAspect>(); setCommandLineProvider([this] {
alternate->setSettingsKey("IncrediBuild.IBConsole.ForceRemote");
alternate->setLabel(Tr::tr("Alternate tasks preference:"));
setCommandLineProvider([=] {
QStringList args; QStringList args;
if (nice->value() != 0) if (nice() != 0)
args.append(QString("--nice %1 ").arg(nice->value())); args.append(QString("--nice %1 ").arg(nice()));
if (alternate->value()) if (alternate())
args.append("--alternate"); args.append("--alternate");
if (forceRemote->value()) if (forceRemote())
args.append("--force-remote"); args.append("--force-remote");
args.append(commandBuilder->fullCommandFlag(keepJobNum->value())); args.append(commandBuilder.fullCommandFlag(keepJobNum()));
return CommandLine("ib_console", args); return CommandLine("ib_console", args);
}); });

View File

@@ -18,6 +18,7 @@
#include <QAction> #include <QAction>
#include <QApplication> #include <QApplication>
#include <QComboBox>
#include <QDialog> #include <QDialog>
#include <QDialogButtonBox> #include <QDialogButtonBox>
#include <QElapsedTimer> #include <QElapsedTimer>
@@ -334,7 +335,7 @@ private:
QTabWidget * const m_tabWidget; QTabWidget * const m_tabWidget;
enum class TabIndex { Log, Capabilities, Custom }; enum class TabIndex { Log, Capabilities, Custom };
QListWidget *m_clients = nullptr; QComboBox *m_clients = nullptr;
}; };
void LspInspector::show(const QString &defaultClient) void LspInspector::show(const QString &defaultClient)
@@ -401,34 +402,34 @@ LspInspectorWidget::LspInspectorWidget(LspInspector *inspector)
this, &LspInspectorWidget::updateCapabilities); this, &LspInspectorWidget::updateCapabilities);
connect(Core::ICore::instance(), &Core::ICore::coreAboutToClose, this, &QWidget::close); connect(Core::ICore::instance(), &Core::ICore::coreAboutToClose, this, &QWidget::close);
m_clients = new QListWidget;
m_clients->addItems(inspector->clients());
m_clients->setSizePolicy(QSizePolicy::Maximum, QSizePolicy::MinimumExpanding);
auto mainLayout = new QVBoxLayout; auto mainLayout = new QVBoxLayout;
auto mainSplitter = new Core::MiniSplitter;
mainSplitter->setOrientation(Qt::Horizontal); m_clients = new QComboBox;
mainSplitter->addWidget(m_clients); m_clients->addItem(Tr::tr("<Select>"));
mainSplitter->addWidget(m_tabWidget); m_clients->addItems(inspector->clients());
mainSplitter->setStretchFactor(0, 0); QHBoxLayout *hbox = new QHBoxLayout;
mainSplitter->setStretchFactor(1, 1); hbox->addWidget(new QLabel(Tr::tr("Language Server:")));
hbox->addWidget(m_clients);
hbox->addStretch();
mainLayout->addLayout(hbox);
m_tabWidget->addTab(new LspLogWidget, Tr::tr("Log")); m_tabWidget->addTab(new LspLogWidget, Tr::tr("Log"));
m_tabWidget->addTab(new LspCapabilitiesWidget, Tr::tr("Capabilities")); m_tabWidget->addTab(new LspCapabilitiesWidget, Tr::tr("Capabilities"));
mainLayout->addWidget(mainSplitter); mainLayout->addWidget(m_tabWidget);
auto buttonBox = new QDialogButtonBox(this); auto buttonBox = new QDialogButtonBox(this);
buttonBox->setStandardButtons(QDialogButtonBox::Save | QDialogButtonBox::Close); buttonBox->setStandardButtons(QDialogButtonBox::Save | QDialogButtonBox::Close);
const auto clearButton = buttonBox->addButton(Tr::tr("Clear"), QDialogButtonBox::ResetRole); const auto clearButton = buttonBox->addButton(Tr::tr("Clear"), QDialogButtonBox::ResetRole);
connect(clearButton, &QPushButton::clicked, this, [this] { connect(clearButton, &QPushButton::clicked, this, [this] {
m_inspector->clear(); m_inspector->clear();
if (m_clients->currentItem()) if (m_clients->currentIndex() != 0)
currentClientChanged(m_clients->currentItem()->text()); currentClientChanged(m_clients->currentText());
}); });
mainLayout->addWidget(buttonBox); mainLayout->addWidget(buttonBox);
setLayout(mainLayout); setLayout(mainLayout);
connect(m_clients, connect(m_clients,
&QListWidget::currentTextChanged, &QComboBox::currentTextChanged,
this, this,
&LspInspectorWidget::currentClientChanged); &LspInspectorWidget::currentClientChanged);
@@ -442,31 +443,26 @@ LspInspectorWidget::LspInspectorWidget(LspInspector *inspector)
void LspInspectorWidget::selectClient(const QString &clientName) void LspInspectorWidget::selectClient(const QString &clientName)
{ {
auto items = m_clients->findItems(clientName, Qt::MatchExactly); const int index = m_clients->findText(clientName, Qt::MatchExactly);
if (items.isEmpty()) if (index >= 0)
return; m_clients->setCurrentIndex(index);
m_clients->setCurrentItem(items.first());
} }
void LspInspectorWidget::addMessage(const QString &clientName, const LspLogMessage &message) void LspInspectorWidget::addMessage(const QString &clientName, const LspLogMessage &message)
{ {
if (m_clients->findItems(clientName, Qt::MatchExactly).isEmpty()) if (m_clients->findText(clientName, Qt::MatchExactly) < 0)
m_clients->addItem(clientName); m_clients->addItem(clientName);
if (const QListWidgetItem *currentItem = m_clients->currentItem(); if (m_clients->currentText() == clientName)
currentItem && currentItem->text() == clientName) {
log()->addMessage(message); log()->addMessage(message);
} }
}
void LspInspectorWidget::updateCapabilities(const QString &clientName) void LspInspectorWidget::updateCapabilities(const QString &clientName)
{ {
if (m_clients->findItems(clientName, Qt::MatchExactly).isEmpty()) if (m_clients->findText(clientName, Qt::MatchExactly) < 0)
m_clients->addItem(clientName); m_clients->addItem(clientName);
if (const QListWidgetItem *currentItem = m_clients->currentItem(); if (m_clients->currentText() == clientName)
currentItem && clientName == currentItem->text()) {
capabilities()->setCapabilities(m_inspector->capabilities(clientName)); capabilities()->setCapabilities(m_inspector->capabilities(clientName));
} }
}
void LspInspectorWidget::currentClientChanged(const QString &clientName) void LspInspectorWidget::currentClientChanged(const QString &clientName)
{ {

View File

@@ -21,5 +21,9 @@
<file>wizards/qmlproject/component.qml.tpl</file> <file>wizards/qmlproject/component.qml.tpl</file>
<file>wizards/qmlproject/wizard.json</file> <file>wizards/qmlproject/wizard.json</file>
<file>wizards/qmlproject/Qul.cmake</file> <file>wizards/qmlproject/Qul.cmake</file>
<file>wizards/qmlproject-empty/CMakeLists.txt</file>
<file>wizards/qmlproject-empty/main.qml.tpl</file>
<file>wizards/qmlproject-empty/project.qmlproject.tpl</file>
<file>wizards/qmlproject-empty/wizard.json</file>
</qresource> </qresource>
</RCC> </RCC>

View File

@@ -0,0 +1,8 @@
cmake_minimum_required (VERSION 3.21.1)
project(%{CorrectedProjectName} VERSION 0.0.1 LANGUAGES C CXX ASM)
find_package(Qul)
qul_add_target(%{CorrectedProjectName} QML_PROJECT %{QmlProjectFile} GENERATE_ENTRYPOINT)
app_target_setup_os(%{CorrectedProjectName})

View File

@@ -0,0 +1,8 @@
import QtQuick
Rectangle {
Text {
anchors.centerIn: parent
text: "Qt for MCUs"
}
}

View File

@@ -0,0 +1,75 @@
import QmlProject 1.3
Project {
qtForMCUs: true // Required by QDS to enable/disable features Supported/Unsupported by QtMCUs projects. Currently ignored by qmlprojectexporter.
// importPaths: [] // Alternative API to ModuleFiles for importing modules.
// projectRootPath: "." // Optional root path relative to qmlproject file path.
mainFile: "%{MainQmlFile}" // The application's entrypoint
MCU.Config {
controlsStyle: "QtQuick.Controls.StyleDefault"
debugBytecode: false
debugLineDirectives: false
// maxResourceCacheSize: 0 // Set to 0 by default. Required for OnDemand resource cache policy and resource compression.
// Global settings for image properties. Can be overridden for selected resources in ImageFiles nodes.
resourceImagePixelFormat: "Automatic"
resourceCachePolicy: "NoCaching"
resourceCompression: false
// Font engine selection
fontEngine: "Static" // alternative option: "Spark".
// Font defaults for both engines
defaultFontFamily: "DejaVu Sans Mono"
defaultFontQuality: "VeryHigh"
glyphsCachePolicy: "NoCaching"
maxParagraphSize: 100
// Font properties for "Static"
addDefaultFonts: true // Set to false to disable add adding default fonts to your project.
autoGenerateGlyphs: true
// Font properties for "Spark"
// These properties are in effect only if the "Spark" font engine is used
complexTextRendering: true // Set this to false if complex scripts are not needed (Arabic scripts, Indic scripts, etc.)
fontCachePriming: false // Set to true to decrease application startup time. Only applies to fonts configured with unicode ranges (font.unicodeCoverage).
fontCacheSize: 0 // If this is needed, use a suitable number. Setting this to a sensible value will improve performance, the global default is 104800.
fontHeapSize: -1 // Set to sufficient value to improve performance. -1 means no restrictions to heap allocation.
fontHeapPrealloc: true
fontCachePrealloc: true
}
QmlFiles {
files: ["%{MainQmlFile}"]
}
ImageFiles {
files: []
}
FontFiles {
files: []
}
TranslationFiles {
files: []
}
InterfaceFiles {
files: []
}
ModuleFiles {
files: []
// Uncomment for adding Qul modules
MCU.qulModules: [
// "Qul::Controls",
// "Qul::ControlsTemplates",
// "Qul::Shapes",
// "Qul::Timeline"
]
}
}

View File

@@ -0,0 +1,71 @@
{
"version": 1,
"supportedProjectTypes": [ "CMakeProjectManager.CMakeProject" ],
"id": "M.McuSupportApplicationEmpty",
"category": "D.ApplicationMCU",
"trDescription": "Suitable for Qt for MCUs versions 2.4 and later. Creates an empty application that you can deploy, run and debug on MCU boards",
"trDisplayName": "Qt for MCUs Empty Application",
"trDisplayCategory": "QmlProject Application (Qt for MCUs)",
"icon": "../icon.png",
"iconKind": "Themed",
"enabled": true,
"options":
[
{ "key": "CorrectedProjectName", "value": "%{JS: '%{ProjectName}'.replace(/-/g, '_')}"},
{ "key": "MainQmlFile", "value": "%{CorrectedProjectName}.qml" },
{ "key": "QmlProjectFile", "value": "%{CorrectedProjectName}.qmlproject" },
{ "key": "CMakeFile", "value": "%{CorrectedProjectName}/CMakeLists.txt" }
],
"pages":
[
{
"trDisplayName": "Project Location",
"trShortTitle": "Location",
"typeId": "Project"
},
{
"trDisplayName": "Kit Selection",
"trShortTitle": "Kits",
"typeId": "Kits",
"enabled": "%{JS: !value('IsSubproject')}",
"data": {
"projectFilePath": "%{CMakeFile}"
}
},
{
"trDisplayName": "Project Management",
"trShortTitle": "Summary",
"typeId": "Summary"
}
],
"generators":
[
{
"typeId": "File",
"data":
[
{
"source": "CMakeLists.txt",
"openAsProject": true
},
{
"source": "project.qmlproject.tpl",
"target": "%{ProjectDirectory}/%{QmlProjectFile}",
"openInEditor": true
},
{
"source": "main.qml.tpl",
"target": "%{ProjectDirectory}/%{MainQmlFile}",
"openInEditor": true
},
{
"source": "%{IDE:ResourcePath}/templates/wizards/projects/git.ignore",
"target": ".gitignore",
"condition": "%{JS: !value('IsSubproject') && value('VersionControl') === 'G.Git'}"
}
]
}
]
}

View File

@@ -4,7 +4,7 @@ Project {
qtForMCUs: true // Required by QDS to enable/disable features Supported/Unsupported by QtMCUs projects. Currently ignored by qmlprojectexporter. qtForMCUs: true // Required by QDS to enable/disable features Supported/Unsupported by QtMCUs projects. Currently ignored by qmlprojectexporter.
// importPaths: ["imports/CustomModule"] // Alternative API for importing modules. // importPaths: ["imports/CustomModule"] // Alternative API for importing modules.
// projectRootPath: "." // Optional root path relative to qmlproject file path. // projectRootPath: "." // Optional root path relative to qmlproject file path.
mainFile: "%{MainQmlFile}" // Required to determin which qml file is the application entrypoint, when no custom c++ entrypoint is specified. mainFile: "%{MainQmlFile}" // The application's entrypoint
/* Global configuration */ /* Global configuration */
MCU.Config { MCU.Config {

View File

@@ -1,10 +1,10 @@
{ {
"version": 1, "version": 1,
"supportedProjectTypes": [ "CMakeProjectManager.CMakeProject" ], "supportedProjectTypes": [ "CMakeProjectManager.CMakeProject" ],
"id": "M.McuSupportApplication", "id": "M.McuSupportApplicationExample",
"category": "D.ApplicationMCU", "category": "D.ApplicationMCU",
"trDescription": "Suitable for Qt for MCUs versions 2.4 and later. Creates an application that uses a subset of Qt QML and Qt Quick Controls types (as supported by Qt for MCUs) that you can deploy, run, and debug on MCU boards.", "trDescription": "Suitable for Qt for MCUs versions 2.4 and later. Creates an application that uses a subset of Qt QML and Qt Quick Controls types (as supported by Qt for MCUs) that you can deploy, run, and debug on MCU boards.",
"trDisplayName": "Qt for MCUs Application", "trDisplayName": "Qt for MCUs Example Application",
"trDisplayCategory": "QmlProject Application (Qt for MCUs)", "trDisplayCategory": "QmlProject Application (Qt for MCUs)",
"icon": "../icon.png", "icon": "../icon.png",
"iconKind": "Themed", "iconKind": "Themed",

View File

@@ -165,7 +165,7 @@ QWidget *BuildStep::createConfigWidget()
Layouting::Form form; Layouting::Form form;
for (BaseAspect *aspect : std::as_const(*this)) { for (BaseAspect *aspect : std::as_const(*this)) {
if (aspect->isVisible()) if (aspect->isVisible())
form.addItem(aspect); form.addItems({aspect, Layouting::br()});
} }
form.addItem(Layouting::noMargin); form.addItem(Layouting::noMargin);
auto widget = form.emerge(); auto widget = form.emerge();

View File

@@ -218,14 +218,14 @@ QString JsonWizard::stringValue(const QString &n) const
if (!v.isValid()) if (!v.isValid())
return QString(); return QString();
if (v.type() == QVariant::String) { if (v.typeId() == QVariant::String) {
QString tmp = m_expander.expand(v.toString()); QString tmp = m_expander.expand(v.toString());
if (tmp.isEmpty()) if (tmp.isEmpty())
tmp = QString::fromLatin1(""); // Make sure isNull() is *not* true. tmp = QString::fromLatin1(""); // Make sure isNull() is *not* true.
return tmp; return tmp;
} }
if (v.type() == QVariant::StringList) if (v.typeId() == QVariant::StringList)
return stringListToArrayString(v.toStringList(), &m_expander); return stringListToArrayString(v.toStringList(), &m_expander);
return v.toString(); return v.toString();
@@ -276,7 +276,7 @@ QVariant JsonWizard::value(const QString &n) const
bool JsonWizard::boolFromVariant(const QVariant &v, MacroExpander *expander) bool JsonWizard::boolFromVariant(const QVariant &v, MacroExpander *expander)
{ {
if (v.type() == QVariant::String) { if (v.typeId() == QVariant::String) {
const QString tmp = expander->expand(v.toString()); const QString tmp = expander->expand(v.toString());
return !(tmp.isEmpty() || tmp == QLatin1String("false")); return !(tmp.isEmpty() || tmp == QLatin1String("false"));
} }
@@ -410,7 +410,7 @@ void JsonWizard::handleError(const QString &message)
QString JsonWizard::stringify(const QVariant &v) const QString JsonWizard::stringify(const QVariant &v) const
{ {
if (v.type() == QVariant::StringList) if (v.typeId() == QVariant::StringList)
return stringListToArrayString(v.toStringList(), &m_expander); return stringListToArrayString(v.toStringList(), &m_expander);
return Wizard::stringify(v); return Wizard::stringify(v);
} }

View File

@@ -102,7 +102,7 @@ static JsonWizardFactory::Generator parseGenerator(const QVariant &value, QStrin
{ {
JsonWizardFactory::Generator gen; JsonWizardFactory::Generator gen;
if (value.type() != QVariant::Map) { if (value.typeId() != QVariant::Map) {
*errorMessage = Tr::tr("Generator is not a object."); *errorMessage = Tr::tr("Generator is not a object.");
return gen; return gen;
} }
@@ -236,8 +236,8 @@ QVariant JsonWizardFactory::getDataValue(const QLatin1String &key, const QVarian
{ {
QVariant retVal = {}; QVariant retVal = {};
if ((valueSet.contains(key) && valueSet.value(key).type() == QVariant::Map) || if ((valueSet.contains(key) && valueSet.value(key).typeId() == QVariant::Map) ||
(defaultValueSet.contains(key) && defaultValueSet.value(key).type() == QVariant::Map)) { (defaultValueSet.contains(key) && defaultValueSet.value(key).typeId() == QVariant::Map)) {
retVal = mergeDataValueMaps(valueSet.value(key), defaultValueSet.value(key)); retVal = mergeDataValueMaps(valueSet.value(key), defaultValueSet.value(key));
} else { } else {
QVariant defaultValue = defaultValueSet.value(key, notExistValue); QVariant defaultValue = defaultValueSet.value(key, notExistValue);
@@ -263,7 +263,7 @@ std::pair<int, QStringList> JsonWizardFactory::screenSizeInfoFromPage(const QStr
return {}; return {};
const QVariant data = it->data; const QVariant data = it->data;
if (data.type() != QVariant::List) if (data.typeId() != QVariant::List)
return {}; return {};
const QVariant screenFactorField = Utils::findOrDefault(data.toList(), const QVariant screenFactorField = Utils::findOrDefault(data.toList(),
@@ -272,11 +272,11 @@ std::pair<int, QStringList> JsonWizardFactory::screenSizeInfoFromPage(const QStr
return "ScreenFactor" == m["name"]; return "ScreenFactor" == m["name"];
}); });
if (screenFactorField.type() != QVariant::Map) if (screenFactorField.typeId() != QVariant::Map)
return {}; return {};
const QVariant screenFactorData = screenFactorField.toMap()["data"]; const QVariant screenFactorData = screenFactorField.toMap()["data"];
if (screenFactorData.type() != QVariant::Map) if (screenFactorData.typeId() != QVariant::Map)
return {}; return {};
const QVariantMap screenFactorDataMap = screenFactorData.toMap(); const QVariantMap screenFactorDataMap = screenFactorData.toMap();
@@ -304,7 +304,7 @@ JsonWizardFactory::Page JsonWizardFactory::parsePage(const QVariant &value, QStr
{ {
JsonWizardFactory::Page p; JsonWizardFactory::Page p;
if (value.type() != QVariant::Map) { if (value.typeId() != QVariant::Map) {
*errorMessage = Tr::tr("Page is not an object."); *errorMessage = Tr::tr("Page is not an object.");
return p; return p;
} }
@@ -351,9 +351,9 @@ JsonWizardFactory::Page JsonWizardFactory::parsePage(const QVariant &value, QStr
if (specifiedSubData.isNull()) if (specifiedSubData.isNull())
subData = defaultSubData; subData = defaultSubData;
else if (specifiedSubData.type() == QVariant::Map) else if (specifiedSubData.typeId() == QVariant::Map)
subData = mergeDataValueMaps(specifiedSubData.toMap(), defaultSubData.toMap()); subData = mergeDataValueMaps(specifiedSubData.toMap(), defaultSubData.toMap());
else if (specifiedSubData.type() == QVariant::List) else if (specifiedSubData.typeId() == QVariant::List)
subData = specifiedSubData; subData = specifiedSubData;
if (!factory->validateData(typeId, subData, errorMessage)) if (!factory->validateData(typeId, subData, errorMessage))
@@ -648,9 +648,9 @@ QList<QVariant> JsonWizardFactory::objectOrList(const QVariant &data, QString *e
QList<QVariant> result; QList<QVariant> result;
if (data.isNull()) if (data.isNull())
*errorMessage = Tr::tr("key not found."); *errorMessage = Tr::tr("key not found.");
else if (data.type() == QVariant::Map) else if (data.typeId() == QVariant::Map)
result.append(data); result.append(data);
else if (data.type() == QVariant::List) else if (data.typeId() == QVariant::List)
result = data.toList(); result = data.toList();
else else
*errorMessage = Tr::tr("Expected an object or a list."); *errorMessage = Tr::tr("Expected an object or a list.");
@@ -661,7 +661,7 @@ QString JsonWizardFactory::localizedString(const QVariant &value)
{ {
if (value.isNull()) if (value.isNull())
return QString(); return QString();
if (value.type() == QVariant::Map) { if (value.typeId() == QVariant::Map) {
QVariantMap tmp = value.toMap(); QVariantMap tmp = value.toMap();
const QString locale = languageSetting().toLower(); const QString locale = languageSetting().toLower();
QStringList locales; QStringList locales;

View File

@@ -96,7 +96,7 @@ Utils::WizardPage *FilePageFactory::create(JsonWizard *wizard, Utils::Id typeId,
bool FilePageFactory::validateData(Utils::Id typeId, const QVariant &data, QString *errorMessage) bool FilePageFactory::validateData(Utils::Id typeId, const QVariant &data, QString *errorMessage)
{ {
QTC_ASSERT(canCreate(typeId), return false); QTC_ASSERT(canCreate(typeId), return false);
if (!data.isNull() && (data.type() != QVariant::Map || !data.toMap().isEmpty())) { if (!data.isNull() && (data.typeId() != QVariant::Map || !data.toMap().isEmpty())) {
*errorMessage = Tr::tr("\"data\" for a \"File\" page needs to be unset or an empty object."); *errorMessage = Tr::tr("\"data\" for a \"File\" page needs to be unset or an empty object.");
return false; return false;
} }
@@ -147,7 +147,7 @@ bool KitsPageFactory::validateData(Utils::Id typeId, const QVariant &data, QStri
{ {
QTC_ASSERT(canCreate(typeId), return false); QTC_ASSERT(canCreate(typeId), return false);
if (data.isNull() || data.type() != QVariant::Map) { if (data.isNull() || data.typeId() != QVariant::Map) {
*errorMessage = Tr::tr("\"data\" must be a JSON object for \"Kits\" pages."); *errorMessage = Tr::tr("\"data\" must be a JSON object for \"Kits\" pages.");
return false; return false;
} }
@@ -206,7 +206,7 @@ bool ProjectPageFactory::validateData(Utils::Id typeId, const QVariant &data, QS
Q_UNUSED(errorMessage) Q_UNUSED(errorMessage)
QTC_ASSERT(canCreate(typeId), return false); QTC_ASSERT(canCreate(typeId), return false);
if (!data.isNull() && data.type() != QVariant::Map) { if (!data.isNull() && data.typeId() != QVariant::Map) {
*errorMessage = Tr::tr("\"data\" must be empty or a JSON object for \"Project\" pages."); *errorMessage = Tr::tr("\"data\" must be empty or a JSON object for \"Project\" pages.");
return false; return false;
} }
@@ -252,7 +252,7 @@ Utils::WizardPage *SummaryPageFactory::create(JsonWizard *wizard, Utils::Id type
bool SummaryPageFactory::validateData(Utils::Id typeId, const QVariant &data, QString *errorMessage) bool SummaryPageFactory::validateData(Utils::Id typeId, const QVariant &data, QString *errorMessage)
{ {
QTC_ASSERT(canCreate(typeId), return false); QTC_ASSERT(canCreate(typeId), return false);
if (!data.isNull() && (data.type() != QVariant::Map)) { if (!data.isNull() && (data.typeId() != QVariant::Map)) {
*errorMessage = Tr::tr("\"data\" for a \"Summary\" page can be unset or needs to be an object."); *errorMessage = Tr::tr("\"data\" for a \"Summary\" page can be unset or needs to be an object.");
return false; return false;
} }

View File

@@ -387,7 +387,7 @@ void ToolChainKitAspect::upgrade(Kit *k)
const QVariant value = k->value(oldIdV2); const QVariant value = k->value(oldIdV2);
if (value.isNull() && !oldValue.isNull()) { if (value.isNull() && !oldValue.isNull()) {
QVariantMap newValue; QVariantMap newValue;
if (oldValue.type() == QVariant::Map) { if (oldValue.typeId() == QVariant::Map) {
// Used between 4.1 and 4.2: // Used between 4.1 and 4.2:
newValue = oldValue.toMap(); newValue = oldValue.toMap();
} else { } else {

View File

@@ -62,6 +62,8 @@
using namespace Utils; using namespace Utils;
using namespace Core; using namespace Core;
namespace PE = ProjectExplorer;
namespace ProjectExplorer { namespace ProjectExplorer {
/*! /*!
@@ -207,9 +209,10 @@ Project::Project(const QString &mimeType, const FilePath &fileName)
d->m_document = std::make_unique<ProjectDocument>(mimeType, fileName, this); d->m_document = std::make_unique<ProjectDocument>(mimeType, fileName, this);
DocumentManager::addDocument(d->m_document.get()); DocumentManager::addDocument(d->m_document.get());
d->m_macroExpander.setDisplayName(Tr::tr("Project")); d->m_macroExpander.setDisplayName(::PE::Tr::tr("Project"));
d->m_macroExpander.registerVariable("Project:Name", Tr::tr("Project Name"), d->m_macroExpander.registerVariable("Project:Name", ::PE::Tr::tr("Project Name"), [this] {
[this] { return displayName(); }); return displayName();
});
// Only set up containernode after d is set so that it will find the project directory! // Only set up containernode after d is set so that it will find the project directory!
d->m_containerNode = std::make_unique<ContainerNode>(this); d->m_containerNode = std::make_unique<ContainerNode>(this);
@@ -443,7 +446,7 @@ Tasks Project::projectIssues(const Kit *k) const
{ {
Tasks result; Tasks result;
if (!k->isValid()) if (!k->isValid())
result.append(createProjectTask(Task::TaskType::Error, Tr::tr("Kit is not valid."))); result.append(createProjectTask(Task::TaskType::Error, ::PE::Tr::tr("Kit is not valid.")));
return {}; return {};
} }
@@ -524,8 +527,8 @@ bool Project::copySteps(Target *sourceTarget, Target *newTarget)
if (fatalError) { if (fatalError) {
// That could be a more granular error message // That could be a more granular error message
QMessageBox::critical(ICore::dialogParent(), QMessageBox::critical(ICore::dialogParent(),
Tr::tr("Incompatible Kit"), ::PE::Tr::tr("Incompatible Kit"),
Tr::tr("Kit %1 is incompatible with kit %2.") ::PE::Tr::tr("Kit %1 is incompatible with kit %2.")
.arg(sourceTarget->kit()->displayName()) .arg(sourceTarget->kit()->displayName())
.arg(newTarget->kit()->displayName())); .arg(newTarget->kit()->displayName()));
} else if (!buildconfigurationError.isEmpty() } else if (!buildconfigurationError.isEmpty()
@@ -534,27 +537,27 @@ bool Project::copySteps(Target *sourceTarget, Target *newTarget)
QString error; QString error;
if (!buildconfigurationError.isEmpty()) if (!buildconfigurationError.isEmpty())
error += Tr::tr("Build configurations:") + QLatin1Char('\n') error += ::PE::Tr::tr("Build configurations:") + QLatin1Char('\n')
+ buildconfigurationError.join(QLatin1Char('\n')); + buildconfigurationError.join(QLatin1Char('\n'));
if (!deployconfigurationError.isEmpty()) { if (!deployconfigurationError.isEmpty()) {
if (!error.isEmpty()) if (!error.isEmpty())
error.append(QLatin1Char('\n')); error.append(QLatin1Char('\n'));
error += Tr::tr("Deploy configurations:") + QLatin1Char('\n') error += ::PE::Tr::tr("Deploy configurations:") + QLatin1Char('\n')
+ deployconfigurationError.join(QLatin1Char('\n')); + deployconfigurationError.join(QLatin1Char('\n'));
} }
if (!runconfigurationError.isEmpty()) { if (!runconfigurationError.isEmpty()) {
if (!error.isEmpty()) if (!error.isEmpty())
error.append(QLatin1Char('\n')); error.append(QLatin1Char('\n'));
error += Tr::tr("Run configurations:") + QLatin1Char('\n') error += ::PE::Tr::tr("Run configurations:") + QLatin1Char('\n')
+ runconfigurationError.join(QLatin1Char('\n')); + runconfigurationError.join(QLatin1Char('\n'));
} }
QMessageBox msgBox(ICore::dialogParent()); QMessageBox msgBox(ICore::dialogParent());
msgBox.setIcon(QMessageBox::Warning); msgBox.setIcon(QMessageBox::Warning);
msgBox.setWindowTitle(Tr::tr("Partially Incompatible Kit")); msgBox.setWindowTitle(::PE::Tr::tr("Partially Incompatible Kit"));
msgBox.setText(Tr::tr("Some configurations could not be copied.")); msgBox.setText(::PE::Tr::tr("Some configurations could not be copied."));
msgBox.setDetailedText(error); msgBox.setDetailedText(error);
msgBox.setStandardButtons(QMessageBox::Ok | QMessageBox::Cancel); msgBox.setStandardButtons(QMessageBox::Ok | QMessageBox::Cancel);
fatalError = msgBox.exec() != QDialog::Accepted; fatalError = msgBox.exec() != QDialog::Accepted;
@@ -728,11 +731,11 @@ FilePath Project::projectDirectory(const FilePath &top)
void Project::changeRootProjectDirectory() void Project::changeRootProjectDirectory()
{ {
FilePath rootPath = FileUtils::getExistingDirectory( FilePath rootPath = FileUtils::getExistingDirectory(nullptr,
nullptr, ::PE::Tr::tr("Select the Root Directory"),
Tr::tr("Select the Root Directory"),
rootProjectDirectory(), rootProjectDirectory(),
QFileDialog::ShowDirsOnly | QFileDialog::DontResolveSymlinks); QFileDialog::ShowDirsOnly
| QFileDialog::DontResolveSymlinks);
if (rootPath != d->m_rootProjectDirectory) { if (rootPath != d->m_rootProjectDirectory) {
d->m_rootProjectDirectory = rootPath; d->m_rootProjectDirectory = rootPath;
setNamedSettings(Constants::PROJECT_ROOT_PATH_KEY, d->m_rootProjectDirectory.toString()); setNamedSettings(Constants::PROJECT_ROOT_PATH_KEY, d->m_rootProjectDirectory.toString());
@@ -817,18 +820,25 @@ void Project::createTargetFromMap(const QVariantMap &map, int index)
if (!deviceTypeId.isValid()) if (!deviceTypeId.isValid())
deviceTypeId = Constants::DESKTOP_DEVICE_TYPE; deviceTypeId = Constants::DESKTOP_DEVICE_TYPE;
const QString formerKitName = targetMap.value(Target::displayNameKey()).toString(); const QString formerKitName = targetMap.value(Target::displayNameKey()).toString();
k = KitManager::registerKit([deviceTypeId, &formerKitName](Kit *kit) { k = KitManager::registerKit(
const QString kitNameSuggestion = formerKitName.contains(Tr::tr("Replacement for")) [deviceTypeId, &formerKitName](Kit *kit) {
? formerKitName : Tr::tr("Replacement for \"%1\"").arg(formerKitName); const QString kitNameSuggestion
= formerKitName.contains(::PE::Tr::tr("Replacement for"))
? formerKitName
: ::PE::Tr::tr("Replacement for \"%1\"").arg(formerKitName);
const QString tempKitName = makeUniquelyNumbered(kitNameSuggestion, const QString tempKitName = makeUniquelyNumbered(kitNameSuggestion,
transform(KitManager::kits(), &Kit::unexpandedDisplayName)); transform(KitManager::kits(), &Kit::unexpandedDisplayName));
kit->setUnexpandedDisplayName(tempKitName); kit->setUnexpandedDisplayName(tempKitName);
DeviceTypeKitAspect::setDeviceTypeId(kit, deviceTypeId); DeviceTypeKitAspect::setDeviceTypeId(kit, deviceTypeId);
kit->makeReplacementKit(); kit->makeReplacementKit();
kit->setup(); kit->setup();
}, id); },
id);
QTC_ASSERT(k, return); QTC_ASSERT(k, return);
TaskHub::addTask(BuildSystemTask(Task::Warning, Tr::tr("Project \"%1\" was configured for " TaskHub::addTask(BuildSystemTask(
Task::Warning,
::PE::Tr::tr(
"Project \"%1\" was configured for "
"kit \"%2\" with id %3, which does not exist anymore. The new kit \"%4\" was " "kit \"%2\" with id %3, which does not exist anymore. The new kit \"%4\" was "
"created in its place, in an attempt not to lose custom project settings.") "created in its place, in an attempt not to lose custom project settings.")
.arg(displayName(), formerKitName, id.toString(), k->displayName()))); .arg(displayName(), formerKitName, id.toString(), k->displayName())));
@@ -1081,7 +1091,8 @@ QStringList Project::availableQmlPreviewTranslations(QString *errorMessage)
const QDir languageDirectory(projectDirectory + "/i18n"); const QDir languageDirectory(projectDirectory + "/i18n");
const auto qmFiles = languageDirectory.entryList({"qml_*.qm"}); const auto qmFiles = languageDirectory.entryList({"qml_*.qm"});
if (qmFiles.isEmpty() && errorMessage) if (qmFiles.isEmpty() && errorMessage)
errorMessage->append(Tr::tr("Could not find any qml_*.qm file at \"%1\"").arg(languageDirectory.absolutePath())); errorMessage->append(::PE::Tr::tr("Could not find any qml_*.qm file at \"%1\"")
.arg(languageDirectory.absolutePath()));
return transform(qmFiles, [](const QString &qmFile) { return transform(qmFiles, [](const QString &qmFile) {
const int localeStartPosition = qmFile.lastIndexOf("_") + 1; const int localeStartPosition = qmFile.lastIndexOf("_") + 1;
const int localeEndPosition = qmFile.size() - QString(".qm").size(); const int localeEndPosition = qmFile.size() - QString(".qm").size();
@@ -1167,7 +1178,7 @@ void Project::addVariablesToMacroExpander(const QByteArray &prefix,
const QByteArray prefixWithoutColon = fullPrefix.chopped(1); const QByteArray prefixWithoutColon = fullPrefix.chopped(1);
expander->registerVariable(fullPrefix + "Name", expander->registerVariable(fullPrefix + "Name",
//: %1 is something like "Active project" //: %1 is something like "Active project"
Tr::tr("%1: Name.").arg(descriptor), ::PE::Tr::tr("%1: Name.").arg(descriptor),
[projectGetter]() -> QString { [projectGetter]() -> QString {
if (const Project *const project = projectGetter()) if (const Project *const project = projectGetter())
return project->displayName(); return project->displayName();
@@ -1175,7 +1186,7 @@ void Project::addVariablesToMacroExpander(const QByteArray &prefix,
}); });
expander->registerFileVariables(prefixWithoutColon, expander->registerFileVariables(prefixWithoutColon,
//: %1 is something like "Active project" //: %1 is something like "Active project"
Tr::tr("%1: Full path to main file.").arg(descriptor), ::PE::Tr::tr("%1: Full path to main file.").arg(descriptor),
[projectGetter]() -> FilePath { [projectGetter]() -> FilePath {
if (const Project *const project = projectGetter()) if (const Project *const project = projectGetter())
return project->projectFilePath(); return project->projectFilePath();
@@ -1183,7 +1194,7 @@ void Project::addVariablesToMacroExpander(const QByteArray &prefix,
}); });
expander->registerVariable(fullPrefix + "Kit:Name", expander->registerVariable(fullPrefix + "Kit:Name",
//: %1 is something like "Active project" //: %1 is something like "Active project"
Tr::tr("%1: The name of the active kit.").arg(descriptor), ::PE::Tr::tr("%1: The name of the active kit.").arg(descriptor),
[targetGetter]() -> QString { [targetGetter]() -> QString {
if (const Target *const target = targetGetter()) if (const Target *const target = targetGetter())
return target->kit()->displayName(); return target->kit()->displayName();
@@ -1191,7 +1202,8 @@ void Project::addVariablesToMacroExpander(const QByteArray &prefix,
}); });
expander->registerVariable(fullPrefix + "BuildConfig:Name", expander->registerVariable(fullPrefix + "BuildConfig:Name",
//: %1 is something like "Active project" //: %1 is something like "Active project"
Tr::tr("%1: Name of the active build configuration.").arg(descriptor), ::PE::Tr::tr("%1: Name of the active build configuration.")
.arg(descriptor),
[bcGetter]() -> QString { [bcGetter]() -> QString {
if (const BuildConfiguration *const bc = bcGetter()) if (const BuildConfiguration *const bc = bcGetter())
return bc->displayName(); return bc->displayName();
@@ -1199,17 +1211,18 @@ void Project::addVariablesToMacroExpander(const QByteArray &prefix,
}); });
expander->registerVariable(fullPrefix + "BuildConfig:Type", expander->registerVariable(fullPrefix + "BuildConfig:Type",
//: %1 is something like "Active project" //: %1 is something like "Active project"
Tr::tr("%1: Type of the active build configuration.").arg(descriptor), ::PE::Tr::tr("%1: Type of the active build configuration.")
.arg(descriptor),
[bcGetter]() -> QString { [bcGetter]() -> QString {
const BuildConfiguration *const bc = bcGetter(); const BuildConfiguration *const bc = bcGetter();
const BuildConfiguration::BuildType type const BuildConfiguration::BuildType type
= bc ? bc->buildType() : BuildConfiguration::Unknown; = bc ? bc->buildType() : BuildConfiguration::Unknown;
return BuildConfiguration::buildTypeName(type); return BuildConfiguration::buildTypeName(type);
}); });
expander expander->registerVariable(fullPrefix + "BuildConfig:Path",
->registerVariable(fullPrefix + "BuildConfig:Path",
//: %1 is something like "Active project" //: %1 is something like "Active project"
Tr::tr("%1: Full build path of active build configuration.").arg(descriptor), ::PE::Tr::tr("%1: Full build path of active build configuration.")
.arg(descriptor),
[bcGetter]() -> QString { [bcGetter]() -> QString {
if (const BuildConfiguration *const bc = bcGetter()) if (const BuildConfiguration *const bc = bcGetter())
return bc->buildDirectory().toUserOutput(); return bc->buildDirectory().toUserOutput();
@@ -1217,7 +1230,8 @@ void Project::addVariablesToMacroExpander(const QByteArray &prefix,
}); });
expander->registerPrefix(fullPrefix + "BuildConfig:Env", expander->registerPrefix(fullPrefix + "BuildConfig:Env",
//: %1 is something like "Active project" //: %1 is something like "Active project"
Tr::tr("%1: Variables in the active build environment.").arg(descriptor), ::PE::Tr::tr("%1: Variables in the active build environment.")
.arg(descriptor),
[bcGetter](const QString &var) { [bcGetter](const QString &var) {
if (BuildConfiguration *const bc = bcGetter()) if (BuildConfiguration *const bc = bcGetter())
return bc->environment().expandedValueForKey(var); return bc->environment().expandedValueForKey(var);
@@ -1226,7 +1240,8 @@ void Project::addVariablesToMacroExpander(const QByteArray &prefix,
expander->registerVariable(fullPrefix + "RunConfig:Name", expander->registerVariable(fullPrefix + "RunConfig:Name",
//: %1 is something like "Active project" //: %1 is something like "Active project"
Tr::tr("%1: Name of the active run configuration.").arg(descriptor), ::PE::Tr::tr("%1: Name of the active run configuration.")
.arg(descriptor),
[rcGetter]() -> QString { [rcGetter]() -> QString {
if (const RunConfiguration *const rc = rcGetter()) if (const RunConfiguration *const rc = rcGetter())
return rc->displayName(); return rc->displayName();
@@ -1234,16 +1249,18 @@ void Project::addVariablesToMacroExpander(const QByteArray &prefix,
}); });
expander->registerFileVariables(fullPrefix + "RunConfig:Executable", expander->registerFileVariables(fullPrefix + "RunConfig:Executable",
//: %1 is something like "Active project" //: %1 is something like "Active project"
Tr::tr("%1: Executable of the active run configuration.") ::PE::Tr::tr("%1: Executable of the active run configuration.")
.arg(descriptor), .arg(descriptor),
[rcGetter]() -> FilePath { [rcGetter]() -> FilePath {
if (const RunConfiguration *const rc = rcGetter()) if (const RunConfiguration *const rc = rcGetter())
return rc->commandLine().executable(); return rc->commandLine().executable();
return {}; return {};
}); });
expander->registerPrefix(fullPrefix + "RunConfig:Env", expander
->registerPrefix(fullPrefix + "RunConfig:Env",
//: %1 is something like "Active project" //: %1 is something like "Active project"
Tr::tr("%1: Variables in the environment of the active run configuration.") ::PE::Tr::tr(
"%1: Variables in the environment of the active run configuration.")
.arg(descriptor), .arg(descriptor),
[rcGetter](const QString &var) { [rcGetter](const QString &var) {
if (const RunConfiguration *const rc = rcGetter()) { if (const RunConfiguration *const rc = rcGetter()) {
@@ -1254,7 +1271,8 @@ void Project::addVariablesToMacroExpander(const QByteArray &prefix,
}); });
expander->registerVariable(fullPrefix + "RunConfig:WorkingDir", expander->registerVariable(fullPrefix + "RunConfig:WorkingDir",
//: %1 is something like "Active project" //: %1 is something like "Active project"
Tr::tr("%1: Working directory of the active run configuration.") ::PE::Tr::tr(
"%1: Working directory of the active run configuration.")
.arg(descriptor), .arg(descriptor),
[rcGetter] { [rcGetter] {
if (const RunConfiguration *const rc = rcGetter()) { if (const RunConfiguration *const rc = rcGetter()) {

View File

@@ -51,11 +51,8 @@ public:
const FilePath &newFilePath) override; const FilePath &newFilePath) override;
QString name() const override { return QLatin1String("python"); } QString name() const override { return QLatin1String("python"); }
bool saveRawFileList(const QStringList &rawFileList);
bool saveRawList(const QStringList &rawList, const FilePath &filePath);
void parse(); void parse();
QStringList processEntries(const QStringList &paths, bool save();
QHash<QString, QString> *map = nullptr) const;
bool writePyProjectFile(const FilePath &filePath, QString &content, bool writePyProjectFile(const FilePath &filePath, QString &content,
const QStringList &rawList, QString *errorMessage); const QStringList &rawList, QString *errorMessage);
@@ -63,12 +60,14 @@ public:
void triggerParsing() final; void triggerParsing() final;
private: private:
QStringList m_rawFileList; struct FileEntry {
QStringList m_files; QString rawEntry;
QStringList m_rawQmlImportPathList; FilePath filePath;
QStringList m_qmlImportPaths; };
QHash<QString, QString> m_rawListEntries; QList<FileEntry> processEntries(const QStringList &paths) const;
QHash<QString, QString> m_rawQmlImportPathEntries;
QList<FileEntry> m_files;
QList<FileEntry> m_qmlImportPaths;
}; };
/** /**
@@ -125,9 +124,9 @@ static QStringList readLines(const FilePath &projectFile)
QSet<QString> visited = { projectFileName }; QSet<QString> visited = { projectFileName };
QStringList lines = { projectFileName }; QStringList lines = { projectFileName };
QFile file(projectFile.toString()); const expected_str<QByteArray> contents = projectFile.fileContents();
if (file.open(QFile::ReadOnly)) { if (contents) {
QTextStream stream(&file); QTextStream stream(contents.value());
while (true) { while (true) {
const QString line = stream.readLine(); const QString line = stream.readLine();
@@ -145,17 +144,17 @@ static QStringList readLines(const FilePath &projectFile)
static QStringList readLinesJson(const FilePath &projectFile, QString *errorMessage) static QStringList readLinesJson(const FilePath &projectFile, QString *errorMessage)
{ {
QStringList lines = { projectFile.fileName() }; const QString projectFileName = projectFile.fileName();
QSet<QString> visited = { projectFileName };
QStringList lines = { projectFileName };
const QJsonObject obj = readObjJson(projectFile, errorMessage); const QJsonObject obj = readObjJson(projectFile, errorMessage);
if (obj.contains("files")) { for (const QJsonValue &file : obj.value("files").toArray()) {
const QJsonValue files = obj.value("files"); const QString fileName = file.toString();
const QJsonArray files_array = files.toArray(); if (visited.contains(fileName))
QSet<QString> visited; continue;
for (const auto &file : files_array) lines.append(fileName);
visited.insert(file.toString()); visited.insert(fileName);
lines.append(Utils::toList(visited));
} }
return lines; return lines;
@@ -226,20 +225,19 @@ void PythonBuildSystem::triggerParsing()
QList<BuildTargetInfo> appTargets; QList<BuildTargetInfo> appTargets;
auto newRoot = std::make_unique<PythonProjectNode>(projectDirectory()); auto newRoot = std::make_unique<PythonProjectNode>(projectDirectory());
for (const QString &f : std::as_const(m_files)) { for (const FileEntry &entry: std::as_const(m_files)) {
const QString displayName = baseDir.relativeFilePath(f); const QString displayName = entry.filePath.relativePathFrom(projectDirectory()).toUserOutput();
const FilePath filePath = FilePath::fromString(f); const FileType fileType = getFileType(entry.filePath);
const FileType fileType = getFileType(filePath);
newRoot->addNestedNode(std::make_unique<PythonFileNode>(filePath, displayName, fileType)); newRoot->addNestedNode(std::make_unique<PythonFileNode>(entry.filePath, displayName, fileType));
const MimeType mt = mimeTypeForFile(filePath, MimeMatchMode::MatchExtension); const MimeType mt = mimeTypeForFile(entry.filePath, MimeMatchMode::MatchExtension);
if (mt.matchesName(Constants::C_PY_MIMETYPE) || mt.matchesName(Constants::C_PY3_MIMETYPE)) { if (mt.matchesName(Constants::C_PY_MIMETYPE) || mt.matchesName(Constants::C_PY3_MIMETYPE)) {
BuildTargetInfo bti; BuildTargetInfo bti;
bti.displayName = displayName; bti.displayName = displayName;
bti.buildKey = f; bti.buildKey = entry.filePath.toString();
bti.targetFilePath = filePath; bti.targetFilePath = entry.filePath;
bti.projectFilePath = projectFilePath(); bti.projectFilePath = projectFilePath();
bti.isQtcRunnable = filePath.fileName() == "main.py"; bti.isQtcRunnable = entry.filePath.fileName() == "main.py";
appTargets.append(bti); appTargets.append(bti);
} }
} }
@@ -252,9 +250,9 @@ void PythonBuildSystem::triggerParsing()
const auto hiddenRccFolders = project()->files(Project::HiddenRccFolders); const auto hiddenRccFolders = project()->files(Project::HiddenRccFolders);
auto projectInfo = modelManager->defaultProjectInfoForProject(project(), hiddenRccFolders); auto projectInfo = modelManager->defaultProjectInfoForProject(project(), hiddenRccFolders);
for (const QString &importPath : std::as_const(m_qmlImportPaths)) { for (const FileEntry &importPath : std::as_const(m_qmlImportPaths)) {
const FilePath filePath = FilePath::fromString(importPath); if (!importPath.filePath.isEmpty())
projectInfo.importPaths.maybeInsert(filePath, QmlJS::Dialect::Qml); projectInfo.importPaths.maybeInsert(importPath.filePath, QmlJS::Dialect::Qml);
} }
modelManager->updateProjectInfo(projectInfo, project()); modelManager->updateProjectInfo(projectInfo, project());
@@ -265,95 +263,62 @@ void PythonBuildSystem::triggerParsing()
emitBuildSystemUpdated(); emitBuildSystemUpdated();
} }
bool PythonBuildSystem::saveRawFileList(const QStringList &rawFileList) bool PythonBuildSystem::save()
{
const bool result = saveRawList(rawFileList, projectFilePath());
// refresh(PythonProject::Files);
return result;
}
bool PythonBuildSystem::saveRawList(const QStringList &rawList, const FilePath &filePath)
{ {
const FilePath filePath = projectFilePath();
const QStringList rawList = Utils::transform(m_files, &FileEntry::rawEntry);
const FileChangeBlocker changeGuarg(filePath); const FileChangeBlocker changeGuarg(filePath);
bool result = false; bool result = false;
QByteArray newContents;
// New project file // New project file
if (filePath.endsWith(".pyproject")) { if (filePath.endsWith(".pyproject")) {
FileSaver saver(filePath, QIODevice::ReadOnly | QIODevice::Text); expected_str<QByteArray> contents = filePath.fileContents();
if (!saver.hasError()) { if (contents) {
QString content = QTextStream(saver.file()).readAll(); QJsonDocument doc = QJsonDocument::fromJson(*contents);
if (saver.finalize(ICore::dialogParent())) { QJsonObject project = doc.object();
QString errorMessage; project["files"] = QJsonArray::fromStringList(rawList);
result = writePyProjectFile(filePath, content, rawList, &errorMessage); doc.setObject(project);
if (!errorMessage.isEmpty()) newContents = doc.toJson();
MessageManager::writeDisrupting(errorMessage); } else {
} MessageManager::writeDisrupting(contents.error());
} }
} else { // Old project file } else { // Old project file
FileSaver saver(filePath, QIODevice::WriteOnly | QIODevice::Text); newContents = rawList.join('\n').toUtf8();
if (!saver.hasError()) {
QTextStream stream(saver.file());
for (const QString &filePath : rawList)
stream << filePath << '\n';
saver.setResult(&stream);
result = saver.finalize(ICore::dialogParent());
}
} }
const expected_str<qint64> writeResult = filePath.writeFileContents(newContents);
if (writeResult)
result = true;
else
MessageManager::writeDisrupting(writeResult.error());
return result; return result;
} }
bool PythonBuildSystem::writePyProjectFile(const FilePath &filePath, QString &content,
const QStringList &rawList, QString *errorMessage)
{
QFile file(filePath.toString());
if (!file.open(QIODevice::WriteOnly | QIODevice::Text)) {
*errorMessage = Tr::tr("Unable to open \"%1\" for writing: %2")
.arg(filePath.toUserOutput(), file.errorString());
return false;
}
// Build list of files with the current rawList for the JSON file
QString files("[");
for (const QString &f : rawList)
if (!f.endsWith(".pyproject"))
files += QString("\"%1\",").arg(f);
files = files.left(files.lastIndexOf(',')); // Removing leading comma
files += ']';
// Removing everything inside square parenthesis
// to replace it with the new list of files for the JSON file.
QRegularExpression pattern(R"(\[.*\])");
content.replace(pattern, files);
file.write(content.toUtf8());
return true;
}
bool PythonBuildSystem::addFiles(Node *, const FilePaths &filePaths, FilePaths *) bool PythonBuildSystem::addFiles(Node *, const FilePaths &filePaths, FilePaths *)
{ {
QStringList newList = m_rawFileList; const Utils::FilePath projectDir = projectDirectory();
const QDir baseDir(projectDirectory().toString()); for (const FilePath &filePath : filePaths) {
for (const FilePath &filePath : filePaths) if (!projectDir.isSameDevice(filePath))
newList.append(baseDir.relativeFilePath(filePath.toString())); return false;
m_files.append(FileEntry{filePath.relativePathFrom(projectDir).toString(), filePath});
}
return saveRawFileList(newList); return save();
} }
RemovedFilesFromProject PythonBuildSystem::removeFiles(Node *, const FilePaths &filePaths, FilePaths *) RemovedFilesFromProject PythonBuildSystem::removeFiles(Node *, const FilePaths &filePaths, FilePaths *)
{ {
QStringList newList = m_rawFileList;
for (const FilePath &filePath : filePaths) { for (const FilePath &filePath : filePaths) {
const QHash<QString, QString>::iterator i = m_rawListEntries.find(filePath.toString()); Utils::eraseOne(m_files,
if (i != m_rawListEntries.end()) [filePath](const FileEntry &entry) { return filePath == entry.filePath; });
newList.removeOne(i.value());
} }
bool res = saveRawFileList(newList); return save() ? RemovedFilesFromProject::Ok : RemovedFilesFromProject::Error;
return res ? RemovedFilesFromProject::Ok : RemovedFilesFromProject::Error;
} }
bool PythonBuildSystem::deleteFiles(Node *, const FilePaths &) bool PythonBuildSystem::deleteFiles(Node *, const FilePaths &)
@@ -363,52 +328,52 @@ bool PythonBuildSystem::deleteFiles(Node *, const FilePaths &)
bool PythonBuildSystem::renameFile(Node *, const FilePath &oldFilePath, const FilePath &newFilePath) bool PythonBuildSystem::renameFile(Node *, const FilePath &oldFilePath, const FilePath &newFilePath)
{ {
QStringList newList = m_rawFileList; for (FileEntry &entry : m_files) {
if (entry.filePath == oldFilePath) {
const QHash<QString, QString>::iterator i = m_rawListEntries.find(oldFilePath.toString()); entry.filePath = newFilePath;
if (i != m_rawListEntries.end()) { entry.rawEntry = newFilePath.relativeChildPath(projectDirectory()).toString();
const int index = newList.indexOf(i.value()); break;
if (index != -1) {
const QDir baseDir(projectDirectory().toString());
newList.replace(index, baseDir.relativeFilePath(newFilePath.toString()));
} }
} }
return saveRawFileList(newList); return save();
} }
void PythonBuildSystem::parse() void PythonBuildSystem::parse()
{ {
m_rawListEntries.clear(); m_files.clear();
m_rawQmlImportPathEntries.clear(); m_qmlImportPaths.clear();
QStringList files;
QStringList qmlImportPaths;
const FilePath filePath = projectFilePath(); const FilePath filePath = projectFilePath();
// The PySide project file is JSON based // The PySide project file is JSON based
if (filePath.endsWith(".pyproject")) { if (filePath.endsWith(".pyproject")) {
QString errorMessage; QString errorMessage;
m_rawFileList = readLinesJson(filePath, &errorMessage); files = readLinesJson(filePath, &errorMessage);
if (!errorMessage.isEmpty()) if (!errorMessage.isEmpty())
MessageManager::writeFlashing(errorMessage); MessageManager::writeFlashing(errorMessage);
errorMessage.clear(); errorMessage.clear();
m_rawQmlImportPathList = readImportPathsJson(filePath, &errorMessage); qmlImportPaths = readImportPathsJson(filePath, &errorMessage);
if (!errorMessage.isEmpty()) if (!errorMessage.isEmpty())
MessageManager::writeFlashing(errorMessage); MessageManager::writeFlashing(errorMessage);
} else if (filePath.endsWith(".pyqtc")) { } else if (filePath.endsWith(".pyqtc")) {
// To keep compatibility with PyQt we keep the compatibility with plain // To keep compatibility with PyQt we keep the compatibility with plain
// text files as project files. // text files as project files.
m_rawFileList = readLines(filePath); files = readLines(filePath);
} }
m_files = processEntries(m_rawFileList, &m_rawListEntries); m_files = processEntries(files);
m_qmlImportPaths = processEntries(m_rawQmlImportPathList, &m_rawQmlImportPathEntries); m_qmlImportPaths = processEntries(qmlImportPaths);
} }
/** /**
* Expands environment variables in the given \a string when they are written * Expands environment variables in the given \a string when they are written
* like $$(VARIABLE). * like $$(VARIABLE).
*/ */
static void expandEnvironmentVariables(const QProcessEnvironment &env, QString &string) static void expandEnvironmentVariables(const Environment &env, QString &string)
{ {
const QRegularExpression candidate("\\$\\$\\((.+)\\)"); const QRegularExpression candidate("\\$\\$\\((.+)\\)");
@@ -426,38 +391,25 @@ static void expandEnvironmentVariables(const QProcessEnvironment &env, QString &
/** /**
* Expands environment variables and converts the path from relative to the * Expands environment variables and converts the path from relative to the
* project to an absolute path. * project to an absolute path for all given raw paths
*
* The \a map variable is an optional argument that will map the returned
* absolute paths back to their original \a paths.
*/ */
QStringList PythonBuildSystem::processEntries(const QStringList &paths, QList<PythonBuildSystem::FileEntry> PythonBuildSystem::processEntries(
QHash<QString, QString> *map) const const QStringList &rawPaths) const
{ {
const QProcessEnvironment env = QProcessEnvironment::systemEnvironment(); QList<FileEntry> processed;
const QDir projectDir(projectDirectory().toString()); const FilePath projectDir = projectDirectory();
const Environment env = projectDirectory().deviceEnvironment();
QFileInfo fileInfo; for (const QString &rawPath : rawPaths) {
QStringList absolutePaths; FilePath resolvedPath;
for (const QString &path : paths) { QString path = rawPath.trimmed();
QString trimmedPath = path.trimmed(); if (!path.isEmpty()) {
if (trimmedPath.isEmpty()) expandEnvironmentVariables(env, path);
continue; resolvedPath = projectDir.resolvePath(path);
expandEnvironmentVariables(env, trimmedPath);
trimmedPath = FilePath::fromUserInput(trimmedPath).toString();
fileInfo.setFile(projectDir, trimmedPath);
if (fileInfo.exists()) {
const QString absPath = fileInfo.absoluteFilePath();
absolutePaths.append(absPath);
if (map)
map->insert(absPath, trimmedPath);
} }
processed << FileEntry{rawPath, resolvedPath};
} }
absolutePaths.removeDuplicates(); return processed;
return absolutePaths;
} }
Project::RestoreResult PythonProject::fromMap(const QVariantMap &map, QString *errorMessage) Project::RestoreResult PythonProject::fromMap(const QVariantMap &map, QString *errorMessage)

View File

@@ -90,6 +90,7 @@ public:
, m_executable(new PathChooser()) , m_executable(new PathChooser())
{ {
m_executable->setExpectedKind(PathChooser::ExistingCommand); m_executable->setExpectedKind(PathChooser::ExistingCommand);
m_executable->setAllowPathFromDevice(true);
connect(m_name, &QLineEdit::textChanged, this, &InterpreterDetailsWidget::changed); connect(m_name, &QLineEdit::textChanged, this, &InterpreterDetailsWidget::changed);
connect(m_executable, &PathChooser::textChanged, this, &InterpreterDetailsWidget::changed); connect(m_executable, &PathChooser::textChanged, this, &InterpreterDetailsWidget::changed);

View File

@@ -60,7 +60,7 @@ QString toJSLiteral(const QVariant &val)
{ {
if (!val.isValid()) if (!val.isValid())
return QString("undefined"); return QString("undefined");
if (val.type() == QVariant::List || val.type() == QVariant::StringList) { if (val.typeId() == QVariant::List || val.typeId() == QVariant::StringList) {
QString res; QString res;
const auto list = val.toList(); const auto list = val.toList();
for (const QVariant &child : list) { for (const QVariant &child : list) {
@@ -71,7 +71,7 @@ QString toJSLiteral(const QVariant &val)
res.append(']'); res.append(']');
return res; return res;
} }
if (val.type() == QVariant::Map) { if (val.typeId() == QVariant::Map) {
const QVariantMap &vm = val.toMap(); const QVariantMap &vm = val.toMap();
QString str("{"); QString str("{");
for (auto it = vm.begin(); it != vm.end(); ++it) { for (auto it = vm.begin(); it != vm.end(); ++it) {
@@ -82,7 +82,7 @@ QString toJSLiteral(const QVariant &val)
str += '}'; str += '}';
return str; return str;
} }
if (val.type() == QVariant::Bool) if (val.typeId() == QVariant::Bool)
return toJSLiteral(val.toBool()); return toJSLiteral(val.toBool());
if (val.canConvert(QVariant::String)) if (val.canConvert(QVariant::String))
return toJSLiteral(val.toString()); return toJSLiteral(val.toString());

View File

@@ -952,7 +952,7 @@ extend_qtc_plugin(QmlDesigner
SOURCES_PREFIX components/richtexteditor SOURCES_PREFIX components/richtexteditor
SOURCES SOURCES
hyperlinkdialog.cpp hyperlinkdialog.h hyperlinkdialog.ui hyperlinkdialog.cpp hyperlinkdialog.h hyperlinkdialog.ui
richtexteditor.cpp richtexteditor.h hyperlinkdialog.ui richtexteditor.cpp richtexteditor.h
richtexteditorproxy.cpp richtexteditorproxy.h richtexteditorproxy.cpp richtexteditorproxy.h
) )

View File

@@ -3,6 +3,8 @@
#include "bakelightsconnectionmanager.h" #include "bakelightsconnectionmanager.h"
#include "qmldesignertr.h"
#include <puppettocreatorcommand.h> #include <puppettocreatorcommand.h>
namespace QmlDesigner { namespace QmlDesigner {
@@ -34,10 +36,10 @@ void BakeLightsConnectionManager::dispatchCommand(const QVariant &command,
m_progressCallback(cmd.data().toString()); m_progressCallback(cmd.data().toString());
break; break;
case PuppetToCreatorCommand::BakeLightsAborted: case PuppetToCreatorCommand::BakeLightsAborted:
m_finishedCallback(tr("Baking aborted: %1").arg(cmd.data().toString())); m_finishedCallback(Tr::tr("Baking aborted: %1").arg(cmd.data().toString()));
break; break;
case PuppetToCreatorCommand::BakeLightsFinished: case PuppetToCreatorCommand::BakeLightsFinished:
m_finishedCallback(tr("Baking finished!")); m_finishedCallback(Tr::tr("Baking finished!"));
break; break;
default: default:
break; break;

View File

@@ -2,9 +2,11 @@
// 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
#include "richtexteditor.h" #include "richtexteditor.h"
#include "ui_richtexteditor.h"
#include "hyperlinkdialog.h" #include "hyperlinkdialog.h"
#include <utils/layoutbuilder.h>
#include <utils/stylehelper.h>
#include <functional> #include <functional>
#include <QAction> #include <QAction>
@@ -19,8 +21,9 @@
#include <QTextTableFormat> #include <QTextTableFormat>
#include <QToolButton> #include <QToolButton>
#include <QWidgetAction> #include <QWidgetAction>
#include <QApplication>
#include <utils/stylehelper.h> #include <QTextEdit>
#include <QToolBar>
namespace QmlDesigner { namespace QmlDesigner {
@@ -89,20 +92,41 @@ static QPixmap drawColorBox(const QColor& color, const QSize& size, int borderWi
RichTextEditor::RichTextEditor(QWidget *parent) RichTextEditor::RichTextEditor(QWidget *parent)
: QWidget(parent) : QWidget(parent)
, ui(new Ui::RichTextEditor)
, m_linkDialog(new HyperlinkDialog(this)) , m_linkDialog(new HyperlinkDialog(this))
{ {
ui->setupUi(this);
ui->textEdit->setTextInteractionFlags(Qt::TextEditorInteraction | Qt::LinksAccessibleByMouse); resize(428, 283);
ui->tableBar->setVisible(false); QSizePolicy pol(QSizePolicy::Preferred, QSizePolicy::Expanding);
pol.setHorizontalStretch(0);
pol.setVerticalStretch(5);
pol.setHeightForWidth(sizePolicy().hasHeightForWidth());
setSizePolicy(pol);
m_toolBar = new QToolBar(this);
m_toolBar->setIconSize(QSize(20, 20));
m_tableBar = new QToolBar(this);
m_tableBar->setIconSize(QSize(20, 20));
m_textEdit = new QTextEdit(this);
m_textEdit->setTextInteractionFlags(Qt::TextEditorInteraction | Qt::LinksAccessibleByMouse);
using namespace Layouting;
Column {
m_toolBar,
m_tableBar,
m_textEdit
}.attachTo(this);
m_tableBar->setVisible(false);
const QColor backColor = Theme::getColor(Theme::DSpanelBackground); const QColor backColor = Theme::getColor(Theme::DSpanelBackground);
const QString toolBarStyleSheet = const QString toolBarStyleSheet =
QString("QToolBar { background-color: %1; border-width: 1px }").arg(backColor.name()); QString("QToolBar { background-color: %1; border-width: 1px }").arg(backColor.name());
ui->toolBar->setStyleSheet(toolBarStyleSheet); m_toolBar->setStyleSheet(toolBarStyleSheet);
ui->tableBar->setStyleSheet(toolBarStyleSheet); m_tableBar->setStyleSheet(toolBarStyleSheet);
setupEditActions(); setupEditActions();
setupTextActions(); setupTextActions();
@@ -113,16 +137,16 @@ RichTextEditor::RichTextEditor(QWidget *parent)
setupFontActions(); setupFontActions();
setupTableActions(); setupTableActions();
connect(ui->textEdit, &QTextEdit::currentCharFormatChanged, connect(m_textEdit, &QTextEdit::currentCharFormatChanged,
this, &RichTextEditor::currentCharFormatChanged); this, &RichTextEditor::currentCharFormatChanged);
connect(ui->textEdit, &QTextEdit::cursorPositionChanged, connect(m_textEdit, &QTextEdit::cursorPositionChanged,
this, &RichTextEditor::cursorPositionChanged); this, &RichTextEditor::cursorPositionChanged);
connect(ui->textEdit, &QTextEdit::textChanged, connect(m_textEdit, &QTextEdit::textChanged,
this, &RichTextEditor::onTextChanged); this, &RichTextEditor::onTextChanged);
connect(m_linkDialog, &QDialog::accepted, [this]() { connect(m_linkDialog, &QDialog::accepted, [this]() {
QTextCharFormat oldFormat = ui->textEdit->textCursor().charFormat(); QTextCharFormat oldFormat = m_textEdit->textCursor().charFormat();
QTextCursor tcursor = ui->textEdit->textCursor(); QTextCursor tcursor = m_textEdit->textCursor();
QTextCharFormat charFormat = tcursor.charFormat(); QTextCharFormat charFormat = tcursor.charFormat();
charFormat.setForeground(QApplication::palette().color(QPalette::Link)); charFormat.setForeground(QApplication::palette().color(QPalette::Link));
@@ -145,7 +169,7 @@ RichTextEditor::RichTextEditor(QWidget *parent)
m_linkDialog->hide(); m_linkDialog->hide();
}); });
ui->textEdit->setFocus(); m_textEdit->setFocus();
m_linkDialog->hide(); m_linkDialog->hide();
} }
@@ -155,22 +179,22 @@ RichTextEditor::~RichTextEditor()
void RichTextEditor::setPlainText(const QString &text) void RichTextEditor::setPlainText(const QString &text)
{ {
ui->textEdit->setPlainText(text); m_textEdit->setPlainText(text);
} }
QString RichTextEditor::plainText() const QString RichTextEditor::plainText() const
{ {
return ui->textEdit->toPlainText(); return m_textEdit->toPlainText();
} }
void RichTextEditor::setRichText(const QString &text) void RichTextEditor::setRichText(const QString &text)
{ {
ui->textEdit->setHtml(text); m_textEdit->setHtml(text);
} }
void RichTextEditor::setTabChangesFocus(bool change) void RichTextEditor::setTabChangesFocus(bool change)
{ {
ui->textEdit->setTabChangesFocus(change); m_textEdit->setTabChangesFocus(change);
} }
void RichTextEditor::setImageActionVisible(bool change) void RichTextEditor::setImageActionVisible(bool change)
@@ -180,7 +204,7 @@ void RichTextEditor::setImageActionVisible(bool change)
void RichTextEditor::setDocumentBaseUrl(const QUrl& url) void RichTextEditor::setDocumentBaseUrl(const QUrl& url)
{ {
ui->textEdit->document()->setBaseUrl(url); m_textEdit->document()->setBaseUrl(url);
} }
QIcon RichTextEditor::getIcon(Theme::Icon icon) QIcon RichTextEditor::getIcon(Theme::Icon icon)
@@ -194,7 +218,7 @@ QIcon RichTextEditor::getIcon(Theme::Icon icon)
QString RichTextEditor::richText() const QString RichTextEditor::richText() const
{ {
return ui->textEdit->toHtml(); return m_textEdit->toHtml();
} }
void RichTextEditor::currentCharFormatChanged(const QTextCharFormat &format) void RichTextEditor::currentCharFormatChanged(const QTextCharFormat &format)
@@ -205,9 +229,9 @@ void RichTextEditor::currentCharFormatChanged(const QTextCharFormat &format)
void RichTextEditor::cursorPositionChanged() void RichTextEditor::cursorPositionChanged()
{ {
alignmentChanged(ui->textEdit->alignment()); alignmentChanged(m_textEdit->alignment());
styleChanged(ui->textEdit->textCursor()); styleChanged(m_textEdit->textCursor());
tableChanged(ui->textEdit->textCursor()); tableChanged(m_textEdit->textCursor());
} }
void RichTextEditor::onTextChanged() { void RichTextEditor::onTextChanged() {
@@ -216,11 +240,11 @@ void RichTextEditor::onTextChanged() {
void RichTextEditor::mergeFormatOnWordOrSelection(const QTextCharFormat &format) void RichTextEditor::mergeFormatOnWordOrSelection(const QTextCharFormat &format)
{ {
QTextCursor cursor = ui->textEdit->textCursor(); QTextCursor cursor = m_textEdit->textCursor();
if (!cursor.hasSelection()) if (!cursor.hasSelection())
cursor.select(QTextCursor::WordUnderCursor); cursor.select(QTextCursor::WordUnderCursor);
cursor.mergeCharFormat(format); cursor.mergeCharFormat(format);
ui->textEdit->mergeCurrentCharFormat(format); m_textEdit->mergeCurrentCharFormat(format);
} }
void RichTextEditor::fontChanged(const QFont &f) void RichTextEditor::fontChanged(const QFont &f)
@@ -243,7 +267,7 @@ void RichTextEditor::fontChanged(const QFont &f)
void RichTextEditor::colorChanged(const QColor &c) void RichTextEditor::colorChanged(const QColor &c)
{ {
QPixmap colorBox(drawColorBox(c, ui->tableBar->iconSize())); QPixmap colorBox(drawColorBox(c, m_tableBar->iconSize()));
m_actionTextColor->setIcon(colorBox); m_actionTextColor->setIcon(colorBox);
} }
@@ -293,7 +317,7 @@ void RichTextEditor::tableChanged(const QTextCursor &cursor)
if (currentTable) { if (currentTable) {
m_actionTableSettings->setChecked(true); m_actionTableSettings->setChecked(true);
ui->tableBar->setVisible(true); m_tableBar->setVisible(true);
setTableActionsActive(true); setTableActionsActive(true);
} }
@@ -305,27 +329,27 @@ void RichTextEditor::tableChanged(const QTextCursor &cursor)
void RichTextEditor::setupEditActions() void RichTextEditor::setupEditActions()
{ {
const QIcon undoIcon(getIcon(Theme::Icon::undo)); const QIcon undoIcon(getIcon(Theme::Icon::undo));
QAction *actionUndo = ui->toolBar->addAction(undoIcon, tr("&Undo"), ui->textEdit, &QTextEdit::undo); QAction *actionUndo = m_toolBar->addAction(undoIcon, tr("&Undo"), m_textEdit, &QTextEdit::undo);
actionUndo->setShortcut(QKeySequence::Undo); actionUndo->setShortcut(QKeySequence::Undo);
connect(ui->textEdit->document(), &QTextDocument::undoAvailable, connect(m_textEdit->document(), &QTextDocument::undoAvailable,
actionUndo, &QAction::setEnabled); actionUndo, &QAction::setEnabled);
const QIcon redoIcon(getIcon(Theme::Icon::redo)); const QIcon redoIcon(getIcon(Theme::Icon::redo));
QAction *actionRedo = ui->toolBar->addAction(redoIcon, tr("&Redo"), ui->textEdit, &QTextEdit::redo); QAction *actionRedo = m_toolBar->addAction(redoIcon, tr("&Redo"), m_textEdit, &QTextEdit::redo);
actionRedo->setShortcut(QKeySequence::Redo); actionRedo->setShortcut(QKeySequence::Redo);
connect(ui->textEdit->document(), &QTextDocument::redoAvailable, connect(m_textEdit->document(), &QTextDocument::redoAvailable,
actionRedo, &QAction::setEnabled); actionRedo, &QAction::setEnabled);
actionUndo->setEnabled(ui->textEdit->document()->isUndoAvailable()); actionUndo->setEnabled(m_textEdit->document()->isUndoAvailable());
actionRedo->setEnabled(ui->textEdit->document()->isRedoAvailable()); actionRedo->setEnabled(m_textEdit->document()->isRedoAvailable());
ui->toolBar->addSeparator(); m_toolBar->addSeparator();
} }
void RichTextEditor::setupTextActions() void RichTextEditor::setupTextActions()
{ {
const QIcon boldIcon(getIcon(Theme::Icon::fontStyleBold)); const QIcon boldIcon(getIcon(Theme::Icon::fontStyleBold));
m_actionTextBold = ui->toolBar->addAction(boldIcon, tr("&Bold"), m_actionTextBold = m_toolBar->addAction(boldIcon, tr("&Bold"),
[this](bool checked) { [this](bool checked) {
QTextCharFormat fmt; QTextCharFormat fmt;
fmt.setFontWeight(checked ? QFont::Bold : QFont::Normal); fmt.setFontWeight(checked ? QFont::Bold : QFont::Normal);
@@ -338,7 +362,7 @@ void RichTextEditor::setupTextActions()
m_actionTextBold->setCheckable(true); m_actionTextBold->setCheckable(true);
const QIcon italicIcon(getIcon(Theme::Icon::fontStyleItalic)); const QIcon italicIcon(getIcon(Theme::Icon::fontStyleItalic));
m_actionTextItalic = ui->toolBar->addAction(italicIcon, tr("&Italic"), m_actionTextItalic = m_toolBar->addAction(italicIcon, tr("&Italic"),
[this](bool checked) { [this](bool checked) {
QTextCharFormat fmt; QTextCharFormat fmt;
fmt.setFontItalic(checked); fmt.setFontItalic(checked);
@@ -351,7 +375,7 @@ void RichTextEditor::setupTextActions()
m_actionTextItalic->setCheckable(true); m_actionTextItalic->setCheckable(true);
const QIcon underlineIcon(getIcon(Theme::Icon::fontStyleUnderline)); const QIcon underlineIcon(getIcon(Theme::Icon::fontStyleUnderline));
m_actionTextUnderline = ui->toolBar->addAction(underlineIcon, tr("&Underline"), m_actionTextUnderline = m_toolBar->addAction(underlineIcon, tr("&Underline"),
[this](bool checked) { [this](bool checked) {
QTextCharFormat fmt; QTextCharFormat fmt;
fmt.setFontUnderline(checked); fmt.setFontUnderline(checked);
@@ -363,7 +387,7 @@ void RichTextEditor::setupTextActions()
m_actionTextUnderline->setFont(underline); m_actionTextUnderline->setFont(underline);
m_actionTextUnderline->setCheckable(true); m_actionTextUnderline->setCheckable(true);
ui->toolBar->addSeparator(); m_toolBar->addSeparator();
} }
void RichTextEditor::setupImageActions() void RichTextEditor::setupImageActions()
@@ -379,12 +403,12 @@ void RichTextEditor::setupImageActions()
for (QString& filePath : files) { for (QString& filePath : files) {
emit insertingImage(filePath); emit insertingImage(filePath);
ui->textEdit->insertHtml("<img src=\"" + filePath + "\" />"); m_textEdit->insertHtml("<img src=\"" + filePath + "\" />");
} }
} }
}; };
m_actionImage = ui->toolBar m_actionImage = m_toolBar
->addAction(getIcon(Theme::Icon::addFile), tr("Insert &Image"), insertImage); ->addAction(getIcon(Theme::Icon::addFile), tr("Insert &Image"), insertImage);
setImageActionVisible(false); setImageActionVisible(false);
@@ -393,8 +417,8 @@ void RichTextEditor::setupImageActions()
void RichTextEditor::setupHyperlinkActions() void RichTextEditor::setupHyperlinkActions()
{ {
const QIcon bulletIcon(getIcon(Theme::Icon::actionIconBinding)); const QIcon bulletIcon(getIcon(Theme::Icon::actionIconBinding));
m_actionHyperlink = ui->toolBar->addAction(bulletIcon, tr("Hyperlink Settings"), [this]() { m_actionHyperlink = m_toolBar->addAction(bulletIcon, tr("Hyperlink Settings"), [this]() {
QTextCursor cursor = ui->textEdit->textCursor(); QTextCursor cursor = m_textEdit->textCursor();
QTextCharFormat linkFormat = cursor.charFormat(); QTextCharFormat linkFormat = cursor.charFormat();
if (linkFormat.isAnchor()) { if (linkFormat.isAnchor()) {
m_linkDialog->setLink(linkFormat.anchorHref()); m_linkDialog->setLink(linkFormat.anchorHref());
@@ -410,37 +434,37 @@ void RichTextEditor::setupHyperlinkActions()
}); });
m_actionHyperlink->setCheckable(false); m_actionHyperlink->setCheckable(false);
ui->toolBar->addSeparator(); m_toolBar->addSeparator();
} }
void RichTextEditor::setupAlignActions() void RichTextEditor::setupAlignActions()
{ {
const QIcon leftIcon(getIcon(Theme::Icon::textAlignLeft)); const QIcon leftIcon(getIcon(Theme::Icon::textAlignLeft));
m_actionAlignLeft = ui->toolBar->addAction(leftIcon, tr("&Left"), [this]() { ui->textEdit->setAlignment(Qt::AlignLeft | Qt::AlignAbsolute); }); m_actionAlignLeft = m_toolBar->addAction(leftIcon, tr("&Left"), [this]() { m_textEdit->setAlignment(Qt::AlignLeft | Qt::AlignAbsolute); });
m_actionAlignLeft->setShortcut(Qt::CTRL | Qt::Key_L); m_actionAlignLeft->setShortcut(Qt::CTRL | Qt::Key_L);
m_actionAlignLeft->setCheckable(true); m_actionAlignLeft->setCheckable(true);
m_actionAlignLeft->setPriority(QAction::LowPriority); m_actionAlignLeft->setPriority(QAction::LowPriority);
const QIcon centerIcon(getIcon(Theme::Icon::textAlignCenter)); const QIcon centerIcon(getIcon(Theme::Icon::textAlignCenter));
m_actionAlignCenter = ui->toolBar->addAction(centerIcon, tr("C&enter"), [this]() { ui->textEdit->setAlignment(Qt::AlignHCenter); }); m_actionAlignCenter = m_toolBar->addAction(centerIcon, tr("C&enter"), [this]() { m_textEdit->setAlignment(Qt::AlignHCenter); });
m_actionAlignCenter->setShortcut(Qt::CTRL | Qt::Key_E); m_actionAlignCenter->setShortcut(Qt::CTRL | Qt::Key_E);
m_actionAlignCenter->setCheckable(true); m_actionAlignCenter->setCheckable(true);
m_actionAlignCenter->setPriority(QAction::LowPriority); m_actionAlignCenter->setPriority(QAction::LowPriority);
const QIcon rightIcon(getIcon(Theme::Icon::textAlignRight)); const QIcon rightIcon(getIcon(Theme::Icon::textAlignRight));
m_actionAlignRight = ui->toolBar->addAction(rightIcon, tr("&Right"), [this]() { ui->textEdit->setAlignment(Qt::AlignRight | Qt::AlignAbsolute); }); m_actionAlignRight = m_toolBar->addAction(rightIcon, tr("&Right"), [this]() { m_textEdit->setAlignment(Qt::AlignRight | Qt::AlignAbsolute); });
m_actionAlignRight->setShortcut(Qt::CTRL | Qt::Key_R); m_actionAlignRight->setShortcut(Qt::CTRL | Qt::Key_R);
m_actionAlignRight->setCheckable(true); m_actionAlignRight->setCheckable(true);
m_actionAlignRight->setPriority(QAction::LowPriority); m_actionAlignRight->setPriority(QAction::LowPriority);
const QIcon fillIcon(getIcon(Theme::Icon::textFullJustification)); const QIcon fillIcon(getIcon(Theme::Icon::textFullJustification));
m_actionAlignJustify = ui->toolBar->addAction(fillIcon, tr("&Justify"), [this]() { ui->textEdit->setAlignment(Qt::AlignJustify); }); m_actionAlignJustify = m_toolBar->addAction(fillIcon, tr("&Justify"), [this]() { m_textEdit->setAlignment(Qt::AlignJustify); });
m_actionAlignJustify->setShortcut(Qt::CTRL | Qt::Key_J); m_actionAlignJustify->setShortcut(Qt::CTRL | Qt::Key_J);
m_actionAlignJustify->setCheckable(true); m_actionAlignJustify->setCheckable(true);
m_actionAlignJustify->setPriority(QAction::LowPriority); m_actionAlignJustify->setPriority(QAction::LowPriority);
// Make sure the alignLeft is always left of the alignRight // Make sure the alignLeft is always left of the alignRight
QActionGroup *alignGroup = new QActionGroup(ui->toolBar); QActionGroup *alignGroup = new QActionGroup(m_toolBar);
if (QApplication::isLeftToRight()) { if (QApplication::isLeftToRight()) {
alignGroup->addAction(m_actionAlignLeft); alignGroup->addAction(m_actionAlignLeft);
@@ -453,15 +477,15 @@ void RichTextEditor::setupAlignActions()
} }
alignGroup->addAction(m_actionAlignJustify); alignGroup->addAction(m_actionAlignJustify);
ui->toolBar->addActions(alignGroup->actions()); m_toolBar->addActions(alignGroup->actions());
ui->toolBar->addSeparator(); m_toolBar->addSeparator();
} }
void RichTextEditor::setupListActions() void RichTextEditor::setupListActions()
{ {
const QIcon bulletIcon(getIcon(Theme::Icon::textBulletList)); const QIcon bulletIcon(getIcon(Theme::Icon::textBulletList));
m_actionBulletList = ui->toolBar->addAction(bulletIcon, tr("Bullet List"), [this](bool checked) { m_actionBulletList = m_toolBar->addAction(bulletIcon, tr("Bullet List"), [this](bool checked) {
if (checked) { if (checked) {
m_actionNumberedList->setChecked(false); m_actionNumberedList->setChecked(false);
textStyle(QTextListFormat::ListDisc); textStyle(QTextListFormat::ListDisc);
@@ -473,7 +497,7 @@ void RichTextEditor::setupListActions()
m_actionBulletList->setCheckable(true); m_actionBulletList->setCheckable(true);
const QIcon numberedIcon(getIcon(Theme::Icon::textNumberedList)); const QIcon numberedIcon(getIcon(Theme::Icon::textNumberedList));
m_actionNumberedList = ui->toolBar->addAction(numberedIcon, tr("Numbered List"), [this](bool checked) { m_actionNumberedList = m_toolBar->addAction(numberedIcon, tr("Numbered List"), [this](bool checked) {
if (checked) { if (checked) {
m_actionBulletList->setChecked(false); m_actionBulletList->setChecked(false);
textStyle(QTextListFormat::ListDecimal); textStyle(QTextListFormat::ListDecimal);
@@ -484,15 +508,15 @@ void RichTextEditor::setupListActions()
}); });
m_actionNumberedList->setCheckable(true); m_actionNumberedList->setCheckable(true);
ui->toolBar->addSeparator(); m_toolBar->addSeparator();
} }
void RichTextEditor::setupFontActions() void RichTextEditor::setupFontActions()
{ {
QPixmap colorBox(drawColorBox(ui->textEdit->textColor(), ui->tableBar->iconSize())); QPixmap colorBox(drawColorBox(m_textEdit->textColor(), m_tableBar->iconSize()));
m_actionTextColor = ui->toolBar->addAction(colorBox, tr("&Color..."), [this]() { m_actionTextColor = m_toolBar->addAction(colorBox, tr("&Color..."), [this]() {
QColor col = QColorDialog::getColor(ui->textEdit->textColor(), this); QColor col = QColorDialog::getColor(m_textEdit->textColor(), this);
if (!col.isValid()) if (!col.isValid())
return; return;
QTextCharFormat fmt; QTextCharFormat fmt;
@@ -505,7 +529,7 @@ void RichTextEditor::setupFontActions()
m_fontNameAction->setInitializer([this](QFontComboBox *w) { m_fontNameAction->setInitializer([this](QFontComboBox *w) {
if (!w) return; if (!w) return;
w->setCurrentIndex(w->findText(ui->textEdit->currentCharFormat().font().family())); w->setCurrentIndex(w->findText(m_textEdit->currentCharFormat().font().family()));
connect(w, &QComboBox::textActivated, [this](const QString &f) { connect(w, &QComboBox::textActivated, [this](const QString &f) {
QTextCharFormat fmt; QTextCharFormat fmt;
fmt.setFontFamily(f); fmt.setFontFamily(f);
@@ -514,7 +538,7 @@ void RichTextEditor::setupFontActions()
}); });
m_fontNameAction->setDefaultWidget(new QFontComboBox); m_fontNameAction->setDefaultWidget(new QFontComboBox);
ui->toolBar->addAction(m_fontNameAction); m_toolBar->addAction(m_fontNameAction);
m_fontSizeAction = new FontWidgetActions<QComboBox>(this); m_fontSizeAction = new FontWidgetActions<QComboBox>(this);
m_fontSizeAction->setInitializer([this](QComboBox *w) { m_fontSizeAction->setInitializer([this](QComboBox *w) {
@@ -525,7 +549,7 @@ void RichTextEditor::setupFontActions()
const QList<int> standardSizes = QFontDatabase::standardSizes(); const QList<int> standardSizes = QFontDatabase::standardSizes();
for (const int size : standardSizes) for (const int size : standardSizes)
w->addItem(QString::number(size)); w->addItem(QString::number(size));
w->setCurrentText(QString::number(ui->textEdit->currentCharFormat().font().pointSize())); w->setCurrentText(QString::number(m_textEdit->currentCharFormat().font().pointSize()));
connect(w, &QComboBox::textActivated, [this](const QString &p) { connect(w, &QComboBox::textActivated, [this](const QString &p) {
qreal pointSize = p.toDouble(); qreal pointSize = p.toDouble();
if (pointSize > 0.0) { if (pointSize > 0.0) {
@@ -537,17 +561,17 @@ void RichTextEditor::setupFontActions()
}); });
m_fontSizeAction->setDefaultWidget(new QComboBox); m_fontSizeAction->setDefaultWidget(new QComboBox);
ui->toolBar->addAction(m_fontSizeAction); m_toolBar->addAction(m_fontSizeAction);
ui->toolBar->addSeparator(); m_toolBar->addSeparator();
} }
void RichTextEditor::setupTableActions() void RichTextEditor::setupTableActions()
{ {
const QIcon tableIcon(getIcon(Theme::Icon::addTable)); const QIcon tableIcon(getIcon(Theme::Icon::addTable));
m_actionTableSettings = ui->toolBar->addAction(tableIcon, tr("&Table Settings"), [this](bool checked) { m_actionTableSettings = m_toolBar->addAction(tableIcon, tr("&Table Settings"), [this](bool checked) {
ui->tableBar->setVisible(checked); m_tableBar->setVisible(checked);
}); });
m_actionTableSettings->setShortcut(Qt::CTRL | Qt::Key_T); m_actionTableSettings->setShortcut(Qt::CTRL | Qt::Key_T);
m_actionTableSettings->setCheckable(true); m_actionTableSettings->setCheckable(true);
@@ -556,8 +580,8 @@ void RichTextEditor::setupTableActions()
//table bar: //table bar:
const QIcon createTableIcon(getIcon(Theme::Icon::addTable)); const QIcon createTableIcon(getIcon(Theme::Icon::addTable));
m_actionCreateTable = ui->tableBar->addAction(createTableIcon, tr("Create Table"), [this]() { m_actionCreateTable = m_tableBar->addAction(createTableIcon, tr("Create Table"), [this]() {
QTextCursor cursor = ui->textEdit->textCursor(); QTextCursor cursor = m_textEdit->textCursor();
cursorEditBlock(cursor, [&] () { cursorEditBlock(cursor, [&] () {
//format table cells to look a bit better: //format table cells to look a bit better:
QTextTableFormat tableFormat; QTextTableFormat tableFormat;
@@ -568,15 +592,15 @@ void RichTextEditor::setupTableActions()
cursor.insertTable(1, 1, tableFormat); cursor.insertTable(1, 1, tableFormat);
//move cursor into the first cell of the table: //move cursor into the first cell of the table:
ui->textEdit->setTextCursor(cursor); m_textEdit->setTextCursor(cursor);
}); });
}); });
m_actionCreateTable->setCheckable(false); m_actionCreateTable->setCheckable(false);
const QIcon removeTableIcon(getIcon(Theme::Icon::deleteTable)); const QIcon removeTableIcon(getIcon(Theme::Icon::deleteTable));
m_actionRemoveTable = ui->tableBar->addAction(removeTableIcon, tr("Remove Table"), [this]() { m_actionRemoveTable = m_tableBar->addAction(removeTableIcon, tr("Remove Table"), [this]() {
QTextCursor cursor = ui->textEdit->textCursor(); QTextCursor cursor = m_textEdit->textCursor();
if (QTextTable *currentTable = ui->textEdit->textCursor().currentTable()) { if (QTextTable *currentTable = m_textEdit->textCursor().currentTable()) {
cursorEditBlock(cursor, [&] () { cursorEditBlock(cursor, [&] () {
currentTable->removeRows(0, currentTable->rows()); currentTable->removeRows(0, currentTable->rows());
}); });
@@ -584,12 +608,12 @@ void RichTextEditor::setupTableActions()
}); });
m_actionRemoveTable->setCheckable(false); m_actionRemoveTable->setCheckable(false);
ui->tableBar->addSeparator(); m_tableBar->addSeparator();
const QIcon addRowIcon(getIcon(Theme::Icon::addRowAfter)); //addRowAfter const QIcon addRowIcon(getIcon(Theme::Icon::addRowAfter)); //addRowAfter
m_actionAddRow = ui->tableBar->addAction(addRowIcon, tr("Add Row"), [this]() { m_actionAddRow = m_tableBar->addAction(addRowIcon, tr("Add Row"), [this]() {
QTextCursor cursor = ui->textEdit->textCursor(); QTextCursor cursor = m_textEdit->textCursor();
if (QTextTable *currentTable = ui->textEdit->textCursor().currentTable()) { if (QTextTable *currentTable = m_textEdit->textCursor().currentTable()) {
cursorEditBlock(cursor, [&] () { cursorEditBlock(cursor, [&] () {
currentTable->insertRows(currentTable->cellAt(cursor).row()+1, 1); currentTable->insertRows(currentTable->cellAt(cursor).row()+1, 1);
}); });
@@ -598,9 +622,9 @@ void RichTextEditor::setupTableActions()
m_actionAddRow->setCheckable(false); m_actionAddRow->setCheckable(false);
const QIcon addColumnIcon(getIcon(Theme::Icon::addColumnAfter)); //addColumnAfter const QIcon addColumnIcon(getIcon(Theme::Icon::addColumnAfter)); //addColumnAfter
m_actionAddColumn = ui->tableBar->addAction(addColumnIcon, tr("Add Column"), [this]() { m_actionAddColumn = m_tableBar->addAction(addColumnIcon, tr("Add Column"), [this]() {
QTextCursor cursor = ui->textEdit->textCursor(); QTextCursor cursor = m_textEdit->textCursor();
if (QTextTable *currentTable = ui->textEdit->textCursor().currentTable()) { if (QTextTable *currentTable = m_textEdit->textCursor().currentTable()) {
cursorEditBlock(cursor, [&] () { cursorEditBlock(cursor, [&] () {
currentTable->insertColumns(currentTable->cellAt(cursor).column()+1, 1); currentTable->insertColumns(currentTable->cellAt(cursor).column()+1, 1);
}); });
@@ -609,8 +633,8 @@ void RichTextEditor::setupTableActions()
m_actionAddColumn->setCheckable(false); m_actionAddColumn->setCheckable(false);
const QIcon removeRowIcon(getIcon(Theme::Icon::deleteRow)); const QIcon removeRowIcon(getIcon(Theme::Icon::deleteRow));
m_actionRemoveRow = ui->tableBar->addAction(removeRowIcon, tr("Remove Row"), [this]() { m_actionRemoveRow = m_tableBar->addAction(removeRowIcon, tr("Remove Row"), [this]() {
QTextCursor cursor = ui->textEdit->textCursor(); QTextCursor cursor = m_textEdit->textCursor();
if (QTextTable *currentTable = cursor.currentTable()) { if (QTextTable *currentTable = cursor.currentTable()) {
cursorEditBlock(cursor, [&] () { cursorEditBlock(cursor, [&] () {
currentTable->insertColumns(currentTable->cellAt(cursor).column()+1, 1); currentTable->insertColumns(currentTable->cellAt(cursor).column()+1, 1);
@@ -633,8 +657,8 @@ void RichTextEditor::setupTableActions()
m_actionRemoveRow->setCheckable(false); m_actionRemoveRow->setCheckable(false);
const QIcon removeColumnIcon(getIcon(Theme::Icon::deleteColumn)); const QIcon removeColumnIcon(getIcon(Theme::Icon::deleteColumn));
m_actionRemoveColumn = ui->tableBar->addAction(removeColumnIcon, tr("Remove Column"), [this]() { m_actionRemoveColumn = m_tableBar->addAction(removeColumnIcon, tr("Remove Column"), [this]() {
QTextCursor cursor = ui->textEdit->textCursor(); QTextCursor cursor = m_textEdit->textCursor();
if (QTextTable *currentTable = cursor.currentTable()) { if (QTextTable *currentTable = cursor.currentTable()) {
cursorEditBlock(cursor, [&] () { cursorEditBlock(cursor, [&] () {
int firstRow = 0; int firstRow = 0;
@@ -654,11 +678,11 @@ void RichTextEditor::setupTableActions()
}); });
m_actionRemoveColumn->setCheckable(false); m_actionRemoveColumn->setCheckable(false);
ui->tableBar->addSeparator(); m_tableBar->addSeparator();
const QIcon mergeCellsIcon(getIcon(Theme::Icon::mergeCells)); const QIcon mergeCellsIcon(getIcon(Theme::Icon::mergeCells));
m_actionMergeCells = ui->tableBar->addAction(mergeCellsIcon, tr("Merge Cells"), [this]() { m_actionMergeCells = m_tableBar->addAction(mergeCellsIcon, tr("Merge Cells"), [this]() {
QTextCursor cursor = ui->textEdit->textCursor(); QTextCursor cursor = m_textEdit->textCursor();
if (QTextTable *currentTable = cursor.currentTable()) { if (QTextTable *currentTable = cursor.currentTable()) {
if (cursor.hasSelection()) { if (cursor.hasSelection()) {
cursorEditBlock(cursor, [&] () { cursorEditBlock(cursor, [&] () {
@@ -670,8 +694,8 @@ void RichTextEditor::setupTableActions()
m_actionMergeCells->setCheckable(false); m_actionMergeCells->setCheckable(false);
const QIcon splitRowIcon(getIcon(Theme::Icon::splitRows)); const QIcon splitRowIcon(getIcon(Theme::Icon::splitRows));
m_actionSplitRow = ui->tableBar->addAction(splitRowIcon, tr("Split Row"), [this]() { m_actionSplitRow = m_tableBar->addAction(splitRowIcon, tr("Split Row"), [this]() {
QTextCursor cursor = ui->textEdit->textCursor(); QTextCursor cursor = m_textEdit->textCursor();
if (QTextTable *currentTable = cursor.currentTable()) { if (QTextTable *currentTable = cursor.currentTable()) {
cursorEditBlock(cursor, [&] () { cursorEditBlock(cursor, [&] () {
currentTable->splitCell(currentTable->cellAt(cursor).row(), currentTable->splitCell(currentTable->cellAt(cursor).row(),
@@ -683,8 +707,8 @@ void RichTextEditor::setupTableActions()
m_actionSplitRow->setCheckable(false); m_actionSplitRow->setCheckable(false);
const QIcon splitColumnIcon(getIcon(Theme::Icon::splitColumns)); const QIcon splitColumnIcon(getIcon(Theme::Icon::splitColumns));
m_actionSplitColumn = ui->tableBar->addAction(splitColumnIcon, tr("Split Column"), [this]() { m_actionSplitColumn = m_tableBar->addAction(splitColumnIcon, tr("Split Column"), [this]() {
QTextCursor cursor = ui->textEdit->textCursor(); QTextCursor cursor = m_textEdit->textCursor();
if (QTextTable *currentTable = cursor.currentTable()) { if (QTextTable *currentTable = cursor.currentTable()) {
cursorEditBlock(cursor, [&] () { cursorEditBlock(cursor, [&] () {
currentTable->splitCell(currentTable->cellAt(cursor).row(), currentTable->splitCell(currentTable->cellAt(cursor).row(),
@@ -698,7 +722,7 @@ void RichTextEditor::setupTableActions()
void RichTextEditor::textStyle(QTextListFormat::Style style) void RichTextEditor::textStyle(QTextListFormat::Style style)
{ {
QTextCursor cursor = ui->textEdit->textCursor(); QTextCursor cursor = m_textEdit->textCursor();
cursorEditBlock(cursor, [&] () { cursorEditBlock(cursor, [&] () {
if (style != QTextListFormat::ListStyleUndefined) { if (style != QTextListFormat::ListStyleUndefined) {
QTextBlockFormat blockFmt = cursor.blockFormat(); QTextBlockFormat blockFmt = cursor.blockFormat();

View File

@@ -5,21 +5,17 @@
#include <theme.h> #include <theme.h>
#include <QWidget>
#include <QToolBar>
#include <QList>
#include <QTextCharFormat>
#include <QTextList>
#include <QFontComboBox> #include <QFontComboBox>
#include <QWidgetAction> #include <QList>
#include <QPointer> #include <QPointer>
#include <QTextCharFormat>
#include <QTextEdit>
#include <QTextList>
#include <QToolBar>
#include <QWidgetAction>
namespace QmlDesigner { namespace QmlDesigner {
namespace Ui {
class RichTextEditor;
}
template <class> template <class>
class FontWidgetActions; class FontWidgetActions;
@@ -77,7 +73,10 @@ private:
void setTableActionsActive(bool active); //switches between "has table/has no table" ui setup void setTableActionsActive(bool active); //switches between "has table/has no table" ui setup
private: private:
QScopedPointer<Ui::RichTextEditor> ui; QTextEdit *m_textEdit;
QToolBar *m_toolBar;
QToolBar *m_tableBar;
QPointer<HyperlinkDialog> m_linkDialog; QPointer<HyperlinkDialog> m_linkDialog;
QAction *m_actionTextBold; QAction *m_actionTextBold;

View File

@@ -1,50 +0,0 @@
<?xml version="1.0" encoding="UTF-8"?>
<ui version="4.0">
<class>QmlDesigner::RichTextEditor</class>
<widget class="QWidget" name="QmlDesigner::RichTextEditor">
<property name="geometry">
<rect>
<x>0</x>
<y>0</y>
<width>428</width>
<height>283</height>
</rect>
</property>
<property name="sizePolicy">
<sizepolicy hsizetype="Preferred" vsizetype="Expanding">
<horstretch>0</horstretch>
<verstretch>5</verstretch>
</sizepolicy>
</property>
<property name="windowTitle">
<string notr="true">Form</string>
</property>
<layout class="QVBoxLayout" name="verticalLayout">
<item>
<widget class="QToolBar" name="toolBar">
<property name="iconSize">
<size>
<width>20</width>
<height>20</height>
</size>
</property>
</widget>
</item>
<item>
<widget class="QToolBar" name="tableBar">
<property name="iconSize">
<size>
<width>20</width>
<height>20</height>
</size>
</property>
</widget>
</item>
<item>
<widget class="QTextEdit" name="textEdit"/>
</item>
</layout>
</widget>
<resources/>
<connections/>
</ui>

View File

@@ -67,6 +67,28 @@ void QmlJsEditingSettings::set()
toSettings(Core::ICore::settings()); toSettings(Core::ICore::settings());
} }
static QStringList intListToStringList(const QList<int> &list)
{
return Utils::transform(list, [](int v) { return QString::number(v); });
}
QList<int> intListFromStringList(const QStringList &list)
{
return Utils::transform<QList<int> >(list, [](const QString &v) { return v.toInt(); });
}
static QStringList defaultDisabledMessagesAsString()
{
static const QStringList result = intListToStringList(defaultDisabledMessages());
return result;
}
static QStringList defaultDisabledNonQuickUiAsString()
{
static const QStringList result = intListToStringList(defaultDisabledMessagesNonQuickUi());
return result;
}
void QmlJsEditingSettings::fromSettings(QSettings *settings) void QmlJsEditingSettings::fromSettings(QSettings *settings)
{ {
settings->beginGroup(QmlJSEditor::Constants::SETTINGS_CATEGORY_QML); settings->beginGroup(QmlJSEditor::Constants::SETTINGS_CATEGORY_QML);
@@ -84,14 +106,13 @@ void QmlJsEditingSettings::fromSettings(QSettings *settings)
m_useCustomFormatCommand = settings->value(CUSTOM_COMMAND, QVariant(false)).toBool(); m_useCustomFormatCommand = settings->value(CUSTOM_COMMAND, QVariant(false)).toBool();
m_useCustomAnalyzer = settings->value(CUSTOM_ANALYZER, QVariant(false)).toBool(); m_useCustomAnalyzer = settings->value(CUSTOM_ANALYZER, QVariant(false)).toBool();
m_disabledMessages = Utils::transform<QSet>( m_disabledMessages = Utils::toSet(
settings->value(DISABLED_MESSAGES, intListFromStringList(settings->value(DISABLED_MESSAGES,
QVariant::fromValue(defaultDisabledMessages())).toList(), defaultDisabledMessagesAsString()).toStringList()));
[](const QVariant &v){ return v.toInt(); });
m_disabledMessagesForNonQuickUi = Utils::transform<QSet>( m_disabledMessagesForNonQuickUi = Utils::toSet(
settings->value(DISABLED_MESSAGES_NONQUICKUI, intListFromStringList(settings->value(DISABLED_MESSAGES_NONQUICKUI,
QVariant::fromValue(defaultDisabledMessagesNonQuickUi())).toList(), defaultDisabledNonQuickUiAsString()).toStringList()));
[](const QVariant &v) { return v.toInt(); });
settings->endGroup(); settings->endGroup();
} }
@@ -122,12 +143,12 @@ void QmlJsEditingSettings::toSettings(QSettings *settings) const
false); false);
Utils::QtcSettings::setValueWithDefault(settings, Utils::QtcSettings::setValueWithDefault(settings,
DISABLED_MESSAGES, DISABLED_MESSAGES,
Utils::sorted(Utils::toList(m_disabledMessages)), intListToStringList(Utils::sorted(Utils::toList(m_disabledMessages))),
defaultDisabledMessages()); defaultDisabledMessagesAsString());
Utils::QtcSettings::setValueWithDefault(settings, Utils::QtcSettings::setValueWithDefault(settings,
DISABLED_MESSAGES_NONQUICKUI, DISABLED_MESSAGES_NONQUICKUI,
Utils::sorted(Utils::toList(m_disabledMessagesForNonQuickUi)), intListToStringList(Utils::sorted(Utils::toList(m_disabledMessagesForNonQuickUi))),
defaultDisabledMessagesNonQuickUi()); defaultDisabledNonQuickUiAsString());
settings->endGroup(); settings->endGroup();
QmllsSettingsManager::instance()->checkForChanges(); QmllsSettingsManager::instance()->checkForChanges();
} }

View File

@@ -255,7 +255,7 @@ void QuickToolBar::setProperty(const QString &propertyName, const QVariant &valu
{ {
QString stringValue = value.toString(); QString stringValue = value.toString();
if (value.type() == QVariant::Color) if (value.typeId() == QVariant::Color)
stringValue = QLatin1Char('\"') + value.toString() + QLatin1Char('\"'); stringValue = QLatin1Char('\"') + value.toString() + QLatin1Char('\"');
if (cast<UiObjectDefinition*>(m_node) || cast<UiObjectBinding*>(m_node)) { if (cast<UiObjectDefinition*>(m_node) || cast<UiObjectBinding*>(m_node)) {

View File

@@ -2,7 +2,9 @@
// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0+ OR GPL-3.0 WITH Qt-GPL-exception-1.0 // SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0+ OR GPL-3.0 WITH Qt-GPL-exception-1.0
#include "qmlbuildsystem.h" #include "qmlbuildsystem.h"
#include "../qmlprojectconstants.h" #include "../qmlprojectconstants.h"
#include "../qmlprojectmanagertr.h"
#include <QtCore5Compat/qtextcodec.h> #include <QtCore5Compat/qtextcodec.h>
#include <qmljs/qmljsmodelmanagerinterface.h> #include <qmljs/qmljsmodelmanagerinterface.h>
@@ -222,7 +224,7 @@ void QmlBuildSystem::parseProjectFiles()
QString errorMessage; QString errorMessage;
if (!reader.fetch(mainFilePath, &errorMessage)) { if (!reader.fetch(mainFilePath, &errorMessage)) {
Core::MessageManager::writeFlashing( Core::MessageManager::writeFlashing(
tr("Warning while loading project file %1.").arg(projectFilePath().toUserOutput())); Tr::tr("Warning while loading project file %1.").arg(projectFilePath().toUserOutput()));
Core::MessageManager::writeSilently(errorMessage); Core::MessageManager::writeSilently(errorMessage);
} }
} }

View File

@@ -197,7 +197,8 @@ Tasks QmlProject::projectIssues(const Kit *k) const
if (version->type() == QtSupport::Constants::DESKTOPQT) { if (version->type() == QtSupport::Constants::DESKTOPQT) {
if (version->qmlRuntimeFilePath().isEmpty()) { if (version->qmlRuntimeFilePath().isEmpty()) {
result.append( result.append(
createProjectTask(Task::TaskType::Error, tr("Qt version has no QML utility."))); createProjectTask(Task::TaskType::Error,
Tr::tr("Qt version has no QML utility.")));
} }
} else { } else {
// Non-desktop Qt on a desktop device? We don't support that. // Non-desktop Qt on a desktop device? We don't support that.

View File

@@ -498,7 +498,7 @@ public:
auto l = new QHBoxLayout(this); auto l = new QHBoxLayout(this);
for (const QnxTarget &target : config->m_targets) { for (const QnxTarget &target : config->m_targets) {
auto button = new QPushButton(tr("Create Kit for %1").arg(target.cpuDir())); auto button = new QPushButton(Tr::tr("Create Kit for %1").arg(target.cpuDir()));
connect(button, &QPushButton::clicked, this, [config, target] { connect(button, &QPushButton::clicked, this, [config, target] {
config->createKit(target); config->createKit(target);
}); });

View File

@@ -337,7 +337,7 @@ int QtKitAspect::qtVersionId(const Kit *k)
int id = -1; int id = -1;
QVariant data = k->value(QtKitAspect::id(), -1); QVariant data = k->value(QtKitAspect::id(), -1);
if (data.type() == QVariant::Int) { if (data.typeId() == QVariant::Int) {
bool ok; bool ok;
id = data.toInt(&ok); id = data.toInt(&ok);
if (!ok) if (!ok)

View File

@@ -282,7 +282,7 @@ bool SquishFileGenerator::setup(const QVariant &data, QString *errorMessage)
if (data.isNull()) if (data.isNull())
return false; return false;
if (data.type() != QVariant::Map) { if (data.typeId() != QVariant::Map) {
*errorMessage = Tr::tr("Key is not an object."); *errorMessage = Tr::tr("Key is not an object.");
return false; return false;
} }

View File

@@ -17,6 +17,15 @@ add_executable(manual_test_debugger_gui
) )
target_link_libraries(manual_test_debugger_gui PRIVATE Qt${QT_VERSION_MAJOR}::Widgets) target_link_libraries(manual_test_debugger_gui PRIVATE Qt${QT_VERSION_MAJOR}::Widgets)
if(APPLE)
# codesign in a way that allows attaching a debugger and writing core files
add_custom_command(TARGET manual_test_debugger_gui
POST_BUILD
VERBATIM
COMMAND codesign -f -s "-" --entitlements "${CMAKE_CURRENT_SOURCE_DIR}/entitlements.plist" "$<TARGET_FILE:manual_test_debugger_gui>"
)
endif()
if (NOT QT_CREATOR_API_DEFINED) if (NOT QT_CREATOR_API_DEFINED)
if (CMAKE_INSTALL_PREFIX_INITIALIZED_TO_DEFAULT) if (CMAKE_INSTALL_PREFIX_INITIALIZED_TO_DEFAULT)
set (CMAKE_INSTALL_PREFIX "/tmp/manual_test_debugger_gui" CACHE PATH "default install path" FORCE) set (CMAKE_INSTALL_PREFIX "/tmp/manual_test_debugger_gui" CACHE PATH "default install path" FORCE)

View File

@@ -0,0 +1,9 @@
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
<plist version="1.0">
<dict>
<!-- Allow ourselves to be debugged -->
<key>com.apple.security.get-task-allow</key>
<true/>
</dict>
</plist>

View File

@@ -9,3 +9,5 @@ SOURCES += \
HEADERS += mainwindow.h HEADERS += mainwindow.h
FORMS += mainwindow.ui FORMS += mainwindow.ui
macos: QMAKE_POST_LINK = codesign -f -s - --entitlements "$${PWD}/entitlements.plist" "$${OUT_PWD}/gui.app"