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 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
-------
* Added a `Terminal` view (QTCREATORBUG-8511)
([Documentation](https://doc-snapshots.qt.io/qtcreator-11.0/creator-output-panes.html#terminal))
* 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 more spacious `Relaxed` toolbar style to `Preferences > Environment >
Interface`
* 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
(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
* Improved performance
* 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
* Fixed the saving of hardlinked files (QTCREATORBUG-19651)
* Fixed an issue of copy and paste with multiple cursors (QTCREATORBUG-29117)
* Fixed the saving of hardlinked files
([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++
* 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
(QTCREATORBUG-28869)
* Added the option to create class members from assignments (QTCREATORBUG-1918)
([QTCREATORBUG-28869](https://bugreports.qt.io/browse/QTCREATORBUG-28869))
* 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
(QTCREATORBUG-13894)
([QTCREATORBUG-13894](https://bugreports.qt.io/browse/QTCREATORBUG-13894))
* Fixed the handling of C++20 keywords and concepts
* 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
* Added experimental support for GitHub Copilot
([GitHub documentation](https://github.com/features/copilot))
([Qt Creator documentation](https://doc-snapshots.qt.io/qtcreator-11.0/creator-copilot.html))
* Added missing actions for opening the `Call Hierarchy` (QTCREATORBUG-28839,
QTCREATORBUG-28842)
* Added missing actions for opening the `Call Hierarchy`
([QTCREATORBUG-28839](https://bugreports.qt.io/browse/QTCREATORBUG-28839),
[QTCREATORBUG-28842](https://bugreports.qt.io/browse/QTCREATORBUG-28842))
### QML
* Fixed the reformatting in the presence of JavaScript directives and function
return type annotations (QTCREATORBUG-29001, QTCREATORBUG-29046)
* Fixed that reformatting changed `of` to `in` (QTCREATORBUG-29123)
* Fixed the completion for Qt Quick Controls (QTCREATORBUG-28648)
return type annotations
([QTCREATORBUG-29001](https://bugreports.qt.io/browse/QTCREATORBUG-29001),
[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
* Added the option to create a virtual environment (`venv`) to the Python
interpreter selector and the wizard (PYSIDE-2152)
### Markdown
* Added a Markdown editor with preview (QTCREATORBUG-27883)
* Added a wizard for Markdown files (QTCREATORBUG-29056)
interpreter selector and the wizard
([PYSIDE-2152](https://bugreports.qt.io/browse/PYSIDE-2152))
Projects
--------
* Made it possible to add devices without going through the wizard
* Added support for moving files to a different directory when renaming
(QTCREATORBUG-15981)
([QTCREATORBUG-15981](https://bugreports.qt.io/browse/QTCREATORBUG-15981))
### CMake
* Implemented adding files to the project (QTCREATORBUG-25922,
QTCREATORBUG-26006, QTCREATORBUG-27213, QTCREATORBUG-27538,
QTCREATORBUG-28493, QTCREATORBUG-28904, QTCREATORBUG-28985,
QTCREATORBUG-29006)
* Implemented adding files to the project
([QTCREATORBUG-25922](https://bugreports.qt.io/browse/QTCREATORBUG-25922),
[QTCREATORBUG-26006](https://bugreports.qt.io/browse/QTCREATORBUG-26006),
[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
(QTCREATORBUG-29075)
([QTCREATORBUG-29075](https://bugreports.qt.io/browse/QTCREATORBUG-29075))
### Python
* Added an option for the interpreter to the wizards
### vcpkg
* Added experimental support for `vcpkg`
([vcpgk documentation](https://vcpkg.io/en/))
* Added an option for the `vcpkg` installation location
* Added a search dialog for packages
* Added a wizard and an editor for `vcpkg.json` files
Debugging
---------
* Improved the UI for enabling and disabling debuggers (QTCREATORBUG-28627)
* Improved the UI for enabling and disabling debuggers
([QTCREATORBUG-28627](https://bugreports.qt.io/browse/QTCREATORBUG-28627))
### C++
@@ -114,16 +177,20 @@ Debugging
(`Preferences > Debugger > Locals & Expressions > Default array size`)
* CDB
* Added automatic source file mapping for Qt packages
* Fixed the variables view on remote Windows devices (QTCREATORBUG-29000)
* Fixed the variables view on remote Windows devices
([QTCREATORBUG-29000](https://bugreports.qt.io/browse/QTCREATORBUG-29000))
* LLDB
* 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
* 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
`Qt Quick > QML/JS Editing` (QTCREATORBUG-29095)
`Qt Quick > QML/JS Editing`
([QTCREATORBUG-29095](https://bugreports.qt.io/browse/QTCREATORBUG-29095))
Analyzer
--------
@@ -131,11 +198,8 @@ Analyzer
### Clang
* Fixed that a `.clang-tidy` file in the project directory was not used by
default (QTCREATORBUG-28852)
### Axivion
* Added experimental support
default
([QTCREATORBUG-28852](https://bugreports.qt.io/browse/QTCREATORBUG-28852))
Version Control Systems
-----------------------
@@ -143,7 +207,8 @@ Version Control Systems
### Git
* 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
Platforms
@@ -151,7 +216,8 @@ Platforms
### 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
@@ -159,14 +225,16 @@ Platforms
### 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
(QTCREATORBUG-28880)
([QTCREATORBUG-28880](https://bugreports.qt.io/browse/QTCREATORBUG-28880))
### QNX
* 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:
--------------------------------

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
If \QC does not automatically detect a device you connected with USB, you can
use a wizard to create either a network connection or a USB connection to
it.
If \QC does not automatically detect a device you connected with USB, select
\uicontrol Edit > \uicontrol Preferences > \uicontrol Devices >
\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
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 >
\uicontrol Devices > \uicontrol Devices.
\image qtcreator-boot2qt-device-configurations.png {Devices dialog}
To reboot the selected device, select \uicontrol {Reboot Device}.
To restore the default application to the device, select
@@ -122,6 +126,10 @@
parameters that have sensible default values. One of
these is the SSH port number, which is available in
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
\li Select \uicontrol Edit > \uicontrol Preferences > \uicontrol Kits >
\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
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 >
\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.
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
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
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
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
any number of tasks of various types, such as ProcessTask, FileTransferTask,
or AsyncTask<ReturnType>:
or ConcurrentCallTask<ReturnType>:
\code
using namespace Tasking;
const Group root {
ProcessTask(...),
AsyncTask<int>(...),
ConcurrentCallTask<int>(...),
FileTransferTask(...)
};
@@ -1149,10 +1149,10 @@ void TaskNode::invokeEndHandler(bool success)
\endcode
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
with ProcessTask. When the ProcessTask finishes successfully, the AsyncTask<int> task is
started. Finally, when the asynchronous task finishes successfully, the
with ProcessTask. When the ProcessTask finishes successfully, the ConcurrentCallTask<int>
task is started. Finally, when the asynchronous task finishes successfully, the
FileTransferTask task is started.
When the last running task finishes with success, the task tree is considered
@@ -1172,26 +1172,26 @@ void TaskNode::invokeEndHandler(bool success)
Group {
parallel,
ProcessTask(...),
AsyncTask<int>(...)
ConcurrentCallTask<int>(...)
},
FileTransferTask(...)
};
\endcode
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
additional \e parallel element that instructs its Group to execute its tasks
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
\e parallel element, its direct child tasks are run in sequence. Thus, the
FileTransferTask starts when the whole subgroup finishes. The group is
considered as finished when all its tasks have finished. The order in which
the tasks finish is not relevant.
So, depending on which task lasts longer (ProcessTask or AsyncTask<int>), the
So, depending on which task lasts longer (ProcessTask or ConcurrentCallTask<int>), the
following scenarios can take place:
\table
@@ -1208,19 +1208,19 @@ void TaskNode::invokeEndHandler(bool success)
\li ProcessTask starts
\li ProcessTask starts
\row
\li AsyncTask<int> starts
\li AsyncTask<int> starts
\li ConcurrentCallTask<int> starts
\li ConcurrentCallTask<int> starts
\row
\li ...
\li ...
\row
\li \b {ProcessTask finishes}
\li \b {AsyncTask<int> finishes}
\li \b {ConcurrentCallTask<int> finishes}
\row
\li ...
\li ...
\row
\li \b {AsyncTask<int> finishes}
\li \b {ConcurrentCallTask<int> finishes}
\li \b {ProcessTask finishes}
\row
\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
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,
the AsyncTask<int> is automatically stopped, the subgroup finishes with an error,
when ProcessTask finishes with an error while ConcurrentCallTask<int> is still being executed,
the ConcurrentCallTask<int> is automatically stopped, the subgroup finishes with an error,
the FileTransferTask is skipped, and the tree finishes with an error.
\section1 Task Types
@@ -1277,11 +1277,11 @@ void TaskNode::invokeEndHandler(bool success)
\row
\li ProcessTask
\li Utils::Process
\li Starts processes.
\li Starts process.
\row
\li AsyncTask<ReturnType>
\li Utils::Async<ReturnType>
\li Starts asynchronous tasks; run in separate thread.
\li ConcurrentCallTask<ReturnType>
\li Tasking::ConcurrentCall<ReturnType>
\li Starts asynchronous task, runs in separate thread.
\row
\li TaskTreeTask
\li Utils::TaskTree
@@ -1540,7 +1540,7 @@ void TaskNode::invokeEndHandler(bool success)
static QByteArray load(const QString &fileName) { ... }
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
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
const TreeStorage<CopyStorage> storage;
const auto onLoaderSetup = [source](Async<QByteArray> &async) {
const auto onLoaderSetup = [source](ConcurrentCall<QByteArray> &async) {
async.setConcurrentCallData(&load, source);
};
// [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
};
// [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
async.setConcurrentCallData(&save, destination, content);
};
const auto onSaverDone = [](const Async<void> &async) {
const auto onSaverDone = [](const ConcurrentCall<void> &async) {
qDebug() << "Save done successfully";
};
const Group root {
// [7] runtime: task tree creates an instance of CopyStorage when root is entered
Storage(storage),
AsyncTask<QByteArray>(onLoaderSetup, onLoaderDone),
AsyncTask<void>(onSaverSetup, onSaverDone)
ConcurrentCallTask<QByteArray>(onLoaderSetup, onLoaderDone),
ConcurrentCallTask<void>(onSaverSetup, onSaverDone)
};
return root;
}
@@ -1650,7 +1650,7 @@ void TaskNode::invokeEndHandler(bool success)
\code
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);
auto initStorage = [](CopyStorage *storage){
storage->content = "initial content";
@@ -1670,7 +1670,7 @@ void TaskNode::invokeEndHandler(bool success)
\code
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);
auto collectStorage = [](CopyStorage *storage){
qDebug() << "final content" << storage->content;
@@ -1758,7 +1758,7 @@ TaskTree::TaskTree(const Group &recipe) : TaskTree()
TaskTree::~TaskTree()
{
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?
delete d;
}

View File

@@ -2346,16 +2346,12 @@ void IntegersAspect::setDefaultValue(const QList<int> &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
type \a type.
*/
TextDisplay::TextDisplay(const QString &message, InfoLabel::InfoType type)
: d(new Internal::TextDisplayPrivate)
TextDisplay::TextDisplay(AspectContainer *container, const QString &message, InfoLabel::InfoType type)
: BaseAspect(container), d(new Internal::TextDisplayPrivate)
{
d->m_message = message;
d->m_type = type;

View File

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

View File

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

View File

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

View File

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

View File

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

View File

@@ -385,6 +385,22 @@ void TerminalInterface::start()
ProcessSetupData stubSetupData = m_setup;
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(
d->stubCreator,
[stubSetupData, this] { d->stubCreator->startStubProcess(stubSetupData); },

View File

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

View File

@@ -191,7 +191,7 @@ void AndroidConfig::load(const QSettings &settings)
{
// user settings
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());
m_emulatorArgs = emulatorArgs.toString();
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()
{
QString error;
int errorLine;
int errorColumn;
QDomDocument doc;
if (doc.setContent(m_textEditorWidget->toPlainText(), &error, &errorLine, &errorColumn)) {
if (checkDocument(doc, &error, &errorLine, &errorColumn)) {
QDomDocument::ParseResult result = doc.setContent(m_textEditorWidget->toPlainText());
if (result) {
if (checkDocument(doc, &result)) {
if (activePage() != Source)
syncToWidgets(doc);
return;
}
}
// some error occurred
updateInfoBar(error, errorLine, errorColumn);
updateInfoBar(result.errorMessage, result.errorLine, result.errorColumn);
setActivePage(Source);
}
@@ -591,39 +610,19 @@ TextEditor::TextEditorWidget *AndroidManifestEditorWidget::textEditorWidget() co
bool AndroidManifestEditorWidget::syncToWidgets()
{
QDomDocument doc;
QString errorMessage;
int errorLine, errorColumn;
if (doc.setContent(m_textEditorWidget->toPlainText(), &errorMessage, &errorLine, &errorColumn)) {
if (checkDocument(doc, &errorMessage, &errorLine, &errorColumn)) {
QDomDocument::ParseResult result = doc.setContent(m_textEditorWidget->toPlainText());
if (result) {
if (checkDocument(doc, &result)) {
hideInfoBar();
syncToWidgets(doc);
return true;
}
}
updateInfoBar(errorMessage, errorLine, errorColumn);
updateInfoBar(result.errorMessage, result.errorLine, result.errorColumn);
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()
{
m_timerParseCheck.start();
@@ -641,16 +640,15 @@ void AndroidManifestEditorWidget::updateInfoBar()
return;
}
QDomDocument doc;
int errorLine, errorColumn;
QString errorMessage;
if (doc.setContent(m_textEditorWidget->toPlainText(), &errorMessage, &errorLine, &errorColumn)) {
if (checkDocument(doc, &errorMessage, &errorLine, &errorColumn)) {
QDomDocument::ParseResult result = doc.setContent(m_textEditorWidget->toPlainText());
if (result) {
if (checkDocument(doc, &result)) {
hideInfoBar();
return;
}
}
updateInfoBar(errorMessage, errorLine, errorColumn);
updateInfoBar(result.errorMessage, result.errorLine, result.errorColumn);
}
void AndroidManifestEditorWidget::updateSdkVersions()
@@ -888,9 +886,9 @@ void AndroidManifestEditorWidget::syncToEditor()
m_dirty = false;
}
namespace {
QXmlStreamAttributes modifyXmlStreamAttributes(const QXmlStreamAttributes &input, const QStringList &keys,
const QStringList &values, const QStringList &remove = QStringList())
static QXmlStreamAttributes modifyXmlStreamAttributes(
const QXmlStreamAttributes &input, const QStringList &keys,
const QStringList &values, const QStringList &remove = {})
{
Q_ASSERT(keys.size() == values.size());
QXmlStreamAttributes result;
@@ -903,8 +901,7 @@ QXmlStreamAttributes modifyXmlStreamAttributes(const QXmlStreamAttributes &input
if (index == -1)
result.push_back(attribute);
else
result.push_back(QXmlStreamAttribute(name,
values.at(index)));
result.push_back(QXmlStreamAttribute(name, values.at(index)));
}
for (int i = 0; i < keys.size(); ++i) {
@@ -913,7 +910,6 @@ QXmlStreamAttributes modifyXmlStreamAttributes(const QXmlStreamAttributes &input
}
return result;
}
} // end namespace
void AndroidManifestEditorWidget::parseManifest(QXmlStreamReader &reader, QXmlStreamWriter &writer)
{

View File

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

View File

@@ -280,7 +280,7 @@ AndroidRunnerWorker::AndroidRunnerWorker(RunWorker *runner, const QString &packa
m_beforeStartAdbCommands.append(QString("shell %1").arg(shellCmd));
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);
for (const QString &shellCmd : commands)
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);
auto progress = new TaskProgress(m_taskTree.get());
progress->setDisplayName(tr("Running Tests"));
progress->setDisplayName(Tr::tr("Running Tests"));
progress->setAutoStopOnCancel(false);
progress->setHalfLifeTimePerTask(10000); // 10 seconds
connect(progress, &TaskProgress::canceled, this, [this, progress] {

View File

@@ -77,10 +77,10 @@ void ArtisticStyleSettings::createDocumentationFile() const
if (process.result() != ProcessResult::FinishedWithSuccess)
return;
if (!documentationFilePath.exists())
documentationFilePath.parentDir().ensureWritableDir();
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))
return;

View File

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

View File

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

View File

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

View File

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

View File

@@ -42,14 +42,14 @@ ProjectInfo::ConstPtr ProjectInfoGenerator::generate(const QPromise<ProjectInfo:
});
};
if (m_cToolchainMissing) {
showWarning(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."));
showWarning(
::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."));
}
if (m_cxxToolchainMissing) {
showWarning(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."));
showWarning(::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."));
}
return projectInfo;
}

View File

@@ -1107,7 +1107,7 @@ QVariant BreakpointItem::data(int column, int role) const
return QVariant();
}
void BreakpointItem::addToCommand(DebuggerCommand *cmd) const
void BreakpointItem::addToCommand(DebuggerCommand *cmd, BreakpointPathUsage defaultPathUsage) const
{
QTC_ASSERT(m_globalBreakpoint, return);
const BreakpointParameters &requested = requestedParameters();
@@ -1120,10 +1120,19 @@ void BreakpointItem::addToCommand(DebuggerCommand *cmd) const
cmd->arg("function", requested.functionName);
cmd->arg("oneshot", requested.oneShot);
cmd->arg("enabled", requested.enabled);
cmd->arg("file", requested.fileName.path());
cmd->arg("line", requested.textPosition.line);
cmd->arg("address", requested.address);
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)

View File

@@ -107,7 +107,9 @@ public:
int markerLineNumber() 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);
int modelId() const;

View File

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

View File

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

View File

@@ -50,6 +50,39 @@ public:
BuildConsoleBuildStep(BuildStepList *buildStepList, Id id);
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)
@@ -57,233 +90,198 @@ BuildConsoleBuildStep::BuildConsoleBuildStep(BuildStepList *buildStepList, Id id
{
setDisplayName(Tr::tr("IncrediBuild for Windows"));
addAspect<TextDisplay>("<b>" + Tr::tr("Target and Configuration"));
commandBuilder.setSettingsKey("IncrediBuild.BuildConsole.CommandBuilder");
auto commandBuilder = addAspect<CommandBuilderAspect>(this);
commandBuilder->setSettingsKey("IncrediBuild.BuildConsole.CommandBuilder");
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 "
"IncrediBuild behavior is to set it to 200."));
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)"));
profileXml.setSettingsKey("IncrediBuild.BuildConsole.ProfileXml");
profileXml.setLabelText(Tr::tr("Profile.xml:"));
profileXml.setExpectedKind(PathChooser::Kind::File);
profileXml.setBaseFileName(PathChooser::homePath());
profileXml.setHistoryCompleter("IncrediBuild.BuildConsole.ProfileXml.History");
profileXml.setToolTip(Tr::tr("Defines how Automatic "
"Interception Interface should handle the various processes "
"involved in a distributed job. It is not necessary for "
"\"Visual Studio\" or \"Make and Build tools\" builds, "
"but can be used to provide configuration options if those "
"builds use additional processes that are not included in "
"those packages. It is required to configure distributable "
"processes in \"Dev Tools\" builds."));
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 "
"IncrediBuild behavior is to set it to 200."));
avoidLocal.setSettingsKey("IncrediBuild.BuildConsole.AvoidLocal");
avoidLocal.setLabel(Tr::tr("Avoid local task execution:"));
avoidLocal.setToolTip(Tr::tr("Overrides the Agent Settings dialog Avoid task execution on local "
"machine when possible option. This allows to free more resources "
"on the initiator machine and could be beneficial to distribution "
"in scenarios where the initiating machine is bottlenecking the "
"build with High CPU usage."));
addAspect<TextDisplay>("<b>" + Tr::tr("IncrediBuild Distribution Control"));
maxCpu.setSettingsKey("IncrediBuild.BuildConsole.MaxCpu");
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. "
"It takes into account both local and remote cores, even if the "
"Avoid Task Execution on Local Machine option is selected."));
maxCpu.setLabel(Tr::tr("Maximum CPUs to utilize in the build:"));
maxCpu.setRange(0, 65536);
auto profileXml = addAspect<FilePathAspect>();
profileXml->setSettingsKey("IncrediBuild.BuildConsole.ProfileXml");
profileXml->setLabelText(Tr::tr("Profile.xml:"));
profileXml->setExpectedKind(PathChooser::Kind::File);
profileXml->setBaseFileName(PathChooser::homePath());
profileXml->setHistoryCompleter("IncrediBuild.BuildConsole.ProfileXml.History");
profileXml->setToolTip(Tr::tr("Defines how Automatic "
"Interception Interface should handle the various processes "
"involved in a distributed job. It is not necessary for "
"\"Visual Studio\" or \"Make and Build tools\" builds, "
"but can be used to provide configuration options if those "
"builds use additional processes that are not included in "
"those packages. It is required to configure distributable "
"processes in \"Dev Tools\" builds."));
auto avoidLocal = addAspect<BoolAspect>();
avoidLocal->setSettingsKey("IncrediBuild.BuildConsole.AvoidLocal");
avoidLocal->setLabel(Tr::tr("Avoid local task execution:"));
avoidLocal->setToolTip(Tr::tr("Overrides the Agent Settings dialog Avoid task execution on local "
"machine when possible option. This allows to free more resources "
"on the initiator machine and could be beneficial to distribution "
"in scenarios where the initiating machine is bottlenecking the "
"build with High CPU usage."));
auto maxCpu = addAspect<IntegerAspect>();
maxCpu->setSettingsKey("IncrediBuild.BuildConsole.MaxCpu");
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. "
"It takes into account both local and remote cores, even if the "
"Avoid Task Execution on Local Machine option is selected."));
maxCpu->setLabel(Tr::tr("Maximum CPUs to utilize in the build:"));
maxCpu->setRange(0, 65536);
auto maxWinVer = addAspect<SelectionAspect>();
maxWinVer->setSettingsKey("IncrediBuild.BuildConsole.MaxWinVer");
maxWinVer->setDisplayName(Tr::tr("Newest allowed helper machine OS:"));
maxWinVer->setDisplayStyle(SelectionAspect::DisplayStyle::ComboBox);
maxWinVer->setToolTip(Tr::tr("Specifies the newest operating system installed on a helper "
"machine to be allowed to participate as helper in the build."));
maxWinVer.setSettingsKey("IncrediBuild.BuildConsole.MaxWinVer");
maxWinVer.setDisplayName(Tr::tr("Newest allowed helper machine OS:"));
maxWinVer.setDisplayStyle(SelectionAspect::DisplayStyle::ComboBox);
maxWinVer.setToolTip(Tr::tr("Specifies the newest operating system installed on a helper "
"machine to be allowed to participate as helper in the build."));
for (const QString &version : supportedWindowsVersions())
maxWinVer->addOption(version);
maxWinVer.addOption(version);
auto minWinVer = addAspect<SelectionAspect>();
minWinVer->setSettingsKey("IncrediBuild.BuildConsole.MinWinVer");
minWinVer->setDisplayName(Tr::tr("Oldest allowed helper machine OS:"));
minWinVer->setDisplayStyle(SelectionAspect::DisplayStyle::ComboBox);
minWinVer->setToolTip(Tr::tr("Specifies the oldest operating system installed on a helper "
"machine to be allowed to participate as helper in the build."));
minWinVer.setSettingsKey("IncrediBuild.BuildConsole.MinWinVer");
minWinVer.setDisplayName(Tr::tr("Oldest allowed helper machine OS:"));
minWinVer.setDisplayStyle(SelectionAspect::DisplayStyle::ComboBox);
minWinVer.setToolTip(Tr::tr("Specifies the oldest operating system installed on a helper "
"machine to be allowed to participate as helper in the build."));
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:"));
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 "
"for the Build History and Build Monitor displays."));
auto title = addAspect<StringAspect>();
title->setSettingsKey("IncrediBuild.BuildConsole.Title");
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 "
"for the Build History and Build Monitor displays."));
monFile.setSettingsKey("IncrediBuild.BuildConsole.MonFile");
monFile.setLabelText(Tr::tr("Save IncrediBuild monitor file:"));
monFile.setExpectedKind(PathChooser::Kind::Any);
monFile.setBaseFileName(PathChooser::homePath());
monFile.setHistoryCompleter(QLatin1String("IncrediBuild.BuildConsole.MonFile.History"));
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 "
"as the file name. The full path of the saved Build Monitor will be "
"written to the end of the build output."));
auto monFile = addAspect<FilePathAspect>();
monFile->setSettingsKey("IncrediBuild.BuildConsole.MonFile");
monFile->setLabelText(Tr::tr("Save IncrediBuild monitor file:"));
monFile->setExpectedKind(PathChooser::Kind::Any);
monFile->setBaseFileName(PathChooser::homePath());
monFile->setHistoryCompleter(QLatin1String("IncrediBuild.BuildConsole.MonFile.History"));
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 "
"as the file name. The full path of the saved Build Monitor will be "
"written to the end of the build output."));
suppressStdOut.setSettingsKey("IncrediBuild.BuildConsole.SuppressStdOut");
suppressStdOut.setLabel(Tr::tr("Suppress STDOUT:"));
suppressStdOut.setToolTip(Tr::tr("Does not write anything to the standard output."));
auto suppressStdOut = addAspect<BoolAspect>();
suppressStdOut->setSettingsKey("IncrediBuild.BuildConsole.SuppressStdOut");
suppressStdOut->setLabel(Tr::tr("Suppress STDOUT:"));
suppressStdOut->setToolTip(Tr::tr("Does not write anything to the standard output."));
logFile.setSettingsKey("IncrediBuild.BuildConsole.LogFile");
logFile.setLabelText(Tr::tr("Output Log file:"));
logFile.setExpectedKind(PathChooser::Kind::SaveFile);
logFile.setBaseFileName(PathChooser::homePath());
logFile.setHistoryCompleter(QLatin1String("IncrediBuild.BuildConsole.LogFile.History"));
logFile.setToolTip(Tr::tr("Writes build output to a file."));
auto logFile = addAspect<FilePathAspect>();
logFile->setSettingsKey("IncrediBuild.BuildConsole.LogFile");
logFile->setLabelText(Tr::tr("Output Log file:"));
logFile->setExpectedKind(PathChooser::Kind::SaveFile);
logFile->setBaseFileName(PathChooser::homePath());
logFile->setHistoryCompleter(QLatin1String("IncrediBuild.BuildConsole.LogFile.History"));
logFile->setToolTip(Tr::tr("Writes build output to a file."));
showCmd.setSettingsKey("IncrediBuild.BuildConsole.ShowCmd");
showCmd.setLabel(Tr::tr("Show Commands in output:"));
showCmd.setToolTip(Tr::tr("Shows, for each file built, the command-line used by IncrediBuild "
"to build the file."));
auto showCmd = addAspect<BoolAspect>();
showCmd->setSettingsKey("IncrediBuild.BuildConsole.ShowCmd");
showCmd->setLabel(Tr::tr("Show Commands in output:"));
showCmd->setToolTip(Tr::tr("Shows, for each file built, the command-line used by IncrediBuild "
"to build the file."));
showAgents.setSettingsKey("IncrediBuild.BuildConsole.ShowAgents");
showAgents.setLabel(Tr::tr("Show Agents in output:"));
showAgents.setToolTip(Tr::tr("Shows the Agent used to build each file."));
auto showAgents = addAspect<BoolAspect>();
showAgents->setSettingsKey("IncrediBuild.BuildConsole.ShowAgents");
showAgents->setLabel(Tr::tr("Show Agents in output:"));
showAgents->setToolTip(Tr::tr("Shows the Agent used to build each file."));
showTime.setSettingsKey("IncrediBuild.BuildConsole.ShowTime");
showTime.setLabel(Tr::tr("Show Time in output:"));
showTime.setToolTip(Tr::tr("Shows the Start and Finish time for each file built."));
auto showTime = addAspect<BoolAspect>();
showTime->setSettingsKey("IncrediBuild.BuildConsole.ShowTime");
showTime->setLabel(Tr::tr("Show Time in output:"));
showTime->setToolTip(Tr::tr("Shows the Start and Finish time for each file built."));
hideHeader.setSettingsKey("IncrediBuild.BuildConsole.HideHeader");
hideHeader.setLabel(Tr::tr("Hide IncrediBuild Header in output:"));
hideHeader.setToolTip(Tr::tr("Suppresses IncrediBuild's header in the build output"));
auto hideHeader = addAspect<BoolAspect>();
hideHeader->setSettingsKey("IncrediBuild.BuildConsole.HideHeader");
hideHeader->setLabel(Tr::tr("Hide IncrediBuild Header in output:"));
hideHeader->setToolTip(Tr::tr("Suppresses IncrediBuild's header in the build output"));
logLevel.setSettingsKey("IncrediBuild.BuildConsole.LogLevel");
logLevel.setDisplayName(Tr::tr("Internal IncrediBuild logging level:"));
logLevel.setDisplayStyle(SelectionAspect::DisplayStyle::ComboBox);
logLevel.addOption(QString());
logLevel.addOption("Minimal");
logLevel.addOption("Extended");
logLevel.addOption("Detailed");
logLevel.setToolTip(Tr::tr("Overrides the internal Incredibuild logging level for this build. "
"Does not affect output or any user accessible logging. Used mainly "
"to troubleshoot issues with the help of IncrediBuild support"));
auto logLevel = addAspect<SelectionAspect>();
logLevel->setSettingsKey("IncrediBuild.BuildConsole.LogLevel");
logLevel->setDisplayName(Tr::tr("Internal IncrediBuild logging level:"));
logLevel->setDisplayStyle(SelectionAspect::DisplayStyle::ComboBox);
logLevel->addOption(QString());
logLevel->addOption("Minimal");
logLevel->addOption("Extended");
logLevel->addOption("Detailed");
logLevel->setToolTip(Tr::tr("Overrides the internal Incredibuild logging level for this build. "
"Does not affect output or any user accessible logging. Used mainly "
"to troubleshoot issues with the help of IncrediBuild support"));
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."));
addAspect<TextDisplay>("<b>" + Tr::tr("Miscellaneous"));
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 "
"\"Visual Studio\" builds, but not the default for "
"\"Make and Build tools\" or \"Dev Tools\" builds"));
auto setEnv = addAspect<StringAspect>();
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."));
additionalArguments.setSettingsKey("IncrediBuild.BuildConsole.AdditionalArguments");
additionalArguments.setLabelText(Tr::tr("Additional Arguments:"));
additionalArguments.setDisplayStyle(StringAspect::LineEditDisplay);
additionalArguments.setToolTip(Tr::tr("Add additional buildconsole arguments manually. "
"The value of this field will be concatenated to the "
"final buildconsole command line"));
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 "
"\"Visual Studio\" builds, but not the default for "
"\"Make and Build tools\" or \"Dev Tools\" builds"));
openMonitor.setSettingsKey("IncrediBuild.BuildConsole.OpenMonitor");
openMonitor.setLabel(Tr::tr("Open Build Monitor:"));
openMonitor.setToolTip(Tr::tr("Opens Build Monitor once the build starts."));
auto additionalArguments = addAspect<StringAspect>();
additionalArguments->setSettingsKey("IncrediBuild.BuildConsole.AdditionalArguments");
additionalArguments->setLabelText(Tr::tr("Additional Arguments:"));
additionalArguments->setDisplayStyle(StringAspect::LineEditDisplay);
additionalArguments->setToolTip(Tr::tr("Add additional buildconsole arguments manually. "
"The value of this field will be concatenated to the "
"final buildconsole command line"));
setCommandLineProvider([this] {
CommandLine cmd("BuildConsole.exe");
auto openMonitor = addAspect<BoolAspect>();
openMonitor->setSettingsKey("IncrediBuild.BuildConsole.OpenMonitor");
openMonitor->setLabel(Tr::tr("Open Build Monitor:"));
openMonitor->setToolTip(Tr::tr("Opens Build Monitor once the build starts."));
cmd.addArgs(QString("/Command=%1").arg(commandBuilder.fullCommandFlag(keepJobNum())), CommandLine::Raw);
setCommandLineProvider([=] {
QStringList args;
if (!profileXml().isEmpty())
cmd.addArg(QString("/Profile=%1").arg(profileXml().path()));
QString cmd("/Command= %1");
cmd = cmd.arg(commandBuilder->fullCommandFlag(keepJobNum->value()));
args.append(cmd);
cmd.addArg(QString("/AvoidLocal=%1").arg(avoidLocal() ? QString("ON") : QString("OFF")));
if (!profileXml->value().isEmpty())
args.append("/Profile=" + profileXml->value());
if (maxCpu() > 0)
cmd.addArg(QString("/MaxCPUs=%1").arg(maxCpu()));
args.append(QString("/AvoidLocal=%1").arg(avoidLocal->value() ? QString("ON") : QString("OFF")));
if (!maxWinVer.stringValue().isEmpty())
cmd.addArg(QString("/MaxWinVer=%1").arg(normalizeWinVerArgument(maxWinVer.stringValue())));
if (maxCpu->value() > 0)
args.append(QString("/MaxCPUs=%1").arg(maxCpu->value()));
if (!minWinVer.stringValue().isEmpty())
cmd.addArg(QString("/MinWinVer=%1").arg(normalizeWinVerArgument(minWinVer.stringValue())));
if (!maxWinVer->stringValue().isEmpty())
args.append(QString("/MaxWinVer=%1").arg(normalizeWinVerArgument(maxWinVer->stringValue())));
if (!title().isEmpty())
cmd.addArg("/Title=" + title());
if (!minWinVer->stringValue().isEmpty())
args.append(QString("/MinWinVer=%1").arg(normalizeWinVerArgument(minWinVer->stringValue())));
if (!monFile().isEmpty())
cmd.addArg("/Mon=" + monFile().path());
if (!title->value().isEmpty())
args.append(QString("/Title=" + title->value()));
if (suppressStdOut())
cmd.addArg("/Silent");
if (!monFile->value().isEmpty())
args.append(QString("/Mon=" + monFile->value()));
if (!logFile().isEmpty())
cmd.addArg("/Log=" + logFile().path());
if (suppressStdOut->value())
args.append("/Silent");
if (showCmd())
cmd.addArg("/ShowCmd");
if (!logFile->value().isEmpty())
args.append(QString("/Log=" + logFile->value()));
if (showAgents())
cmd.addArg("/ShowAgent");
if (showCmd->value())
args.append("/ShowCmd");
if (showAgents())
cmd.addArg("/ShowTime");
if (showAgents->value())
args.append("/ShowAgent");
if (hideHeader())
cmd.addArg("/NoLogo");
if (showAgents->value())
args.append("/ShowTime");
if (!logLevel.stringValue().isEmpty())
cmd.addArg("/LogLevel=" + logLevel.stringValue());
if (hideHeader->value())
args.append("/NoLogo");
if (!setEnv().isEmpty())
cmd.addArg("/SetEnv=" + setEnv());
if (!logLevel->stringValue().isEmpty())
args.append(QString("/LogLevel=" + logLevel->stringValue()));
if (stopOnError())
cmd.addArg("/StopOnErrors");
if (!setEnv->value().isEmpty())
args.append(QString("/SetEnv=" + setEnv->value()));
if (!additionalArguments().isEmpty())
cmd.addArgs(additionalArguments(), CommandLine::Raw);
if (stopOnError->value())
args.append("/StopOnErrors");
if (openMonitor())
cmd.addArg("/OpenMonitor");
if (!additionalArguments->value().isEmpty())
args.append(additionalArguments->value());
if (openMonitor->value())
args.append("/OpenMonitor");
return CommandLine("BuildConsole.exe", args);
return cmd;
});
}

View File

@@ -28,6 +28,21 @@ public:
IBConsoleBuildStep(BuildStepList *buildStepList, Id id);
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)
@@ -35,52 +50,38 @@ IBConsoleBuildStep::IBConsoleBuildStep(BuildStepList *buildStepList, Id id)
{
setDisplayName(Tr::tr("IncrediBuild for Linux"));
addAspect<TextDisplay>("<b>" + Tr::tr("Target and Configuration"));
commandBuilder.setSettingsKey("IncrediBuild.IBConsole.CommandBuilder");
auto commandBuilder = addAspect<CommandBuilderAspect>(this);
commandBuilder->setSettingsKey("IncrediBuild.IBConsole.CommandBuilder");
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 "
"IncrediBuild behavior is to set it to 200."));
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)"));
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 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 "
"IncrediBuild behavior is to set it to 200."));
forceRemote.setSettingsKey("IncrediBuild.IBConsole.Alternate");
forceRemote.setLabel(Tr::tr("Force remote:"));
addAspect<TextDisplay>("<b>" + Tr::tr("IncrediBuild Distribution Control"));
alternate.setSettingsKey("IncrediBuild.IBConsole.ForceRemote");
alternate.setLabel(Tr::tr("Alternate tasks preference:"));
auto nice = addAspect<IntegerAspect>();
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 forceRemote = addAspect<BoolAspect>();
forceRemote->setSettingsKey("IncrediBuild.IBConsole.Alternate");
forceRemote->setLabel(Tr::tr("Force remote:"));
auto alternate = addAspect<BoolAspect>();
alternate->setSettingsKey("IncrediBuild.IBConsole.ForceRemote");
alternate->setLabel(Tr::tr("Alternate tasks preference:"));
setCommandLineProvider([=] {
setCommandLineProvider([this] {
QStringList args;
if (nice->value() != 0)
args.append(QString("--nice %1 ").arg(nice->value()));
if (nice() != 0)
args.append(QString("--nice %1 ").arg(nice()));
if (alternate->value())
if (alternate())
args.append("--alternate");
if (forceRemote->value())
if (forceRemote())
args.append("--force-remote");
args.append(commandBuilder->fullCommandFlag(keepJobNum->value()));
args.append(commandBuilder.fullCommandFlag(keepJobNum()));
return CommandLine("ib_console", args);
});

View File

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

View File

@@ -21,5 +21,9 @@
<file>wizards/qmlproject/component.qml.tpl</file>
<file>wizards/qmlproject/wizard.json</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>
</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.
// importPaths: ["imports/CustomModule"] // Alternative API for importing modules.
// 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 */
MCU.Config {

View File

@@ -1,10 +1,10 @@
{
"version": 1,
"supportedProjectTypes": [ "CMakeProjectManager.CMakeProject" ],
"id": "M.McuSupportApplication",
"id": "M.McuSupportApplicationExample",
"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.",
"trDisplayName": "Qt for MCUs Application",
"trDisplayName": "Qt for MCUs Example Application",
"trDisplayCategory": "QmlProject Application (Qt for MCUs)",
"icon": "../icon.png",
"iconKind": "Themed",

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

@@ -90,6 +90,7 @@ public:
, m_executable(new PathChooser())
{
m_executable->setExpectedKind(PathChooser::ExistingCommand);
m_executable->setAllowPathFromDevice(true);
connect(m_name, &QLineEdit::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())
return QString("undefined");
if (val.type() == QVariant::List || val.type() == QVariant::StringList) {
if (val.typeId() == QVariant::List || val.typeId() == QVariant::StringList) {
QString res;
const auto list = val.toList();
for (const QVariant &child : list) {
@@ -71,7 +71,7 @@ QString toJSLiteral(const QVariant &val)
res.append(']');
return res;
}
if (val.type() == QVariant::Map) {
if (val.typeId() == QVariant::Map) {
const QVariantMap &vm = val.toMap();
QString str("{");
for (auto it = vm.begin(); it != vm.end(); ++it) {
@@ -82,7 +82,7 @@ QString toJSLiteral(const QVariant &val)
str += '}';
return str;
}
if (val.type() == QVariant::Bool)
if (val.typeId() == QVariant::Bool)
return toJSLiteral(val.toBool());
if (val.canConvert(QVariant::String))
return toJSLiteral(val.toString());

View File

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

View File

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

View File

@@ -2,9 +2,11 @@
// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only WITH Qt-GPL-exception-1.0
#include "richtexteditor.h"
#include "ui_richtexteditor.h"
#include "hyperlinkdialog.h"
#include <utils/layoutbuilder.h>
#include <utils/stylehelper.h>
#include <functional>
#include <QAction>
@@ -19,8 +21,9 @@
#include <QTextTableFormat>
#include <QToolButton>
#include <QWidgetAction>
#include <utils/stylehelper.h>
#include <QApplication>
#include <QTextEdit>
#include <QToolBar>
namespace QmlDesigner {
@@ -89,20 +92,41 @@ static QPixmap drawColorBox(const QColor& color, const QSize& size, int borderWi
RichTextEditor::RichTextEditor(QWidget *parent)
: QWidget(parent)
, ui(new Ui::RichTextEditor)
, m_linkDialog(new HyperlinkDialog(this))
{
ui->setupUi(this);
ui->textEdit->setTextInteractionFlags(Qt::TextEditorInteraction | Qt::LinksAccessibleByMouse);
ui->tableBar->setVisible(false);
resize(428, 283);
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 QString toolBarStyleSheet =
QString("QToolBar { background-color: %1; border-width: 1px }").arg(backColor.name());
ui->toolBar->setStyleSheet(toolBarStyleSheet);
ui->tableBar->setStyleSheet(toolBarStyleSheet);
m_toolBar->setStyleSheet(toolBarStyleSheet);
m_tableBar->setStyleSheet(toolBarStyleSheet);
setupEditActions();
setupTextActions();
@@ -113,16 +137,16 @@ RichTextEditor::RichTextEditor(QWidget *parent)
setupFontActions();
setupTableActions();
connect(ui->textEdit, &QTextEdit::currentCharFormatChanged,
connect(m_textEdit, &QTextEdit::currentCharFormatChanged,
this, &RichTextEditor::currentCharFormatChanged);
connect(ui->textEdit, &QTextEdit::cursorPositionChanged,
connect(m_textEdit, &QTextEdit::cursorPositionChanged,
this, &RichTextEditor::cursorPositionChanged);
connect(ui->textEdit, &QTextEdit::textChanged,
connect(m_textEdit, &QTextEdit::textChanged,
this, &RichTextEditor::onTextChanged);
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();
charFormat.setForeground(QApplication::palette().color(QPalette::Link));
@@ -145,7 +169,7 @@ RichTextEditor::RichTextEditor(QWidget *parent)
m_linkDialog->hide();
});
ui->textEdit->setFocus();
m_textEdit->setFocus();
m_linkDialog->hide();
}
@@ -155,22 +179,22 @@ RichTextEditor::~RichTextEditor()
void RichTextEditor::setPlainText(const QString &text)
{
ui->textEdit->setPlainText(text);
m_textEdit->setPlainText(text);
}
QString RichTextEditor::plainText() const
{
return ui->textEdit->toPlainText();
return m_textEdit->toPlainText();
}
void RichTextEditor::setRichText(const QString &text)
{
ui->textEdit->setHtml(text);
m_textEdit->setHtml(text);
}
void RichTextEditor::setTabChangesFocus(bool change)
{
ui->textEdit->setTabChangesFocus(change);
m_textEdit->setTabChangesFocus(change);
}
void RichTextEditor::setImageActionVisible(bool change)
@@ -180,7 +204,7 @@ void RichTextEditor::setImageActionVisible(bool change)
void RichTextEditor::setDocumentBaseUrl(const QUrl& url)
{
ui->textEdit->document()->setBaseUrl(url);
m_textEdit->document()->setBaseUrl(url);
}
QIcon RichTextEditor::getIcon(Theme::Icon icon)
@@ -194,7 +218,7 @@ QIcon RichTextEditor::getIcon(Theme::Icon icon)
QString RichTextEditor::richText() const
{
return ui->textEdit->toHtml();
return m_textEdit->toHtml();
}
void RichTextEditor::currentCharFormatChanged(const QTextCharFormat &format)
@@ -205,9 +229,9 @@ void RichTextEditor::currentCharFormatChanged(const QTextCharFormat &format)
void RichTextEditor::cursorPositionChanged()
{
alignmentChanged(ui->textEdit->alignment());
styleChanged(ui->textEdit->textCursor());
tableChanged(ui->textEdit->textCursor());
alignmentChanged(m_textEdit->alignment());
styleChanged(m_textEdit->textCursor());
tableChanged(m_textEdit->textCursor());
}
void RichTextEditor::onTextChanged() {
@@ -216,11 +240,11 @@ void RichTextEditor::onTextChanged() {
void RichTextEditor::mergeFormatOnWordOrSelection(const QTextCharFormat &format)
{
QTextCursor cursor = ui->textEdit->textCursor();
QTextCursor cursor = m_textEdit->textCursor();
if (!cursor.hasSelection())
cursor.select(QTextCursor::WordUnderCursor);
cursor.mergeCharFormat(format);
ui->textEdit->mergeCurrentCharFormat(format);
m_textEdit->mergeCurrentCharFormat(format);
}
void RichTextEditor::fontChanged(const QFont &f)
@@ -243,7 +267,7 @@ void RichTextEditor::fontChanged(const QFont &f)
void RichTextEditor::colorChanged(const QColor &c)
{
QPixmap colorBox(drawColorBox(c, ui->tableBar->iconSize()));
QPixmap colorBox(drawColorBox(c, m_tableBar->iconSize()));
m_actionTextColor->setIcon(colorBox);
}
@@ -293,7 +317,7 @@ void RichTextEditor::tableChanged(const QTextCursor &cursor)
if (currentTable) {
m_actionTableSettings->setChecked(true);
ui->tableBar->setVisible(true);
m_tableBar->setVisible(true);
setTableActionsActive(true);
}
@@ -305,27 +329,27 @@ void RichTextEditor::tableChanged(const QTextCursor &cursor)
void RichTextEditor::setupEditActions()
{
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);
connect(ui->textEdit->document(), &QTextDocument::undoAvailable,
connect(m_textEdit->document(), &QTextDocument::undoAvailable,
actionUndo, &QAction::setEnabled);
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);
connect(ui->textEdit->document(), &QTextDocument::redoAvailable,
connect(m_textEdit->document(), &QTextDocument::redoAvailable,
actionRedo, &QAction::setEnabled);
actionUndo->setEnabled(ui->textEdit->document()->isUndoAvailable());
actionRedo->setEnabled(ui->textEdit->document()->isRedoAvailable());
actionUndo->setEnabled(m_textEdit->document()->isUndoAvailable());
actionRedo->setEnabled(m_textEdit->document()->isRedoAvailable());
ui->toolBar->addSeparator();
m_toolBar->addSeparator();
}
void RichTextEditor::setupTextActions()
{
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) {
QTextCharFormat fmt;
fmt.setFontWeight(checked ? QFont::Bold : QFont::Normal);
@@ -338,7 +362,7 @@ void RichTextEditor::setupTextActions()
m_actionTextBold->setCheckable(true);
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) {
QTextCharFormat fmt;
fmt.setFontItalic(checked);
@@ -351,7 +375,7 @@ void RichTextEditor::setupTextActions()
m_actionTextItalic->setCheckable(true);
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) {
QTextCharFormat fmt;
fmt.setFontUnderline(checked);
@@ -363,7 +387,7 @@ void RichTextEditor::setupTextActions()
m_actionTextUnderline->setFont(underline);
m_actionTextUnderline->setCheckable(true);
ui->toolBar->addSeparator();
m_toolBar->addSeparator();
}
void RichTextEditor::setupImageActions()
@@ -379,12 +403,12 @@ void RichTextEditor::setupImageActions()
for (QString& filePath : files) {
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);
setImageActionVisible(false);
@@ -393,8 +417,8 @@ void RichTextEditor::setupImageActions()
void RichTextEditor::setupHyperlinkActions()
{
const QIcon bulletIcon(getIcon(Theme::Icon::actionIconBinding));
m_actionHyperlink = ui->toolBar->addAction(bulletIcon, tr("Hyperlink Settings"), [this]() {
QTextCursor cursor = ui->textEdit->textCursor();
m_actionHyperlink = m_toolBar->addAction(bulletIcon, tr("Hyperlink Settings"), [this]() {
QTextCursor cursor = m_textEdit->textCursor();
QTextCharFormat linkFormat = cursor.charFormat();
if (linkFormat.isAnchor()) {
m_linkDialog->setLink(linkFormat.anchorHref());
@@ -410,37 +434,37 @@ void RichTextEditor::setupHyperlinkActions()
});
m_actionHyperlink->setCheckable(false);
ui->toolBar->addSeparator();
m_toolBar->addSeparator();
}
void RichTextEditor::setupAlignActions()
{
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->setCheckable(true);
m_actionAlignLeft->setPriority(QAction::LowPriority);
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->setCheckable(true);
m_actionAlignCenter->setPriority(QAction::LowPriority);
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->setCheckable(true);
m_actionAlignRight->setPriority(QAction::LowPriority);
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->setCheckable(true);
m_actionAlignJustify->setPriority(QAction::LowPriority);
// 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()) {
alignGroup->addAction(m_actionAlignLeft);
@@ -453,15 +477,15 @@ void RichTextEditor::setupAlignActions()
}
alignGroup->addAction(m_actionAlignJustify);
ui->toolBar->addActions(alignGroup->actions());
m_toolBar->addActions(alignGroup->actions());
ui->toolBar->addSeparator();
m_toolBar->addSeparator();
}
void RichTextEditor::setupListActions()
{
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) {
m_actionNumberedList->setChecked(false);
textStyle(QTextListFormat::ListDisc);
@@ -473,7 +497,7 @@ void RichTextEditor::setupListActions()
m_actionBulletList->setCheckable(true);
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) {
m_actionBulletList->setChecked(false);
textStyle(QTextListFormat::ListDecimal);
@@ -484,15 +508,15 @@ void RichTextEditor::setupListActions()
});
m_actionNumberedList->setCheckable(true);
ui->toolBar->addSeparator();
m_toolBar->addSeparator();
}
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]() {
QColor col = QColorDialog::getColor(ui->textEdit->textColor(), this);
m_actionTextColor = m_toolBar->addAction(colorBox, tr("&Color..."), [this]() {
QColor col = QColorDialog::getColor(m_textEdit->textColor(), this);
if (!col.isValid())
return;
QTextCharFormat fmt;
@@ -505,7 +529,7 @@ void RichTextEditor::setupFontActions()
m_fontNameAction->setInitializer([this](QFontComboBox *w) {
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) {
QTextCharFormat fmt;
fmt.setFontFamily(f);
@@ -514,7 +538,7 @@ void RichTextEditor::setupFontActions()
});
m_fontNameAction->setDefaultWidget(new QFontComboBox);
ui->toolBar->addAction(m_fontNameAction);
m_toolBar->addAction(m_fontNameAction);
m_fontSizeAction = new FontWidgetActions<QComboBox>(this);
m_fontSizeAction->setInitializer([this](QComboBox *w) {
@@ -525,7 +549,7 @@ void RichTextEditor::setupFontActions()
const QList<int> standardSizes = QFontDatabase::standardSizes();
for (const int size : standardSizes)
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) {
qreal pointSize = p.toDouble();
if (pointSize > 0.0) {
@@ -537,17 +561,17 @@ void RichTextEditor::setupFontActions()
});
m_fontSizeAction->setDefaultWidget(new QComboBox);
ui->toolBar->addAction(m_fontSizeAction);
m_toolBar->addAction(m_fontSizeAction);
ui->toolBar->addSeparator();
m_toolBar->addSeparator();
}
void RichTextEditor::setupTableActions()
{
const QIcon tableIcon(getIcon(Theme::Icon::addTable));
m_actionTableSettings = ui->toolBar->addAction(tableIcon, tr("&Table Settings"), [this](bool checked) {
ui->tableBar->setVisible(checked);
m_actionTableSettings = m_toolBar->addAction(tableIcon, tr("&Table Settings"), [this](bool checked) {
m_tableBar->setVisible(checked);
});
m_actionTableSettings->setShortcut(Qt::CTRL | Qt::Key_T);
m_actionTableSettings->setCheckable(true);
@@ -556,8 +580,8 @@ void RichTextEditor::setupTableActions()
//table bar:
const QIcon createTableIcon(getIcon(Theme::Icon::addTable));
m_actionCreateTable = ui->tableBar->addAction(createTableIcon, tr("Create Table"), [this]() {
QTextCursor cursor = ui->textEdit->textCursor();
m_actionCreateTable = m_tableBar->addAction(createTableIcon, tr("Create Table"), [this]() {
QTextCursor cursor = m_textEdit->textCursor();
cursorEditBlock(cursor, [&] () {
//format table cells to look a bit better:
QTextTableFormat tableFormat;
@@ -568,15 +592,15 @@ void RichTextEditor::setupTableActions()
cursor.insertTable(1, 1, tableFormat);
//move cursor into the first cell of the table:
ui->textEdit->setTextCursor(cursor);
m_textEdit->setTextCursor(cursor);
});
});
m_actionCreateTable->setCheckable(false);
const QIcon removeTableIcon(getIcon(Theme::Icon::deleteTable));
m_actionRemoveTable = ui->tableBar->addAction(removeTableIcon, tr("Remove Table"), [this]() {
QTextCursor cursor = ui->textEdit->textCursor();
if (QTextTable *currentTable = ui->textEdit->textCursor().currentTable()) {
m_actionRemoveTable = m_tableBar->addAction(removeTableIcon, tr("Remove Table"), [this]() {
QTextCursor cursor = m_textEdit->textCursor();
if (QTextTable *currentTable = m_textEdit->textCursor().currentTable()) {
cursorEditBlock(cursor, [&] () {
currentTable->removeRows(0, currentTable->rows());
});
@@ -584,12 +608,12 @@ void RichTextEditor::setupTableActions()
});
m_actionRemoveTable->setCheckable(false);
ui->tableBar->addSeparator();
m_tableBar->addSeparator();
const QIcon addRowIcon(getIcon(Theme::Icon::addRowAfter)); //addRowAfter
m_actionAddRow = ui->tableBar->addAction(addRowIcon, tr("Add Row"), [this]() {
QTextCursor cursor = ui->textEdit->textCursor();
if (QTextTable *currentTable = ui->textEdit->textCursor().currentTable()) {
m_actionAddRow = m_tableBar->addAction(addRowIcon, tr("Add Row"), [this]() {
QTextCursor cursor = m_textEdit->textCursor();
if (QTextTable *currentTable = m_textEdit->textCursor().currentTable()) {
cursorEditBlock(cursor, [&] () {
currentTable->insertRows(currentTable->cellAt(cursor).row()+1, 1);
});
@@ -598,9 +622,9 @@ void RichTextEditor::setupTableActions()
m_actionAddRow->setCheckable(false);
const QIcon addColumnIcon(getIcon(Theme::Icon::addColumnAfter)); //addColumnAfter
m_actionAddColumn = ui->tableBar->addAction(addColumnIcon, tr("Add Column"), [this]() {
QTextCursor cursor = ui->textEdit->textCursor();
if (QTextTable *currentTable = ui->textEdit->textCursor().currentTable()) {
m_actionAddColumn = m_tableBar->addAction(addColumnIcon, tr("Add Column"), [this]() {
QTextCursor cursor = m_textEdit->textCursor();
if (QTextTable *currentTable = m_textEdit->textCursor().currentTable()) {
cursorEditBlock(cursor, [&] () {
currentTable->insertColumns(currentTable->cellAt(cursor).column()+1, 1);
});
@@ -609,8 +633,8 @@ void RichTextEditor::setupTableActions()
m_actionAddColumn->setCheckable(false);
const QIcon removeRowIcon(getIcon(Theme::Icon::deleteRow));
m_actionRemoveRow = ui->tableBar->addAction(removeRowIcon, tr("Remove Row"), [this]() {
QTextCursor cursor = ui->textEdit->textCursor();
m_actionRemoveRow = m_tableBar->addAction(removeRowIcon, tr("Remove Row"), [this]() {
QTextCursor cursor = m_textEdit->textCursor();
if (QTextTable *currentTable = cursor.currentTable()) {
cursorEditBlock(cursor, [&] () {
currentTable->insertColumns(currentTable->cellAt(cursor).column()+1, 1);
@@ -633,8 +657,8 @@ void RichTextEditor::setupTableActions()
m_actionRemoveRow->setCheckable(false);
const QIcon removeColumnIcon(getIcon(Theme::Icon::deleteColumn));
m_actionRemoveColumn = ui->tableBar->addAction(removeColumnIcon, tr("Remove Column"), [this]() {
QTextCursor cursor = ui->textEdit->textCursor();
m_actionRemoveColumn = m_tableBar->addAction(removeColumnIcon, tr("Remove Column"), [this]() {
QTextCursor cursor = m_textEdit->textCursor();
if (QTextTable *currentTable = cursor.currentTable()) {
cursorEditBlock(cursor, [&] () {
int firstRow = 0;
@@ -654,11 +678,11 @@ void RichTextEditor::setupTableActions()
});
m_actionRemoveColumn->setCheckable(false);
ui->tableBar->addSeparator();
m_tableBar->addSeparator();
const QIcon mergeCellsIcon(getIcon(Theme::Icon::mergeCells));
m_actionMergeCells = ui->tableBar->addAction(mergeCellsIcon, tr("Merge Cells"), [this]() {
QTextCursor cursor = ui->textEdit->textCursor();
m_actionMergeCells = m_tableBar->addAction(mergeCellsIcon, tr("Merge Cells"), [this]() {
QTextCursor cursor = m_textEdit->textCursor();
if (QTextTable *currentTable = cursor.currentTable()) {
if (cursor.hasSelection()) {
cursorEditBlock(cursor, [&] () {
@@ -670,8 +694,8 @@ void RichTextEditor::setupTableActions()
m_actionMergeCells->setCheckable(false);
const QIcon splitRowIcon(getIcon(Theme::Icon::splitRows));
m_actionSplitRow = ui->tableBar->addAction(splitRowIcon, tr("Split Row"), [this]() {
QTextCursor cursor = ui->textEdit->textCursor();
m_actionSplitRow = m_tableBar->addAction(splitRowIcon, tr("Split Row"), [this]() {
QTextCursor cursor = m_textEdit->textCursor();
if (QTextTable *currentTable = cursor.currentTable()) {
cursorEditBlock(cursor, [&] () {
currentTable->splitCell(currentTable->cellAt(cursor).row(),
@@ -683,8 +707,8 @@ void RichTextEditor::setupTableActions()
m_actionSplitRow->setCheckable(false);
const QIcon splitColumnIcon(getIcon(Theme::Icon::splitColumns));
m_actionSplitColumn = ui->tableBar->addAction(splitColumnIcon, tr("Split Column"), [this]() {
QTextCursor cursor = ui->textEdit->textCursor();
m_actionSplitColumn = m_tableBar->addAction(splitColumnIcon, tr("Split Column"), [this]() {
QTextCursor cursor = m_textEdit->textCursor();
if (QTextTable *currentTable = cursor.currentTable()) {
cursorEditBlock(cursor, [&] () {
currentTable->splitCell(currentTable->cellAt(cursor).row(),
@@ -698,7 +722,7 @@ void RichTextEditor::setupTableActions()
void RichTextEditor::textStyle(QTextListFormat::Style style)
{
QTextCursor cursor = ui->textEdit->textCursor();
QTextCursor cursor = m_textEdit->textCursor();
cursorEditBlock(cursor, [&] () {
if (style != QTextListFormat::ListStyleUndefined) {
QTextBlockFormat blockFmt = cursor.blockFormat();

View File

@@ -5,21 +5,17 @@
#include <theme.h>
#include <QWidget>
#include <QToolBar>
#include <QList>
#include <QTextCharFormat>
#include <QTextList>
#include <QFontComboBox>
#include <QWidgetAction>
#include <QList>
#include <QPointer>
#include <QTextCharFormat>
#include <QTextEdit>
#include <QTextList>
#include <QToolBar>
#include <QWidgetAction>
namespace QmlDesigner {
namespace Ui {
class RichTextEditor;
}
template <class>
class FontWidgetActions;
@@ -77,7 +73,10 @@ private:
void setTableActionsActive(bool active); //switches between "has table/has no table" ui setup
private:
QScopedPointer<Ui::RichTextEditor> ui;
QTextEdit *m_textEdit;
QToolBar *m_toolBar;
QToolBar *m_tableBar;
QPointer<HyperlinkDialog> m_linkDialog;
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());
}
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)
{
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_useCustomAnalyzer = settings->value(CUSTOM_ANALYZER, QVariant(false)).toBool();
m_disabledMessages = Utils::transform<QSet>(
settings->value(DISABLED_MESSAGES,
QVariant::fromValue(defaultDisabledMessages())).toList(),
[](const QVariant &v){ return v.toInt(); });
m_disabledMessagesForNonQuickUi = Utils::transform<QSet>(
settings->value(DISABLED_MESSAGES_NONQUICKUI,
QVariant::fromValue(defaultDisabledMessagesNonQuickUi())).toList(),
[](const QVariant &v) { return v.toInt(); });
m_disabledMessages = Utils::toSet(
intListFromStringList(settings->value(DISABLED_MESSAGES,
defaultDisabledMessagesAsString()).toStringList()));
m_disabledMessagesForNonQuickUi = Utils::toSet(
intListFromStringList(settings->value(DISABLED_MESSAGES_NONQUICKUI,
defaultDisabledNonQuickUiAsString()).toStringList()));
settings->endGroup();
}
@@ -122,12 +143,12 @@ void QmlJsEditingSettings::toSettings(QSettings *settings) const
false);
Utils::QtcSettings::setValueWithDefault(settings,
DISABLED_MESSAGES,
Utils::sorted(Utils::toList(m_disabledMessages)),
defaultDisabledMessages());
intListToStringList(Utils::sorted(Utils::toList(m_disabledMessages))),
defaultDisabledMessagesAsString());
Utils::QtcSettings::setValueWithDefault(settings,
DISABLED_MESSAGES_NONQUICKUI,
Utils::sorted(Utils::toList(m_disabledMessagesForNonQuickUi)),
defaultDisabledMessagesNonQuickUi());
intListToStringList(Utils::sorted(Utils::toList(m_disabledMessagesForNonQuickUi))),
defaultDisabledNonQuickUiAsString());
settings->endGroup();
QmllsSettingsManager::instance()->checkForChanges();
}

View File

@@ -255,7 +255,7 @@ void QuickToolBar::setProperty(const QString &propertyName, const QVariant &valu
{
QString stringValue = value.toString();
if (value.type() == QVariant::Color)
if (value.typeId() == QVariant::Color)
stringValue = QLatin1Char('\"') + value.toString() + QLatin1Char('\"');
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
#include "qmlbuildsystem.h"
#include "../qmlprojectconstants.h"
#include "../qmlprojectmanagertr.h"
#include <QtCore5Compat/qtextcodec.h>
#include <qmljs/qmljsmodelmanagerinterface.h>
@@ -222,7 +224,7 @@ void QmlBuildSystem::parseProjectFiles()
QString errorMessage;
if (!reader.fetch(mainFilePath, &errorMessage)) {
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);
}
}

View File

@@ -197,7 +197,8 @@ Tasks QmlProject::projectIssues(const Kit *k) const
if (version->type() == QtSupport::Constants::DESKTOPQT) {
if (version->qmlRuntimeFilePath().isEmpty()) {
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 {
// Non-desktop Qt on a desktop device? We don't support that.

View File

@@ -498,7 +498,7 @@ public:
auto l = new QHBoxLayout(this);
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] {
config->createKit(target);
});

View File

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

View File

@@ -282,7 +282,7 @@ bool SquishFileGenerator::setup(const QVariant &data, QString *errorMessage)
if (data.isNull())
return false;
if (data.type() != QVariant::Map) {
if (data.typeId() != QVariant::Map) {
*errorMessage = Tr::tr("Key is not an object.");
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)
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 (CMAKE_INSTALL_PREFIX_INITIALIZED_TO_DEFAULT)
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
FORMS += mainwindow.ui
macos: QMAKE_POST_LINK = codesign -f -s - --entitlements "$${PWD}/entitlements.plist" "$${OUT_PWD}/gui.app"