forked from qt-creator/qt-creator
Merge remote-tracking branch 'origin/14.0'
Change-Id: I4260181d32ed514e1a912188dbf1040857a83f54
This commit is contained in:
94
dist/changelog/changes-13.0.2.md
vendored
Normal file
94
dist/changelog/changes-13.0.2.md
vendored
Normal file
@@ -0,0 +1,94 @@
|
|||||||
|
Qt Creator 13.0.2
|
||||||
|
=================
|
||||||
|
|
||||||
|
Qt Creator version 13.0.2 contains bug fixes.
|
||||||
|
|
||||||
|
The most important changes are listed in this document. For a complete list of
|
||||||
|
changes, see the Git log for the Qt Creator sources that you can check out from
|
||||||
|
the public Git repository. For example:
|
||||||
|
|
||||||
|
git clone git://code.qt.io/qt-creator/qt-creator.git
|
||||||
|
git log --cherry-pick --pretty=oneline v13.0.1..v13.0.2
|
||||||
|
|
||||||
|
General
|
||||||
|
-------
|
||||||
|
|
||||||
|
* Fixed that the `-client` option could start a new Qt Creator instance instead
|
||||||
|
of using a running one (which affects for example version control operations)
|
||||||
|
([QTCREATORBUG-30624](https://bugreports.qt.io/browse/QTCREATORBUG-30624))
|
||||||
|
|
||||||
|
Editing
|
||||||
|
-------
|
||||||
|
|
||||||
|
* Fixed that closing files with the tool button didn't add an entry to the
|
||||||
|
navigation history
|
||||||
|
|
||||||
|
### Widget Designer
|
||||||
|
|
||||||
|
* Fixed that `Use Qt module name in #include-directive` used Qt 4 module names
|
||||||
|
([QTCREATORBUG-30751](https://bugreports.qt.io/browse/QTCREATORBUG-30751))
|
||||||
|
|
||||||
|
### Copilot
|
||||||
|
|
||||||
|
* Adapted to changes in the Copilot neovim plugin
|
||||||
|
|
||||||
|
Projects
|
||||||
|
--------
|
||||||
|
|
||||||
|
### CMake
|
||||||
|
|
||||||
|
* Fixed the environment macro expansion for Presets
|
||||||
|
|
||||||
|
### Meson
|
||||||
|
|
||||||
|
* Fixed a crash when selecting kits
|
||||||
|
([QTCREATORBUG-30698](https://bugreports.qt.io/browse/QTCREATORBUG-30698))
|
||||||
|
|
||||||
|
Terminal
|
||||||
|
--------
|
||||||
|
|
||||||
|
* Fixed the handling of environment variables with an equal sign `=` in the
|
||||||
|
value
|
||||||
|
([QTCREATORBUG-30844](https://bugreports.qt.io/browse/QTCREATORBUG-30844))
|
||||||
|
|
||||||
|
Version Control Systems
|
||||||
|
-----------------------
|
||||||
|
|
||||||
|
### Git
|
||||||
|
|
||||||
|
* Fixed a crash in `Instant Blame` when reloading externally modified files
|
||||||
|
([QTCREATORBUG-30824](https://bugreports.qt.io/browse/QTCREATORBUG-30824))
|
||||||
|
|
||||||
|
Platforms
|
||||||
|
---------
|
||||||
|
|
||||||
|
### Windows
|
||||||
|
|
||||||
|
* Fixed missing paths with `Add build library search path to PATH` for CMake
|
||||||
|
projects
|
||||||
|
([QTCREATORBUG-30556](https://bugreports.qt.io/browse/QTCREATORBUG-30556),
|
||||||
|
[QTCREATORBUG-30827](https://bugreports.qt.io/browse/QTCREATORBUG-30827),
|
||||||
|
[QTCREATORBUG-30932](https://bugreports.qt.io/browse/QTCREATORBUG-30932))
|
||||||
|
|
||||||
|
### Android
|
||||||
|
|
||||||
|
* Fixed a crash when re-connecting devices
|
||||||
|
([QTCREATORBUG-30645](https://bugreports.qt.io/browse/QTCREATORBUG-30645),
|
||||||
|
[QTCREATORBUG-30770](https://bugreports.qt.io/browse/QTCREATORBUG-30770))
|
||||||
|
|
||||||
|
### Remote Linux
|
||||||
|
|
||||||
|
* Fixed passing more than one argument to `rsync`
|
||||||
|
([QTCREATORBUG-30795](https://bugreports.qt.io/browse/QTCREATORBUG-30795))
|
||||||
|
|
||||||
|
Credits for these changes go to:
|
||||||
|
--------------------------------
|
||||||
|
Alessandro Portale
|
||||||
|
Christian Kandeler
|
||||||
|
Christian Stenger
|
||||||
|
Cristian Adam
|
||||||
|
David Schulz
|
||||||
|
Eike Ziller
|
||||||
|
Leena Miettinen
|
||||||
|
Marcus Tillmanns
|
||||||
|
Robert Löhning
|
@@ -140,12 +140,18 @@
|
|||||||
|
|
||||||
To connect to an Axivion dashboard server:
|
To connect to an Axivion dashboard server:
|
||||||
|
|
||||||
\list 1
|
\list
|
||||||
\li Select \uicontrol Edit to create a connection to the Axivion
|
\li Select \uicontrol Add to add a new connection to an Axivion
|
||||||
dashboard server.
|
dashboard server.
|
||||||
|
\li Select \uicontrol Edit to modify an existing connection to
|
||||||
|
an Axivion dashboard server.
|
||||||
\image qtcreator-edit-dashboard-configuration.webp {Edit Dashboard Configuration dialog}
|
\image qtcreator-edit-dashboard-configuration.webp {Edit Dashboard Configuration dialog}
|
||||||
\li In \uicontrol {Dashboard URL}, enter the URL of the server.
|
\list
|
||||||
\li In \uicontrol Username, enter the username to access the server.
|
\li In \uicontrol {Dashboard URL}, enter the URL of the server.
|
||||||
|
\li In \uicontrol Username, enter the username to access the server.
|
||||||
|
\endlist
|
||||||
|
\li Select \uicontrol Remove to remove the current selected connection
|
||||||
|
to an Axivion dashboard server.
|
||||||
\endlist
|
\endlist
|
||||||
|
|
||||||
The first time you access the server, you must enter the password that
|
The first time you access the server, you must enter the password that
|
||||||
@@ -173,6 +179,8 @@
|
|||||||
\li Go to \uicontrol Projects > \uicontrol {Project Settings} >
|
\li Go to \uicontrol Projects > \uicontrol {Project Settings} >
|
||||||
\uicontrol Axivion.
|
\uicontrol Axivion.
|
||||||
\image qtcreator-preferences-axivion-project.webp {Axivion settings in Project Settings}
|
\image qtcreator-preferences-axivion-project.webp {Axivion settings in Project Settings}
|
||||||
|
\li From \uicontrol {Dashboard} select one of the configured Axivion
|
||||||
|
dashboard configurations.
|
||||||
\li Select \uicontrol {Fetch Projects} to list projects from Axivion.
|
\li Select \uicontrol {Fetch Projects} to list projects from Axivion.
|
||||||
\li Select a project, and then select \uicontrol {Link Project} to link
|
\li Select a project, and then select \uicontrol {Link Project} to link
|
||||||
to it.
|
to it.
|
||||||
|
@@ -113,7 +113,7 @@
|
|||||||
LTTng is a tracing toolkit for Linux that you can apply on embedded Linux
|
LTTng is a tracing toolkit for Linux that you can apply on embedded Linux
|
||||||
systems to find out how to optimize the startup time of an application.
|
systems to find out how to optimize the startup time of an application.
|
||||||
|
|
||||||
Since Qt 5.13, Qt has a set of kernel trace points and a tracing
|
Qt has a set of kernel trace points and a tracing
|
||||||
subsystem for custom user space trace points.
|
subsystem for custom user space trace points.
|
||||||
|
|
||||||
\section2 Configuring the Kernel
|
\section2 Configuring the Kernel
|
||||||
|
@@ -131,22 +131,24 @@
|
|||||||
C:\Users\Username\AppData\Local\QtProject\qtcreator\android\sdk_definitions.json
|
C:\Users\Username\AppData\Local\QtProject\qtcreator\android\sdk_definitions.json
|
||||||
\endcode
|
\endcode
|
||||||
|
|
||||||
For example, the SDK configuration file sets the NDK version 19.2.5345600
|
For example, the SDK configuration file sets the NDK version 22.1.7171670
|
||||||
for use with Qt 5.12.0 to 5.12.5 and Qt 5.13.0 to 5.13.1:
|
for use with Qt 6.3, Qt 6.2, and Qt 5.15.9 to 5.15.20:
|
||||||
|
|
||||||
\badcode
|
\badcode
|
||||||
"specific_qt_versions": [
|
"specific_qt_versions": [
|
||||||
{
|
{ "versions": ["6.3", "6.2", "5.15.[9-20]"],
|
||||||
"versions": ["5.12.[0-5]", "5.13.[0-1]"],
|
"sdk_essential_packages": ["build-tools;31.0.0", "ndk;22.1.7171670"]
|
||||||
"sdk_essential_packages": ["build-tools;28.0.2", "ndk;19.2.5345600"],
|
},
|
||||||
"ndk_path": "ndk/19.2.5345600"
|
|
||||||
}
|
|
||||||
]
|
]
|
||||||
\endcode
|
\endcode
|
||||||
|
|
||||||
You can view the latest version of the configuration file that is up-to-date
|
You can view the latest version of the configuration file that is up-to-date
|
||||||
with the Android SDK and NDK changes, \l{sdk_definitions.json}, in Git.
|
with the Android SDK and NDK changes, \l{sdk_definitions.json}, in Git.
|
||||||
|
|
||||||
|
\note For Qt 6.5 or later, \QC reads the NDK version that was used for
|
||||||
|
building Qt from \c modules/Core.json and uses it instead of the version
|
||||||
|
in \c sdk_definitions.json.
|
||||||
|
|
||||||
\sa {Android}{How To: Develop for Android},
|
\sa {Android}{How To: Develop for Android},
|
||||||
{Developing for Android}
|
{Developing for Android}
|
||||||
*/
|
*/
|
||||||
|
@@ -25,10 +25,6 @@
|
|||||||
information about the state of the UI, and inspect QML properties and
|
information about the state of the UI, and inspect QML properties and
|
||||||
JavaScript variables, as well as change their values temporarily at runtime.
|
JavaScript variables, as well as change their values temporarily at runtime.
|
||||||
|
|
||||||
\if defined(qtcreator)
|
|
||||||
\note You need Qt 5.0 or later to debug Qt Quick projects.
|
|
||||||
\endif
|
|
||||||
|
|
||||||
For an example of how to debug Qt Quick Projects, see
|
For an example of how to debug Qt Quick Projects, see
|
||||||
\l{Debugging a Qt Quick Application}.
|
\l{Debugging a Qt Quick Application}.
|
||||||
|
|
||||||
@@ -86,7 +82,7 @@
|
|||||||
rebuild the project.
|
rebuild the project.
|
||||||
|
|
||||||
\li To debug applications on \l{glossary-device}{devices}, check that
|
\li To debug applications on \l{glossary-device}{devices}, check that
|
||||||
Qt 5.0, or later, libraries are installed on the device and
|
Qt libraries are installed on the device and
|
||||||
\l{Run on many platforms}{select the corresponding kit for the device}
|
\l{Run on many platforms}{select the corresponding kit for the device}
|
||||||
before you start debugging.
|
before you start debugging.
|
||||||
|
|
||||||
@@ -250,12 +246,6 @@
|
|||||||
application to jump to their definitions in the code. The properties of the
|
application to jump to their definitions in the code. The properties of the
|
||||||
selected item are displayed in the \uicontrol {Locals} view.
|
selected item are displayed in the \uicontrol {Locals} view.
|
||||||
|
|
||||||
\if defined(qtcreator)
|
|
||||||
The \uicontrol Select tool will be enabled either if your application is
|
|
||||||
using Qt 5.7 or later, or if your application is using an earlier version
|
|
||||||
of Qt and is based on the \c QQuickView class.
|
|
||||||
\endif
|
|
||||||
|
|
||||||
You can also view the item hierarchy in the running application:
|
You can also view the item hierarchy in the running application:
|
||||||
|
|
||||||
Double-click an item in the running application to cycle through the item
|
Double-click an item in the running application to cycle through the item
|
||||||
|
@@ -417,18 +417,18 @@
|
|||||||
|
|
||||||
\image qtcreator-options-texteditor-behavior-file-encodings.png {File encoding preferences}
|
\image qtcreator-options-texteditor-behavior-file-encodings.png {File encoding preferences}
|
||||||
|
|
||||||
Qt 5 and Qt 6 require UTF-8 encoded source files, and therefore the default
|
Qt requires UTF-8 encoded source files, and therefore the default
|
||||||
encoding is set to \uicontrol UTF-8.
|
encoding is set to \uicontrol UTF-8.
|
||||||
Detecting the correct encoding is tricky, so \QC will not try to do so.
|
|
||||||
Instead, it displays the following error message when you try to edit a file
|
If you try to edit a file that is not UTF-8 encoded, you see the following
|
||||||
that is not UTF-8 encoded: \uicontrol {Error: Could not decode "filename" with
|
error message: \uicontrol {Error: Could not decode "filename" with
|
||||||
"UTF-8"-encoding. Editing not possible.}
|
"UTF-8"-encoding. Editing not possible.}
|
||||||
|
|
||||||
To resolve the issue, use a file conversion tool to convert the file
|
To resolve the issue, use a file conversion tool to convert the file
|
||||||
encoding to UTF-8 when developing Qt 5 applications. Otherwise, conversion
|
encoding to UTF-8. Otherwise, conversion of string constants to
|
||||||
of string constants to QString might not work as expected.
|
QString might not work as expected.
|
||||||
|
|
||||||
If you develop only Qt 4 applications or other than Qt applications, you
|
If you do not develop Qt applications, you
|
||||||
can set other encoding options as the default encoding. Select the
|
can set other encoding options as the default encoding. Select the
|
||||||
\uicontrol System option to use the file encoding used by your system.
|
\uicontrol System option to use the file encoding used by your system.
|
||||||
|
|
||||||
|
@@ -849,8 +849,7 @@
|
|||||||
|
|
||||||
\section1 Blacklisting Tests
|
\section1 Blacklisting Tests
|
||||||
|
|
||||||
Since Qt 5.4, you can add a BLACKLIST file for tests. It is mainly used
|
A BLACKLIST file for tests is mainly used internally by the Qt CI system.
|
||||||
internally by the Qt CI system.
|
|
||||||
|
|
||||||
\table
|
\table
|
||||||
\header
|
\header
|
||||||
|
@@ -121,14 +121,10 @@
|
|||||||
\b {The Qt API Reference Documentation is missing and context help does
|
\b {The Qt API Reference Documentation is missing and context help does
|
||||||
not find topics. What can I do?}
|
not find topics. What can I do?}
|
||||||
|
|
||||||
\QC comes fully integrated with Qt documentation and examples using
|
Install a Qt version and Qt documentation with \QOI.
|
||||||
the Qt Help plugin. The integrated Qt Reference Documentation is available
|
|
||||||
for Qt 4.4 and later. \QC and other Qt deliverables have
|
|
||||||
documentation as .qch files. All the documentation is accessible in the
|
|
||||||
\uicontrol Help mode.
|
|
||||||
|
|
||||||
To view the documentation that is available and to add documentation,
|
To view the installed documentation (.qch files) and to add documentation,
|
||||||
select \preferences > \uicontrol Help >
|
go to \preferences > \uicontrol Help >
|
||||||
\uicontrol Documentation. For more information, see
|
\uicontrol Documentation. For more information, see
|
||||||
\l{Add external documentation}.
|
\l{Add external documentation}.
|
||||||
|
|
||||||
|
@@ -16,8 +16,8 @@
|
|||||||
the necessary \l{Kits}{kits} to build applications for and run them on
|
the necessary \l{Kits}{kits} to build applications for and run them on
|
||||||
configured iOS devices.
|
configured iOS devices.
|
||||||
|
|
||||||
You only need Qt libraries that are built for iOS. You can install them as
|
You only need Qt libraries that are built for iOS. You can install Qt for iOS
|
||||||
part of Qt 5.2, or later.
|
with \QOI.
|
||||||
|
|
||||||
\section1 iOS 17 Devices
|
\section1 iOS 17 Devices
|
||||||
|
|
||||||
|
@@ -45,8 +45,7 @@
|
|||||||
\li libxft-dev
|
\li libxft-dev
|
||||||
\li libxi-dev
|
\li libxi-dev
|
||||||
\li libxrandr-dev
|
\li libxrandr-dev
|
||||||
\li libgl-dev and libglu-dev if you use Qt OpenGL (deprecated
|
\li libgl-dev and libglu-dev if you use Qt GUI OpenGL functions
|
||||||
in Qt 5) or Qt GUI OpenGL functions
|
|
||||||
\endlist
|
\endlist
|
||||||
|
|
||||||
\section1 macOS
|
\section1 macOS
|
||||||
|
@@ -141,6 +141,10 @@
|
|||||||
|
|
||||||
Use the following syntax to enter environment variable names and values:
|
Use the following syntax to enter environment variable names and values:
|
||||||
\c {<VARIABLE>=<VALUE>}.
|
\c {<VARIABLE>=<VALUE>}.
|
||||||
|
To temporarily disable a variable, add a hash character (#) to the beginning
|
||||||
|
of the line.
|
||||||
|
\note Using this approach for a different statement (append, prepend, unset)
|
||||||
|
may result in unexpected changes of the environment.
|
||||||
|
|
||||||
To remove a variable value from the environment, enter the variable name.
|
To remove a variable value from the environment, enter the variable name.
|
||||||
For example, \c TEST sets the value of the \c TEST variable empty when
|
For example, \c TEST sets the value of the \c TEST variable empty when
|
||||||
@@ -160,8 +164,8 @@
|
|||||||
following lines. However, you can remove a value after you have referred to
|
following lines. However, you can remove a value after you have referred to
|
||||||
it on an earlier line.
|
it on an earlier line.
|
||||||
|
|
||||||
To temporarily disable a variable, add a hash character (#) to the beginning
|
To add a comment or disable any of the above actions, prefix it with two hash
|
||||||
of the line.
|
characters (##).
|
||||||
|
|
||||||
\sa {Specify the environment for projects}, {Configure projects for building},
|
\sa {Specify the environment for projects}, {Configure projects for building},
|
||||||
{Configure projects for running}, {Use Qt Creator variables}
|
{Configure projects for running}, {Use Qt Creator variables}
|
||||||
|
@@ -149,8 +149,7 @@
|
|||||||
imports that are used in the QML files.
|
imports that are used in the QML files.
|
||||||
|
|
||||||
You can add imports later to combine Qt Quick basic types with
|
You can add imports later to combine Qt Quick basic types with
|
||||||
Qt Quick Controls, Qt Quick Dialogs, and Qt Quick Layouts (available
|
Qt Quick Controls, Qt Quick Dialogs, and Qt Quick Layouts.
|
||||||
since Qt 5.1).
|
|
||||||
|
|
||||||
\li Select the \uicontrol {Use Qt Virtual Keyboard} check box to add
|
\li Select the \uicontrol {Use Qt Virtual Keyboard} check box to add
|
||||||
support for \l{Qt Virtual Keyboard} to the application.
|
support for \l{Qt Virtual Keyboard} to the application.
|
||||||
|
@@ -261,33 +261,24 @@
|
|||||||
of the code the event is associated with.
|
of the code the event is associated with.
|
||||||
|
|
||||||
The following types of events are displayed in the timeline view on one or
|
The following types of events are displayed in the timeline view on one or
|
||||||
several rows. The availability of event types depends on the Qt version that
|
several rows.
|
||||||
you build the application with and the Qt Quick version you use.
|
|
||||||
|
|
||||||
\table
|
\table
|
||||||
|
|
||||||
\header
|
\header
|
||||||
\li Event Category
|
\li Event Category
|
||||||
\li Description
|
\li Description
|
||||||
\li Minimum Qt Version
|
|
||||||
\li Qt Quick Version
|
|
||||||
|
|
||||||
\row
|
\row
|
||||||
\li \uicontrol {Pixmap Cache}
|
\li \uicontrol {Pixmap Cache}
|
||||||
\li Displays the general amount of pixmap data cached, in pixels. In
|
\li Displays the general amount of pixmap data cached, in pixels. In
|
||||||
addition, displays a separate event for each picture being loaded,
|
addition, displays a separate event for each picture being loaded,
|
||||||
with specifics about its file name and size.
|
with specifics about its file name and size.
|
||||||
\li Qt 5.1
|
|
||||||
\li Qt Quick 2
|
|
||||||
|
|
||||||
\row
|
\row
|
||||||
\li \uicontrol {Scene Graph}
|
\li \uicontrol {Scene Graph}
|
||||||
\li Displays the time when scene graph frames are rendered and some
|
\li Displays the time when scene graph frames are rendered and some
|
||||||
additional timing information for the various stages executed to do
|
additional timing information for the various stages executed to do
|
||||||
so.
|
so.
|
||||||
\li Qt 5.1
|
|
||||||
\li Qt Quick 2
|
|
||||||
|
|
||||||
\row
|
\row
|
||||||
\li \uicontrol {Memory Usage}
|
\li \uicontrol {Memory Usage}
|
||||||
\li Displays block allocations of the JavaScript memory manager.
|
\li Displays block allocations of the JavaScript memory manager.
|
||||||
@@ -300,82 +291,49 @@
|
|||||||
The second row displays the actual usage of the allocated memory.
|
The second row displays the actual usage of the allocated memory.
|
||||||
This is the amount of JavaScript heap the application has actually
|
This is the amount of JavaScript heap the application has actually
|
||||||
requested.
|
requested.
|
||||||
\li Qt 5.4
|
|
||||||
\li Qt Quick 2
|
|
||||||
|
|
||||||
\row
|
\row
|
||||||
\li \uicontrol {Input Events}
|
\li \uicontrol {Input Events}
|
||||||
\li Displays mouse and keyboard events.
|
\li Displays mouse and keyboard events.
|
||||||
\li Qt 4.7.4
|
|
||||||
\li Qt Quick 1 or Qt Quick 2
|
|
||||||
|
|
||||||
\row
|
\row
|
||||||
\li \uicontrol Painting
|
\li \uicontrol Painting
|
||||||
\li Displays the time spent painting the scene for each frame.
|
\li Not used.
|
||||||
\li Qt 4.7.4
|
|
||||||
\li Qt Quick 1
|
|
||||||
|
|
||||||
\row
|
\row
|
||||||
\li \uicontrol Animations
|
\li \uicontrol Animations
|
||||||
\li Displays the amount of animations that are active and the frame
|
\li Displays the amount of animations that are active and the frame
|
||||||
rate that they are running at.
|
rate that they are running at.
|
||||||
Information about render thread animations is displayed for
|
Render thread animations are shown on a separate row.
|
||||||
applications that are built with Qt 5.3 or later. Render thread
|
|
||||||
animations are shown in a separate row then.
|
|
||||||
\li Qt 5.0 (Qt 5.3)
|
|
||||||
\li Qt Quick 2
|
|
||||||
|
|
||||||
\row
|
\row
|
||||||
\li \uicontrol Compiling
|
\li \uicontrol Compiling
|
||||||
\li Displays the time spent compiling the QML files.
|
\li Displays the time spent compiling the QML files.
|
||||||
\li Qt 4.7.4
|
|
||||||
\li Qt Quick 1 or Qt Quick 2
|
|
||||||
|
|
||||||
\row
|
\row
|
||||||
\li \uicontrol Creating
|
\li \uicontrol Creating
|
||||||
\li Displays the time spent creating the elements in the scene. In Qt
|
\li Displays the time spent creating the elements in the scene.
|
||||||
Quick 2, creation of elements takes place in two stages. The first
|
The creation of elements takes place in two stages. The first
|
||||||
stage is for the creation of the data structures, including child
|
stage is for the creation of the data structures, including child
|
||||||
elements. The second stage represents the completion callbacks. Not
|
elements. The second stage represents the completion callbacks. Not
|
||||||
all elements trigger completion callbacks, though. The stages are
|
all elements trigger completion callbacks, though. The stages are
|
||||||
shown as separate events in the timeline.
|
shown as separate events in the timeline.
|
||||||
For Qt Quick 2 applications compiled with versions of Qt before
|
|
||||||
5.2.1 only the creation of top-level elements is shown, as single
|
|
||||||
events.
|
|
||||||
\li Qt 4.7.4 (Qt 5.2.1)
|
|
||||||
\li Qt Quick 1 or Qt Quick 2
|
|
||||||
|
|
||||||
\row
|
\row
|
||||||
\li \uicontrol Binding
|
\li \uicontrol Binding
|
||||||
\li Displays the time when a binding is evaluated and how long the
|
\li Displays the time when a binding is evaluated and how long the
|
||||||
evaluation takes.
|
evaluation takes.
|
||||||
\li Qt 4.7.4
|
|
||||||
\li Qt Quick 1 or Qt Quick 2
|
|
||||||
|
|
||||||
\row
|
\row
|
||||||
\li \uicontrol {Handling Signal}
|
\li \uicontrol {Handling Signal}
|
||||||
\li Displays the time when a signal is handled and how long the
|
\li Displays the time when a signal is handled and how long the
|
||||||
handling takes.
|
handling takes.
|
||||||
\li Qt 4.7.4
|
|
||||||
\li Qt Quick 1 or Qt Quick 2
|
|
||||||
|
|
||||||
\row
|
\row
|
||||||
\li \uicontrol JavaScript
|
\li \uicontrol JavaScript
|
||||||
\li Displays the time spent executing the actual JavaScript behind
|
\li Displays the time spent executing the actual JavaScript behind
|
||||||
bindings and signal handlers. It lists all the JavaScript functions
|
bindings and signal handlers. It lists all the JavaScript functions
|
||||||
you may be using to evaluate bindings or handle signals.
|
you may be using to evaluate bindings or handle signals.
|
||||||
\li Qt 5.3
|
|
||||||
\li Qt Quick 2
|
|
||||||
|
|
||||||
\row
|
\row
|
||||||
\li \uicontrol Quick3D
|
\li \uicontrol Quick3D
|
||||||
\li Displays the time spent rendering Qt Quick 3D frames, timing information
|
\li Displays the time spent rendering Qt Quick 3D frames, timing information
|
||||||
for frame preparation and synchronization, particle system update times
|
for frame preparation and synchronization, particle system update times
|
||||||
and particle update count, as well as texture and mesh memory allocations
|
and particle update count, as well as texture and mesh memory allocations
|
||||||
and memory consumption.
|
and memory consumption.
|
||||||
\li Qt 6.3
|
|
||||||
\li Qt Quick 3D
|
|
||||||
|
|
||||||
|
This event type is available since Qt 6.3.
|
||||||
\endtable
|
\endtable
|
||||||
|
|
||||||
\section2 Analyzing Scene Graph Events
|
\section2 Analyzing Scene Graph Events
|
||||||
@@ -399,7 +357,6 @@
|
|||||||
\li Render Loop Types
|
\li Render Loop Types
|
||||||
\li Label in output of QSG_RENDER_TIMING
|
\li Label in output of QSG_RENDER_TIMING
|
||||||
\li Description
|
\li Description
|
||||||
\li Caveats
|
|
||||||
\row
|
\row
|
||||||
\li \uicontrol {Polish}
|
\li \uicontrol {Polish}
|
||||||
\li GUI
|
\li GUI
|
||||||
@@ -407,8 +364,6 @@
|
|||||||
\li polish
|
\li polish
|
||||||
\li Final touch-up of items before they are rendered using
|
\li Final touch-up of items before they are rendered using
|
||||||
QQuickItem::updatePolish().
|
QQuickItem::updatePolish().
|
||||||
\li Versions of Qt prior to Qt 5.4 record no polish times for the basic
|
|
||||||
render loop and incorrect ones for the windows render loop.
|
|
||||||
\row
|
\row
|
||||||
\li \uicontrol {GUI Thread Wait}
|
\li \uicontrol {GUI Thread Wait}
|
||||||
\li GUI
|
\li GUI
|
||||||
@@ -419,14 +374,12 @@
|
|||||||
the same mutex at \uicontrol {GUI Thread Sync}. If this starts long
|
the same mutex at \uicontrol {GUI Thread Sync}. If this starts long
|
||||||
before \uicontrol {Render Thread Sync}, there is \e free time in the GUI
|
before \uicontrol {Render Thread Sync}, there is \e free time in the GUI
|
||||||
thread you could be using for running additional QML or JavaScript.
|
thread you could be using for running additional QML or JavaScript.
|
||||||
\li None
|
|
||||||
\row
|
\row
|
||||||
\li \uicontrol {GUI Thread Sync}
|
\li \uicontrol {GUI Thread Sync}
|
||||||
\li GUI
|
\li GUI
|
||||||
\li Threaded
|
\li Threaded
|
||||||
\li blockedForSync
|
\li blockedForSync
|
||||||
\li The time the GUI thread is blocked, waiting for the render thread.
|
\li The time the GUI thread is blocked, waiting for the render thread.
|
||||||
\li None
|
|
||||||
\row
|
\row
|
||||||
\li \uicontrol {Animations}
|
\li \uicontrol {Animations}
|
||||||
\li GUI
|
\li GUI
|
||||||
@@ -437,7 +390,6 @@
|
|||||||
animation events will be shown when using the basic render loop.
|
animation events will be shown when using the basic render loop.
|
||||||
Watch the \uicontrol {Animations} category to see animation timing in
|
Watch the \uicontrol {Animations} category to see animation timing in
|
||||||
this case.
|
this case.
|
||||||
\li None
|
|
||||||
\row
|
\row
|
||||||
\li \uicontrol {Render Thread Sync}
|
\li \uicontrol {Render Thread Sync}
|
||||||
\li Render
|
\li Render
|
||||||
@@ -445,7 +397,6 @@
|
|||||||
\li Frame rendered ... sync
|
\li Frame rendered ... sync
|
||||||
\li Synchronizing the QML state into the scene graph using
|
\li Synchronizing the QML state into the scene graph using
|
||||||
QQuickItem::updatePaintNode().
|
QQuickItem::updatePaintNode().
|
||||||
\li None
|
|
||||||
\row
|
\row
|
||||||
\li \uicontrol {Render}
|
\li \uicontrol {Render}
|
||||||
\li Render
|
\li Render
|
||||||
@@ -455,20 +406,12 @@
|
|||||||
uploading all the necessary data to the GPU. This is the \e gross
|
uploading all the necessary data to the GPU. This is the \e gross
|
||||||
render time. Do not confuse it with the \e net \uicontrol{Render Render}
|
render time. Do not confuse it with the \e net \uicontrol{Render Render}
|
||||||
time below.
|
time below.
|
||||||
\li With versions of Qt prior to Qt 5.5, the gross render time and the
|
|
||||||
below breakup of render times may be misaligned by some
|
|
||||||
microseconds due to different, unsynchronized timers being used to
|
|
||||||
measure them. For example \uicontrol {Render Preprocess} might seem to
|
|
||||||
start before \uicontrol {Render Thread Sync} is finished.
|
|
||||||
\row
|
\row
|
||||||
\li \uicontrol {Swap}
|
\li \uicontrol {Swap}
|
||||||
\li Render
|
\li Render
|
||||||
\li Threaded, Basic, Windows
|
\li Threaded, Basic, Windows
|
||||||
\li Frame rendered ... swap
|
\li Frame rendered ... swap
|
||||||
\li Swapping frames after rendering.
|
\li Swapping frames after rendering.
|
||||||
\li The output of swap times triggered by setting QSG_RENDER_TIMING is
|
|
||||||
incorrect for the basic render loop and versions of Qt prior to
|
|
||||||
Qt 5.4. QML Profiler shows the correct swap times.
|
|
||||||
\row
|
\row
|
||||||
\li \uicontrol {Render Preprocess}
|
\li \uicontrol {Render Preprocess}
|
||||||
\li Render
|
\li Render
|
||||||
@@ -476,8 +419,6 @@
|
|||||||
\li time in renderer ... preprocess
|
\li time in renderer ... preprocess
|
||||||
\li Calling QSGNode::preprocess() on all nodes that need to be
|
\li Calling QSGNode::preprocess() on all nodes that need to be
|
||||||
preprocessed. This is part of the gross \uicontrol {Render} step.
|
preprocessed. This is part of the gross \uicontrol {Render} step.
|
||||||
\li May not be properly aligned with \uicontrol {Render} with versions of Qt
|
|
||||||
prior to Qt 5.5.
|
|
||||||
\row
|
\row
|
||||||
\li \uicontrol {Render Update}
|
\li \uicontrol {Render Update}
|
||||||
\li Render
|
\li Render
|
||||||
@@ -489,8 +430,6 @@
|
|||||||
with state from the GUI thread. In \uicontrol {Render Update}, all the
|
with state from the GUI thread. In \uicontrol {Render Update}, all the
|
||||||
nodes are combined to create the final scene. This is part of the
|
nodes are combined to create the final scene. This is part of the
|
||||||
gross \uicontrol {Render} step.
|
gross \uicontrol {Render} step.
|
||||||
\li May not be properly aligned with \uicontrol {Render} with versions of Qt
|
|
||||||
prior to Qt 5.5.
|
|
||||||
\row
|
\row
|
||||||
\li \uicontrol {Render Bind}
|
\li \uicontrol {Render Bind}
|
||||||
\li Render
|
\li Render
|
||||||
@@ -498,8 +437,6 @@
|
|||||||
\li time in renderer ... binding
|
\li time in renderer ... binding
|
||||||
\li Binding the correct framebuffer for OpenGL rendering. This is part
|
\li Binding the correct framebuffer for OpenGL rendering. This is part
|
||||||
of the gross \uicontrol {Render} step.
|
of the gross \uicontrol {Render} step.
|
||||||
\li May not be properly aligned with \uicontrol {Render} with versions of Qt
|
|
||||||
prior to Qt 5.5.
|
|
||||||
\row
|
\row
|
||||||
\li \uicontrol {Render Render}
|
\li \uicontrol {Render Render}
|
||||||
\li Render
|
\li Render
|
||||||
@@ -507,38 +444,30 @@
|
|||||||
\li time in renderer ... rendering
|
\li time in renderer ... rendering
|
||||||
\li The actual process of sending all the data to the GPU via OpenGL.
|
\li The actual process of sending all the data to the GPU via OpenGL.
|
||||||
This is part of the gross \uicontrol {Render} step.
|
This is part of the gross \uicontrol {Render} step.
|
||||||
\li May not be properly aligned with \uicontrol {Render} with versions of Qt
|
|
||||||
prior to Qt 5.5.
|
|
||||||
\row
|
\row
|
||||||
\li \uicontrol {Material Compile}
|
\li \uicontrol {Material Compile}
|
||||||
\li Render
|
\li Render
|
||||||
\li Threaded, Basic, Windows
|
\li Threaded, Basic, Windows
|
||||||
\li shader compiled
|
\li shader compiled
|
||||||
\li Compiling GLSL shader programs.
|
\li Compiling GLSL shader programs.
|
||||||
\li None
|
|
||||||
\row
|
\row
|
||||||
\li \uicontrol {Glyph Render}
|
\li \uicontrol {Glyph Render}
|
||||||
\li Render
|
\li Render
|
||||||
\li Threaded, Basic, Windows
|
\li Threaded, Basic, Windows
|
||||||
\li glyphs ... rendering
|
\li glyphs ... rendering
|
||||||
\li Rendering of font glyphs into textures.
|
\li Rendering of font glyphs into textures.
|
||||||
\li Versions of Qt prior to Qt 5.4 report incorrect times for these
|
|
||||||
events.
|
|
||||||
\row
|
\row
|
||||||
\li \uicontrol {Glyph Upload}
|
\li \uicontrol {Glyph Upload}
|
||||||
\li Render
|
\li Render
|
||||||
\li Threaded, Basic, Windows
|
\li Threaded, Basic, Windows
|
||||||
\li glyphs ... upload
|
\li glyphs ... upload
|
||||||
\li Uploading of glyph textures to the GPU.
|
\li Uploading of glyph textures to the GPU.
|
||||||
\li Versions of Qt prior to Qt 5.4 report incorrect times for these
|
|
||||||
events.
|
|
||||||
\row
|
\row
|
||||||
\li \uicontrol {Texture Bind}
|
\li \uicontrol {Texture Bind}
|
||||||
\li Render
|
\li Render
|
||||||
\li Threaded, Basic, Windows
|
\li Threaded, Basic, Windows
|
||||||
\li plain texture ... bind
|
\li plain texture ... bind
|
||||||
\li Binding a texture in the OpenGL context using glBindTextures.
|
\li Binding a texture in the OpenGL context using glBindTextures.
|
||||||
\li None
|
|
||||||
\row
|
\row
|
||||||
\li \uicontrol {Texture Convert}
|
\li \uicontrol {Texture Convert}
|
||||||
\li Render
|
\li Render
|
||||||
@@ -546,35 +475,30 @@
|
|||||||
\li plain texture ... convert
|
\li plain texture ... convert
|
||||||
\li Converting the format and downscaling an image to make it suitable
|
\li Converting the format and downscaling an image to make it suitable
|
||||||
for usage as a texture.
|
for usage as a texture.
|
||||||
\li None
|
|
||||||
\row
|
\row
|
||||||
\li \uicontrol {Texture Swizzle}
|
\li \uicontrol {Texture Swizzle}
|
||||||
\li Render
|
\li Render
|
||||||
\li Threaded, Basic, Windows
|
\li Threaded, Basic, Windows
|
||||||
\li plain texture ... swizzle
|
\li plain texture ... swizzle
|
||||||
\li Swizzling the texture data on the CPU if necessary.
|
\li Swizzling the texture data on the CPU if necessary.
|
||||||
\li None
|
|
||||||
\row
|
\row
|
||||||
\li \uicontrol {Texture Upload}
|
\li \uicontrol {Texture Upload}
|
||||||
\li Render
|
\li Render
|
||||||
\li Threaded, Basic, Windows
|
\li Threaded, Basic, Windows
|
||||||
\li plain texture ... upload / atlastexture uploaded
|
\li plain texture ... upload / atlastexture uploaded
|
||||||
\li Uploading the texture data to the GPU.
|
\li Uploading the texture data to the GPU.
|
||||||
\li None
|
|
||||||
\row
|
\row
|
||||||
\li \uicontrol {Texture Mipmap}
|
\li \uicontrol {Texture Mipmap}
|
||||||
\li Render
|
\li Render
|
||||||
\li Threaded, Basic, Windows
|
\li Threaded, Basic, Windows
|
||||||
\li plain texture ... mipmap
|
\li plain texture ... mipmap
|
||||||
\li Mipmapping a texture on the GPU.
|
\li Mipmapping a texture on the GPU.
|
||||||
\li None
|
|
||||||
\row
|
\row
|
||||||
\li \uicontrol {Texture Delete}
|
\li \uicontrol {Texture Delete}
|
||||||
\li Render
|
\li Render
|
||||||
\li Threaded, Basic, Windows
|
\li Threaded, Basic, Windows
|
||||||
\li plain texture deleted
|
\li plain texture deleted
|
||||||
\li Deleting a texture from the GPU that became unnecessary.
|
\li Deleting a texture from the GPU that became unnecessary.
|
||||||
\li None
|
|
||||||
\endtable
|
\endtable
|
||||||
|
|
||||||
\section2 Analyzing Qt Quick 3D Events
|
\section2 Analyzing Qt Quick 3D Events
|
||||||
@@ -676,9 +600,6 @@
|
|||||||
To copy the contents of one view or row to the clipboard, select
|
To copy the contents of one view or row to the clipboard, select
|
||||||
\uicontrol {Copy Table} or \uicontrol {Copy Row} in the context menu.
|
\uicontrol {Copy Table} or \uicontrol {Copy Row} in the context menu.
|
||||||
|
|
||||||
JavaScript events are shown in the \uicontrol Statistics view only for applications
|
|
||||||
that use Qt Quick 2 and are built with Qt 5.3 or later.
|
|
||||||
|
|
||||||
\section2 Visualizing Statistics as Flame Graphs
|
\section2 Visualizing Statistics as Flame Graphs
|
||||||
|
|
||||||
The \uicontrol {Flame Graph} view shows a more concise statistical overview
|
The \uicontrol {Flame Graph} view shows a more concise statistical overview
|
||||||
|
@@ -3,6 +3,7 @@ set(resource_directories
|
|||||||
cplusplus
|
cplusplus
|
||||||
glsl
|
glsl
|
||||||
indexer_preincludes
|
indexer_preincludes
|
||||||
|
jsonschemas
|
||||||
modeleditor
|
modeleditor
|
||||||
qmldesigner
|
qmldesigner
|
||||||
qmlicons
|
qmlicons
|
||||||
|
57
share/qtcreator/jsonschemas/project.json
Normal file
57
share/qtcreator/jsonschemas/project.json
Normal file
@@ -0,0 +1,57 @@
|
|||||||
|
{
|
||||||
|
"$schema": "http://json-schema.org/draft-04/schema#",
|
||||||
|
"title": "Qt Creator workspace project definition",
|
||||||
|
"description": "A Qt Creator workspace project definition",
|
||||||
|
"type": "object",
|
||||||
|
"properties": {
|
||||||
|
"project.name": {
|
||||||
|
"type": "string",
|
||||||
|
"description": "The name of the project"
|
||||||
|
},
|
||||||
|
"files.exclude": {
|
||||||
|
"type": "array",
|
||||||
|
"items": [
|
||||||
|
{
|
||||||
|
"type": "string"
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"description": "Files to exclude from the project"
|
||||||
|
},
|
||||||
|
"targets": {
|
||||||
|
"type": "array",
|
||||||
|
"description": "A list of targets",
|
||||||
|
"items": [
|
||||||
|
{
|
||||||
|
"type": "object",
|
||||||
|
"properties": {
|
||||||
|
"arguments": {
|
||||||
|
"type": "array",
|
||||||
|
"items": [
|
||||||
|
{
|
||||||
|
"type": "string"
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"description": "Arguments to pass to the executable"
|
||||||
|
},
|
||||||
|
"executable": {
|
||||||
|
"type": "string",
|
||||||
|
"description": "The executable to run"
|
||||||
|
},
|
||||||
|
"name": {
|
||||||
|
"type": "string",
|
||||||
|
"description": "The name of the target"
|
||||||
|
},
|
||||||
|
"workingDirectory": {
|
||||||
|
"type": "string",
|
||||||
|
"description": "The working directory to run the executable in"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"required": [
|
||||||
|
"executable",
|
||||||
|
"name"
|
||||||
|
]
|
||||||
|
}
|
||||||
|
]
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
@@ -36,3 +36,8 @@ Token_Notification_Alert=ffc98014
|
|||||||
Token_Notification_Success=ff1f9b5d
|
Token_Notification_Success=ff1f9b5d
|
||||||
Token_Notification_Neutral=ff016876
|
Token_Notification_Neutral=ff016876
|
||||||
Token_Notification_Danger=ffb22245
|
Token_Notification_Danger=ffb22245
|
||||||
|
|
||||||
|
Token_Gradient01_Start=ff016876
|
||||||
|
Token_Gradient01_End=ff1F9B5D
|
||||||
|
Token_Gradient02_Start=ff3A3A3A
|
||||||
|
Token_Gradient02_End=ff838383
|
||||||
|
@@ -35,3 +35,8 @@ Token_Notification_Alert=ffeb991f
|
|||||||
Token_Notification_Success=ff23b26a
|
Token_Notification_Success=ff23b26a
|
||||||
Token_Notification_Neutral=ff0e7887
|
Token_Notification_Neutral=ff0e7887
|
||||||
Token_Notification_Danger=ffdc1343
|
Token_Notification_Danger=ffdc1343
|
||||||
|
|
||||||
|
Token_Gradient01_Start=ff23B26A
|
||||||
|
Token_Gradient01_End=ff0E7887
|
||||||
|
Token_Gradient02_Start=ff949494
|
||||||
|
Token_Gradient02_End=ff474747
|
||||||
|
@@ -16,6 +16,7 @@ Product {
|
|||||||
"debugger/**/*",
|
"debugger/**/*",
|
||||||
"designer/**/*",
|
"designer/**/*",
|
||||||
"glsl/**/*",
|
"glsl/**/*",
|
||||||
|
"jsonschemas/**/*",
|
||||||
"modeleditor/**/*",
|
"modeleditor/**/*",
|
||||||
"qml/**/*",
|
"qml/**/*",
|
||||||
"qmldesigner/**/*",
|
"qmldesigner/**/*",
|
||||||
|
@@ -307,7 +307,7 @@ recognize:
|
|||||||
|
|
||||||
if (currentExpanded) {
|
if (currentExpanded) {
|
||||||
QTC_ASSERT(macroOffset != -1 && macroLength != -1, continue);
|
QTC_ASSERT(macroOffset != -1 && macroLength != -1, continue);
|
||||||
_expansionPositions[_tokens->size() - 1] = std::make_pair(macroOffset, macroLength);
|
_expansionPositions[int(_tokens->size()) - 1] = std::make_pair(macroOffset, macroLength);
|
||||||
}
|
}
|
||||||
} while (tk.kind());
|
} while (tk.kind());
|
||||||
|
|
||||||
|
@@ -627,10 +627,14 @@ void PluginSpec::setEnabledIndirectly(bool value)
|
|||||||
}
|
}
|
||||||
void PluginSpec::setForceDisabled(bool value)
|
void PluginSpec::setForceDisabled(bool value)
|
||||||
{
|
{
|
||||||
|
if (value)
|
||||||
|
d->forceEnabled = false;
|
||||||
d->forceDisabled = value;
|
d->forceDisabled = value;
|
||||||
}
|
}
|
||||||
void PluginSpec::setForceEnabled(bool value)
|
void PluginSpec::setForceEnabled(bool value)
|
||||||
{
|
{
|
||||||
|
if (value)
|
||||||
|
d->forceDisabled = false;
|
||||||
d->forceEnabled = value;
|
d->forceEnabled = value;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@@ -1157,11 +1157,8 @@ QColor StereotypeDefinitionParser::parseColorExpression()
|
|||||||
Token token = d->m_scanner->read();
|
Token token = d->m_scanner->read();
|
||||||
if (token.type() == Token::TokenIdentifier || token.type() == Token::TokenColor) {
|
if (token.type() == Token::TokenIdentifier || token.type() == Token::TokenColor) {
|
||||||
QString value = token.text().toLower();
|
QString value = token.text().toLower();
|
||||||
QColor color;
|
if (QColor::isValidColorName(value))
|
||||||
if (QColor::isValidColor(value)) {
|
return QColor::fromString(value);
|
||||||
color.setNamedColor(value);
|
|
||||||
return color;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
throw StereotypeDefinitionParserError("Expected color name.", token.sourcePos());
|
throw StereotypeDefinitionParserError("Expected color name.", token.sourcePos());
|
||||||
}
|
}
|
||||||
@@ -1191,9 +1188,8 @@ StereotypeDefinitionParser::Value StereotypeDefinitionParser::parseExpression()
|
|||||||
return Value(Float, QVariant(value));
|
return Value(Float, QVariant(value));
|
||||||
} else if (token.type() == Token::TokenColor) {
|
} else if (token.type() == Token::TokenColor) {
|
||||||
QString value = token.text().toLower();
|
QString value = token.text().toLower();
|
||||||
QColor color;
|
if (QColor::isValidColorName(value)) {
|
||||||
if (QColor::isValidColor(value)) {
|
const QColor color = QColor::fromString(value);
|
||||||
color.setNamedColor(value);
|
|
||||||
return Value(Color, QVariant(color));
|
return Value(Color, QVariant(color));
|
||||||
} else {
|
} else {
|
||||||
throw StereotypeDefinitionParserError("Invalid color.", token.sourcePos());
|
throw StereotypeDefinitionParserError("Invalid color.", token.sourcePos());
|
||||||
|
@@ -73,7 +73,7 @@ ModelTreeFilter::ModelTreeFilter(QWidget *parent) :
|
|||||||
},
|
},
|
||||||
d->relationsCheckBox,
|
d->relationsCheckBox,
|
||||||
d->diagramElementsCheckBox,
|
d->diagramElementsCheckBox,
|
||||||
customMargin({margin, 0, margin, 0}),
|
customMargins(margin, 0, margin, 0),
|
||||||
},
|
},
|
||||||
Space(10),
|
Space(10),
|
||||||
line(),
|
line(),
|
||||||
@@ -88,11 +88,11 @@ ModelTreeFilter::ModelTreeFilter(QWidget *parent) :
|
|||||||
Tr::tr("Name:"), d->nameLineEdit, br,
|
Tr::tr("Name:"), d->nameLineEdit, br,
|
||||||
Tr::tr("Direction:"), d->directionComboBox, br,
|
Tr::tr("Direction:"), d->directionComboBox, br,
|
||||||
},
|
},
|
||||||
customMargin({margin, 0, margin, 0}),
|
customMargins(margin, 0, margin, 0),
|
||||||
},
|
},
|
||||||
st,
|
st,
|
||||||
line(),
|
line(),
|
||||||
customMargin({0, margin, 0, 0}),
|
customMargins(0, margin, 0, 0),
|
||||||
}.attachTo(this);
|
}.attachTo(this);
|
||||||
|
|
||||||
connect(d->resetViewButton, &QPushButton::clicked, this, &ModelTreeFilter::resetView);
|
connect(d->resetViewButton, &QPushButton::clicked, this, &ModelTreeFilter::resetView);
|
||||||
|
@@ -6,23 +6,20 @@
|
|||||||
namespace Tasking {
|
namespace Tasking {
|
||||||
|
|
||||||
// That's cut down qtcassert.{c,h} to avoid the dependency.
|
// That's cut down qtcassert.{c,h} to avoid the dependency.
|
||||||
#define QTC_STRINGIFY_HELPER(x) #x
|
#define QT_STRING(cond) qDebug("SOFT ASSERT: \"%s\" in %s: %s", cond, __FILE__, QT_STRINGIFY(__LINE__))
|
||||||
#define QTC_STRINGIFY(x) QTC_STRINGIFY_HELPER(x)
|
#define QT_ASSERT(cond, action) if (Q_LIKELY(cond)) {} else { QT_STRING(#cond); action; } do {} while (0)
|
||||||
#define QTC_STRING(cond) qDebug("SOFT ASSERT: \"%s\" in %s: %s", cond, __FILE__, QTC_STRINGIFY(__LINE__))
|
|
||||||
#define QTC_ASSERT(cond, action) if (Q_LIKELY(cond)) {} else { QTC_STRING(#cond); action; } do {} while (0)
|
|
||||||
#define QTC_CHECK(cond) if (cond) {} else { QTC_STRING(#cond); } do {} while (0)
|
|
||||||
|
|
||||||
void Barrier::setLimit(int value)
|
void Barrier::setLimit(int value)
|
||||||
{
|
{
|
||||||
QTC_ASSERT(!isRunning(), return);
|
QT_ASSERT(!isRunning(), return);
|
||||||
QTC_ASSERT(value > 0, return);
|
QT_ASSERT(value > 0, return);
|
||||||
|
|
||||||
m_limit = value;
|
m_limit = value;
|
||||||
}
|
}
|
||||||
|
|
||||||
void Barrier::start()
|
void Barrier::start()
|
||||||
{
|
{
|
||||||
QTC_ASSERT(!isRunning(), return);
|
QT_ASSERT(!isRunning(), return);
|
||||||
m_current = 0;
|
m_current = 0;
|
||||||
m_result = {};
|
m_result = {};
|
||||||
}
|
}
|
||||||
@@ -30,7 +27,7 @@ void Barrier::start()
|
|||||||
void Barrier::advance()
|
void Barrier::advance()
|
||||||
{
|
{
|
||||||
// Calling advance on finished is OK
|
// Calling advance on finished is OK
|
||||||
QTC_ASSERT(isRunning() || m_result, return);
|
QT_ASSERT(isRunning() || m_result, return);
|
||||||
if (!isRunning()) // no-op
|
if (!isRunning()) // no-op
|
||||||
return;
|
return;
|
||||||
++m_current;
|
++m_current;
|
||||||
@@ -41,7 +38,7 @@ void Barrier::advance()
|
|||||||
void Barrier::stopWithResult(DoneResult result)
|
void Barrier::stopWithResult(DoneResult result)
|
||||||
{
|
{
|
||||||
// Calling stopWithResult on finished is OK when the same success is passed
|
// Calling stopWithResult on finished is OK when the same success is passed
|
||||||
QTC_ASSERT(isRunning() || (m_result && *m_result == result), return);
|
QT_ASSERT(isRunning() || (m_result && *m_result == result), return);
|
||||||
if (!isRunning()) // no-op
|
if (!isRunning()) // no-op
|
||||||
return;
|
return;
|
||||||
m_current = -1;
|
m_current = -1;
|
||||||
|
@@ -25,7 +25,7 @@ public:
|
|||||||
int current() const { return m_current; }
|
int current() const { return m_current; }
|
||||||
std::optional<DoneResult> result() const { return m_result; }
|
std::optional<DoneResult> result() const { return m_result; }
|
||||||
|
|
||||||
signals:
|
Q_SIGNALS:
|
||||||
void done(DoneResult success);
|
void done(DoneResult success);
|
||||||
|
|
||||||
private:
|
private:
|
||||||
|
@@ -5,7 +5,7 @@
|
|||||||
|
|
||||||
#include "tasktree.h"
|
#include "tasktree.h"
|
||||||
|
|
||||||
#include <QtConcurrent>
|
#include <QtConcurrent/QtConcurrent>
|
||||||
|
|
||||||
namespace Tasking {
|
namespace Tasking {
|
||||||
|
|
||||||
@@ -76,7 +76,7 @@ public:
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void start() {
|
void start() final {
|
||||||
if (!this->task()->m_startHandler) {
|
if (!this->task()->m_startHandler) {
|
||||||
emit this->done(DoneResult::Error); // TODO: Add runtime assert
|
emit this->done(DoneResult::Error); // TODO: Add runtime assert
|
||||||
return;
|
return;
|
||||||
|
@@ -3,7 +3,7 @@
|
|||||||
|
|
||||||
#include "networkquery.h"
|
#include "networkquery.h"
|
||||||
|
|
||||||
#include <QNetworkAccessManager>
|
#include <QtNetwork/QNetworkAccessManager>
|
||||||
|
|
||||||
namespace Tasking {
|
namespace Tasking {
|
||||||
|
|
||||||
|
@@ -7,8 +7,8 @@
|
|||||||
|
|
||||||
#include "tasktree.h"
|
#include "tasktree.h"
|
||||||
|
|
||||||
#include <QNetworkReply>
|
#include <QtNetwork/QNetworkReply>
|
||||||
#include <QNetworkRequest>
|
#include <QtNetwork/QNetworkRequest>
|
||||||
|
|
||||||
#include <memory>
|
#include <memory>
|
||||||
|
|
||||||
@@ -37,7 +37,7 @@ public:
|
|||||||
QNetworkReply *reply() const { return m_reply.get(); }
|
QNetworkReply *reply() const { return m_reply.get(); }
|
||||||
void start();
|
void start();
|
||||||
|
|
||||||
signals:
|
Q_SIGNALS:
|
||||||
void started();
|
void started();
|
||||||
void done(DoneResult result);
|
void done(DoneResult result);
|
||||||
|
|
||||||
|
@@ -3,12 +3,12 @@
|
|||||||
|
|
||||||
#include "qprocesstask.h"
|
#include "qprocesstask.h"
|
||||||
|
|
||||||
#include <QCoreApplication>
|
#include <QtCore/QCoreApplication>
|
||||||
#include <QDebug>
|
#include <QtCore/QDebug>
|
||||||
#include <QMutex>
|
#include <QtCore/QMutex>
|
||||||
#include <QThread>
|
#include <QtCore/QThread>
|
||||||
#include <QTimer>
|
#include <QtCore/QTimer>
|
||||||
#include <QWaitCondition>
|
#include <QtCore/QWaitCondition>
|
||||||
|
|
||||||
namespace Tasking {
|
namespace Tasking {
|
||||||
|
|
||||||
@@ -60,7 +60,7 @@ public:
|
|||||||
terminate();
|
terminate();
|
||||||
}
|
}
|
||||||
|
|
||||||
signals:
|
Q_SIGNALS:
|
||||||
void finished();
|
void finished();
|
||||||
|
|
||||||
private:
|
private:
|
||||||
|
@@ -7,7 +7,7 @@
|
|||||||
|
|
||||||
#include "tasktree.h"
|
#include "tasktree.h"
|
||||||
|
|
||||||
#include <QProcess>
|
#include <QtCore/QProcess>
|
||||||
|
|
||||||
namespace Tasking {
|
namespace Tasking {
|
||||||
|
|
||||||
@@ -45,17 +45,17 @@ public:
|
|||||||
class TASKING_EXPORT QProcessAdapter : public TaskAdapter<QProcess, QProcessDeleter>
|
class TASKING_EXPORT QProcessAdapter : public TaskAdapter<QProcess, QProcessDeleter>
|
||||||
{
|
{
|
||||||
private:
|
private:
|
||||||
void start() override {
|
void start() final {
|
||||||
connect(task(), &QProcess::finished, this, [this] {
|
connect(task(), &QProcess::finished, this, [this] {
|
||||||
const bool success = task()->exitStatus() == QProcess::NormalExit
|
const bool success = task()->exitStatus() == QProcess::NormalExit
|
||||||
&& task()->error() == QProcess::UnknownError
|
&& task()->error() == QProcess::UnknownError
|
||||||
&& task()->exitCode() == 0;
|
&& task()->exitCode() == 0;
|
||||||
emit done(toDoneResult(success));
|
Q_EMIT done(toDoneResult(success));
|
||||||
});
|
});
|
||||||
connect(task(), &QProcess::errorOccurred, this, [this](QProcess::ProcessError error) {
|
connect(task(), &QProcess::errorOccurred, this, [this](QProcess::ProcessError error) {
|
||||||
if (error != QProcess::FailedToStart)
|
if (error != QProcess::FailedToStart)
|
||||||
return;
|
return;
|
||||||
emit done(DoneResult::Error);
|
Q_EMIT done(DoneResult::Error);
|
||||||
});
|
});
|
||||||
task()->start();
|
task()->start();
|
||||||
}
|
}
|
||||||
|
@@ -3,7 +3,7 @@
|
|||||||
|
|
||||||
#pragma once
|
#pragma once
|
||||||
|
|
||||||
#include <qglobal.h>
|
#include <QtCore/qglobal.h>
|
||||||
|
|
||||||
#if defined(TASKING_LIBRARY)
|
#if defined(TASKING_LIBRARY)
|
||||||
# define TASKING_EXPORT Q_DECL_EXPORT
|
# define TASKING_EXPORT Q_DECL_EXPORT
|
||||||
|
@@ -5,17 +5,17 @@
|
|||||||
|
|
||||||
#include "barrier.h"
|
#include "barrier.h"
|
||||||
|
|
||||||
#include <QDebug>
|
#include <QtCore/QDebug>
|
||||||
#include <QEventLoop>
|
#include <QtCore/QEventLoop>
|
||||||
#include <QFutureWatcher>
|
#include <QtCore/QFutureWatcher>
|
||||||
#include <QHash>
|
#include <QtCore/QHash>
|
||||||
#include <QMetaEnum>
|
#include <QtCore/QMetaEnum>
|
||||||
#include <QMutex>
|
#include <QtCore/QMutex>
|
||||||
#include <QPromise>
|
#include <QtCore/QPointer>
|
||||||
#include <QPointer>
|
#include <QtCore/QPromise>
|
||||||
#include <QSet>
|
#include <QtCore/QSet>
|
||||||
#include <QTime>
|
#include <QtCore/QTime>
|
||||||
#include <QTimer>
|
#include <QtCore/QTimer>
|
||||||
|
|
||||||
using namespace std::chrono;
|
using namespace std::chrono;
|
||||||
|
|
||||||
@@ -1461,7 +1461,7 @@ static QString currentTime() { return QTime::currentTime().toString(Qt::ISODateW
|
|||||||
ExecutableItem ExecutableItem::withLog(const QString &logName) const
|
ExecutableItem ExecutableItem::withLog(const QString &logName) const
|
||||||
{
|
{
|
||||||
const auto header = [logName] {
|
const auto header = [logName] {
|
||||||
return QString("TASK TREE LOG [%1] \"%2\"").arg(currentTime(), logName);
|
return QString::fromLatin1("TASK TREE LOG [%1] \"%2\"").arg(currentTime(), logName);
|
||||||
};
|
};
|
||||||
struct LogStorage
|
struct LogStorage
|
||||||
{
|
{
|
||||||
@@ -1482,8 +1482,8 @@ ExecutableItem ExecutableItem::withLog(const QString &logName) const
|
|||||||
const int asyncCountDiff = activeTaskTree()->asyncCount() - storage->asyncCount;
|
const int asyncCountDiff = activeTaskTree()->asyncCount() - storage->asyncCount;
|
||||||
QT_CHECK(asyncCountDiff >= 0);
|
QT_CHECK(asyncCountDiff >= 0);
|
||||||
const QMetaEnum doneWithEnum = QMetaEnum::fromType<DoneWith>();
|
const QMetaEnum doneWithEnum = QMetaEnum::fromType<DoneWith>();
|
||||||
const QString syncType = asyncCountDiff ? QString("asynchronously")
|
const QString syncType = asyncCountDiff ? QString::fromLatin1("asynchronously")
|
||||||
: QString("synchronously");
|
: QString::fromLatin1("synchronously");
|
||||||
qDebug().noquote().nospace() << header() << " finished " << syncType << " with "
|
qDebug().noquote().nospace() << header() << " finished " << syncType << " with "
|
||||||
<< doneWithEnum.valueToKey(int(result)) << " within " << elapsed.count() << "ms.";
|
<< doneWithEnum.valueToKey(int(result)) << " within " << elapsed.count() << "ms.";
|
||||||
})
|
})
|
||||||
|
@@ -5,8 +5,8 @@
|
|||||||
|
|
||||||
#include "tasking_global.h"
|
#include "tasking_global.h"
|
||||||
|
|
||||||
#include <QObject>
|
#include <QtCore/QList>
|
||||||
#include <QList>
|
#include <QtCore/QObject>
|
||||||
|
|
||||||
#include <memory>
|
#include <memory>
|
||||||
|
|
||||||
@@ -84,7 +84,7 @@ class TASKING_EXPORT TaskInterface : public QObject
|
|||||||
{
|
{
|
||||||
Q_OBJECT
|
Q_OBJECT
|
||||||
|
|
||||||
signals:
|
Q_SIGNALS:
|
||||||
void done(DoneResult result);
|
void done(DoneResult result);
|
||||||
|
|
||||||
private:
|
private:
|
||||||
@@ -345,7 +345,7 @@ private:
|
|||||||
std::invoke(handler);
|
std::invoke(handler);
|
||||||
return SetupResult::Continue;
|
return SetupResult::Continue;
|
||||||
};
|
};
|
||||||
};
|
}
|
||||||
template <typename Handler>
|
template <typename Handler>
|
||||||
static GroupDoneHandler wrapGroupDone(Handler &&handler)
|
static GroupDoneHandler wrapGroupDone(Handler &&handler)
|
||||||
{
|
{
|
||||||
@@ -368,7 +368,7 @@ private:
|
|||||||
std::invoke(handler);
|
std::invoke(handler);
|
||||||
return result == DoneWith::Success ? DoneResult::Success : DoneResult::Error;
|
return result == DoneWith::Success ? DoneResult::Success : DoneResult::Error;
|
||||||
};
|
};
|
||||||
};
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
template <typename Handler>
|
template <typename Handler>
|
||||||
@@ -433,7 +433,7 @@ private:
|
|||||||
std::invoke(handler);
|
std::invoke(handler);
|
||||||
return SetupResult::StopWithSuccess;
|
return SetupResult::StopWithSuccess;
|
||||||
};
|
};
|
||||||
};
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
template <typename Task, typename Deleter = std::default_delete<Task>>
|
template <typename Task, typename Deleter = std::default_delete<Task>>
|
||||||
@@ -490,7 +490,7 @@ private:
|
|||||||
std::invoke(handler, *adapter.task());
|
std::invoke(handler, *adapter.task());
|
||||||
return SetupResult::Continue;
|
return SetupResult::Continue;
|
||||||
};
|
};
|
||||||
};
|
}
|
||||||
|
|
||||||
template <typename Handler>
|
template <typename Handler>
|
||||||
static InterfaceDoneHandler wrapDone(Handler &&handler) {
|
static InterfaceDoneHandler wrapDone(Handler &&handler) {
|
||||||
@@ -529,7 +529,7 @@ private:
|
|||||||
std::invoke(handler);
|
std::invoke(handler);
|
||||||
return result == DoneWith::Success ? DoneResult::Success : DoneResult::Error;
|
return result == DoneWith::Success ? DoneResult::Success : DoneResult::Error;
|
||||||
};
|
};
|
||||||
};
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
class TASKING_EXPORT TaskTree final : public QObject
|
class TASKING_EXPORT TaskTree final : public QObject
|
||||||
@@ -579,7 +579,7 @@ public:
|
|||||||
wrapHandler<const StorageStruct>(std::forward<Handler>(handler)));
|
wrapHandler<const StorageStruct>(std::forward<Handler>(handler)));
|
||||||
}
|
}
|
||||||
|
|
||||||
signals:
|
Q_SIGNALS:
|
||||||
void started();
|
void started();
|
||||||
void done(DoneWith result);
|
void done(DoneWith result);
|
||||||
void asyncCountChanged(int count);
|
void asyncCountChanged(int count);
|
||||||
|
@@ -6,7 +6,7 @@
|
|||||||
#include "tasking_global.h"
|
#include "tasking_global.h"
|
||||||
#include "tasktree.h"
|
#include "tasktree.h"
|
||||||
|
|
||||||
#include <QObject>
|
#include <QtCore/QObject>
|
||||||
|
|
||||||
namespace Tasking {
|
namespace Tasking {
|
||||||
|
|
||||||
@@ -33,7 +33,7 @@ public:
|
|||||||
// No done() signal is emitted.
|
// No done() signal is emitted.
|
||||||
void reset();
|
void reset();
|
||||||
|
|
||||||
signals:
|
Q_SIGNALS:
|
||||||
void aboutToStart(TaskTree *taskTree);
|
void aboutToStart(TaskTree *taskTree);
|
||||||
void done(DoneWith result);
|
void done(DoneWith result);
|
||||||
|
|
||||||
|
@@ -1410,6 +1410,7 @@ public:
|
|||||||
FilePath m_baseFileName;
|
FilePath m_baseFileName;
|
||||||
StringAspect::ValueAcceptor m_valueAcceptor;
|
StringAspect::ValueAcceptor m_valueAcceptor;
|
||||||
std::optional<FancyLineEdit::ValidationFunction> m_validator;
|
std::optional<FancyLineEdit::ValidationFunction> m_validator;
|
||||||
|
std::optional<FilePath> m_effectiveBinary;
|
||||||
std::function<void()> m_openTerminal;
|
std::function<void()> m_openTerminal;
|
||||||
|
|
||||||
CheckableAspectImplementation m_checkerImpl;
|
CheckableAspectImplementation m_checkerImpl;
|
||||||
@@ -1430,6 +1431,8 @@ FilePathAspect::FilePathAspect(AspectContainer *container)
|
|||||||
|
|
||||||
addDataExtractor(this, &FilePathAspect::value, &Data::value);
|
addDataExtractor(this, &FilePathAspect::value, &Data::value);
|
||||||
addDataExtractor(this, &FilePathAspect::operator(), &Data::filePath);
|
addDataExtractor(this, &FilePathAspect::operator(), &Data::filePath);
|
||||||
|
|
||||||
|
connect(this, &BaseAspect::changed, this, [this] { d->m_effectiveBinary.reset(); });
|
||||||
}
|
}
|
||||||
|
|
||||||
FilePathAspect::~FilePathAspect() = default;
|
FilePathAspect::~FilePathAspect() = default;
|
||||||
@@ -1455,6 +1458,29 @@ FilePath FilePathAspect::expandedValue() const
|
|||||||
return FilePath::fromUserInput(value);
|
return FilePath::fromUserInput(value);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/*!
|
||||||
|
Returns the full path of the set command. Only makes a difference if
|
||||||
|
expected kind is \c Command or \c ExistingCommand and the current
|
||||||
|
file path is an executable provided without its path.
|
||||||
|
Performs a lookup in PATH if necessary.
|
||||||
|
*/
|
||||||
|
FilePath FilePathAspect::effectiveBinary() const
|
||||||
|
{
|
||||||
|
if (d->m_effectiveBinary)
|
||||||
|
return *d->m_effectiveBinary;
|
||||||
|
|
||||||
|
const FilePath current = expandedValue();
|
||||||
|
const PathChooser::Kind kind = d->m_expectedKind;
|
||||||
|
if (kind != PathChooser::ExistingCommand && kind != PathChooser::Command)
|
||||||
|
return current;
|
||||||
|
|
||||||
|
if (current.needsDevice())
|
||||||
|
return current;
|
||||||
|
|
||||||
|
d->m_effectiveBinary.emplace(current.searchInPath());
|
||||||
|
return *d->m_effectiveBinary;
|
||||||
|
}
|
||||||
|
|
||||||
QString FilePathAspect::value() const
|
QString FilePathAspect::value() const
|
||||||
{
|
{
|
||||||
return TypedAspect::value();
|
return TypedAspect::value();
|
||||||
@@ -1693,9 +1719,12 @@ void FilePathAspect::setAutoApplyOnEditingFinished(bool applyOnEditingFinished)
|
|||||||
*/
|
*/
|
||||||
void FilePathAspect::setExpectedKind(const PathChooser::Kind expectedKind)
|
void FilePathAspect::setExpectedKind(const PathChooser::Kind expectedKind)
|
||||||
{
|
{
|
||||||
d->m_expectedKind = expectedKind;
|
if (d->m_expectedKind != expectedKind) {
|
||||||
if (d->m_pathChooserDisplay)
|
d->m_expectedKind = expectedKind;
|
||||||
d->m_pathChooserDisplay->setExpectedKind(expectedKind);
|
d->m_effectiveBinary.reset();
|
||||||
|
if (d->m_pathChooserDisplay)
|
||||||
|
d->m_pathChooserDisplay->setExpectedKind(expectedKind);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void FilePathAspect::setEnvironment(const Environment &env)
|
void FilePathAspect::setEnvironment(const Environment &env)
|
||||||
|
@@ -663,6 +663,7 @@ public:
|
|||||||
};
|
};
|
||||||
|
|
||||||
FilePath operator()() const;
|
FilePath operator()() const;
|
||||||
|
FilePath effectiveBinary() const;
|
||||||
FilePath expandedValue() const;
|
FilePath expandedValue() const;
|
||||||
QString value() const;
|
QString value() const;
|
||||||
void setValue(const FilePath &filePath, Announcement howToAnnounce = DoEmit);
|
void setValue(const FilePath &filePath, Announcement howToAnnounce = DoEmit);
|
||||||
|
@@ -397,7 +397,8 @@ EnvironmentItems EnvironmentModel::userChanges() const
|
|||||||
void EnvironmentModel::setUserChanges(const EnvironmentItems &items)
|
void EnvironmentModel::setUserChanges(const EnvironmentItems &items)
|
||||||
{
|
{
|
||||||
EnvironmentItems filtered = Utils::filtered(items, [](const EnvironmentItem &i) {
|
EnvironmentItems filtered = Utils::filtered(items, [](const EnvironmentItem &i) {
|
||||||
return i.name != "export " && !i.name.contains('=');
|
return i.operation == EnvironmentItem::Comment
|
||||||
|
|| (i.name != "export " && !i.name.contains('='));
|
||||||
});
|
});
|
||||||
// We assume nobody is reordering the items here.
|
// We assume nobody is reordering the items here.
|
||||||
if (filtered == d->m_items)
|
if (filtered == d->m_items)
|
||||||
|
@@ -1230,6 +1230,9 @@ FilePathInfo FilePath::filePathInfo() const
|
|||||||
*/
|
*/
|
||||||
bool FilePath::exists() const
|
bool FilePath::exists() const
|
||||||
{
|
{
|
||||||
|
if (isEmpty())
|
||||||
|
return false;
|
||||||
|
|
||||||
const expected_str<DeviceFileAccess *> access = getFileAccess(*this);
|
const expected_str<DeviceFileAccess *> access = getFileAccess(*this);
|
||||||
if (!access)
|
if (!access)
|
||||||
return false;
|
return false;
|
||||||
@@ -1242,6 +1245,9 @@ bool FilePath::exists() const
|
|||||||
*/
|
*/
|
||||||
bool FilePath::isExecutableFile() const
|
bool FilePath::isExecutableFile() const
|
||||||
{
|
{
|
||||||
|
if (isEmpty())
|
||||||
|
return false;
|
||||||
|
|
||||||
const expected_str<DeviceFileAccess *> access = getFileAccess(*this);
|
const expected_str<DeviceFileAccess *> access = getFileAccess(*this);
|
||||||
if (!access)
|
if (!access)
|
||||||
return false;
|
return false;
|
||||||
@@ -1254,6 +1260,9 @@ bool FilePath::isExecutableFile() const
|
|||||||
*/
|
*/
|
||||||
bool FilePath::isWritableDir() const
|
bool FilePath::isWritableDir() const
|
||||||
{
|
{
|
||||||
|
if (isEmpty())
|
||||||
|
return false;
|
||||||
|
|
||||||
const expected_str<DeviceFileAccess *> access = getFileAccess(*this);
|
const expected_str<DeviceFileAccess *> access = getFileAccess(*this);
|
||||||
if (!access)
|
if (!access)
|
||||||
return false;
|
return false;
|
||||||
@@ -1266,6 +1275,9 @@ bool FilePath::isWritableDir() const
|
|||||||
*/
|
*/
|
||||||
bool FilePath::isWritableFile() const
|
bool FilePath::isWritableFile() const
|
||||||
{
|
{
|
||||||
|
if (isEmpty())
|
||||||
|
return false;
|
||||||
|
|
||||||
const expected_str<DeviceFileAccess *> access = getFileAccess(*this);
|
const expected_str<DeviceFileAccess *> access = getFileAccess(*this);
|
||||||
if (!access)
|
if (!access)
|
||||||
return false;
|
return false;
|
||||||
@@ -1273,9 +1285,11 @@ bool FilePath::isWritableFile() const
|
|||||||
return (*access)->isWritableFile(*this);
|
return (*access)->isWritableFile(*this);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
bool FilePath::isReadableFile() const
|
bool FilePath::isReadableFile() const
|
||||||
{
|
{
|
||||||
|
if (isEmpty())
|
||||||
|
return false;
|
||||||
|
|
||||||
const expected_str<DeviceFileAccess *> access = getFileAccess(*this);
|
const expected_str<DeviceFileAccess *> access = getFileAccess(*this);
|
||||||
if (!access)
|
if (!access)
|
||||||
return false;
|
return false;
|
||||||
@@ -1285,6 +1299,9 @@ bool FilePath::isReadableFile() const
|
|||||||
|
|
||||||
bool FilePath::isReadableDir() const
|
bool FilePath::isReadableDir() const
|
||||||
{
|
{
|
||||||
|
if (isEmpty())
|
||||||
|
return false;
|
||||||
|
|
||||||
const expected_str<DeviceFileAccess *> access = getFileAccess(*this);
|
const expected_str<DeviceFileAccess *> access = getFileAccess(*this);
|
||||||
if (!access)
|
if (!access)
|
||||||
return false;
|
return false;
|
||||||
@@ -1294,6 +1311,9 @@ bool FilePath::isReadableDir() const
|
|||||||
|
|
||||||
bool FilePath::isFile() const
|
bool FilePath::isFile() const
|
||||||
{
|
{
|
||||||
|
if (isEmpty())
|
||||||
|
return false;
|
||||||
|
|
||||||
const expected_str<DeviceFileAccess *> access = getFileAccess(*this);
|
const expected_str<DeviceFileAccess *> access = getFileAccess(*this);
|
||||||
if (!access)
|
if (!access)
|
||||||
return false;
|
return false;
|
||||||
@@ -1303,6 +1323,9 @@ bool FilePath::isFile() const
|
|||||||
|
|
||||||
bool FilePath::isDir() const
|
bool FilePath::isDir() const
|
||||||
{
|
{
|
||||||
|
if (isEmpty())
|
||||||
|
return false;
|
||||||
|
|
||||||
const expected_str<DeviceFileAccess *> access = getFileAccess(*this);
|
const expected_str<DeviceFileAccess *> access = getFileAccess(*this);
|
||||||
if (!access)
|
if (!access)
|
||||||
return false;
|
return false;
|
||||||
@@ -1312,6 +1335,9 @@ bool FilePath::isDir() const
|
|||||||
|
|
||||||
bool FilePath::isSymLink() const
|
bool FilePath::isSymLink() const
|
||||||
{
|
{
|
||||||
|
if (isEmpty())
|
||||||
|
return false;
|
||||||
|
|
||||||
const expected_str<DeviceFileAccess *> access = getFileAccess(*this);
|
const expected_str<DeviceFileAccess *> access = getFileAccess(*this);
|
||||||
if (!access)
|
if (!access)
|
||||||
return false;
|
return false;
|
||||||
|
@@ -54,11 +54,11 @@ public:
|
|||||||
optCopy.state |= QStyle::State_HasFocus;
|
optCopy.state |= QStyle::State_HasFocus;
|
||||||
QItemDelegate::paint(painter,option,index);
|
QItemDelegate::paint(painter,option,index);
|
||||||
// add remove button
|
// add remove button
|
||||||
QWindow *window = view->window()->windowHandle();
|
const qreal devicePixelRatio = painter->device()->devicePixelRatio();
|
||||||
const QPixmap iconPixmap = icon.pixmap(window, option.rect.size());
|
const QPixmap iconPixmap = icon.pixmap(option.rect.size(), devicePixelRatio);
|
||||||
QRect pixmapRect = QStyle::alignedRect(option.direction,
|
QRect pixmapRect = QStyle::alignedRect(option.direction,
|
||||||
Qt::AlignRight | Qt::AlignVCenter,
|
Qt::AlignRight | Qt::AlignVCenter,
|
||||||
iconPixmap.size() / window->devicePixelRatio(),
|
iconPixmap.size() / devicePixelRatio,
|
||||||
option.rect);
|
option.rect);
|
||||||
if (!clearIconSize.isValid())
|
if (!clearIconSize.isValid())
|
||||||
clearIconSize = pixmapRect.size();
|
clearIconSize = pixmapRect.size();
|
||||||
|
@@ -221,11 +221,11 @@ QIcon Icon::modeIcon(const Icon &classic, const Icon &flat, const Icon &flatActi
|
|||||||
QIcon Icon::combinedIcon(const QList<QIcon> &icons)
|
QIcon Icon::combinedIcon(const QList<QIcon> &icons)
|
||||||
{
|
{
|
||||||
QIcon result;
|
QIcon result;
|
||||||
QWindow *window = QApplication::allWidgets().constFirst()->windowHandle();
|
const qreal devicePixelRatio = QApplication::allWidgets().constFirst()->devicePixelRatio();
|
||||||
for (const QIcon &icon: icons)
|
for (const QIcon &icon: icons)
|
||||||
for (const QIcon::Mode mode: {QIcon::Disabled, QIcon::Normal})
|
for (const QIcon::Mode mode: {QIcon::Disabled, QIcon::Normal})
|
||||||
for (const QSize &size: icon.availableSizes(mode))
|
for (const QSize &size: icon.availableSizes(mode))
|
||||||
result.addPixmap(icon.pixmap(window, size, mode), mode);
|
result.addPixmap(icon.pixmap(size, devicePixelRatio, mode), mode);
|
||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@@ -118,10 +118,9 @@ void InfoLabel::paintEvent(QPaintEvent *event)
|
|||||||
p.restore();
|
p.restore();
|
||||||
}
|
}
|
||||||
const QIcon &icon = iconForType(m_type);
|
const QIcon &icon = iconForType(m_type);
|
||||||
QWindow *window = this->window()->windowHandle();
|
|
||||||
const QIcon::Mode mode = !this->isEnabled() ? QIcon::Disabled : QIcon::Normal;
|
const QIcon::Mode mode = !this->isEnabled() ? QIcon::Disabled : QIcon::Normal;
|
||||||
const QPixmap iconPx =
|
const QPixmap iconPx =
|
||||||
icon.pixmap(window, QSize(iconSize, iconSize) * devicePixelRatio(), mode);
|
icon.pixmap(QSize(iconSize, iconSize) * devicePixelRatio(), devicePixelRatio(), mode);
|
||||||
p.drawPixmap(iconRect, iconPx);
|
p.drawPixmap(iconRect, iconPx);
|
||||||
ElidingLabel::paintEvent(event);
|
ElidingLabel::paintEvent(event);
|
||||||
}
|
}
|
||||||
|
@@ -339,19 +339,19 @@ void Layout::span(int cols, int rows)
|
|||||||
pendingItems.back().spanRows = rows;
|
pendingItems.back().spanRows = rows;
|
||||||
}
|
}
|
||||||
|
|
||||||
void Layout::noMargin()
|
void Layout::setNoMargins()
|
||||||
{
|
{
|
||||||
customMargin({});
|
setContentsMargins(0, 0, 0, 0);
|
||||||
}
|
}
|
||||||
|
|
||||||
void Layout::normalMargin()
|
void Layout::setNormalMargins()
|
||||||
{
|
{
|
||||||
customMargin({9, 9, 9, 9});
|
setContentsMargins(9, 9, 9, 9);
|
||||||
}
|
}
|
||||||
|
|
||||||
void Layout::customMargin(const QMargins &margin)
|
void Layout::setContentsMargins(int left, int top, int right, int bottom)
|
||||||
{
|
{
|
||||||
access(this)->setContentsMargins(margin);
|
access(this)->setContentsMargins(left, top, right, bottom);
|
||||||
}
|
}
|
||||||
|
|
||||||
/*!
|
/*!
|
||||||
@@ -467,11 +467,11 @@ void addToLayout(Layout *layout, const QString &inner)
|
|||||||
layout->addLayoutItem(item);
|
layout->addLayoutItem(item);
|
||||||
}
|
}
|
||||||
|
|
||||||
void empty(Layout *iface)
|
void empty(Layout *layout)
|
||||||
{
|
{
|
||||||
LayoutItem item;
|
LayoutItem item;
|
||||||
item.empty = true;
|
item.empty = true;
|
||||||
iface->addLayoutItem(item);
|
layout->addLayoutItem(item);
|
||||||
}
|
}
|
||||||
|
|
||||||
void hr(Layout *layout)
|
void hr(Layout *layout)
|
||||||
@@ -479,26 +479,26 @@ void hr(Layout *layout)
|
|||||||
layout->addLayoutItem(createHr());
|
layout->addLayoutItem(createHr());
|
||||||
}
|
}
|
||||||
|
|
||||||
void br(Layout *iface)
|
void br(Layout *layout)
|
||||||
{
|
{
|
||||||
iface->flush();
|
layout->flush();
|
||||||
}
|
}
|
||||||
|
|
||||||
void st(Layout *iface)
|
void st(Layout *layout)
|
||||||
{
|
{
|
||||||
LayoutItem item;
|
LayoutItem item;
|
||||||
item.stretch = 1;
|
item.stretch = 1;
|
||||||
iface->addLayoutItem(item);
|
layout->addLayoutItem(item);
|
||||||
}
|
}
|
||||||
|
|
||||||
void noMargin(Layout *iface)
|
void noMargin(Layout *layout)
|
||||||
{
|
{
|
||||||
iface->noMargin();
|
layout->setNoMargins();
|
||||||
}
|
}
|
||||||
|
|
||||||
void normalMargin(Layout *iface)
|
void normalMargin(Layout *layout)
|
||||||
{
|
{
|
||||||
iface->normalMargin();
|
layout->setNormalMargins();
|
||||||
}
|
}
|
||||||
|
|
||||||
QFormLayout *Layout::asForm()
|
QFormLayout *Layout::asForm()
|
||||||
@@ -612,9 +612,9 @@ void Layout::flush_() const
|
|||||||
const_cast<Layout *>(this)->flush();
|
const_cast<Layout *>(this)->flush();
|
||||||
}
|
}
|
||||||
|
|
||||||
void withFormAlignment(Layout *iface)
|
void withFormAlignment(Layout *layout)
|
||||||
{
|
{
|
||||||
iface->useFormAlignment = true;
|
layout->useFormAlignment = true;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Flow
|
// Flow
|
||||||
@@ -672,7 +672,7 @@ Form::Form(std::initializer_list<I> ps)
|
|||||||
flush();
|
flush();
|
||||||
}
|
}
|
||||||
|
|
||||||
void Layout::fieldGrowthPolicy(int policy)
|
void Layout::setFieldGrowthPolicy(int policy)
|
||||||
{
|
{
|
||||||
if (auto lt = asForm())
|
if (auto lt = asForm())
|
||||||
lt->setFieldGrowthPolicy(QFormLayout::FieldGrowthPolicy(policy));
|
lt->setFieldGrowthPolicy(QFormLayout::FieldGrowthPolicy(policy));
|
||||||
@@ -699,7 +699,7 @@ Widget::Widget(std::initializer_list<I> ps)
|
|||||||
apply(this, ps);
|
apply(this, ps);
|
||||||
}
|
}
|
||||||
|
|
||||||
void Widget::resize(int w, int h)
|
void Widget::setSize(int w, int h)
|
||||||
{
|
{
|
||||||
access(this)->resize(w, h);
|
access(this)->resize(w, h);
|
||||||
}
|
}
|
||||||
@@ -724,19 +724,19 @@ void Widget::show()
|
|||||||
access(this)->show();
|
access(this)->show();
|
||||||
}
|
}
|
||||||
|
|
||||||
void Widget::noMargin(int)
|
void Widget::setNoMargins(int)
|
||||||
{
|
{
|
||||||
customMargin({});
|
setContentsMargins(0, 0, 0, 0);
|
||||||
}
|
}
|
||||||
|
|
||||||
void Widget::normalMargin(int)
|
void Widget::setNormalMargins(int)
|
||||||
{
|
{
|
||||||
customMargin({9, 9, 9, 9});
|
setContentsMargins(9, 9, 9, 9);
|
||||||
}
|
}
|
||||||
|
|
||||||
void Widget::customMargin(const QMargins &margin)
|
void Widget::setContentsMargins(int left, int top, int right, int bottom)
|
||||||
{
|
{
|
||||||
access(this)->setContentsMargins(margin);
|
access(this)->setContentsMargins(left, top, right, bottom);
|
||||||
}
|
}
|
||||||
|
|
||||||
QWidget *Widget::emerge() const
|
QWidget *Widget::emerge() const
|
||||||
@@ -979,7 +979,7 @@ void addToLayout(Layout *layout, const Span &inner)
|
|||||||
|
|
||||||
LayoutModifier spacing(int space)
|
LayoutModifier spacing(int space)
|
||||||
{
|
{
|
||||||
return [space](Layout *iface) { iface->setSpacing(space); };
|
return [space](Layout *layout) { layout->setSpacing(space); };
|
||||||
}
|
}
|
||||||
|
|
||||||
void addToLayout(Layout *layout, const Space &inner)
|
void addToLayout(Layout *layout, const Space &inner)
|
||||||
|
@@ -3,7 +3,6 @@
|
|||||||
|
|
||||||
#pragma once
|
#pragma once
|
||||||
|
|
||||||
#include <QMargins>
|
|
||||||
#include <QString>
|
#include <QString>
|
||||||
|
|
||||||
#include <functional>
|
#include <functional>
|
||||||
@@ -26,7 +25,6 @@ class QGroupBox;
|
|||||||
class QHBoxLayout;
|
class QHBoxLayout;
|
||||||
class QLabel;
|
class QLabel;
|
||||||
class QLayout;
|
class QLayout;
|
||||||
class QMargins;
|
|
||||||
class QObject;
|
class QObject;
|
||||||
class QPushButton;
|
class QPushButton;
|
||||||
class QSpinBox;
|
class QSpinBox;
|
||||||
@@ -52,6 +50,45 @@ public:
|
|||||||
const T2 arg; // FIXME: Could be const &, but this would currently break bindTo().
|
const T2 arg; // FIXME: Could be const &, but this would currently break bindTo().
|
||||||
};
|
};
|
||||||
|
|
||||||
|
template<typename T1, typename T2>
|
||||||
|
struct Arg2
|
||||||
|
{
|
||||||
|
Arg2(const T1 &a1, const T2 &a2)
|
||||||
|
: p1(a1)
|
||||||
|
, p2(a2)
|
||||||
|
{}
|
||||||
|
const T1 p1;
|
||||||
|
const T2 p2;
|
||||||
|
};
|
||||||
|
|
||||||
|
template<typename T1, typename T2, typename T3>
|
||||||
|
struct Arg3
|
||||||
|
{
|
||||||
|
Arg3(const T1 &a1, const T2 &a2, const T3 &a3)
|
||||||
|
: p1(a1)
|
||||||
|
, p2(a2)
|
||||||
|
, p3(a3)
|
||||||
|
{}
|
||||||
|
const T1 p1;
|
||||||
|
const T2 p2;
|
||||||
|
const T3 p3;
|
||||||
|
};
|
||||||
|
|
||||||
|
template<typename T1, typename T2, typename T3, typename T4>
|
||||||
|
struct Arg4
|
||||||
|
{
|
||||||
|
Arg4(const T1 &a1, const T2 &a2, const T3 &a3, const T4 &a4)
|
||||||
|
: p1(a1)
|
||||||
|
, p2(a2)
|
||||||
|
, p3(a3)
|
||||||
|
, p4(a4)
|
||||||
|
{}
|
||||||
|
const T1 p1;
|
||||||
|
const T2 p2;
|
||||||
|
const T3 p3;
|
||||||
|
const T4 p4;
|
||||||
|
};
|
||||||
|
|
||||||
// The main dispatcher
|
// The main dispatcher
|
||||||
|
|
||||||
void doit(auto x, auto id, auto p);
|
void doit(auto x, auto id, auto p);
|
||||||
@@ -139,13 +176,16 @@ public:
|
|||||||
Layout(Implementation *w) { ptr = w; }
|
Layout(Implementation *w) { ptr = w; }
|
||||||
|
|
||||||
void span(int cols, int rows);
|
void span(int cols, int rows);
|
||||||
void noMargin();
|
|
||||||
void normalMargin();
|
void setNoMargins();
|
||||||
void customMargin(const QMargins &margin);
|
void setNormalMargins();
|
||||||
|
void setContentsMargins(int left, int top, int right, int bottom);
|
||||||
void setColumnStretch(int cols, int rows);
|
void setColumnStretch(int cols, int rows);
|
||||||
void setSpacing(int space);
|
void setSpacing(int space);
|
||||||
|
void setFieldGrowthPolicy(int policy);
|
||||||
|
|
||||||
void attachTo(QWidget *);
|
void attachTo(QWidget *);
|
||||||
|
|
||||||
void addItem(I item);
|
void addItem(I item);
|
||||||
void addItems(std::initializer_list<I> items);
|
void addItems(std::initializer_list<I> items);
|
||||||
void addRow(std::initializer_list<I> items);
|
void addRow(std::initializer_list<I> items);
|
||||||
@@ -153,7 +193,6 @@ public:
|
|||||||
|
|
||||||
void flush();
|
void flush();
|
||||||
void flush_() const;
|
void flush_() const;
|
||||||
void fieldGrowthPolicy(int policy);
|
|
||||||
|
|
||||||
QWidget *emerge() const;
|
QWidget *emerge() const;
|
||||||
void show() const;
|
void show() const;
|
||||||
@@ -258,15 +297,15 @@ public:
|
|||||||
Widget(Implementation *w) { ptr = w; }
|
Widget(Implementation *w) { ptr = w; }
|
||||||
|
|
||||||
QWidget *emerge() const;
|
QWidget *emerge() const;
|
||||||
|
|
||||||
void show();
|
void show();
|
||||||
void resize(int, int);
|
|
||||||
void setLayout(const Layout &layout);
|
void setLayout(const Layout &layout);
|
||||||
|
void setSize(int, int);
|
||||||
void setWindowTitle(const QString &);
|
void setWindowTitle(const QString &);
|
||||||
void setToolTip(const QString &);
|
void setToolTip(const QString &);
|
||||||
void noMargin(int = 0);
|
void setNoMargins(int = 0);
|
||||||
void normalMargin(int = 0);
|
void setNormalMargins(int = 0);
|
||||||
void customMargin(const QMargins &margin);
|
void setContentsMargins(int left, int top, int right, int bottom);
|
||||||
};
|
};
|
||||||
|
|
||||||
class QTCREATOR_UTILS_EXPORT Label : public Widget
|
class QTCREATOR_UTILS_EXPORT Label : public Widget
|
||||||
@@ -439,69 +478,42 @@ void doit(Interface *x, IdId, auto p)
|
|||||||
|
|
||||||
// Setter dispatchers
|
// Setter dispatchers
|
||||||
|
|
||||||
class SizeId {};
|
#define QTCREATOR_SETTER(name, setter) \
|
||||||
auto size(auto w, auto h) { return IdAndArg{SizeId{}, std::pair{w, h}}; }
|
class name##_TAG {}; \
|
||||||
void doit(auto x, SizeId, auto p) { x->resize(p->first, p->second); }
|
inline auto name(auto p) { return IdAndArg{name##_TAG{}, p}; } \
|
||||||
|
inline void doit(auto x, name##_TAG, auto p) { x->setter(p); }
|
||||||
|
|
||||||
class TextId {};
|
#define QTCREATOR_SETTER2(name, setter) \
|
||||||
auto text(auto p) { return IdAndArg{TextId{}, p}; }
|
class name##_TAG {}; \
|
||||||
void doit(auto x, TextId, auto p) { x->setText(p); }
|
inline auto name(auto p1, auto p2) { return IdAndArg{name##_TAG{}, Arg2{p1, p2}}; } \
|
||||||
|
inline void doit(auto x, name##_TAG, auto p) { x->setter(p.p1, p.p2); }
|
||||||
|
|
||||||
class TitleId {};
|
#define QTCREATOR_SETTER3(name, setter) \
|
||||||
auto title(auto p) { return IdAndArg{TitleId{}, p}; }
|
class name##_TAG {}; \
|
||||||
void doit(auto x, TitleId, auto p) { x->setTitle(p); }
|
inline auto name(auto p1, auto p2, auto p3) { return IdAndArg{name##_TAG{}, Arg3{p1, p2, p3}}; } \
|
||||||
|
inline void doit(auto x, name##_TAG, auto p) { x->setter(p.p1, p.p2, p.p3); }
|
||||||
|
|
||||||
class TextFormatId {};
|
#define QTCREATOR_SETTER4(name, setter) \
|
||||||
auto textFormat(auto p) { return IdAndArg{TextFormatId{}, p}; }
|
class name##_TAG {}; \
|
||||||
void doit(auto x, TextFormatId, auto p) { x->setTextFormat(p); }
|
inline auto name(auto p1, auto p2, auto p3, auto p4) { return IdAndArg{name##_TAG{}, Arg4{p1, p2, p3, p4}}; } \
|
||||||
|
inline void doit(auto x, name##_TAG, auto p) { x->setter(p.p1, p.p2, p.p3, p.p4); }
|
||||||
|
|
||||||
class WordWrapId {};
|
QTCREATOR_SETTER(fieldGrowthPolicy, setFieldGrowthPolicy);
|
||||||
auto wordWrap(auto p) { return IdAndArg{WordWrapId{}, p}; }
|
QTCREATOR_SETTER(groupChecker, setGroupChecker);
|
||||||
void doit(auto x, WordWrapId, auto p) { x->setWordWrap(p); }
|
QTCREATOR_SETTER(openExternalLinks, setOpenExternalLinks);
|
||||||
|
QTCREATOR_SETTER2(size, setSize)
|
||||||
class TextInteractionFlagId {};
|
QTCREATOR_SETTER(text, setText)
|
||||||
auto textInteractionFlags(auto p) { return IdAndArg{TextInteractionFlagId{}, p}; }
|
QTCREATOR_SETTER(textFormat, setTextFormat);
|
||||||
void doit(auto x, TextInteractionFlagId, auto p) { x->setTextInteractionFlags(p); }
|
QTCREATOR_SETTER(textInteractionFlags, setTextInteractionFlags);
|
||||||
|
QTCREATOR_SETTER(title, setTitle)
|
||||||
class OpenExternalLinksId {};
|
QTCREATOR_SETTER(toolTip, setToolTip);
|
||||||
auto openExternalLinks(auto p) { return IdAndArg{OpenExternalLinksId{}, p}; }
|
QTCREATOR_SETTER(windowTitle, setWindowTitle);
|
||||||
void doit(auto x, OpenExternalLinksId, auto p) { x->setOpenExternalLinks(p); }
|
QTCREATOR_SETTER(wordWrap, setWordWrap);
|
||||||
|
QTCREATOR_SETTER2(columnStretch, setColumnStretch);
|
||||||
class OnLinkHoveredId {};
|
QTCREATOR_SETTER2(onClicked, onClicked);
|
||||||
auto onLinkHovered(auto p, QObject *guard) { return IdAndArg{OnLinkHoveredId{}, std::pair{p, guard}}; }
|
QTCREATOR_SETTER2(onLinkHovered, onLinkHovered);
|
||||||
void doit(auto x, OnLinkHoveredId, auto p) { x->onLinkHovered(p.first, p.second); }
|
QTCREATOR_SETTER2(onTextChanged, onTextChanged);
|
||||||
|
QTCREATOR_SETTER4(customMargins, setContentsMargins);
|
||||||
class GroupCheckerId {};
|
|
||||||
auto groupChecker(auto p) { return IdAndArg{GroupCheckerId{}, p}; }
|
|
||||||
void doit(auto x, GroupCheckerId, auto p) { x->setGroupChecker(p); }
|
|
||||||
|
|
||||||
class ToolTipId {};
|
|
||||||
auto toolTip(auto p) { return IdAndArg{ToolTipId{}, p}; }
|
|
||||||
void doit(auto x, ToolTipId, auto p) { x->setToolTip(p); }
|
|
||||||
|
|
||||||
class WindowTitleId {};
|
|
||||||
auto windowTitle(auto p) { return IdAndArg{WindowTitleId{}, p}; }
|
|
||||||
void doit(auto x, WindowTitleId, auto p) { x->setWindowTitle(p); }
|
|
||||||
|
|
||||||
class OnTextChangedId {};
|
|
||||||
auto onTextChanged(auto p) { return IdAndArg{OnTextChangedId{}, p}; }
|
|
||||||
void doit(auto x, OnTextChangedId, auto p) { x->onTextChanged(p); }
|
|
||||||
|
|
||||||
class OnClickedId {};
|
|
||||||
auto onClicked(auto p, auto guard) { return IdAndArg{OnClickedId{}, std::pair{p, guard}}; }
|
|
||||||
void doit(auto x, OnClickedId, auto p) { x->onClicked(p.first, p.second); }
|
|
||||||
|
|
||||||
class CustomMarginId {};
|
|
||||||
inline auto customMargin(const QMargins &p) { return IdAndArg{CustomMarginId{}, p}; }
|
|
||||||
void doit(auto x, CustomMarginId, auto p) { x->customMargin(p); }
|
|
||||||
|
|
||||||
class FieldGrowthPolicyId {};
|
|
||||||
inline auto fieldGrowthPolicy(auto p) { return IdAndArg{FieldGrowthPolicyId{}, p}; }
|
|
||||||
void doit(auto x, FieldGrowthPolicyId, auto p) { x->fieldGrowthPolicy(p); }
|
|
||||||
|
|
||||||
class ColumnStretchId {};
|
|
||||||
inline auto columnStretch(int column, int stretch) { return IdAndArg{ColumnStretchId{}, std::pair{column, stretch}}; }
|
|
||||||
void doit(auto x, ColumnStretchId, auto p) { x->setColumnStretch(p.first, p.second); }
|
|
||||||
|
|
||||||
// Nesting dispatchers
|
// Nesting dispatchers
|
||||||
|
|
||||||
|
@@ -19,6 +19,10 @@ EnvironmentItems EnvironmentItem::fromStringList(const QStringList &list)
|
|||||||
{
|
{
|
||||||
EnvironmentItems result;
|
EnvironmentItems result;
|
||||||
for (const QString &string : list) {
|
for (const QString &string : list) {
|
||||||
|
if (string.startsWith("##")) {
|
||||||
|
result.append({string.mid(2), {}, EnvironmentItem::Comment});
|
||||||
|
continue;
|
||||||
|
}
|
||||||
int pos = string.indexOf("+=");
|
int pos = string.indexOf("+=");
|
||||||
if (pos != -1) {
|
if (pos != -1) {
|
||||||
result.append({string.left(pos), string.mid(pos + 2), EnvironmentItem::Append});
|
result.append({string.left(pos), string.mid(pos + 2), EnvironmentItem::Append});
|
||||||
@@ -59,6 +63,8 @@ QStringList EnvironmentItem::toStringList(const EnvironmentItems &list)
|
|||||||
return QString('#' + item.name + '=' + item.value);
|
return QString('#' + item.name + '=' + item.value);
|
||||||
case EnvironmentItem::SetEnabled:
|
case EnvironmentItem::SetEnabled:
|
||||||
return QString(item.name + '=' + item.value);
|
return QString(item.name + '=' + item.value);
|
||||||
|
case EnvironmentItem::Comment:
|
||||||
|
return QString("##" + item.name);
|
||||||
}
|
}
|
||||||
return QString();
|
return QString();
|
||||||
});
|
});
|
||||||
@@ -170,6 +176,8 @@ void EnvironmentItem::apply(NameValueDictionary *dictionary, Operation op) const
|
|||||||
apply(dictionary, SetEnabled);
|
apply(dictionary, SetEnabled);
|
||||||
}
|
}
|
||||||
} break;
|
} break;
|
||||||
|
case Comment: // ignore comments when applying to environment
|
||||||
|
break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -195,6 +203,9 @@ QDebug operator<<(QDebug debug, const EnvironmentItem &i)
|
|||||||
case EnvironmentItem::Append:
|
case EnvironmentItem::Append:
|
||||||
debug << "append to \"" << i.name << "\":\"" << i.value << '"';
|
debug << "append to \"" << i.name << "\":\"" << i.value << '"';
|
||||||
break;
|
break;
|
||||||
|
case EnvironmentItem::Comment:
|
||||||
|
debug << "comment:" << i.name;
|
||||||
|
break;
|
||||||
}
|
}
|
||||||
debug << ')';
|
debug << ')';
|
||||||
return debug;
|
return debug;
|
||||||
|
@@ -16,7 +16,7 @@ namespace Utils {
|
|||||||
class QTCREATOR_UTILS_EXPORT EnvironmentItem
|
class QTCREATOR_UTILS_EXPORT EnvironmentItem
|
||||||
{
|
{
|
||||||
public:
|
public:
|
||||||
enum Operation : char { SetEnabled, Unset, Prepend, Append, SetDisabled };
|
enum Operation : char { SetEnabled, Unset, Prepend, Append, SetDisabled, Comment };
|
||||||
EnvironmentItem() = default;
|
EnvironmentItem() = default;
|
||||||
EnvironmentItem(const QString &key, const QString &value, Operation operation = SetEnabled)
|
EnvironmentItem(const QString &key, const QString &value, Operation operation = SetEnabled)
|
||||||
: name(key)
|
: name(key)
|
||||||
|
@@ -60,11 +60,12 @@ NameValueItemsWidget::NameValueItemsWidget(QWidget *parent)
|
|||||||
const QString helpText = Tr::tr(
|
const QString helpText = Tr::tr(
|
||||||
"Enter one environment variable per line.\n"
|
"Enter one environment variable per line.\n"
|
||||||
"To set or change a variable, use VARIABLE=VALUE.\n"
|
"To set or change a variable, use VARIABLE=VALUE.\n"
|
||||||
|
"To disable a variable, prefix this line with \"#\".\n"
|
||||||
"To append to a variable, use VARIABLE+=VALUE.\n"
|
"To append to a variable, use VARIABLE+=VALUE.\n"
|
||||||
"To prepend to a variable, use VARIABLE=+VALUE.\n"
|
"To prepend to a variable, use VARIABLE=+VALUE.\n"
|
||||||
"Existing variables can be referenced in a VALUE with ${OTHER}.\n"
|
"Existing variables can be referenced in a VALUE with ${OTHER}.\n"
|
||||||
"To clear a variable, put its name on a line with nothing else on it.\n"
|
"To clear a variable, put its name on a line with nothing else on it.\n"
|
||||||
"To disable a variable, prefix the line with \"#\".");
|
"Lines starting with \"##\" will be treated as comments.");
|
||||||
|
|
||||||
m_editor = new Internal::TextEditHelper(this);
|
m_editor = new Internal::TextEditHelper(this);
|
||||||
auto layout = new QVBoxLayout(this);
|
auto layout = new QVBoxLayout(this);
|
||||||
@@ -141,7 +142,7 @@ bool NameValueItemsWidget::editVariable(const QString &name, Selection selection
|
|||||||
skipWhiteSpace();
|
skipWhiteSpace();
|
||||||
if (offset < line.length()) {
|
if (offset < line.length()) {
|
||||||
QChar nextChar = line.at(offset);
|
QChar nextChar = line.at(offset);
|
||||||
if (nextChar.isLetterOrNumber())
|
if (nextChar.isLetterOrNumber() || nextChar == '_')
|
||||||
continue;
|
continue;
|
||||||
if (nextChar == '=') {
|
if (nextChar == '=') {
|
||||||
if (++offset < line.length() && line.at(offset) == '+')
|
if (++offset < line.length() && line.at(offset) == '+')
|
||||||
|
@@ -8,16 +8,34 @@
|
|||||||
#include <QEvent>
|
#include <QEvent>
|
||||||
#include <QPainter>
|
#include <QPainter>
|
||||||
|
|
||||||
|
namespace Utils::Internal {
|
||||||
|
class OverlayWidgetPrivate
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
OverlayWidget::PaintFunction m_paint;
|
||||||
|
OverlayWidget::ResizeFunction m_resize;
|
||||||
|
};
|
||||||
|
} // namespace Utils::Internal
|
||||||
|
|
||||||
Utils::OverlayWidget::OverlayWidget(QWidget *parent)
|
Utils::OverlayWidget::OverlayWidget(QWidget *parent)
|
||||||
|
: d(new Internal::OverlayWidgetPrivate)
|
||||||
{
|
{
|
||||||
setAttribute(Qt::WA_TransparentForMouseEvents);
|
setAttribute(Qt::WA_TransparentForMouseEvents);
|
||||||
if (parent)
|
if (parent)
|
||||||
attachToWidget(parent);
|
attachToWidget(parent);
|
||||||
|
d->m_resize = [](QWidget *w, const QSize &size) { w->setGeometry(QRect(QPoint(0, 0), size)); };
|
||||||
}
|
}
|
||||||
|
|
||||||
|
Utils::OverlayWidget::~OverlayWidget() = default;
|
||||||
|
|
||||||
void Utils::OverlayWidget::setPaintFunction(const Utils::OverlayWidget::PaintFunction &paint)
|
void Utils::OverlayWidget::setPaintFunction(const Utils::OverlayWidget::PaintFunction &paint)
|
||||||
{
|
{
|
||||||
m_paint = paint;
|
d->m_paint = paint;
|
||||||
|
}
|
||||||
|
|
||||||
|
void Utils::OverlayWidget::setResizeFunction(const ResizeFunction &resize)
|
||||||
|
{
|
||||||
|
d->m_resize = resize;
|
||||||
}
|
}
|
||||||
|
|
||||||
bool Utils::OverlayWidget::eventFilter(QObject *obj, QEvent *ev)
|
bool Utils::OverlayWidget::eventFilter(QObject *obj, QEvent *ev)
|
||||||
@@ -29,9 +47,9 @@ bool Utils::OverlayWidget::eventFilter(QObject *obj, QEvent *ev)
|
|||||||
|
|
||||||
void Utils::OverlayWidget::paintEvent(QPaintEvent *ev)
|
void Utils::OverlayWidget::paintEvent(QPaintEvent *ev)
|
||||||
{
|
{
|
||||||
if (m_paint) {
|
if (d->m_paint) {
|
||||||
QPainter p(this);
|
QPainter p(this);
|
||||||
m_paint(this, p, ev);
|
d->m_paint(this, p, ev);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -50,5 +68,6 @@ void Utils::OverlayWidget::attachToWidget(QWidget *parent)
|
|||||||
void Utils::OverlayWidget::resizeToParent()
|
void Utils::OverlayWidget::resizeToParent()
|
||||||
{
|
{
|
||||||
QTC_ASSERT(parentWidget(), return );
|
QTC_ASSERT(parentWidget(), return );
|
||||||
setGeometry(QRect(QPoint(0, 0), parentWidget()->size()));
|
if (d->m_resize)
|
||||||
|
d->m_resize(this, parentWidget()->size());
|
||||||
}
|
}
|
||||||
|
@@ -8,18 +8,26 @@
|
|||||||
#include <QWidget>
|
#include <QWidget>
|
||||||
|
|
||||||
#include <functional>
|
#include <functional>
|
||||||
|
#include <memory>
|
||||||
|
|
||||||
namespace Utils {
|
namespace Utils {
|
||||||
|
|
||||||
|
namespace Internal {
|
||||||
|
class OverlayWidgetPrivate;
|
||||||
|
}
|
||||||
|
|
||||||
class QTCREATOR_UTILS_EXPORT OverlayWidget : public QWidget
|
class QTCREATOR_UTILS_EXPORT OverlayWidget : public QWidget
|
||||||
{
|
{
|
||||||
public:
|
public:
|
||||||
using PaintFunction = std::function<void(QWidget *, QPainter &, QPaintEvent *)>;
|
using PaintFunction = std::function<void(QWidget *, QPainter &, QPaintEvent *)>;
|
||||||
|
using ResizeFunction = std::function<void(QWidget *, QSize)>;
|
||||||
|
|
||||||
explicit OverlayWidget(QWidget *parent = nullptr);
|
explicit OverlayWidget(QWidget *parent = nullptr);
|
||||||
|
~OverlayWidget();
|
||||||
|
|
||||||
void attachToWidget(QWidget *parent);
|
void attachToWidget(QWidget *parent);
|
||||||
void setPaintFunction(const PaintFunction &paint);
|
void setPaintFunction(const PaintFunction &paint);
|
||||||
|
void setResizeFunction(const ResizeFunction &resize);
|
||||||
|
|
||||||
protected:
|
protected:
|
||||||
bool eventFilter(QObject *obj, QEvent *ev) override;
|
bool eventFilter(QObject *obj, QEvent *ev) override;
|
||||||
@@ -28,7 +36,7 @@ protected:
|
|||||||
private:
|
private:
|
||||||
void resizeToParent();
|
void resizeToParent();
|
||||||
|
|
||||||
PaintFunction m_paint;
|
std::unique_ptr<Internal::OverlayWidgetPrivate> d;
|
||||||
};
|
};
|
||||||
|
|
||||||
} // namespace Utils
|
} // namespace Utils
|
||||||
|
@@ -551,8 +551,7 @@ void StyleHelper::drawIconWithShadow(const QIcon &icon, const QRect &rect,
|
|||||||
// return a high-dpi pixmap, which will in that case have a devicePixelRatio
|
// return a high-dpi pixmap, which will in that case have a devicePixelRatio
|
||||||
// different than 1. The shadow drawing caluculations are done in device
|
// different than 1. The shadow drawing caluculations are done in device
|
||||||
// pixels.
|
// pixels.
|
||||||
QWindow *window = dynamic_cast<QWidget*>(p->device())->window()->windowHandle();
|
QPixmap px = icon.pixmap(rect.size(), devicePixelRatio, iconMode);
|
||||||
QPixmap px = icon.pixmap(window, rect.size(), iconMode);
|
|
||||||
int radius = int(dipRadius * devicePixelRatio);
|
int radius = int(dipRadius * devicePixelRatio);
|
||||||
QPoint offset = dipOffset * devicePixelRatio;
|
QPoint offset = dipOffset * devicePixelRatio;
|
||||||
cache = QPixmap(px.size() + QSize(radius * 2, radius * 2));
|
cache = QPixmap(px.size() + QSize(radius * 2, radius * 2));
|
||||||
@@ -563,7 +562,7 @@ void StyleHelper::drawIconWithShadow(const QIcon &icon, const QRect &rect,
|
|||||||
const bool hasDisabledState =
|
const bool hasDisabledState =
|
||||||
icon.availableSizes().count() == icon.availableSizes(QIcon::Disabled).count();
|
icon.availableSizes().count() == icon.availableSizes(QIcon::Disabled).count();
|
||||||
if (!hasDisabledState)
|
if (!hasDisabledState)
|
||||||
px = disabledSideBarIcon(icon.pixmap(window, rect.size()));
|
px = disabledSideBarIcon(icon.pixmap(rect.size(), devicePixelRatio));
|
||||||
} else if (creatorTheme()->flag(Theme::ToolBarIconShadow)) {
|
} else if (creatorTheme()->flag(Theme::ToolBarIconShadow)) {
|
||||||
// Draw shadow
|
// Draw shadow
|
||||||
QImage tmp(px.size() + QSize(radius * 2, radius * 2 + 1), QImage::Format_ARGB32_Premultiplied);
|
QImage tmp(px.size() + QSize(radius * 2, radius * 2 + 1), QImage::Format_ARGB32_Premultiplied);
|
||||||
@@ -950,6 +949,8 @@ static const UiFontMetrics& uiFontMetrics(StyleHelper::UiElement element)
|
|||||||
{StyleHelper::UiElementBody2, {12, 20, QFont::Light}},
|
{StyleHelper::UiElementBody2, {12, 20, QFont::Light}},
|
||||||
{StyleHelper::UiElementButtonMedium, {12, 16, QFont::Bold}},
|
{StyleHelper::UiElementButtonMedium, {12, 16, QFont::Bold}},
|
||||||
{StyleHelper::UiElementButtonSmall, {10, 12, QFont::Bold}},
|
{StyleHelper::UiElementButtonSmall, {10, 12, QFont::Bold}},
|
||||||
|
{StyleHelper::UiElementLabelMedium, {12, 16, QFont::DemiBold}},
|
||||||
|
{StyleHelper::UiElementLabelSmall, {10, 12, QFont::DemiBold}},
|
||||||
{StyleHelper::UiElementCaptionStrong, {10, 12, QFont::DemiBold}},
|
{StyleHelper::UiElementCaptionStrong, {10, 12, QFont::DemiBold}},
|
||||||
{StyleHelper::UiElementCaption, {10, 12, QFont::Normal}},
|
{StyleHelper::UiElementCaption, {10, 12, QFont::Normal}},
|
||||||
{StyleHelper::UiElementIconStandard, {12, 16, QFont::Medium}},
|
{StyleHelper::UiElementIconStandard, {12, 16, QFont::Medium}},
|
||||||
|
@@ -79,6 +79,8 @@ enum ToolbarStyle {
|
|||||||
};
|
};
|
||||||
constexpr ToolbarStyle defaultToolbarStyle = ToolbarStyleCompact;
|
constexpr ToolbarStyle defaultToolbarStyle = ToolbarStyleCompact;
|
||||||
|
|
||||||
|
// Keep in sync with:
|
||||||
|
// SyleHelper::uiFontMetrics, ICore::uiConfigInformation, tst_manual_widgets_uifonts::main
|
||||||
enum UiElement {
|
enum UiElement {
|
||||||
UiElementH1,
|
UiElementH1,
|
||||||
UiElementH2,
|
UiElementH2,
|
||||||
@@ -91,6 +93,8 @@ enum UiElement {
|
|||||||
UiElementBody2,
|
UiElementBody2,
|
||||||
UiElementButtonMedium,
|
UiElementButtonMedium,
|
||||||
UiElementButtonSmall,
|
UiElementButtonSmall,
|
||||||
|
UiElementLabelMedium,
|
||||||
|
UiElementLabelSmall,
|
||||||
UiElementCaptionStrong,
|
UiElementCaptionStrong,
|
||||||
UiElementCaption,
|
UiElementCaption,
|
||||||
UiElementIconStandard,
|
UiElementIconStandard,
|
||||||
|
@@ -334,22 +334,12 @@ void TerminalInterface::start()
|
|||||||
|
|
||||||
Environment finalEnv = m_setup.m_environment;
|
Environment finalEnv = m_setup.m_environment;
|
||||||
|
|
||||||
if (HostOsInfo::isWindowsHost()) {
|
if (HostOsInfo::isMacHost())
|
||||||
if (!finalEnv.hasKey("PATH")) {
|
|
||||||
const QString path = qtcEnvironmentVariable("PATH");
|
|
||||||
if (!path.isEmpty())
|
|
||||||
finalEnv.set("PATH", path);
|
|
||||||
}
|
|
||||||
if (!finalEnv.hasKey("SystemRoot")) {
|
|
||||||
const QString systemRoot = qtcEnvironmentVariable("SystemRoot");
|
|
||||||
if (!systemRoot.isEmpty())
|
|
||||||
finalEnv.set("SystemRoot", systemRoot);
|
|
||||||
}
|
|
||||||
} else if (HostOsInfo::isMacHost()) {
|
|
||||||
finalEnv.set("TERM", "xterm-256color");
|
finalEnv.set("TERM", "xterm-256color");
|
||||||
}
|
|
||||||
|
|
||||||
if (finalEnv.hasChanges()) {
|
if (finalEnv.hasChanges()) {
|
||||||
|
finalEnv = finalEnv.appliedToEnvironment(Environment::systemEnvironment());
|
||||||
|
|
||||||
d->envListFile = std::make_unique<QTemporaryFile>(this);
|
d->envListFile = std::make_unique<QTemporaryFile>(this);
|
||||||
if (!d->envListFile->open()) {
|
if (!d->envListFile->open()) {
|
||||||
cleanupAfterStartFailure(msgCannotCreateTempFile(d->envListFile->errorString()));
|
cleanupAfterStartFailure(msgCannotCreateTempFile(d->envListFile->errorString()));
|
||||||
|
@@ -247,6 +247,10 @@ public:
|
|||||||
Token_Notification_Success,
|
Token_Notification_Success,
|
||||||
Token_Notification_Neutral,
|
Token_Notification_Neutral,
|
||||||
Token_Notification_Danger,
|
Token_Notification_Danger,
|
||||||
|
Token_Gradient01_Start,
|
||||||
|
Token_Gradient01_End,
|
||||||
|
Token_Gradient02_Start,
|
||||||
|
Token_Gradient02_End,
|
||||||
|
|
||||||
/* Timeline Library */
|
/* Timeline Library */
|
||||||
Timeline_TextColor,
|
Timeline_TextColor,
|
||||||
|
@@ -45,7 +45,9 @@ public:
|
|||||||
m_indicatorPixmap(indicatorPixmap)
|
m_indicatorPixmap(indicatorPixmap)
|
||||||
{
|
{
|
||||||
m_indicatorLabel = new QLabel(this);
|
m_indicatorLabel = new QLabel(this);
|
||||||
m_indicatorLabel->setFixedSize(m_indicatorPixmap.size());
|
const QSizeF indicatorSize = m_indicatorPixmap.deviceIndependentSize();
|
||||||
|
m_indicatorLabel->setFixedSize(
|
||||||
|
{qCeil(indicatorSize.width()), qCeil(indicatorSize.height())});
|
||||||
m_titleLabel = new QLabel(title, this);
|
m_titleLabel = new QLabel(title, this);
|
||||||
auto l = new QHBoxLayout(this);
|
auto l = new QHBoxLayout(this);
|
||||||
l->setContentsMargins(0, 0, 0, 0);
|
l->setContentsMargins(0, 0, 0, 0);
|
||||||
|
@@ -89,12 +89,18 @@ bool startAvdAsync(const QString &avdName)
|
|||||||
|
|
||||||
QString findAvd(const QString &avdName)
|
QString findAvd(const QString &avdName)
|
||||||
{
|
{
|
||||||
const QList<AndroidDeviceInfo> devices = AndroidConfig::connectedDevices();
|
const QStringList lines = AndroidConfig::devicesCommandOutput();
|
||||||
for (const AndroidDeviceInfo &device : devices) {
|
for (const QString &line : lines) {
|
||||||
if (device.type != ProjectExplorer::IDevice::Emulator)
|
// skip the daemon logs
|
||||||
|
if (line.startsWith("* daemon"))
|
||||||
continue;
|
continue;
|
||||||
if (device.avdName == avdName)
|
|
||||||
return device.serialNumber;
|
const QString serialNumber = line.left(line.indexOf('\t')).trimmed();
|
||||||
|
if (!serialNumber.startsWith("emulator"))
|
||||||
|
continue;
|
||||||
|
|
||||||
|
if (AndroidConfig::getAvdName(serialNumber) == avdName)
|
||||||
|
return serialNumber;
|
||||||
}
|
}
|
||||||
return {};
|
return {};
|
||||||
}
|
}
|
||||||
|
@@ -141,33 +141,6 @@ static QString buildToolsPackageMarker()
|
|||||||
return QLatin1String(Constants::buildToolsPackageName) + ";";
|
return QLatin1String(Constants::buildToolsPackageName) + ";";
|
||||||
}
|
}
|
||||||
|
|
||||||
static QString getAvdName(const QString &serialnumber)
|
|
||||||
{
|
|
||||||
const int index = serialnumber.indexOf(QLatin1String("-"));
|
|
||||||
if (index == -1)
|
|
||||||
return {};
|
|
||||||
bool ok;
|
|
||||||
const int port = serialnumber.mid(index + 1).toInt(&ok);
|
|
||||||
if (!ok)
|
|
||||||
return {};
|
|
||||||
|
|
||||||
QTcpSocket tcpSocket;
|
|
||||||
tcpSocket.connectToHost(QHostAddress(QHostAddress::LocalHost), port);
|
|
||||||
if (!tcpSocket.waitForConnected(100)) // Don't wait more than 100ms for a local connection
|
|
||||||
return {};
|
|
||||||
|
|
||||||
tcpSocket.write("avd name\nexit\n");
|
|
||||||
tcpSocket.waitForDisconnected(500);
|
|
||||||
|
|
||||||
const QByteArrayList response = tcpSocket.readAll().split('\n');
|
|
||||||
// The input "avd name" might not be echoed as-is, but contain ASCII control sequences.
|
|
||||||
for (int i = response.size() - 1; i > 1; --i) {
|
|
||||||
if (response.at(i).startsWith("OK"))
|
|
||||||
return QString::fromLatin1(response.at(i - 1)).trimmed();
|
|
||||||
}
|
|
||||||
return {};
|
|
||||||
}
|
|
||||||
|
|
||||||
static QString getDeviceProperty(const QString &device, const QString &property)
|
static QString getDeviceProperty(const QString &device, const QString &property)
|
||||||
{
|
{
|
||||||
// workaround for '????????????' serial numbers
|
// workaround for '????????????' serial numbers
|
||||||
@@ -311,6 +284,33 @@ static FilePath ndkSubPathFromQtVersion(const QtVersion &version)
|
|||||||
// AndroidConfig
|
// AndroidConfig
|
||||||
//////////////////////////////////
|
//////////////////////////////////
|
||||||
|
|
||||||
|
QString getAvdName(const QString &serialnumber)
|
||||||
|
{
|
||||||
|
const int index = serialnumber.indexOf(QLatin1String("-"));
|
||||||
|
if (index == -1)
|
||||||
|
return {};
|
||||||
|
bool ok;
|
||||||
|
const int port = serialnumber.mid(index + 1).toInt(&ok);
|
||||||
|
if (!ok)
|
||||||
|
return {};
|
||||||
|
|
||||||
|
QTcpSocket tcpSocket;
|
||||||
|
tcpSocket.connectToHost(QHostAddress(QHostAddress::LocalHost), port);
|
||||||
|
if (!tcpSocket.waitForConnected(100)) // Don't wait more than 100ms for a local connection
|
||||||
|
return {};
|
||||||
|
|
||||||
|
tcpSocket.write("avd name\nexit\n");
|
||||||
|
tcpSocket.waitForDisconnected(500);
|
||||||
|
|
||||||
|
const QByteArrayList response = tcpSocket.readAll().split('\n');
|
||||||
|
// The input "avd name" might not be echoed as-is, but contain ASCII control sequences.
|
||||||
|
for (int i = response.size() - 1; i > 1; --i) {
|
||||||
|
if (response.at(i).startsWith("OK"))
|
||||||
|
return QString::fromLatin1(response.at(i - 1)).trimmed();
|
||||||
|
}
|
||||||
|
return {};
|
||||||
|
}
|
||||||
|
|
||||||
QLatin1String displayName(const Abi &abi)
|
QLatin1String displayName(const Abi &abi)
|
||||||
{
|
{
|
||||||
switch (abi.architecture()) {
|
switch (abi.architecture()) {
|
||||||
@@ -674,66 +674,25 @@ FilePath keytoolPath()
|
|||||||
return openJDKBinPath().pathAppended(keytoolName).withExecutableSuffix();
|
return openJDKBinPath().pathAppended(keytoolName).withExecutableSuffix();
|
||||||
}
|
}
|
||||||
|
|
||||||
QList<AndroidDeviceInfo> connectedDevices(QString *error)
|
QStringList devicesCommandOutput()
|
||||||
{
|
{
|
||||||
QList<AndroidDeviceInfo> devices;
|
Process adbProcess;
|
||||||
Process adbProc;
|
adbProcess.setCommand({adbToolPath(), {"devices"}});
|
||||||
CommandLine cmd{adbToolPath(), {"devices"}};
|
adbProcess.runBlocking();
|
||||||
adbProc.setCommand(cmd);
|
if (adbProcess.result() != ProcessResult::FinishedWithSuccess)
|
||||||
using namespace std::chrono_literals;
|
return {};
|
||||||
adbProc.runBlocking(30s);
|
|
||||||
if (adbProc.result() != ProcessResult::FinishedWithSuccess) {
|
|
||||||
if (error)
|
|
||||||
*error = Tr::tr("Could not run: %1").arg(cmd.toUserOutput());
|
|
||||||
return devices;
|
|
||||||
}
|
|
||||||
QStringList adbDevs = adbProc.allOutput().split('\n', Qt::SkipEmptyParts);
|
|
||||||
if (adbDevs.empty())
|
|
||||||
return devices;
|
|
||||||
|
|
||||||
for (const QString &line : adbDevs) // remove the daemon logs
|
// mid(1) - remove "List of devices attached" header line.
|
||||||
if (line.startsWith("* daemon"))
|
// Example output: "List of devices attached\nemulator-5554\tdevice\n\n".
|
||||||
adbDevs.removeOne(line);
|
return adbProcess.allOutput().split('\n', Qt::SkipEmptyParts).mid(1);
|
||||||
adbDevs.removeFirst(); // remove "List of devices attached" header line
|
|
||||||
|
|
||||||
// workaround for '????????????' serial numbers:
|
|
||||||
// can use "adb -d" when only one usb device attached
|
|
||||||
for (const QString &device : std::as_const(adbDevs)) {
|
|
||||||
const QString serialNo = device.left(device.indexOf('\t')).trimmed();
|
|
||||||
const QString deviceType = device.mid(device.indexOf('\t')).trimmed();
|
|
||||||
AndroidDeviceInfo dev;
|
|
||||||
dev.serialNumber = serialNo;
|
|
||||||
dev.type = serialNo.startsWith(QLatin1String("emulator")) ? IDevice::Emulator
|
|
||||||
: IDevice::Hardware;
|
|
||||||
dev.sdk = getSDKVersion(dev.serialNumber);
|
|
||||||
dev.cpuAbi = getAbis(dev.serialNumber);
|
|
||||||
if (deviceType == QLatin1String("unauthorized"))
|
|
||||||
dev.state = IDevice::DeviceConnected;
|
|
||||||
else if (deviceType == QLatin1String("offline"))
|
|
||||||
dev.state = IDevice::DeviceDisconnected;
|
|
||||||
else
|
|
||||||
dev.state = IDevice::DeviceReadyToUse;
|
|
||||||
|
|
||||||
if (dev.type == IDevice::Emulator) {
|
|
||||||
dev.avdName = getAvdName(dev.serialNumber);
|
|
||||||
if (dev.avdName.isEmpty())
|
|
||||||
dev.avdName = serialNo;
|
|
||||||
}
|
|
||||||
|
|
||||||
devices.push_back(dev);
|
|
||||||
}
|
|
||||||
|
|
||||||
Utils::sort(devices);
|
|
||||||
if (devices.isEmpty() && error)
|
|
||||||
*error = Tr::tr("No devices found in output of: %1").arg(cmd.toUserOutput());
|
|
||||||
return devices;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
bool isConnected(const QString &serialNumber)
|
bool isConnected(const QString &serialNumber)
|
||||||
{
|
{
|
||||||
const QList<AndroidDeviceInfo> devices = connectedDevices();
|
const QStringList lines = devicesCommandOutput();
|
||||||
for (const AndroidDeviceInfo &device : devices) {
|
for (const QString &line : lines) {
|
||||||
if (device.serialNumber == serialNumber)
|
// skip the daemon logs
|
||||||
|
if (!line.startsWith("* daemon") && line.left(line.indexOf('\t')).trimmed() == serialNumber)
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
return false;
|
return false;
|
||||||
@@ -1588,8 +1547,7 @@ void AndroidConfigurations::updateAndroidDevice()
|
|||||||
IDevice::ConstPtr dev = devMgr->find(Constants::ANDROID_DEVICE_ID);
|
IDevice::ConstPtr dev = devMgr->find(Constants::ANDROID_DEVICE_ID);
|
||||||
if (dev)
|
if (dev)
|
||||||
devMgr->removeDevice(dev->id());
|
devMgr->removeDevice(dev->id());
|
||||||
|
AndroidDeviceManager::setupDevicesWatcher();
|
||||||
AndroidDeviceManager::instance()->setupDevicesWatcher();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
#ifdef WITH_TESTS
|
#ifdef WITH_TESTS
|
||||||
|
@@ -38,6 +38,7 @@ public:
|
|||||||
|
|
||||||
namespace AndroidConfig {
|
namespace AndroidConfig {
|
||||||
|
|
||||||
|
QString getAvdName(const QString &serialnumber);
|
||||||
QStringList apiLevelNamesFor(const SdkPlatformList &platforms);
|
QStringList apiLevelNamesFor(const SdkPlatformList &platforms);
|
||||||
QString apiLevelNameFor(const SdkPlatform *platform);
|
QString apiLevelNameFor(const SdkPlatform *platform);
|
||||||
|
|
||||||
@@ -88,7 +89,7 @@ Utils::FilePath makePathFromNdk(const Utils::FilePath &ndkLocation);
|
|||||||
|
|
||||||
Utils::FilePath keytoolPath();
|
Utils::FilePath keytoolPath();
|
||||||
|
|
||||||
QList<AndroidDeviceInfo> connectedDevices(QString *error = nullptr);
|
QStringList devicesCommandOutput();
|
||||||
|
|
||||||
QString bestNdkPlatformMatch(int target, const QtSupport::QtVersion *qtVersion);
|
QString bestNdkPlatformMatch(int target, const QtSupport::QtVersion *qtVersion);
|
||||||
|
|
||||||
|
@@ -39,6 +39,7 @@
|
|||||||
#include <QTimer>
|
#include <QTimer>
|
||||||
|
|
||||||
using namespace ProjectExplorer;
|
using namespace ProjectExplorer;
|
||||||
|
using namespace Tasking;
|
||||||
using namespace Utils;
|
using namespace Utils;
|
||||||
|
|
||||||
namespace {
|
namespace {
|
||||||
@@ -51,16 +52,160 @@ static constexpr char ipRegexStr[] = "(\\d{1,3}\\.\\d{1,3}\\.\\d{1,3}\\.\\d{1,3}
|
|||||||
static const QRegularExpression ipRegex = QRegularExpression(ipRegexStr);
|
static const QRegularExpression ipRegex = QRegularExpression(ipRegexStr);
|
||||||
static constexpr char wifiDevicePort[] = "5555";
|
static constexpr char wifiDevicePort[] = "5555";
|
||||||
|
|
||||||
|
enum TagModification { CommentOut, Uncomment };
|
||||||
|
static class AndroidDeviceManagerInstance *s_instance = nullptr;
|
||||||
|
|
||||||
|
class AndroidDeviceManagerInstance : public QObject
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
AndroidDeviceManagerInstance(QObject *parent);
|
||||||
|
~AndroidDeviceManagerInstance()
|
||||||
|
{
|
||||||
|
QTC_ASSERT(s_instance == this, return);
|
||||||
|
s_instance = nullptr;
|
||||||
|
}
|
||||||
|
|
||||||
|
void setupDevicesWatcher();
|
||||||
|
void eraseAvd(const IDevice::Ptr &device, QWidget *parent);
|
||||||
|
|
||||||
|
Group m_avdListRecipe;
|
||||||
|
TaskTreeRunner m_avdListRunner;
|
||||||
|
std::unique_ptr<Process> m_removeAvdProcess;
|
||||||
|
QFileSystemWatcher m_avdFileSystemWatcher;
|
||||||
|
Guard m_avdPathGuard;
|
||||||
|
std::unique_ptr<Process> m_adbDeviceWatcherProcess;
|
||||||
|
};
|
||||||
|
|
||||||
static QString displayNameFromInfo(const AndroidDeviceInfo &info)
|
static QString displayNameFromInfo(const AndroidDeviceInfo &info)
|
||||||
{
|
{
|
||||||
return info.type == IDevice::Hardware ? AndroidConfig::getProductModel(info.serialNumber)
|
return info.type == IDevice::Hardware ? AndroidConfig::getProductModel(info.serialNumber)
|
||||||
: info.avdName;
|
: info.avdName;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static IDevice::DeviceState getDeviceState(const QString &serial, IDevice::MachineType type)
|
||||||
|
{
|
||||||
|
const QStringList args = AndroidDeviceInfo::adbSelector(serial) << "shell" << "echo 1";
|
||||||
|
const SdkToolResult result = AndroidManager::runAdbCommand(args);
|
||||||
|
if (result.success())
|
||||||
|
return IDevice::DeviceReadyToUse;
|
||||||
|
else if (type == IDevice::Emulator || result.stdErr().contains("unauthorized"))
|
||||||
|
return IDevice::DeviceConnected;
|
||||||
|
return IDevice::DeviceDisconnected;
|
||||||
|
}
|
||||||
|
|
||||||
|
static void updateDeviceState(const IDevice::ConstPtr &device)
|
||||||
|
{
|
||||||
|
const AndroidDevice *dev = static_cast<const AndroidDevice *>(device.get());
|
||||||
|
const QString serial = dev->serialNumber();
|
||||||
|
DeviceManager *const devMgr = DeviceManager::instance();
|
||||||
|
const Id id = dev->id();
|
||||||
|
if (!serial.isEmpty())
|
||||||
|
devMgr->setDeviceState(id, getDeviceState(serial, dev->machineType()));
|
||||||
|
else if (dev->machineType() == IDevice::Emulator)
|
||||||
|
devMgr->setDeviceState(id, IDevice::DeviceConnected);
|
||||||
|
}
|
||||||
|
|
||||||
|
static void startAvd(const IDevice::Ptr &device, QWidget *parent)
|
||||||
|
{
|
||||||
|
Q_UNUSED(parent)
|
||||||
|
const AndroidDevice *androidDev = static_cast<const AndroidDevice *>(device.get());
|
||||||
|
const QString name = androidDev->avdName();
|
||||||
|
qCDebug(androidDeviceLog, "Starting Android AVD id \"%s\".", qPrintable(name));
|
||||||
|
auto future = Utils::asyncRun([name, device] {
|
||||||
|
const QString serialNumber = AndroidAvdManager::startAvd(name);
|
||||||
|
// Mark the AVD as ReadyToUse once we know it's started
|
||||||
|
if (!serialNumber.isEmpty()) {
|
||||||
|
DeviceManager *const devMgr = DeviceManager::instance();
|
||||||
|
devMgr->setDeviceState(device->id(), IDevice::DeviceReadyToUse);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
// TODO: use future!
|
||||||
|
}
|
||||||
|
|
||||||
|
static void setEmulatorArguments(QWidget *parent)
|
||||||
|
{
|
||||||
|
const QString helpUrl =
|
||||||
|
"https://developer.android.com/studio/run/emulator-commandline#startup-options";
|
||||||
|
|
||||||
|
QInputDialog dialog(parent ? parent : Core::ICore::dialogParent());
|
||||||
|
dialog.setWindowTitle(Tr::tr("Emulator Command-line Startup Options"));
|
||||||
|
dialog.setLabelText(Tr::tr("Emulator command-line startup options "
|
||||||
|
"(<a href=\"%1\">Help Web Page</a>):")
|
||||||
|
.arg(helpUrl));
|
||||||
|
dialog.setTextValue(AndroidConfig::emulatorArgs());
|
||||||
|
|
||||||
|
if (auto label = dialog.findChild<QLabel *>()) {
|
||||||
|
label->setOpenExternalLinks(true);
|
||||||
|
label->setMinimumWidth(500);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (dialog.exec() == QDialog::Accepted)
|
||||||
|
AndroidConfig::setEmulatorArgs(dialog.textValue());
|
||||||
|
}
|
||||||
|
|
||||||
|
static QString emulatorName(const QString &serialNumber)
|
||||||
|
{
|
||||||
|
const QStringList args = AndroidDeviceInfo::adbSelector(serialNumber) << "emu" << "avd" << "name";
|
||||||
|
return AndroidManager::runAdbCommand(args).stdOut();
|
||||||
|
}
|
||||||
|
|
||||||
|
static QString getRunningAvdsSerialNumber(const QString &name)
|
||||||
|
{
|
||||||
|
const QStringList lines = AndroidConfig::devicesCommandOutput();
|
||||||
|
for (const QString &line : lines) {
|
||||||
|
// skip the daemon logs
|
||||||
|
if (line.startsWith("* daemon"))
|
||||||
|
continue;
|
||||||
|
|
||||||
|
const QString serialNumber = line.left(line.indexOf('\t')).trimmed();
|
||||||
|
if (!serialNumber.startsWith("emulator"))
|
||||||
|
continue;
|
||||||
|
|
||||||
|
const QString stdOut = emulatorName(serialNumber);
|
||||||
|
if (stdOut.isEmpty())
|
||||||
|
continue; // Not an avd
|
||||||
|
|
||||||
|
if (stdOut.left(stdOut.indexOf('\n')) == name)
|
||||||
|
return serialNumber;
|
||||||
|
}
|
||||||
|
return {};
|
||||||
|
}
|
||||||
|
|
||||||
|
static FilePath avdFilePath()
|
||||||
|
{
|
||||||
|
QString avdEnvVar = qtcEnvironmentVariable("ANDROID_AVD_HOME");
|
||||||
|
if (avdEnvVar.isEmpty()) {
|
||||||
|
avdEnvVar = qtcEnvironmentVariable("ANDROID_SDK_HOME");
|
||||||
|
if (avdEnvVar.isEmpty())
|
||||||
|
avdEnvVar = qtcEnvironmentVariable("HOME");
|
||||||
|
avdEnvVar.append("/.android/avd");
|
||||||
|
}
|
||||||
|
return FilePath::fromUserInput(avdEnvVar);
|
||||||
|
}
|
||||||
|
|
||||||
|
static IDevice::Ptr createDeviceFromInfo(const CreateAvdInfo &info)
|
||||||
|
{
|
||||||
|
if (info.apiLevel < 0) {
|
||||||
|
qCWarning(androidDeviceLog) << "System image of the created AVD is nullptr";
|
||||||
|
return IDevice::Ptr();
|
||||||
|
}
|
||||||
|
AndroidDevice *dev = new AndroidDevice;
|
||||||
|
const Id deviceId = AndroidDevice::idFromAvdInfo(info);
|
||||||
|
dev->setupId(IDevice::AutoDetected, deviceId);
|
||||||
|
dev->setMachineType(IDevice::Emulator);
|
||||||
|
dev->settings()->displayName.setValue(info.name);
|
||||||
|
dev->setDeviceState(IDevice::DeviceConnected);
|
||||||
|
dev->setAvdPath(avdFilePath() / (info.name + ".avd"));
|
||||||
|
dev->setExtraData(Constants::AndroidAvdName, info.name);
|
||||||
|
dev->setExtraData(Constants::AndroidCpuAbi, {info.abi});
|
||||||
|
dev->setExtraData(Constants::AndroidSdk, info.apiLevel);
|
||||||
|
return IDevice::Ptr(dev);
|
||||||
|
}
|
||||||
|
|
||||||
class AndroidDeviceWidget : public IDeviceWidget
|
class AndroidDeviceWidget : public IDeviceWidget
|
||||||
{
|
{
|
||||||
public:
|
public:
|
||||||
AndroidDeviceWidget(const ProjectExplorer::IDevice::Ptr &device);
|
AndroidDeviceWidget(const IDevice::Ptr &device);
|
||||||
|
|
||||||
void updateDeviceFromUi() final {}
|
void updateDeviceFromUi() final {}
|
||||||
static QString dialogTitle();
|
static QString dialogTitle();
|
||||||
@@ -70,6 +215,66 @@ public:
|
|||||||
static bool questionDialog(const QString &question, QWidget *parent = nullptr);
|
static bool questionDialog(const QString &question, QWidget *parent = nullptr);
|
||||||
};
|
};
|
||||||
|
|
||||||
|
static void setupWifiForDevice(const IDevice::Ptr &device, QWidget *parent)
|
||||||
|
{
|
||||||
|
if (device->deviceState() != IDevice::DeviceReadyToUse) {
|
||||||
|
AndroidDeviceWidget::infoDialog(
|
||||||
|
Tr::tr("The device has to be connected with ADB debugging "
|
||||||
|
"enabled to use this feature."), parent);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
const auto androidDev = static_cast<const AndroidDevice *>(device.get());
|
||||||
|
const QStringList adbSelector = AndroidDeviceInfo::adbSelector(androidDev->serialNumber());
|
||||||
|
// prepare port
|
||||||
|
QStringList args = adbSelector;
|
||||||
|
args.append({"tcpip", wifiDevicePort});
|
||||||
|
const SdkToolResult result = AndroidManager::runAdbCommand(args);
|
||||||
|
if (!result.success()) {
|
||||||
|
AndroidDeviceWidget::criticalDialog(
|
||||||
|
Tr::tr("Opening connection port %1 failed.").arg(wifiDevicePort),
|
||||||
|
parent);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
QTimer::singleShot(2000, parent, [adbSelector, parent] {
|
||||||
|
// Get device IP address
|
||||||
|
QStringList args = adbSelector;
|
||||||
|
args.append({"shell", "ip", "route"});
|
||||||
|
const SdkToolResult ipRes = AndroidManager::runAdbCommand(args);
|
||||||
|
if (!ipRes.success()) {
|
||||||
|
AndroidDeviceWidget::criticalDialog(
|
||||||
|
Tr::tr("Retrieving the device IP address failed."), parent);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Expected output from "ip route" is:
|
||||||
|
// 192.168.1.0/24 dev wlan0 proto kernel scope link src 192.168.1.190
|
||||||
|
// where the ip of interest is at the end of the line
|
||||||
|
const QStringList ipParts = ipRes.stdOut().split(" ");
|
||||||
|
QString ip;
|
||||||
|
if (!ipParts.isEmpty()) {
|
||||||
|
ip = ipParts.last();
|
||||||
|
}
|
||||||
|
if (!ipRegex.match(ipParts.last()).hasMatch()) {
|
||||||
|
AndroidDeviceWidget::criticalDialog(
|
||||||
|
Tr::tr("The retrieved IP address is invalid."), parent);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Connect to device
|
||||||
|
args = adbSelector;
|
||||||
|
args.append({"connect", QString("%1:%2").arg(ip).arg(wifiDevicePort)});
|
||||||
|
const SdkToolResult connectRes = AndroidManager::runAdbCommand(args);
|
||||||
|
if (!connectRes.success()) {
|
||||||
|
AndroidDeviceWidget::criticalDialog(
|
||||||
|
Tr::tr("Connecting to the device IP \"%1\" failed.").arg(ip),
|
||||||
|
parent);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
AndroidDeviceWidget::AndroidDeviceWidget(const IDevice::Ptr &device)
|
AndroidDeviceWidget::AndroidDeviceWidget(const IDevice::Ptr &device)
|
||||||
: IDeviceWidget(device)
|
: IDeviceWidget(device)
|
||||||
{
|
{
|
||||||
@@ -168,7 +373,7 @@ AndroidDevice::AndroidDevice()
|
|||||||
|
|
||||||
addDeviceAction({Tr::tr("Refresh"), [](const IDevice::Ptr &device, QWidget *parent) {
|
addDeviceAction({Tr::tr("Refresh"), [](const IDevice::Ptr &device, QWidget *parent) {
|
||||||
Q_UNUSED(parent)
|
Q_UNUSED(parent)
|
||||||
AndroidDeviceManager::instance()->updateDeviceState(device);
|
updateDeviceState(device);
|
||||||
}});
|
}});
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -198,26 +403,26 @@ void AndroidDevice::addActionsIfNotFound()
|
|||||||
if (machineType() == Emulator) {
|
if (machineType() == Emulator) {
|
||||||
if (!hasStartAction) {
|
if (!hasStartAction) {
|
||||||
addDeviceAction({startAvdAction, [](const IDevice::Ptr &device, QWidget *parent) {
|
addDeviceAction({startAvdAction, [](const IDevice::Ptr &device, QWidget *parent) {
|
||||||
AndroidDeviceManager::instance()->startAvd(device, parent);
|
startAvd(device, parent);
|
||||||
}});
|
}});
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!hasEraseAction) {
|
if (!hasEraseAction) {
|
||||||
addDeviceAction({eraseAvdAction, [](const IDevice::Ptr &device, QWidget *parent) {
|
addDeviceAction({eraseAvdAction, [](const IDevice::Ptr &device, QWidget *parent) {
|
||||||
AndroidDeviceManager::instance()->eraseAvd(device, parent);
|
s_instance->eraseAvd(device, parent);
|
||||||
}});
|
}});
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!hasAvdArgumentsAction) {
|
if (!hasAvdArgumentsAction) {
|
||||||
addDeviceAction({avdArgumentsAction, [](const IDevice::Ptr &device, QWidget *parent) {
|
addDeviceAction({avdArgumentsAction, [](const IDevice::Ptr &device, QWidget *parent) {
|
||||||
Q_UNUSED(device)
|
Q_UNUSED(device)
|
||||||
AndroidDeviceManager::instance()->setEmulatorArguments(parent);
|
setEmulatorArguments(parent);
|
||||||
}});
|
}});
|
||||||
}
|
}
|
||||||
} else if (machineType() == Hardware && !ipRegex.match(id().toString()).hasMatch()) {
|
} else if (machineType() == Hardware && !ipRegex.match(id().toString()).hasMatch()) {
|
||||||
if (!hasSetupWifi) {
|
if (!hasSetupWifi) {
|
||||||
addDeviceAction({setupWifi, [](const IDevice::Ptr &device, QWidget *parent) {
|
addDeviceAction({setupWifi, [](const IDevice::Ptr &device, QWidget *parent) {
|
||||||
AndroidDeviceManager::instance()->setupWifiForDevice(device, parent);
|
setupWifiForDevice(device, parent);
|
||||||
}});
|
}});
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -247,7 +452,6 @@ AndroidDeviceInfo AndroidDevice::androidDeviceInfoFromIDevice(const IDevice *dev
|
|||||||
info.avdPath = FilePath::fromSettings(dev->extraData(Constants::AndroidAvdPath));
|
info.avdPath = FilePath::fromSettings(dev->extraData(Constants::AndroidAvdPath));
|
||||||
info.sdk = dev->extraData(Constants::AndroidSdk).toInt();
|
info.sdk = dev->extraData(Constants::AndroidSdk).toInt();
|
||||||
info.type = dev->machineType();
|
info.type = dev->machineType();
|
||||||
|
|
||||||
return info;
|
return info;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -259,7 +463,7 @@ Id AndroidDevice::idFromDeviceInfo(const AndroidDeviceInfo &info)
|
|||||||
|
|
||||||
Id AndroidDevice::idFromAvdInfo(const CreateAvdInfo &info)
|
Id AndroidDevice::idFromAvdInfo(const CreateAvdInfo &info)
|
||||||
{
|
{
|
||||||
return Id(Constants::ANDROID_DEVICE_ID).withSuffix(':' + info.name);
|
return Id(Constants::ANDROID_DEVICE_ID).withSuffix(':' + info.name);
|
||||||
}
|
}
|
||||||
|
|
||||||
QStringList AndroidDevice::supportedAbis() const
|
QStringList AndroidDevice::supportedAbis() const
|
||||||
@@ -318,8 +522,7 @@ QString AndroidDevice::serialNumber() const
|
|||||||
const QString serialNumber = extraData(Constants::AndroidSerialNumber).toString();
|
const QString serialNumber = extraData(Constants::AndroidSerialNumber).toString();
|
||||||
if (machineType() == Hardware)
|
if (machineType() == Hardware)
|
||||||
return serialNumber;
|
return serialNumber;
|
||||||
|
return getRunningAvdsSerialNumber(avdName());
|
||||||
return AndroidDeviceManager::instance()->getRunningAvdsSerialNumber(avdName());
|
|
||||||
}
|
}
|
||||||
|
|
||||||
QString AndroidDevice::avdName() const
|
QString AndroidDevice::avdName() const
|
||||||
@@ -413,395 +616,7 @@ void AndroidDevice::initAvdSettings()
|
|||||||
m_avdSettings.reset(new QSettings(configPath.toUserOutput(), QSettings::IniFormat));
|
m_avdSettings.reset(new QSettings(configPath.toUserOutput(), QSettings::IniFormat));
|
||||||
}
|
}
|
||||||
|
|
||||||
void AndroidDeviceManager::updateAvdList()
|
static void handleDevicesListChange(const QString &serialNumber)
|
||||||
{
|
|
||||||
if (AndroidConfig::adbToolPath().exists())
|
|
||||||
m_avdListRunner.start(m_avdListRecipe);
|
|
||||||
}
|
|
||||||
|
|
||||||
IDevice::DeviceState AndroidDeviceManager::getDeviceState(const QString &serial,
|
|
||||||
IDevice::MachineType type) const
|
|
||||||
{
|
|
||||||
const QStringList args = AndroidDeviceInfo::adbSelector(serial) << "shell" << "echo 1";
|
|
||||||
const SdkToolResult result = AndroidManager::runAdbCommand(args);
|
|
||||||
if (result.success())
|
|
||||||
return IDevice::DeviceReadyToUse;
|
|
||||||
else if (type == IDevice::Emulator || result.stdErr().contains("unauthorized"))
|
|
||||||
return IDevice::DeviceConnected;
|
|
||||||
|
|
||||||
return IDevice::DeviceDisconnected;
|
|
||||||
}
|
|
||||||
|
|
||||||
void AndroidDeviceManager::updateDeviceState(const ProjectExplorer::IDevice::ConstPtr &device)
|
|
||||||
{
|
|
||||||
const AndroidDevice *dev = static_cast<const AndroidDevice *>(device.get());
|
|
||||||
const QString serial = dev->serialNumber();
|
|
||||||
DeviceManager *const devMgr = DeviceManager::instance();
|
|
||||||
const Id id = dev->id();
|
|
||||||
if (!serial.isEmpty())
|
|
||||||
devMgr->setDeviceState(id, getDeviceState(serial, dev->machineType()));
|
|
||||||
else if (dev->machineType() == IDevice::Emulator)
|
|
||||||
devMgr->setDeviceState(id, IDevice::DeviceConnected);
|
|
||||||
}
|
|
||||||
|
|
||||||
expected_str<void> AndroidDeviceManager::createAvd(const CreateAvdInfo &info, bool force)
|
|
||||||
{
|
|
||||||
CommandLine cmd(AndroidConfig::avdManagerToolPath(), {"create", "avd", "-n", info.name});
|
|
||||||
cmd.addArgs({"-k", info.sdkStylePath});
|
|
||||||
if (info.sdcardSize > 0)
|
|
||||||
cmd.addArgs({"-c", QString("%1M").arg(info.sdcardSize)});
|
|
||||||
|
|
||||||
const QString deviceDef = info.deviceDefinition;
|
|
||||||
if (!deviceDef.isEmpty() && deviceDef != "Custom")
|
|
||||||
cmd.addArgs({"-d", deviceDef});
|
|
||||||
|
|
||||||
if (force)
|
|
||||||
cmd.addArg("-f");
|
|
||||||
|
|
||||||
Process process;
|
|
||||||
process.setProcessMode(ProcessMode::Writer);
|
|
||||||
process.setEnvironment(AndroidConfig::toolsEnvironment());
|
|
||||||
process.setCommand(cmd);
|
|
||||||
process.setWriteData("yes\n"); // yes to "Do you wish to create a custom hardware profile"
|
|
||||||
|
|
||||||
QByteArray buffer;
|
|
||||||
QObject::connect(&process, &Process::readyReadStandardOutput, &process, [&process, &buffer] {
|
|
||||||
// This interaction is needed only if there is no "-d" arg for the avdmanager command.
|
|
||||||
buffer += process.readAllRawStandardOutput();
|
|
||||||
if (buffer.endsWith(QByteArray("]:"))) {
|
|
||||||
// truncate to last line
|
|
||||||
const int index = buffer.lastIndexOf('\n');
|
|
||||||
if (index != -1)
|
|
||||||
buffer = buffer.mid(index);
|
|
||||||
if (buffer.contains("hw.gpu.enabled"))
|
|
||||||
process.write("yes\n");
|
|
||||||
else
|
|
||||||
process.write("\n");
|
|
||||||
buffer.clear();
|
|
||||||
}
|
|
||||||
});
|
|
||||||
|
|
||||||
GuardLocker locker(m_avdPathGuard);
|
|
||||||
process.runBlocking();
|
|
||||||
if (process.result() != ProcessResult::FinishedWithSuccess)
|
|
||||||
return Utils::make_unexpected(process.exitMessage());
|
|
||||||
return {};
|
|
||||||
}
|
|
||||||
|
|
||||||
void AndroidDeviceManager::startAvd(const ProjectExplorer::IDevice::Ptr &device, QWidget *parent)
|
|
||||||
{
|
|
||||||
Q_UNUSED(parent)
|
|
||||||
const AndroidDevice *androidDev = static_cast<const AndroidDevice *>(device.get());
|
|
||||||
const QString name = androidDev->avdName();
|
|
||||||
qCDebug(androidDeviceLog, "Starting Android AVD id \"%s\".", qPrintable(name));
|
|
||||||
auto future = Utils::asyncRun([name, device] {
|
|
||||||
const QString serialNumber = AndroidAvdManager::startAvd(name);
|
|
||||||
// Mark the AVD as ReadyToUse once we know it's started
|
|
||||||
if (!serialNumber.isEmpty()) {
|
|
||||||
DeviceManager *const devMgr = DeviceManager::instance();
|
|
||||||
devMgr->setDeviceState(device->id(), IDevice::DeviceReadyToUse);
|
|
||||||
}
|
|
||||||
});
|
|
||||||
// TODO: use future!
|
|
||||||
}
|
|
||||||
|
|
||||||
void AndroidDeviceManager::eraseAvd(const IDevice::Ptr &device, QWidget *parent)
|
|
||||||
{
|
|
||||||
if (!device)
|
|
||||||
return;
|
|
||||||
|
|
||||||
if (device->machineType() == IDevice::Hardware)
|
|
||||||
return;
|
|
||||||
|
|
||||||
const QString name = static_cast<const AndroidDevice *>(device.get())->avdName();
|
|
||||||
const QString question
|
|
||||||
= Tr::tr("Erase the Android AVD \"%1\"?\nThis cannot be undone.").arg(name);
|
|
||||||
if (!AndroidDeviceWidget::questionDialog(question, parent))
|
|
||||||
return;
|
|
||||||
|
|
||||||
qCDebug(androidDeviceLog) << QString("Erasing Android AVD \"%1\" from the system.").arg(name);
|
|
||||||
m_removeAvdProcess.reset(new Process);
|
|
||||||
const CommandLine command(AndroidConfig::avdManagerToolPath(), {"delete", "avd", "-n", name});
|
|
||||||
qCDebug(androidDeviceLog).noquote() << "Running command (removeAvd):" << command.toUserOutput();
|
|
||||||
m_removeAvdProcess->setEnvironment(AndroidConfig::toolsEnvironment());
|
|
||||||
m_removeAvdProcess->setCommand(command);
|
|
||||||
connect(m_removeAvdProcess.get(), &Process::done, this, [this, device] {
|
|
||||||
const QString name = device->displayName();
|
|
||||||
if (m_removeAvdProcess->result() == ProcessResult::FinishedWithSuccess) {
|
|
||||||
qCDebug(androidDeviceLog, "Android AVD id \"%s\" removed from the system.",
|
|
||||||
qPrintable(name));
|
|
||||||
// Remove the device from QtC after it's been removed using avdmanager.
|
|
||||||
DeviceManager::instance()->removeDevice(device->id());
|
|
||||||
} else {
|
|
||||||
AndroidDeviceWidget::criticalDialog(Tr::tr("An error occurred while removing the "
|
|
||||||
"Android AVD \"%1\" using avdmanager tool.").arg(name));
|
|
||||||
}
|
|
||||||
m_removeAvdProcess.release()->deleteLater();
|
|
||||||
});
|
|
||||||
m_removeAvdProcess->start();
|
|
||||||
}
|
|
||||||
|
|
||||||
void AndroidDeviceManager::setupWifiForDevice(const IDevice::Ptr &device, QWidget *parent)
|
|
||||||
{
|
|
||||||
if (device->deviceState() != IDevice::DeviceReadyToUse) {
|
|
||||||
AndroidDeviceWidget::infoDialog(
|
|
||||||
Tr::tr("The device has to be connected with ADB debugging "
|
|
||||||
"enabled to use this feature."), parent);
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
const auto androidDev = static_cast<const AndroidDevice *>(device.get());
|
|
||||||
const QStringList adbSelector = AndroidDeviceInfo::adbSelector(androidDev->serialNumber());
|
|
||||||
// prepare port
|
|
||||||
QStringList args = adbSelector;
|
|
||||||
args.append({"tcpip", wifiDevicePort});
|
|
||||||
const SdkToolResult result = AndroidManager::runAdbCommand(args);
|
|
||||||
if (!result.success()) {
|
|
||||||
AndroidDeviceWidget::criticalDialog(
|
|
||||||
Tr::tr("Opening connection port %1 failed.").arg(wifiDevicePort),
|
|
||||||
parent);
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
QTimer::singleShot(2000, parent, [adbSelector, parent] {
|
|
||||||
// Get device IP address
|
|
||||||
QStringList args = adbSelector;
|
|
||||||
args.append({"shell", "ip", "route"});
|
|
||||||
const SdkToolResult ipRes = AndroidManager::runAdbCommand(args);
|
|
||||||
if (!ipRes.success()) {
|
|
||||||
AndroidDeviceWidget::criticalDialog(
|
|
||||||
Tr::tr("Retrieving the device IP address failed."), parent);
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
// Expected output from "ip route" is:
|
|
||||||
// 192.168.1.0/24 dev wlan0 proto kernel scope link src 192.168.1.190
|
|
||||||
// where the ip of interest is at the end of the line
|
|
||||||
const QStringList ipParts = ipRes.stdOut().split(" ");
|
|
||||||
QString ip;
|
|
||||||
if (!ipParts.isEmpty()) {
|
|
||||||
ip = ipParts.last();
|
|
||||||
}
|
|
||||||
if (!ipRegex.match(ipParts.last()).hasMatch()) {
|
|
||||||
AndroidDeviceWidget::criticalDialog(
|
|
||||||
Tr::tr("The retrieved IP address is invalid."), parent);
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
// Connect to device
|
|
||||||
args = adbSelector;
|
|
||||||
args.append({"connect", QString("%1:%2").arg(ip).arg(wifiDevicePort)});
|
|
||||||
const SdkToolResult connectRes = AndroidManager::runAdbCommand(args);
|
|
||||||
if (!connectRes.success()) {
|
|
||||||
AndroidDeviceWidget::criticalDialog(
|
|
||||||
Tr::tr("Connecting to the device IP \"%1\" failed.").arg(ip),
|
|
||||||
parent);
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
QString AndroidDeviceManager::emulatorName(const QString &serialNumber) const
|
|
||||||
{
|
|
||||||
QStringList args = AndroidDeviceInfo::adbSelector(serialNumber);
|
|
||||||
args.append({"emu", "avd", "name"});
|
|
||||||
return AndroidManager::runAdbCommand(args).stdOut();
|
|
||||||
}
|
|
||||||
|
|
||||||
void AndroidDeviceManager::setEmulatorArguments(QWidget *parent)
|
|
||||||
{
|
|
||||||
const QString helpUrl =
|
|
||||||
"https://developer.android.com/studio/run/emulator-commandline#startup-options";
|
|
||||||
|
|
||||||
QInputDialog dialog(parent ? parent : Core::ICore::dialogParent());
|
|
||||||
dialog.setWindowTitle(Tr::tr("Emulator Command-line Startup Options"));
|
|
||||||
dialog.setLabelText(Tr::tr("Emulator command-line startup options "
|
|
||||||
"(<a href=\"%1\">Help Web Page</a>):")
|
|
||||||
.arg(helpUrl));
|
|
||||||
dialog.setTextValue(AndroidConfig::emulatorArgs());
|
|
||||||
|
|
||||||
if (auto label = dialog.findChild<QLabel*>()) {
|
|
||||||
label->setOpenExternalLinks(true);
|
|
||||||
label->setMinimumWidth(500);
|
|
||||||
}
|
|
||||||
|
|
||||||
if (dialog.exec() != QDialog::Accepted)
|
|
||||||
return;
|
|
||||||
|
|
||||||
AndroidConfig::setEmulatorArgs(dialog.textValue());
|
|
||||||
}
|
|
||||||
|
|
||||||
QString AndroidDeviceManager::getRunningAvdsSerialNumber(const QString &name) const
|
|
||||||
{
|
|
||||||
for (const AndroidDeviceInfo &dev : AndroidConfig::connectedDevices()) {
|
|
||||||
if (!dev.serialNumber.startsWith("emulator"))
|
|
||||||
continue;
|
|
||||||
const QString stdOut = emulatorName(dev.serialNumber);
|
|
||||||
if (stdOut.isEmpty())
|
|
||||||
continue; // Not an avd
|
|
||||||
const QStringList outputLines = stdOut.split('\n');
|
|
||||||
if (outputLines.size() > 1 && outputLines.first() == name)
|
|
||||||
return dev.serialNumber;
|
|
||||||
}
|
|
||||||
|
|
||||||
return {};
|
|
||||||
}
|
|
||||||
|
|
||||||
static FilePath avdFilePath()
|
|
||||||
{
|
|
||||||
QString avdEnvVar = qtcEnvironmentVariable("ANDROID_AVD_HOME");
|
|
||||||
if (avdEnvVar.isEmpty()) {
|
|
||||||
avdEnvVar = qtcEnvironmentVariable("ANDROID_SDK_HOME");
|
|
||||||
if (avdEnvVar.isEmpty())
|
|
||||||
avdEnvVar = qtcEnvironmentVariable("HOME");
|
|
||||||
avdEnvVar.append("/.android/avd");
|
|
||||||
}
|
|
||||||
return FilePath::fromUserInput(avdEnvVar);
|
|
||||||
}
|
|
||||||
|
|
||||||
void AndroidDeviceManager::setupDevicesWatcher()
|
|
||||||
{
|
|
||||||
if (!AndroidConfig::adbToolPath().exists()) {
|
|
||||||
qCDebug(androidDeviceLog) << "Cannot start ADB device watcher"
|
|
||||||
<< "because adb path does not exist.";
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (!m_adbDeviceWatcherProcess)
|
|
||||||
m_adbDeviceWatcherProcess.reset(new Process(this));
|
|
||||||
|
|
||||||
if (m_adbDeviceWatcherProcess->isRunning()) {
|
|
||||||
qCDebug(androidDeviceLog) << "ADB device watcher is already running.";
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
connect(m_adbDeviceWatcherProcess.get(), &Process::done, this, [this] {
|
|
||||||
if (m_adbDeviceWatcherProcess->error() != QProcess::UnknownError) {
|
|
||||||
qCDebug(androidDeviceLog) << "ADB device watcher encountered an error:"
|
|
||||||
<< m_adbDeviceWatcherProcess->errorString();
|
|
||||||
if (!m_adbDeviceWatcherProcess->isRunning()) {
|
|
||||||
qCDebug(androidDeviceLog) << "Restarting the ADB device watcher now.";
|
|
||||||
QTimer::singleShot(0, m_adbDeviceWatcherProcess.get(), &Process::start);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
qCDebug(androidDeviceLog) << "ADB device watcher finished.";
|
|
||||||
});
|
|
||||||
|
|
||||||
m_adbDeviceWatcherProcess->setStdErrLineCallback([](const QString &error) {
|
|
||||||
qCDebug(androidDeviceLog) << "ADB device watcher error" << error; });
|
|
||||||
m_adbDeviceWatcherProcess->setStdOutLineCallback([this](const QString &output) {
|
|
||||||
handleDevicesListChange(output);
|
|
||||||
});
|
|
||||||
|
|
||||||
const CommandLine command{AndroidConfig::adbToolPath(), {"track-devices"}};
|
|
||||||
m_adbDeviceWatcherProcess->setCommand(command);
|
|
||||||
m_adbDeviceWatcherProcess->setWorkingDirectory(command.executable().parentDir());
|
|
||||||
m_adbDeviceWatcherProcess->setEnvironment(AndroidConfig::toolsEnvironment());
|
|
||||||
m_adbDeviceWatcherProcess->start();
|
|
||||||
|
|
||||||
// Setup AVD filesystem watcher to listen for changes when an avd is created/deleted,
|
|
||||||
// or started/stopped
|
|
||||||
m_avdFileSystemWatcher.addPath(avdFilePath().toString());
|
|
||||||
connect(&m_avdFileSystemWatcher, &QFileSystemWatcher::directoryChanged, this, [this] {
|
|
||||||
if (!m_avdPathGuard.isLocked())
|
|
||||||
updateAvdList();
|
|
||||||
});
|
|
||||||
// Call initial update
|
|
||||||
updateAvdList();
|
|
||||||
}
|
|
||||||
|
|
||||||
IDevice::Ptr AndroidDeviceManager::createDeviceFromInfo(const CreateAvdInfo &info)
|
|
||||||
{
|
|
||||||
if (info.apiLevel < 0) {
|
|
||||||
qCWarning(androidDeviceLog) << "System image of the created AVD is nullptr";
|
|
||||||
return IDevice::Ptr();
|
|
||||||
}
|
|
||||||
AndroidDevice *dev = new AndroidDevice;
|
|
||||||
const Utils::Id deviceId = AndroidDevice::idFromAvdInfo(info);
|
|
||||||
dev->setupId(IDevice::AutoDetected, deviceId);
|
|
||||||
dev->setMachineType(IDevice::Emulator);
|
|
||||||
dev->settings()->displayName.setValue(info.name);
|
|
||||||
dev->setDeviceState(IDevice::DeviceConnected);
|
|
||||||
dev->setAvdPath(avdFilePath() / (info.name + ".avd"));
|
|
||||||
dev->setExtraData(Constants::AndroidAvdName, info.name);
|
|
||||||
dev->setExtraData(Constants::AndroidCpuAbi, {info.abi});
|
|
||||||
dev->setExtraData(Constants::AndroidSdk, info.apiLevel);
|
|
||||||
return IDevice::Ptr(dev);
|
|
||||||
}
|
|
||||||
|
|
||||||
void AndroidDeviceManager::handleAvdListChange(const AndroidDeviceInfoList &avdList)
|
|
||||||
{
|
|
||||||
DeviceManager *const devMgr = DeviceManager::instance();
|
|
||||||
|
|
||||||
QList<Id> existingAvds;
|
|
||||||
for (int i = 0; i < devMgr->deviceCount(); ++i) {
|
|
||||||
const IDevice::ConstPtr dev = devMgr->deviceAt(i);
|
|
||||||
const bool isEmulator = dev->machineType() == IDevice::Emulator;
|
|
||||||
if (isEmulator && dev->type() == Constants::ANDROID_DEVICE_TYPE)
|
|
||||||
existingAvds.append(dev->id());
|
|
||||||
}
|
|
||||||
|
|
||||||
QList<Id> connectedDevs;
|
|
||||||
for (const AndroidDeviceInfo &item : avdList) {
|
|
||||||
const Id deviceId = AndroidDevice::idFromDeviceInfo(item);
|
|
||||||
const QString displayName = displayNameFromInfo(item);
|
|
||||||
IDevice::ConstPtr dev = devMgr->find(deviceId);
|
|
||||||
if (dev) {
|
|
||||||
const auto androidDev = static_cast<const AndroidDevice *>(dev.get());
|
|
||||||
// DeviceManager doens't seem to have a way to directly update the name, if the name
|
|
||||||
// of the device has changed, remove it and register it again with the new name.
|
|
||||||
// Also account for the case of an AVD registered through old QC which might have
|
|
||||||
// invalid data by checking if the avdPath is not empty.
|
|
||||||
if (dev->displayName() != displayName || androidDev->avdPath().toString().isEmpty()) {
|
|
||||||
devMgr->removeDevice(dev->id());
|
|
||||||
} else {
|
|
||||||
// Find the state of the AVD retrieved from the AVD watcher
|
|
||||||
const QString serial = getRunningAvdsSerialNumber(item.avdName);
|
|
||||||
if (!serial.isEmpty()) {
|
|
||||||
const IDevice::DeviceState state = getDeviceState(serial, IDevice::Emulator);
|
|
||||||
if (dev->deviceState() != state) {
|
|
||||||
devMgr->setDeviceState(dev->id(), state);
|
|
||||||
qCDebug(androidDeviceLog, "Device id \"%s\" changed its state.",
|
|
||||||
dev->id().toString().toUtf8().data());
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
devMgr->setDeviceState(dev->id(), IDevice::DeviceConnected);
|
|
||||||
}
|
|
||||||
connectedDevs.append(dev->id());
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
AndroidDevice *newDev = new AndroidDevice();
|
|
||||||
newDev->setupId(IDevice::AutoDetected, deviceId);
|
|
||||||
newDev->settings()->displayName.setValue(displayName);
|
|
||||||
newDev->setMachineType(item.type);
|
|
||||||
newDev->setDeviceState(item.state);
|
|
||||||
|
|
||||||
newDev->setExtraData(Constants::AndroidAvdName, item.avdName);
|
|
||||||
newDev->setExtraData(Constants::AndroidSerialNumber, item.serialNumber);
|
|
||||||
newDev->setExtraData(Constants::AndroidCpuAbi, item.cpuAbi);
|
|
||||||
newDev->setExtraData(Constants::AndroidSdk, item.sdk);
|
|
||||||
newDev->setAvdPath(item.avdPath);
|
|
||||||
|
|
||||||
qCDebug(androidDeviceLog, "Registering new Android device id \"%s\".",
|
|
||||||
newDev->id().toString().toUtf8().data());
|
|
||||||
const IDevice::ConstPtr constNewDev = IDevice::ConstPtr(newDev);
|
|
||||||
devMgr->addDevice(IDevice::ConstPtr(constNewDev));
|
|
||||||
connectedDevs.append(constNewDev->id());
|
|
||||||
}
|
|
||||||
|
|
||||||
// Set devices no longer connected to disconnected state.
|
|
||||||
for (const Id &id : existingAvds) {
|
|
||||||
if (!connectedDevs.contains(id)) {
|
|
||||||
qCDebug(androidDeviceLog, "Removing AVD id \"%s\" because it no longer exists.",
|
|
||||||
id.toString().toUtf8().data());
|
|
||||||
devMgr->removeDevice(id);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
void AndroidDeviceManager::handleDevicesListChange(const QString &serialNumber)
|
|
||||||
{
|
{
|
||||||
DeviceManager *const devMgr = DeviceManager::instance();
|
DeviceManager *const devMgr = DeviceManager::instance();
|
||||||
const QStringList serialBits = serialNumber.split('\t');
|
const QStringList serialBits = serialNumber.split('\t');
|
||||||
@@ -870,15 +685,6 @@ void AndroidDeviceManager::handleDevicesListChange(const QString &serialNumber)
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
static AndroidDeviceManager *s_instance = nullptr;
|
|
||||||
|
|
||||||
AndroidDeviceManager *AndroidDeviceManager::instance()
|
|
||||||
{
|
|
||||||
return s_instance;
|
|
||||||
}
|
|
||||||
|
|
||||||
enum TagModification { CommentOut, Uncomment };
|
|
||||||
|
|
||||||
static void modifyManufacturerTag(const FilePath &avdPath, TagModification modification)
|
static void modifyManufacturerTag(const FilePath &avdPath, TagModification modification)
|
||||||
{
|
{
|
||||||
if (!avdPath.exists())
|
if (!avdPath.exists())
|
||||||
@@ -905,15 +711,85 @@ static void modifyManufacturerTag(const FilePath &avdPath, TagModification modif
|
|||||||
saver.finalize();
|
saver.finalize();
|
||||||
}
|
}
|
||||||
|
|
||||||
AndroidDeviceManager::AndroidDeviceManager(QObject *parent)
|
static void handleAvdListChange(const AndroidDeviceInfoList &avdList)
|
||||||
|
{
|
||||||
|
DeviceManager *const devMgr = DeviceManager::instance();
|
||||||
|
|
||||||
|
QList<Id> existingAvds;
|
||||||
|
for (int i = 0; i < devMgr->deviceCount(); ++i) {
|
||||||
|
const IDevice::ConstPtr dev = devMgr->deviceAt(i);
|
||||||
|
const bool isEmulator = dev->machineType() == IDevice::Emulator;
|
||||||
|
if (isEmulator && dev->type() == Constants::ANDROID_DEVICE_TYPE)
|
||||||
|
existingAvds.append(dev->id());
|
||||||
|
}
|
||||||
|
|
||||||
|
QList<Id> connectedDevs;
|
||||||
|
for (const AndroidDeviceInfo &item : avdList) {
|
||||||
|
const Id deviceId = AndroidDevice::idFromDeviceInfo(item);
|
||||||
|
const QString displayName = displayNameFromInfo(item);
|
||||||
|
IDevice::ConstPtr dev = devMgr->find(deviceId);
|
||||||
|
if (dev) {
|
||||||
|
const auto androidDev = static_cast<const AndroidDevice *>(dev.get());
|
||||||
|
// DeviceManager doens't seem to have a way to directly update the name, if the name
|
||||||
|
// of the device has changed, remove it and register it again with the new name.
|
||||||
|
// Also account for the case of an AVD registered through old QC which might have
|
||||||
|
// invalid data by checking if the avdPath is not empty.
|
||||||
|
if (dev->displayName() != displayName || androidDev->avdPath().toString().isEmpty()) {
|
||||||
|
devMgr->removeDevice(dev->id());
|
||||||
|
} else {
|
||||||
|
// Find the state of the AVD retrieved from the AVD watcher
|
||||||
|
const QString serial = getRunningAvdsSerialNumber(item.avdName);
|
||||||
|
if (!serial.isEmpty()) {
|
||||||
|
const IDevice::DeviceState state = getDeviceState(serial, IDevice::Emulator);
|
||||||
|
if (dev->deviceState() != state) {
|
||||||
|
devMgr->setDeviceState(dev->id(), state);
|
||||||
|
qCDebug(androidDeviceLog, "Device id \"%s\" changed its state.",
|
||||||
|
dev->id().toString().toUtf8().data());
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
devMgr->setDeviceState(dev->id(), IDevice::DeviceConnected);
|
||||||
|
}
|
||||||
|
connectedDevs.append(dev->id());
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
AndroidDevice *newDev = new AndroidDevice;
|
||||||
|
newDev->setupId(IDevice::AutoDetected, deviceId);
|
||||||
|
newDev->settings()->displayName.setValue(displayName);
|
||||||
|
newDev->setMachineType(item.type);
|
||||||
|
newDev->setDeviceState(item.state);
|
||||||
|
|
||||||
|
newDev->setExtraData(Constants::AndroidAvdName, item.avdName);
|
||||||
|
newDev->setExtraData(Constants::AndroidSerialNumber, item.serialNumber);
|
||||||
|
newDev->setExtraData(Constants::AndroidCpuAbi, item.cpuAbi);
|
||||||
|
newDev->setExtraData(Constants::AndroidSdk, item.sdk);
|
||||||
|
newDev->setAvdPath(item.avdPath);
|
||||||
|
|
||||||
|
qCDebug(androidDeviceLog, "Registering new Android device id \"%s\".",
|
||||||
|
newDev->id().toString().toUtf8().data());
|
||||||
|
const IDevice::ConstPtr constNewDev = IDevice::ConstPtr(newDev);
|
||||||
|
devMgr->addDevice(IDevice::ConstPtr(constNewDev));
|
||||||
|
connectedDevs.append(constNewDev->id());
|
||||||
|
}
|
||||||
|
|
||||||
|
// Set devices no longer connected to disconnected state.
|
||||||
|
for (const Id &id : existingAvds) {
|
||||||
|
if (!connectedDevs.contains(id)) {
|
||||||
|
qCDebug(androidDeviceLog, "Removing AVD id \"%s\" because it no longer exists.",
|
||||||
|
id.toString().toUtf8().data());
|
||||||
|
devMgr->removeDevice(id);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
AndroidDeviceManagerInstance::AndroidDeviceManagerInstance(QObject *parent)
|
||||||
: QObject(parent)
|
: QObject(parent)
|
||||||
, m_avdListRecipe{}
|
, m_avdListRecipe{}
|
||||||
{
|
{
|
||||||
QTC_ASSERT(!s_instance, return);
|
QTC_ASSERT(!s_instance, return);
|
||||||
s_instance = this;
|
s_instance = this;
|
||||||
|
|
||||||
using namespace Tasking;
|
|
||||||
|
|
||||||
const Storage<FilePaths> storage;
|
const Storage<FilePaths> storage;
|
||||||
|
|
||||||
const LoopUntil iterator([storage](int iteration) {
|
const LoopUntil iterator([storage](int iteration) {
|
||||||
@@ -926,7 +802,7 @@ AndroidDeviceManager::AndroidDeviceManager(QObject *parent)
|
|||||||
process.setEnvironment(AndroidConfig::toolsEnvironment());
|
process.setEnvironment(AndroidConfig::toolsEnvironment());
|
||||||
process.setCommand(cmd);
|
process.setCommand(cmd);
|
||||||
};
|
};
|
||||||
const auto onProcessDone = [this, storage](const Process &process, DoneWith result) {
|
const auto onProcessDone = [storage](const Process &process, DoneWith result) {
|
||||||
const QString output = process.allOutput();
|
const QString output = process.allOutput();
|
||||||
if (result != DoneWith::Success) {
|
if (result != DoneWith::Success) {
|
||||||
qCDebug(androidDeviceLog)
|
qCDebug(androidDeviceLog)
|
||||||
@@ -962,15 +838,153 @@ AndroidDeviceManager::AndroidDeviceManager(QObject *parent)
|
|||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
AndroidDeviceManager::~AndroidDeviceManager()
|
void AndroidDeviceManagerInstance::setupDevicesWatcher()
|
||||||
{
|
{
|
||||||
QTC_ASSERT(s_instance == this, return);
|
if (!AndroidConfig::adbToolPath().exists()) {
|
||||||
s_instance = nullptr;
|
qCDebug(androidDeviceLog) << "Cannot start ADB device watcher"
|
||||||
|
<< "because adb path does not exist.";
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!m_adbDeviceWatcherProcess)
|
||||||
|
m_adbDeviceWatcherProcess.reset(new Process(this));
|
||||||
|
|
||||||
|
if (m_adbDeviceWatcherProcess->isRunning()) {
|
||||||
|
qCDebug(androidDeviceLog) << "ADB device watcher is already running.";
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
connect(m_adbDeviceWatcherProcess.get(), &Process::done, this, [this] {
|
||||||
|
if (m_adbDeviceWatcherProcess->error() != QProcess::UnknownError) {
|
||||||
|
qCDebug(androidDeviceLog) << "ADB device watcher encountered an error:"
|
||||||
|
<< m_adbDeviceWatcherProcess->errorString();
|
||||||
|
if (!m_adbDeviceWatcherProcess->isRunning()) {
|
||||||
|
qCDebug(androidDeviceLog) << "Restarting the ADB device watcher now.";
|
||||||
|
QTimer::singleShot(0, m_adbDeviceWatcherProcess.get(), &Process::start);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
qCDebug(androidDeviceLog) << "ADB device watcher finished.";
|
||||||
|
});
|
||||||
|
|
||||||
|
m_adbDeviceWatcherProcess->setStdErrLineCallback([](const QString &error) {
|
||||||
|
qCDebug(androidDeviceLog) << "ADB device watcher error" << error; });
|
||||||
|
m_adbDeviceWatcherProcess->setStdOutLineCallback([](const QString &output) {
|
||||||
|
handleDevicesListChange(output);
|
||||||
|
});
|
||||||
|
|
||||||
|
const CommandLine command{AndroidConfig::adbToolPath(), {"track-devices"}};
|
||||||
|
m_adbDeviceWatcherProcess->setCommand(command);
|
||||||
|
m_adbDeviceWatcherProcess->setWorkingDirectory(command.executable().parentDir());
|
||||||
|
m_adbDeviceWatcherProcess->setEnvironment(AndroidConfig::toolsEnvironment());
|
||||||
|
m_adbDeviceWatcherProcess->start();
|
||||||
|
|
||||||
|
// Setup AVD filesystem watcher to listen for changes when an avd is created/deleted,
|
||||||
|
// or started/stopped
|
||||||
|
m_avdFileSystemWatcher.addPath(avdFilePath().toString());
|
||||||
|
connect(&m_avdFileSystemWatcher, &QFileSystemWatcher::directoryChanged, this, [this] {
|
||||||
|
if (!m_avdPathGuard.isLocked())
|
||||||
|
AndroidDeviceManager::updateAvdList();
|
||||||
|
});
|
||||||
|
// Call initial update
|
||||||
|
AndroidDeviceManager::updateAvdList();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void AndroidDeviceManagerInstance::eraseAvd(const IDevice::Ptr &device, QWidget *parent)
|
||||||
|
{
|
||||||
|
if (!device)
|
||||||
|
return;
|
||||||
|
|
||||||
|
if (device->machineType() == IDevice::Hardware)
|
||||||
|
return;
|
||||||
|
|
||||||
|
const QString name = static_cast<const AndroidDevice *>(device.get())->avdName();
|
||||||
|
const QString question
|
||||||
|
= Tr::tr("Erase the Android AVD \"%1\"?\nThis cannot be undone.").arg(name);
|
||||||
|
if (!AndroidDeviceWidget::questionDialog(question, parent))
|
||||||
|
return;
|
||||||
|
|
||||||
|
qCDebug(androidDeviceLog) << QString("Erasing Android AVD \"%1\" from the system.").arg(name);
|
||||||
|
m_removeAvdProcess.reset(new Process);
|
||||||
|
const CommandLine command(AndroidConfig::avdManagerToolPath(), {"delete", "avd", "-n", name});
|
||||||
|
qCDebug(androidDeviceLog).noquote() << "Running command (removeAvd):" << command.toUserOutput();
|
||||||
|
m_removeAvdProcess->setEnvironment(AndroidConfig::toolsEnvironment());
|
||||||
|
m_removeAvdProcess->setCommand(command);
|
||||||
|
connect(m_removeAvdProcess.get(), &Process::done, this, [this, device] {
|
||||||
|
const QString name = device->displayName();
|
||||||
|
if (m_removeAvdProcess->result() == ProcessResult::FinishedWithSuccess) {
|
||||||
|
qCDebug(androidDeviceLog, "Android AVD id \"%s\" removed from the system.",
|
||||||
|
qPrintable(name));
|
||||||
|
// Remove the device from QtC after it's been removed using avdmanager.
|
||||||
|
DeviceManager::instance()->removeDevice(device->id());
|
||||||
|
} else {
|
||||||
|
AndroidDeviceWidget::criticalDialog(Tr::tr("An error occurred while removing the "
|
||||||
|
"Android AVD \"%1\" using avdmanager tool.").arg(name));
|
||||||
|
}
|
||||||
|
m_removeAvdProcess.release()->deleteLater();
|
||||||
|
});
|
||||||
|
m_removeAvdProcess->start();
|
||||||
|
}
|
||||||
|
|
||||||
|
namespace AndroidDeviceManager {
|
||||||
|
|
||||||
|
void setupDevicesWatcher() { s_instance->setupDevicesWatcher(); }
|
||||||
|
|
||||||
|
void updateAvdList()
|
||||||
|
{
|
||||||
|
if (AndroidConfig::adbToolPath().exists())
|
||||||
|
s_instance->m_avdListRunner.start(s_instance->m_avdListRecipe);
|
||||||
|
}
|
||||||
|
|
||||||
|
expected_str<void> createAvd(const CreateAvdInfo &info, bool force)
|
||||||
|
{
|
||||||
|
CommandLine cmd(AndroidConfig::avdManagerToolPath(), {"create", "avd", "-n", info.name});
|
||||||
|
cmd.addArgs({"-k", info.sdkStylePath});
|
||||||
|
if (info.sdcardSize > 0)
|
||||||
|
cmd.addArgs({"-c", QString("%1M").arg(info.sdcardSize)});
|
||||||
|
|
||||||
|
const QString deviceDef = info.deviceDefinition;
|
||||||
|
if (!deviceDef.isEmpty() && deviceDef != "Custom")
|
||||||
|
cmd.addArgs({"-d", deviceDef});
|
||||||
|
|
||||||
|
if (force)
|
||||||
|
cmd.addArg("-f");
|
||||||
|
|
||||||
|
Process process;
|
||||||
|
process.setProcessMode(ProcessMode::Writer);
|
||||||
|
process.setEnvironment(AndroidConfig::toolsEnvironment());
|
||||||
|
process.setCommand(cmd);
|
||||||
|
process.setWriteData("yes\n"); // yes to "Do you wish to create a custom hardware profile"
|
||||||
|
|
||||||
|
QByteArray buffer;
|
||||||
|
QObject::connect(&process, &Process::readyReadStandardOutput, &process, [&process, &buffer] {
|
||||||
|
// This interaction is needed only if there is no "-d" arg for the avdmanager command.
|
||||||
|
buffer += process.readAllRawStandardOutput();
|
||||||
|
if (buffer.endsWith(QByteArray("]:"))) {
|
||||||
|
// truncate to last line
|
||||||
|
const int index = buffer.lastIndexOf('\n');
|
||||||
|
if (index != -1)
|
||||||
|
buffer = buffer.mid(index);
|
||||||
|
if (buffer.contains("hw.gpu.enabled"))
|
||||||
|
process.write("yes\n");
|
||||||
|
else
|
||||||
|
process.write("\n");
|
||||||
|
buffer.clear();
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
GuardLocker locker(s_instance->m_avdPathGuard);
|
||||||
|
process.runBlocking();
|
||||||
|
if (process.result() != ProcessResult::FinishedWithSuccess)
|
||||||
|
return Utils::make_unexpected(process.exitMessage());
|
||||||
|
return {};
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
} // namespace AndroidDeviceManager
|
||||||
|
|
||||||
// Factory
|
// Factory
|
||||||
|
|
||||||
class AndroidDeviceFactory final : public ProjectExplorer::IDeviceFactory
|
class AndroidDeviceFactory final : public IDeviceFactory
|
||||||
{
|
{
|
||||||
public:
|
public:
|
||||||
AndroidDeviceFactory()
|
AndroidDeviceFactory()
|
||||||
@@ -990,7 +1004,7 @@ public:
|
|||||||
if (dialog.exec() != QDialog::Accepted)
|
if (dialog.exec() != QDialog::Accepted)
|
||||||
return IDevice::Ptr();
|
return IDevice::Ptr();
|
||||||
|
|
||||||
const IDevice::Ptr dev = AndroidDeviceManager::createDeviceFromInfo(dialog.avdInfo());
|
const IDevice::Ptr dev = createDeviceFromInfo(dialog.avdInfo());
|
||||||
if (const auto androidDev = static_cast<AndroidDevice *>(dev.get())) {
|
if (const auto androidDev = static_cast<AndroidDevice *>(dev.get())) {
|
||||||
qCDebug(androidDeviceLog, "Created new Android AVD id \"%s\".",
|
qCDebug(androidDeviceLog, "Created new Android AVD id \"%s\".",
|
||||||
qPrintable(androidDev->avdName()));
|
qPrintable(androidDev->avdName()));
|
||||||
@@ -1010,7 +1024,7 @@ void setupAndroidDevice()
|
|||||||
|
|
||||||
void setupAndroidDeviceManager(QObject *guard)
|
void setupAndroidDeviceManager(QObject *guard)
|
||||||
{
|
{
|
||||||
(void) new AndroidDeviceManager(guard);
|
(void) new AndroidDeviceManagerInstance(guard);
|
||||||
}
|
}
|
||||||
|
|
||||||
} // Android::Internal
|
} // Android::Internal
|
||||||
|
@@ -70,44 +70,13 @@ private:
|
|||||||
std::unique_ptr<QSettings> m_avdSettings;
|
std::unique_ptr<QSettings> m_avdSettings;
|
||||||
};
|
};
|
||||||
|
|
||||||
class AndroidDeviceManager : public QObject
|
namespace AndroidDeviceManager {
|
||||||
{
|
|
||||||
public:
|
|
||||||
static AndroidDeviceManager *instance();
|
|
||||||
void setupDevicesWatcher();
|
|
||||||
void updateAvdList();
|
|
||||||
IDevice::DeviceState getDeviceState(const QString &serial, IDevice::MachineType type) const;
|
|
||||||
void updateDeviceState(const ProjectExplorer::IDevice::ConstPtr &device);
|
|
||||||
|
|
||||||
Utils::expected_str<void> createAvd(const CreateAvdInfo &info, bool force);
|
void setupDevicesWatcher();
|
||||||
void startAvd(const ProjectExplorer::IDevice::Ptr &device, QWidget *parent = nullptr);
|
void updateAvdList();
|
||||||
void eraseAvd(const ProjectExplorer::IDevice::Ptr &device, QWidget *parent = nullptr);
|
Utils::expected_str<void> createAvd(const CreateAvdInfo &info, bool force);
|
||||||
void setupWifiForDevice(const ProjectExplorer::IDevice::Ptr &device, QWidget *parent = nullptr);
|
|
||||||
|
|
||||||
void setEmulatorArguments(QWidget *parent = nullptr);
|
} // namespace AndroidDeviceManager
|
||||||
|
|
||||||
QString getRunningAvdsSerialNumber(const QString &name) const;
|
|
||||||
|
|
||||||
static ProjectExplorer::IDevice::Ptr createDeviceFromInfo(const CreateAvdInfo &info);
|
|
||||||
|
|
||||||
private:
|
|
||||||
explicit AndroidDeviceManager(QObject *parent);
|
|
||||||
~AndroidDeviceManager();
|
|
||||||
|
|
||||||
void handleDevicesListChange(const QString &serialNumber);
|
|
||||||
void handleAvdListChange(const AndroidDeviceInfoList &avdList);
|
|
||||||
|
|
||||||
QString emulatorName(const QString &serialNumber) const;
|
|
||||||
|
|
||||||
Tasking::Group m_avdListRecipe;
|
|
||||||
Tasking::TaskTreeRunner m_avdListRunner;
|
|
||||||
std::unique_ptr<Utils::Process> m_removeAvdProcess;
|
|
||||||
QFileSystemWatcher m_avdFileSystemWatcher;
|
|
||||||
Utils::Guard m_avdPathGuard;
|
|
||||||
std::unique_ptr<Utils::Process> m_adbDeviceWatcherProcess;
|
|
||||||
|
|
||||||
friend void setupAndroidDeviceManager(QObject *guard);
|
|
||||||
};
|
|
||||||
|
|
||||||
void setupAndroidDevice();
|
void setupAndroidDevice();
|
||||||
void setupAndroidDeviceManager(QObject *guard);
|
void setupAndroidDeviceManager(QObject *guard);
|
||||||
|
@@ -628,17 +628,15 @@ void AndroidRunnerWorker::asyncStart()
|
|||||||
using namespace Tasking;
|
using namespace Tasking;
|
||||||
|
|
||||||
const Storage<PidUserPair> pidStorage;
|
const Storage<PidUserPair> pidStorage;
|
||||||
const LoopUntil iterator([pidStorage](int) { return pidStorage->first <= 0; });
|
|
||||||
|
|
||||||
const FilePath adbPath = AndroidConfig::adbToolPath();
|
const FilePath adbPath = AndroidConfig::adbToolPath();
|
||||||
const QStringList args = selector();
|
const QStringList args = selector();
|
||||||
|
const QString pidScript = m_isPreNougat
|
||||||
|
? QString("for p in /proc/[0-9]*; do cat <$p/cmdline && echo :${p##*/}; done")
|
||||||
|
: QString("pidof -s '%1'").arg(m_packageName);
|
||||||
|
|
||||||
const auto onPidSetup = [adbPath, args, packageName = m_packageName,
|
const auto onPidSetup = [adbPath, args, pidScript](Process &process) {
|
||||||
isPreNougat = m_isPreNougat](Process &process) {
|
process.setCommand({adbPath, {args, "shell", pidScript}});
|
||||||
const QString pidScript = isPreNougat
|
|
||||||
? QString("for p in /proc/[0-9]*; do cat <$p/cmdline && echo :${p##*/}; done")
|
|
||||||
: QString("pidof -s '%1'").arg(packageName);
|
|
||||||
process.setCommand({adbPath, args + QStringList{"shell", pidScript}});
|
|
||||||
};
|
};
|
||||||
const auto onPidDone = [pidStorage, packageName = m_packageName,
|
const auto onPidDone = [pidStorage, packageName = m_packageName,
|
||||||
isPreNougat = m_isPreNougat](const Process &process) {
|
isPreNougat = m_isPreNougat](const Process &process) {
|
||||||
@@ -650,8 +648,8 @@ void AndroidRunnerWorker::asyncStart()
|
|||||||
};
|
};
|
||||||
|
|
||||||
const auto onUserSetup = [pidStorage, adbPath, args](Process &process) {
|
const auto onUserSetup = [pidStorage, adbPath, args](Process &process) {
|
||||||
process.setCommand({adbPath, args
|
process.setCommand({adbPath, {args, "shell", "ps", "-o", "user", "-p",
|
||||||
+ QStringList{"shell", "ps", "-o", "user", "-p", QString::number(pidStorage->first)}});
|
QString::number(pidStorage->first)}});
|
||||||
};
|
};
|
||||||
const auto onUserDone = [pidStorage](const Process &process) {
|
const auto onUserDone = [pidStorage](const Process &process) {
|
||||||
const QString out = process.allOutput();
|
const QString out = process.allOutput();
|
||||||
@@ -674,10 +672,11 @@ void AndroidRunnerWorker::asyncStart()
|
|||||||
const Group root {
|
const Group root {
|
||||||
pidStorage,
|
pidStorage,
|
||||||
onGroupSetup([pidStorage] { *pidStorage = {-1, 0}; }),
|
onGroupSetup([pidStorage] { *pidStorage = {-1, 0}; }),
|
||||||
Group {
|
Forever {
|
||||||
iterator,
|
stopOnSuccess,
|
||||||
ProcessTask(onPidSetup, onPidDone, CallDoneIf::Success),
|
ProcessTask(onPidSetup, onPidDone, CallDoneIf::Success),
|
||||||
TimeoutTask([](std::chrono::milliseconds &timeout) { timeout = 200ms; })
|
TimeoutTask([](std::chrono::milliseconds &timeout) { timeout = 200ms; },
|
||||||
|
[] { return DoneResult::Error; })
|
||||||
}.withTimeout(45s),
|
}.withTimeout(45s),
|
||||||
ProcessTask(onUserSetup, onUserDone, CallDoneIf::Success),
|
ProcessTask(onUserSetup, onUserDone, CallDoneIf::Success),
|
||||||
onGroupDone([pidStorage, this] { onProcessIdChanged(*pidStorage); })
|
onGroupDone([pidStorage, this] { onProcessIdChanged(*pidStorage); })
|
||||||
|
@@ -131,15 +131,15 @@ int AvdDialog::exec()
|
|||||||
|
|
||||||
const CreateAvdInfo avdInfo{si->sdkStylePath(), si->apiLevel(), name(), abi(),
|
const CreateAvdInfo avdInfo{si->sdkStylePath(), si->apiLevel(), name(), abi(),
|
||||||
deviceDefinition(), sdcardSize()};
|
deviceDefinition(), sdcardSize()};
|
||||||
const auto result = AndroidDeviceManager::instance()->createAvd(
|
const auto result = AndroidDeviceManager::createAvd(avdInfo,
|
||||||
avdInfo, m_overwriteCheckBox->isChecked());
|
m_overwriteCheckBox->isChecked());
|
||||||
if (!result) {
|
if (!result) {
|
||||||
QMessageBox::warning(Core::ICore::dialogParent(), Tr::tr("Create new AVD"),
|
QMessageBox::warning(Core::ICore::dialogParent(), Tr::tr("Create new AVD"),
|
||||||
result.error());
|
result.error());
|
||||||
return QDialog::Rejected;
|
return QDialog::Rejected;
|
||||||
}
|
}
|
||||||
m_createdAvdInfo = avdInfo;
|
m_createdAvdInfo = avdInfo;
|
||||||
AndroidDeviceManager::instance()->updateAvdList();
|
AndroidDeviceManager::updateAvdList();
|
||||||
}
|
}
|
||||||
return execResult;
|
return execResult;
|
||||||
}
|
}
|
||||||
|
@@ -1,4 +1,8 @@
|
|||||||
|
find_package(Qt6 COMPONENTS Charts QUIET)
|
||||||
|
|
||||||
add_qtc_plugin(AppStatisticsMonitor
|
add_qtc_plugin(AppStatisticsMonitor
|
||||||
|
CONDITION TARGET Qt6::Charts
|
||||||
|
DEPENDS Qt6::Charts
|
||||||
SKIP_TRANSLATION
|
SKIP_TRANSLATION
|
||||||
PLUGIN_DEPENDS Core ProjectExplorer
|
PLUGIN_DEPENDS Core ProjectExplorer
|
||||||
SOURCES
|
SOURCES
|
||||||
|
@@ -3,6 +3,9 @@ QtcPlugin {
|
|||||||
|
|
||||||
Depends { name: "Core" }
|
Depends { name: "Core" }
|
||||||
Depends { name: "ProjectExplorer" }
|
Depends { name: "ProjectExplorer" }
|
||||||
|
Depends { name: "Qt.charts"; required: false }
|
||||||
|
|
||||||
|
condition: Qt.charts.present
|
||||||
|
|
||||||
files: [
|
files: [
|
||||||
"appstatisticsmonitorplugin.cpp",
|
"appstatisticsmonitorplugin.cpp",
|
||||||
|
@@ -5,11 +5,19 @@
|
|||||||
|
|
||||||
#include <utils/theme/theme.h>
|
#include <utils/theme/theme.h>
|
||||||
|
|
||||||
|
#include <QAbstractAxis>
|
||||||
|
#include <QChartView>
|
||||||
|
#include <QDebug>
|
||||||
#include <QPaintEvent>
|
#include <QPaintEvent>
|
||||||
#include <QPainter>
|
#include <QPainter>
|
||||||
#include <QPen>
|
#include <QPen>
|
||||||
#include <QPointF>
|
#include <QPointF>
|
||||||
|
#include <QRandomGenerator>
|
||||||
|
#include <QSplineSeries>
|
||||||
#include <QString>
|
#include <QString>
|
||||||
|
#include <QValueAxis>
|
||||||
|
|
||||||
|
using namespace Utils;
|
||||||
|
|
||||||
namespace AppStatisticsMonitor::Internal {
|
namespace AppStatisticsMonitor::Internal {
|
||||||
|
|
||||||
@@ -17,6 +25,100 @@ static const int padding = 40;
|
|||||||
static const int numPadding = 10;
|
static const int numPadding = 10;
|
||||||
static const QRectF dataRangeDefault = QRectF(0, 0, 5, 1);
|
static const QRectF dataRangeDefault = QRectF(0, 0, 5, 1);
|
||||||
|
|
||||||
|
AppStatisticsMonitorChart::AppStatisticsMonitorChart(
|
||||||
|
const QString &name, QGraphicsItem *parent, Qt::WindowFlags wFlags)
|
||||||
|
: QChart(QChart::ChartTypeCartesian, parent, wFlags)
|
||||||
|
, m_series(new QLineSeries(this))
|
||||||
|
, m_axisX(new QValueAxis())
|
||||||
|
, m_axisY(new QValueAxis())
|
||||||
|
, m_point(0, 0)
|
||||||
|
, m_chartView(new QChartView(this))
|
||||||
|
, m_name(name)
|
||||||
|
{
|
||||||
|
m_chartView->setMinimumHeight(200);
|
||||||
|
m_chartView->setMinimumWidth(400);
|
||||||
|
const QBrush brushTitle(creatorColor(Theme::Token_Text_Muted));
|
||||||
|
const QBrush brush(creatorColor(Theme::Token_Background_Default));
|
||||||
|
const QPen penBack(creatorColor(Theme::Token_Text_Muted));
|
||||||
|
const QPen penAxis(creatorColor(Theme::Token_Text_Muted));
|
||||||
|
|
||||||
|
setTitleBrush(brushTitle);
|
||||||
|
setBackgroundBrush(brush);
|
||||||
|
setBackgroundPen(penBack);
|
||||||
|
m_axisX->setLinePen(penAxis);
|
||||||
|
m_axisY->setLinePen(penAxis);
|
||||||
|
m_axisX->setLabelsColor(creatorColor(Theme::Token_Text_Muted));
|
||||||
|
m_axisY->setLabelsColor(creatorColor(Theme::Token_Text_Muted));
|
||||||
|
QPen pen(creatorColor(Theme::Token_Accent_Default));
|
||||||
|
pen.setWidth(2);
|
||||||
|
m_series->setPen(pen);
|
||||||
|
|
||||||
|
setTitle(m_name + " " + QString::number(m_point.y(), 'g', 4) + "%");
|
||||||
|
m_chartView->setRenderHint(QPainter::Antialiasing);
|
||||||
|
m_chartView->setSizePolicy(QSizePolicy::Expanding, QSizePolicy::Expanding);
|
||||||
|
addSeries(m_series);
|
||||||
|
|
||||||
|
addAxis(m_axisX, Qt::AlignBottom);
|
||||||
|
addAxis(m_axisY, Qt::AlignLeft);
|
||||||
|
m_series->attachAxis(m_axisX);
|
||||||
|
m_series->attachAxis(m_axisY);
|
||||||
|
m_axisX->applyNiceNumbers();
|
||||||
|
m_axisY->applyNiceNumbers();
|
||||||
|
legend()->hide();
|
||||||
|
|
||||||
|
clear();
|
||||||
|
}
|
||||||
|
|
||||||
|
QChartView *AppStatisticsMonitorChart::chartView()
|
||||||
|
{
|
||||||
|
return m_chartView;
|
||||||
|
}
|
||||||
|
|
||||||
|
void AppStatisticsMonitorChart::addNewPoint(const QPointF &point)
|
||||||
|
{
|
||||||
|
m_point = point;
|
||||||
|
if (m_axisY->max() < m_point.y())
|
||||||
|
m_axisY->setRange(0, qRound(m_point.y()) + 1);
|
||||||
|
m_axisX->setRange(0, qRound(m_point.x()) + 1);
|
||||||
|
|
||||||
|
setTitle(m_name + " " + QString::number(m_point.y(), 'g', 4) + "%");
|
||||||
|
m_series->append(m_point);
|
||||||
|
}
|
||||||
|
|
||||||
|
void AppStatisticsMonitorChart::loadNewProcessData(const QList<double> &data)
|
||||||
|
{
|
||||||
|
clear();
|
||||||
|
QList<QPointF> points{{0, 0}};
|
||||||
|
int i = 0;
|
||||||
|
double max_y = 0;
|
||||||
|
|
||||||
|
for (double e : qAsConst(data)) {
|
||||||
|
points.push_back({double(++i), e});
|
||||||
|
max_y = qMax(max_y, e);
|
||||||
|
}
|
||||||
|
|
||||||
|
m_axisY->setRange(0, qRound(max_y) + 1);
|
||||||
|
m_axisX->setRange(0, data.size() + 1);
|
||||||
|
|
||||||
|
m_series->clear();
|
||||||
|
m_series->append(points);
|
||||||
|
}
|
||||||
|
|
||||||
|
void AppStatisticsMonitorChart::clear()
|
||||||
|
{
|
||||||
|
m_axisX->setRange(0, 5);
|
||||||
|
m_axisY->setRange(0, 1);
|
||||||
|
m_series->clear();
|
||||||
|
m_series->append(0, 0);
|
||||||
|
}
|
||||||
|
|
||||||
|
double AppStatisticsMonitorChart::lastPointX() const
|
||||||
|
{
|
||||||
|
return m_point.x();
|
||||||
|
}
|
||||||
|
|
||||||
|
//---------------------- Chart -----------------------
|
||||||
|
|
||||||
Chart::Chart(const QString &name, QWidget *parent)
|
Chart::Chart(const QString &name, QWidget *parent)
|
||||||
: QWidget(parent)
|
: QWidget(parent)
|
||||||
, m_name(name)
|
, m_name(name)
|
||||||
@@ -31,7 +133,7 @@ void Chart::addNewPoint(const QPointF &point)
|
|||||||
update();
|
update();
|
||||||
}
|
}
|
||||||
|
|
||||||
void Chart::loadNewProcessData(QList<double> data)
|
void Chart::loadNewProcessData(const QList<double> &data)
|
||||||
{
|
{
|
||||||
clear();
|
clear();
|
||||||
for (long i = 0; i < data.size(); ++i) {
|
for (long i = 0; i < data.size(); ++i) {
|
||||||
@@ -59,7 +161,7 @@ void Chart::paintEvent(QPaintEvent *event)
|
|||||||
Q_UNUSED(event);
|
Q_UNUSED(event);
|
||||||
QPainter painter(this);
|
QPainter painter(this);
|
||||||
|
|
||||||
painter.fillRect(rect(), Utils::creatorColor(Utils::Theme::Token_Background_Default));
|
painter.fillRect(rect(), creatorColor(Theme::Token_Background_Default));
|
||||||
|
|
||||||
// add the name of the chart in the middle of the widget width and on the top
|
// add the name of the chart in the middle of the widget width and on the top
|
||||||
painter.drawText(
|
painter.drawText(
|
||||||
@@ -74,10 +176,10 @@ void Chart::paintEvent(QPaintEvent *event)
|
|||||||
double xPos = padding + (x - dataRange.left()) * m_xScale;
|
double xPos = padding + (x - dataRange.left()) * m_xScale;
|
||||||
if (xPos < padding || xPos > width() - padding)
|
if (xPos < padding || xPos > width() - padding)
|
||||||
continue;
|
continue;
|
||||||
painter.setPen(Utils::creatorColor(Utils::Theme::Token_Foreground_Default));
|
painter.setPen(creatorColor(Theme::Token_Foreground_Default));
|
||||||
painter.drawLine(xPos, padding, xPos, height() - padding);
|
painter.drawLine(xPos, padding, xPos, height() - padding);
|
||||||
|
|
||||||
painter.setPen(Utils::creatorColor(Utils::Theme::Token_Text_Muted));
|
painter.setPen(creatorColor(Theme::Token_Text_Muted));
|
||||||
painter.drawText(xPos, height() - numPadding, QString::number(x));
|
painter.drawText(xPos, height() - numPadding, QString::number(x));
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -86,18 +188,18 @@ void Chart::paintEvent(QPaintEvent *event)
|
|||||||
if (yPos < padding || yPos > height() - padding)
|
if (yPos < padding || yPos > height() - padding)
|
||||||
continue;
|
continue;
|
||||||
|
|
||||||
painter.setPen(Utils::creatorColor(Utils::Theme::Token_Foreground_Default));
|
painter.setPen(creatorColor(Theme::Token_Foreground_Default));
|
||||||
painter.drawLine(padding, yPos, width() - padding, yPos);
|
painter.drawLine(padding, yPos, width() - padding, yPos);
|
||||||
|
|
||||||
painter.setPen(Utils::creatorColor(Utils::Theme::Token_Text_Muted));
|
painter.setPen(creatorColor(Theme::Token_Text_Muted));
|
||||||
painter.drawText(numPadding, yPos, QString::number(y));
|
painter.drawText(numPadding, yPos, QString::number(y));
|
||||||
}
|
}
|
||||||
|
|
||||||
painter.setPen(Utils::creatorColor(Utils::Theme::Token_Foreground_Default));
|
painter.setPen(creatorColor(Theme::Token_Foreground_Default));
|
||||||
painter.drawLine(padding, height() - padding, width() - padding, height() - padding); // X axis
|
painter.drawLine(padding, height() - padding, width() - padding, height() - padding); // X axis
|
||||||
painter.drawLine(padding, height() - padding, padding, padding); // Y axis
|
painter.drawLine(padding, height() - padding, padding, padding); // Y axis
|
||||||
|
|
||||||
QPen pen(Utils::creatorColor(Utils::Theme::Token_Accent_Default));
|
QPen pen(creatorColor(Theme::Token_Accent_Default));
|
||||||
pen.setWidth(2);
|
pen.setWidth(2);
|
||||||
painter.setPen(pen);
|
painter.setPen(pen);
|
||||||
painter.setRenderHint(QPainter::Antialiasing);
|
painter.setRenderHint(QPainter::Antialiasing);
|
||||||
|
@@ -2,21 +2,51 @@
|
|||||||
// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0+ OR GPL-3.0 WITH Qt-GPL-exception-1.0
|
// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0+ OR GPL-3.0 WITH Qt-GPL-exception-1.0
|
||||||
#pragma once
|
#pragma once
|
||||||
|
|
||||||
|
#include <QChart>
|
||||||
#include <QList>
|
#include <QList>
|
||||||
#include <QPaintEvent>
|
#include <QPaintEvent>
|
||||||
#include <QPointF>
|
#include <QPointF>
|
||||||
#include <QRectF>
|
#include <QRectF>
|
||||||
#include <QWidget>
|
#include <QWidget>
|
||||||
|
|
||||||
|
QT_BEGIN_NAMESPACE
|
||||||
|
class QChartView;
|
||||||
|
class QLineSeries;
|
||||||
|
class QValueAxis;
|
||||||
|
QT_END_NAMESPACE
|
||||||
|
|
||||||
namespace AppStatisticsMonitor::Internal {
|
namespace AppStatisticsMonitor::Internal {
|
||||||
|
|
||||||
|
class AppStatisticsMonitorChart : public QChart
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
AppStatisticsMonitorChart(
|
||||||
|
const QString &name, QGraphicsItem *parent = nullptr, Qt::WindowFlags wFlags = {});
|
||||||
|
|
||||||
|
void addNewPoint(const QPointF &point);
|
||||||
|
void loadNewProcessData(const QList<double> &data);
|
||||||
|
double lastPointX() const;
|
||||||
|
void clear();
|
||||||
|
QChartView *chartView();
|
||||||
|
|
||||||
|
private:
|
||||||
|
QLineSeries *m_series;
|
||||||
|
QStringList m_titles;
|
||||||
|
QValueAxis *m_axisX;
|
||||||
|
QValueAxis *m_axisY;
|
||||||
|
QPointF m_point;
|
||||||
|
|
||||||
|
QChartView *m_chartView;
|
||||||
|
QString m_name;
|
||||||
|
};
|
||||||
|
|
||||||
class Chart : public QWidget
|
class Chart : public QWidget
|
||||||
{
|
{
|
||||||
public:
|
public:
|
||||||
Chart(const QString &name, QWidget *parent = nullptr);
|
Chart(const QString &name, QWidget *parent = nullptr);
|
||||||
|
|
||||||
void addNewPoint(const QPointF &point);
|
void addNewPoint(const QPointF &point);
|
||||||
void loadNewProcessData(QList<double> data);
|
void loadNewProcessData(const QList<double> &data);
|
||||||
double lastPointX() const;
|
double lastPointX() const;
|
||||||
|
|
||||||
void clear();
|
void clear();
|
||||||
|
@@ -11,6 +11,7 @@
|
|||||||
#include <projectexplorer/projectexplorer.h>
|
#include <projectexplorer/projectexplorer.h>
|
||||||
#include <projectexplorer/runcontrol.h>
|
#include <projectexplorer/runcontrol.h>
|
||||||
|
|
||||||
|
#include <QChartView>
|
||||||
#include <QFormLayout>
|
#include <QFormLayout>
|
||||||
#include <QGraphicsItem>
|
#include <QGraphicsItem>
|
||||||
#include <QHash>
|
#include <QHash>
|
||||||
@@ -24,15 +25,15 @@ class AppStatisticsMonitorView : public QWidget
|
|||||||
{
|
{
|
||||||
public:
|
public:
|
||||||
explicit AppStatisticsMonitorView(
|
explicit AppStatisticsMonitorView(
|
||||||
AppStatisticsMonitorManager *appStatisticManager, QWidget *parent = nullptr);
|
AppStatisticsMonitorManager *appStatisticManager);
|
||||||
|
|
||||||
~AppStatisticsMonitorView() override;
|
~AppStatisticsMonitorView() override;
|
||||||
|
|
||||||
private:
|
private:
|
||||||
QComboBox *m_comboBox;
|
QComboBox *m_comboBox;
|
||||||
|
|
||||||
Chart *m_memChart;
|
std::unique_ptr<AppStatisticsMonitorChart> m_chartMem;
|
||||||
Chart *m_cpuChart;
|
std::unique_ptr<AppStatisticsMonitorChart> m_chartCpu;
|
||||||
|
|
||||||
AppStatisticsMonitorManager *m_manager;
|
AppStatisticsMonitorManager *m_manager;
|
||||||
};
|
};
|
||||||
@@ -114,25 +115,21 @@ QHash<qint64, QString> AppStatisticsMonitorManager::pidNameMap() const
|
|||||||
}
|
}
|
||||||
|
|
||||||
// AppStatisticsMonitorView
|
// AppStatisticsMonitorView
|
||||||
AppStatisticsMonitorView::AppStatisticsMonitorView(AppStatisticsMonitorManager *dapManager, QWidget *)
|
AppStatisticsMonitorView::AppStatisticsMonitorView(AppStatisticsMonitorManager *appManager)
|
||||||
: m_manager(dapManager)
|
: m_manager(appManager)
|
||||||
{
|
{
|
||||||
auto layout = new QVBoxLayout;
|
auto layout = new QVBoxLayout;
|
||||||
auto form = new QFormLayout;
|
auto form = new QFormLayout;
|
||||||
setLayout(layout);
|
setLayout(layout);
|
||||||
|
|
||||||
m_comboBox = new QComboBox();
|
m_comboBox = new QComboBox(this);
|
||||||
form->addRow(m_comboBox);
|
form->addRow(m_comboBox);
|
||||||
|
|
||||||
m_memChart = new Chart("Memory consumption ");
|
m_chartMem = std::make_unique<AppStatisticsMonitorChart>(tr("Memory consumption"));
|
||||||
m_memChart->setSizePolicy(QSizePolicy::Expanding, QSizePolicy::Expanding);
|
m_chartCpu = std::make_unique<AppStatisticsMonitorChart>(tr("CPU consumption"));
|
||||||
m_memChart->clear();
|
|
||||||
form->addRow(m_memChart);
|
|
||||||
|
|
||||||
m_cpuChart = new Chart("CPU consumption ");
|
form->addRow(m_chartMem->chartView());
|
||||||
m_cpuChart->setSizePolicy(QSizePolicy::Expanding, QSizePolicy::Expanding);
|
form->addRow(m_chartCpu->chartView());
|
||||||
m_cpuChart->clear();
|
|
||||||
form->addRow(m_cpuChart);
|
|
||||||
|
|
||||||
layout->addLayout(form);
|
layout->addLayout(form);
|
||||||
|
|
||||||
@@ -142,16 +139,19 @@ AppStatisticsMonitorView::AppStatisticsMonitorView(AppStatisticsMonitorManager *
|
|||||||
}
|
}
|
||||||
m_comboBox->setCurrentIndex(m_comboBox->count() - 1);
|
m_comboBox->setCurrentIndex(m_comboBox->count() - 1);
|
||||||
|
|
||||||
m_memChart->clear();
|
m_chartCpu->clear();
|
||||||
m_cpuChart->clear();
|
m_chartMem->clear();
|
||||||
|
|
||||||
auto updateCharts = [this](int index) {
|
auto updateCharts = [this](int index) {
|
||||||
m_manager->setCurrentDataProvider(m_comboBox->itemData(index).toLongLong());
|
m_manager->setCurrentDataProvider(m_comboBox->itemData(index).toLongLong());
|
||||||
if (m_manager->currentDataProvider() != nullptr) {
|
if (m_manager->currentDataProvider() != nullptr) {
|
||||||
m_memChart->loadNewProcessData(
|
const QList<double> &memConsumptionHistory
|
||||||
m_manager->currentDataProvider()->memoryConsumptionHistory());
|
= m_manager->currentDataProvider()->memoryConsumptionHistory();
|
||||||
m_cpuChart->loadNewProcessData(
|
const QList<double> &cpuConsumptionHistory
|
||||||
m_manager->currentDataProvider()->cpuConsumptionHistory());
|
= m_manager->currentDataProvider()->cpuConsumptionHistory();
|
||||||
|
|
||||||
|
m_chartMem->loadNewProcessData(memConsumptionHistory);
|
||||||
|
m_chartCpu->loadNewProcessData(cpuConsumptionHistory);
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
@@ -170,16 +170,17 @@ AppStatisticsMonitorView::AppStatisticsMonitorView(AppStatisticsMonitorManager *
|
|||||||
if (pid != m_comboBox->currentData()) {
|
if (pid != m_comboBox->currentData()) {
|
||||||
m_comboBox->addItem(name + " : " + QString::number(pid), pid);
|
m_comboBox->addItem(name + " : " + QString::number(pid), pid);
|
||||||
|
|
||||||
m_memChart->clear();
|
m_chartMem->clear();
|
||||||
m_cpuChart->clear();
|
m_chartCpu->clear();
|
||||||
|
|
||||||
m_comboBox->setCurrentIndex(m_comboBox->count() - 1);
|
m_comboBox->setCurrentIndex(m_comboBox->count() - 1);
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
connect(m_manager, &AppStatisticsMonitorManager::appStoped, this, [this](qint64 pid) {
|
connect(m_manager, &AppStatisticsMonitorManager::appStoped, this, [this](qint64 pid) {
|
||||||
m_memChart->addNewPoint({m_memChart->lastPointX() + 1, 0});
|
m_chartMem->addNewPoint({m_chartMem->lastPointX() + 1, 0});
|
||||||
m_cpuChart->addNewPoint({m_cpuChart->lastPointX() + 1, 0});
|
m_chartCpu->addNewPoint({m_chartCpu->lastPointX() + 1, 0});
|
||||||
|
|
||||||
const int indx = m_comboBox->findData(pid);
|
const int indx = m_comboBox->findData(pid);
|
||||||
if (indx != -1)
|
if (indx != -1)
|
||||||
m_comboBox->removeItem(indx);
|
m_comboBox->removeItem(indx);
|
||||||
@@ -188,10 +189,10 @@ AppStatisticsMonitorView::AppStatisticsMonitorView(AppStatisticsMonitorManager *
|
|||||||
connect(m_manager, &AppStatisticsMonitorManager::newDataAvailable, this, [this] {
|
connect(m_manager, &AppStatisticsMonitorManager::newDataAvailable, this, [this] {
|
||||||
const IDataProvider *currentDataProvider = m_manager->currentDataProvider();
|
const IDataProvider *currentDataProvider = m_manager->currentDataProvider();
|
||||||
if (currentDataProvider != nullptr) {
|
if (currentDataProvider != nullptr) {
|
||||||
m_memChart->addNewPoint(
|
m_chartMem->addNewPoint(
|
||||||
{(double) currentDataProvider->memoryConsumptionHistory().size(),
|
{(double) currentDataProvider->memoryConsumptionHistory().size(),
|
||||||
currentDataProvider->memoryConsumptionLast()});
|
currentDataProvider->memoryConsumptionLast()});
|
||||||
m_cpuChart->addNewPoint(
|
m_chartCpu->addNewPoint(
|
||||||
{(double) currentDataProvider->cpuConsumptionHistory().size(),
|
{(double) currentDataProvider->cpuConsumptionHistory().size(),
|
||||||
currentDataProvider->cpuConsumptionLast()});
|
currentDataProvider->cpuConsumptionLast()});
|
||||||
}
|
}
|
||||||
|
@@ -53,13 +53,12 @@ void TestResultDelegate::paint(QPainter *painter, const QStyleOptionViewItem &op
|
|||||||
const TestResult testResult = resultFilterModel->testResult(index);
|
const TestResult testResult = resultFilterModel->testResult(index);
|
||||||
QTC_ASSERT(testResult.isValid(), painter->restore(); return);
|
QTC_ASSERT(testResult.isValid(), painter->restore(); return);
|
||||||
|
|
||||||
const QWidget *widget = dynamic_cast<const QWidget*>(painter->device());
|
|
||||||
QWindow *window = widget ? widget->window()->windowHandle() : nullptr;
|
|
||||||
|
|
||||||
QIcon icon = index.data(Qt::DecorationRole).value<QIcon>();
|
QIcon icon = index.data(Qt::DecorationRole).value<QIcon>();
|
||||||
if (!icon.isNull())
|
if (!icon.isNull()) {
|
||||||
painter->drawPixmap(positions.left(), positions.top(),
|
painter->drawPixmap(positions.left(), positions.top(),
|
||||||
icon.pixmap(window, QSize(positions.iconSize(), positions.iconSize())));
|
icon.pixmap(QSize(positions.iconSize(), positions.iconSize()),
|
||||||
|
painter->device()->devicePixelRatio()));
|
||||||
|
}
|
||||||
|
|
||||||
TestResultItem *item = resultFilterModel->itemForIndex(index);
|
TestResultItem *item = resultFilterModel->itemForIndex(index);
|
||||||
QTC_ASSERT(item, painter->restore(); return);
|
QTC_ASSERT(item, painter->restore(); return);
|
||||||
|
@@ -138,11 +138,8 @@ bool GdbServerProvider::isValid() const
|
|||||||
bool GdbServerProvider::aboutToRun(DebuggerRunTool *runTool, QString &errorMessage) const
|
bool GdbServerProvider::aboutToRun(DebuggerRunTool *runTool, QString &errorMessage) const
|
||||||
{
|
{
|
||||||
QTC_ASSERT(runTool, return false);
|
QTC_ASSERT(runTool, return false);
|
||||||
const RunControl *runControl = runTool->runControl();
|
const ProcessRunData runnable = runTool->runControl()->runnable();
|
||||||
const auto exeAspect = runControl->aspectData<ExecutableAspect>();
|
const FilePath bin = FilePath::fromString(runnable.command.executable().path());
|
||||||
QTC_ASSERT(exeAspect, return false);
|
|
||||||
|
|
||||||
const FilePath bin = FilePath::fromString(exeAspect->executable.path());
|
|
||||||
if (bin.isEmpty()) {
|
if (bin.isEmpty()) {
|
||||||
errorMessage = Tr::tr("Cannot debug: Local executable is not set.");
|
errorMessage = Tr::tr("Cannot debug: Local executable is not set.");
|
||||||
return false;
|
return false;
|
||||||
@@ -155,8 +152,7 @@ bool GdbServerProvider::aboutToRun(DebuggerRunTool *runTool, QString &errorMessa
|
|||||||
|
|
||||||
ProcessRunData inferior;
|
ProcessRunData inferior;
|
||||||
inferior.command.setExecutable(bin);
|
inferior.command.setExecutable(bin);
|
||||||
if (const auto argAspect = runControl->aspectData<ArgumentsAspect>())
|
inferior.command.setArguments(runnable.command.arguments());
|
||||||
inferior.command.setArguments(argAspect->arguments);
|
|
||||||
runTool->setInferior(inferior);
|
runTool->setInferior(inferior);
|
||||||
runTool->setSymbolFile(bin);
|
runTool->setSymbolFile(bin);
|
||||||
runTool->setStartMode(AttachToRemoteServer);
|
runTool->setStartMode(AttachToRemoteServer);
|
||||||
|
@@ -168,11 +168,7 @@ QString UvscServerProvider::channelString() const
|
|||||||
bool UvscServerProvider::aboutToRun(DebuggerRunTool *runTool, QString &errorMessage) const
|
bool UvscServerProvider::aboutToRun(DebuggerRunTool *runTool, QString &errorMessage) const
|
||||||
{
|
{
|
||||||
QTC_ASSERT(runTool, return false);
|
QTC_ASSERT(runTool, return false);
|
||||||
const RunControl *runControl = runTool->runControl();
|
const FilePath bin = runTool->runControl()->runnable().command.executable();
|
||||||
const auto exeAspect = runControl->aspectData<ExecutableAspect>();
|
|
||||||
QTC_ASSERT(exeAspect, return false);
|
|
||||||
|
|
||||||
const FilePath bin = exeAspect->executable;
|
|
||||||
if (bin.isEmpty()) {
|
if (bin.isEmpty()) {
|
||||||
errorMessage = Tr::tr("Cannot debug: Local executable is not set.");
|
errorMessage = Tr::tr("Cannot debug: Local executable is not set.");
|
||||||
return false;
|
return false;
|
||||||
|
@@ -884,7 +884,7 @@ bool BazaarPluginPrivate::managesFile(const FilePath &workingDirectory, const QS
|
|||||||
|
|
||||||
bool BazaarPluginPrivate::isConfigured() const
|
bool BazaarPluginPrivate::isConfigured() const
|
||||||
{
|
{
|
||||||
const FilePath binary = settings().binaryPath();
|
const FilePath binary = settings().binaryPath.effectiveBinary();
|
||||||
return !binary.isEmpty() && binary.isExecutableFile();
|
return !binary.isEmpty() && binary.isExecutableFile();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@@ -1011,9 +1011,10 @@ void ClangdClient::followSymbol(TextDocument *document,
|
|||||||
: ClangdFollowSymbol::Origin::Code;
|
: ClangdFollowSymbol::Origin::Code;
|
||||||
if (origin == ClangdFollowSymbol::Origin::User) {
|
if (origin == ClangdFollowSymbol::Origin::User) {
|
||||||
for (auto it = d->followSymbolOps.begin(); it != d->followSymbolOps.end(); ) {
|
for (auto it = d->followSymbolOps.begin(); it != d->followSymbolOps.end(); ) {
|
||||||
if ((*it)->isInteractive()) {
|
ClangdFollowSymbol * const followSymbol = *it;
|
||||||
(*it)->cancel();
|
if (followSymbol->isInteractive()) {
|
||||||
it = d->followSymbolOps.erase(it);
|
it = d->followSymbolOps.erase(it);
|
||||||
|
followSymbol->cancel();
|
||||||
} else {
|
} else {
|
||||||
++it;
|
++it;
|
||||||
}
|
}
|
||||||
|
@@ -210,6 +210,21 @@ static bool comesDirectlyAfterIf(const QTextDocument *doc, int pos)
|
|||||||
return pos > 0 && doc->characterAt(pos) == 'f' && doc->characterAt(pos - 1) == 'i';
|
return pos > 0 && doc->characterAt(pos) == 'f' && doc->characterAt(pos - 1) == 'i';
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static bool startsWithKeyWord(const QString &keyWord, const QString &text)
|
||||||
|
{
|
||||||
|
if (text.size() <= keyWord.size())
|
||||||
|
return false;
|
||||||
|
|
||||||
|
const QChar chAfter = text.at(keyWord.size());
|
||||||
|
return text.startsWith(keyWord) && !chAfter.isDigit() && !chAfter.isLetter() && chAfter != '_';
|
||||||
|
}
|
||||||
|
|
||||||
|
static bool startsWithKeyWords(const QString &text)
|
||||||
|
{
|
||||||
|
return startsWithKeyWord("if", text) || startsWithKeyWord("while", text)
|
||||||
|
|| startsWithKeyWord("for", text);
|
||||||
|
}
|
||||||
|
|
||||||
static CharacterContext characterContext(const QTextBlock ¤tBlock)
|
static CharacterContext characterContext(const QTextBlock ¤tBlock)
|
||||||
{
|
{
|
||||||
QTextBlock previousNonEmptyBlock = reverseFindLastEmptyBlock(currentBlock);
|
QTextBlock previousNonEmptyBlock = reverseFindLastEmptyBlock(currentBlock);
|
||||||
@@ -220,8 +235,9 @@ static CharacterContext characterContext(const QTextBlock ¤tBlock)
|
|||||||
if (prevLineText.isEmpty())
|
if (prevLineText.isEmpty())
|
||||||
return CharacterContext::NewStatementOrContinuation;
|
return CharacterContext::NewStatementOrContinuation;
|
||||||
|
|
||||||
if ((currentBlock.text().trimmed().isEmpty() || currentBlock.text().trimmed().endsWith(")"))
|
const QString currentBlockText = currentBlock.text().trimmed();
|
||||||
&& prevLineText.endsWith("{"))
|
if ((currentBlockText.isEmpty() || currentBlockText.endsWith(")"))
|
||||||
|
&& prevLineText.endsWith("{") && !startsWithKeyWords(currentBlockText))
|
||||||
return CharacterContext::BracketAfterFunctionCall;
|
return CharacterContext::BracketAfterFunctionCall;
|
||||||
|
|
||||||
const QChar firstNonWhitespaceChar = findFirstNonWhitespaceCharacter(currentBlock);
|
const QChar firstNonWhitespaceChar = findFirstNonWhitespaceCharacter(currentBlock);
|
||||||
|
@@ -114,8 +114,10 @@ private slots:
|
|||||||
void testFunctionCallClosingParenthesis();
|
void testFunctionCallClosingParenthesis();
|
||||||
void testFunctionCallClosingParenthesisEmptyLine();
|
void testFunctionCallClosingParenthesisEmptyLine();
|
||||||
void testNoIndentationInMiddleOfLine();
|
void testNoIndentationInMiddleOfLine();
|
||||||
void testIndentationInTheBegginingOfLine();
|
|
||||||
void testIndentationInMiddleOfLine();
|
void testIndentationInMiddleOfLine();
|
||||||
|
void testIndentationInTheBegginingOfLine();
|
||||||
|
void testIndentationReturnAfterIf();
|
||||||
|
void testIndentationReturnAfterIfSomthingFunction();
|
||||||
|
|
||||||
private:
|
private:
|
||||||
void insertLines(const std::vector<QString> &lines);
|
void insertLines(const std::vector<QString> &lines);
|
||||||
@@ -965,6 +967,38 @@ void ClangFormatTest::testIndentationInTheBegginingOfLine()
|
|||||||
"}"}));
|
"}"}));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void ClangFormatTest::testIndentationReturnAfterIf()
|
||||||
|
{
|
||||||
|
insertLines({"int main()",
|
||||||
|
"{",
|
||||||
|
" if (true)",
|
||||||
|
" return 0;",
|
||||||
|
"}"});
|
||||||
|
m_indenter->indent(*m_cursor, QChar::Null, TextEditor::TabSettings());
|
||||||
|
QCOMPARE(documentLines(),
|
||||||
|
(std::vector<QString>{"int main()",
|
||||||
|
"{",
|
||||||
|
" if (true)",
|
||||||
|
" return 0;",
|
||||||
|
"}"}));
|
||||||
|
}
|
||||||
|
|
||||||
|
void ClangFormatTest::testIndentationReturnAfterIfSomthingFunction()
|
||||||
|
{
|
||||||
|
insertLines({"int main()",
|
||||||
|
"{",
|
||||||
|
" if_somthing()",
|
||||||
|
" return 0;",
|
||||||
|
"}"});
|
||||||
|
m_indenter->indent(*m_cursor, QChar::Null, TextEditor::TabSettings());
|
||||||
|
QCOMPARE(documentLines(),
|
||||||
|
(std::vector<QString>{"int main()",
|
||||||
|
"{",
|
||||||
|
" if_somthing()",
|
||||||
|
" return 0;",
|
||||||
|
"}"}));
|
||||||
|
}
|
||||||
|
|
||||||
QObject *createClangFormatTest()
|
QObject *createClangFormatTest()
|
||||||
{
|
{
|
||||||
return new ClangFormatTest;
|
return new ClangFormatTest;
|
||||||
|
@@ -34,6 +34,7 @@
|
|||||||
#include <projectexplorer/devicesupport/idevice.h>
|
#include <projectexplorer/devicesupport/idevice.h>
|
||||||
#include <projectexplorer/environmentaspectwidget.h>
|
#include <projectexplorer/environmentaspectwidget.h>
|
||||||
#include <projectexplorer/environmentwidget.h>
|
#include <projectexplorer/environmentwidget.h>
|
||||||
|
#include <projectexplorer/gcctoolchain.h>
|
||||||
#include <projectexplorer/kitaspects.h>
|
#include <projectexplorer/kitaspects.h>
|
||||||
#include <projectexplorer/namedwidget.h>
|
#include <projectexplorer/namedwidget.h>
|
||||||
#include <projectexplorer/processparameters.h>
|
#include <projectexplorer/processparameters.h>
|
||||||
@@ -96,6 +97,13 @@ const char USER_ENVIRONMENT_CHANGES_KEY[] = "CMake.Configure.UserEnvironmentChan
|
|||||||
const char BASE_ENVIRONMENT_KEY[] = "CMake.Configure.BaseEnvironment";
|
const char BASE_ENVIRONMENT_KEY[] = "CMake.Configure.BaseEnvironment";
|
||||||
const char GENERATE_QMLLS_INI_SETTING[] = "J.QtQuick/QmlJSEditor.GenerateQmllsIniFiles";
|
const char GENERATE_QMLLS_INI_SETTING[] = "J.QtQuick/QmlJSEditor.GenerateQmllsIniFiles";
|
||||||
|
|
||||||
|
const char CMAKE_TOOLCHAIN_FILE[] = "CMAKE_TOOLCHAIN_FILE";
|
||||||
|
const char CMAKE_C_FLAGS_INIT[] = "CMAKE_C_FLAGS_INIT";
|
||||||
|
const char CMAKE_CXX_FLAGS_INIT[] = "CMAKE_CXX_FLAGS_INIT";
|
||||||
|
const char CMAKE_CXX_FLAGS[] = "CMAKE_CXX_FLAGS";
|
||||||
|
const char CMAKE_CXX_FLAGS_DEBUG[] = "CMAKE_CXX_FLAGS_DEBUG";
|
||||||
|
const char CMAKE_CXX_FLAGS_RELWITHDEBINFO[] = "CMAKE_CXX_FLAGS_RELWITHDEBINFO";
|
||||||
|
|
||||||
namespace Internal {
|
namespace Internal {
|
||||||
|
|
||||||
class CMakeBuildSettingsWidget : public NamedWidget
|
class CMakeBuildSettingsWidget : public NamedWidget
|
||||||
@@ -888,11 +896,11 @@ CMakeConfig CMakeBuildSettingsWidget::getQmlDebugCxxFlags()
|
|||||||
const bool enable = m_buildConfig->qmlDebugging() == TriState::Enabled;
|
const bool enable = m_buildConfig->qmlDebugging() == TriState::Enabled;
|
||||||
|
|
||||||
const CMakeConfig configList = m_buildConfig->cmakeBuildSystem()->configurationFromCMake();
|
const CMakeConfig configList = m_buildConfig->cmakeBuildSystem()->configurationFromCMake();
|
||||||
const QByteArrayList cxxFlagsPrev{"CMAKE_CXX_FLAGS",
|
const QByteArrayList cxxFlagsPrev{CMAKE_CXX_FLAGS,
|
||||||
"CMAKE_CXX_FLAGS_DEBUG",
|
CMAKE_CXX_FLAGS_DEBUG,
|
||||||
"CMAKE_CXX_FLAGS_RELWITHDEBINFO",
|
CMAKE_CXX_FLAGS_RELWITHDEBINFO,
|
||||||
"CMAKE_CXX_FLAGS_INIT"};
|
CMAKE_CXX_FLAGS_INIT};
|
||||||
const QByteArrayList cxxFlags{"CMAKE_CXX_FLAGS_INIT", "CMAKE_CXX_FLAGS"};
|
const QByteArrayList cxxFlags{CMAKE_CXX_FLAGS_INIT, CMAKE_CXX_FLAGS};
|
||||||
const QByteArray qmlDebug(QT_QML_DEBUG_PARAM);
|
const QByteArray qmlDebug(QT_QML_DEBUG_PARAM);
|
||||||
|
|
||||||
CMakeConfig changedConfig;
|
CMakeConfig changedConfig;
|
||||||
@@ -1176,6 +1184,30 @@ static CommandLine defaultInitialCMakeCommand(
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// GCC compiler and linker specific flags
|
||||||
|
for (Toolchain *tc : ToolchainKitAspect::toolChains(k)) {
|
||||||
|
if (auto *gccTc = tc->asGccToolchain()) {
|
||||||
|
const QStringList compilerFlags = gccTc->platformCodeGenFlags();
|
||||||
|
|
||||||
|
QLatin1String languageFlagsInit;
|
||||||
|
if (gccTc->language() == ProjectExplorer::Constants::C_LANGUAGE_ID)
|
||||||
|
languageFlagsInit = QLatin1String(CMAKE_C_FLAGS_INIT);
|
||||||
|
else if (gccTc->language() == ProjectExplorer::Constants::CXX_LANGUAGE_ID)
|
||||||
|
languageFlagsInit = QLatin1String(CMAKE_CXX_FLAGS_INIT);
|
||||||
|
|
||||||
|
if (!languageFlagsInit.isEmpty() && !compilerFlags.isEmpty())
|
||||||
|
cmd.addArg("-D" + languageFlagsInit + ":STRING=" + compilerFlags.join(" "));
|
||||||
|
|
||||||
|
const QStringList linkerFlags = gccTc->platformLinkerFlags();
|
||||||
|
if (!linkerFlags.isEmpty()) {
|
||||||
|
const QString joinedLinkerFlags = linkerFlags.join(" ");
|
||||||
|
cmd.addArg("-DCMAKE_EXE_LINKER_FLAGS_INIT:STRING=" + joinedLinkerFlags);
|
||||||
|
cmd.addArg("-DCMAKE_MODULE_LINKER_FLAGS_INIT:STRING=" + joinedLinkerFlags);
|
||||||
|
cmd.addArg("-DCMAKE_SHARED_LINKER_FLAGS_INIT:STRING=" + joinedLinkerFlags);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
cmd.addArgs(CMakeConfigurationKitAspect::toArgumentsList(k));
|
cmd.addArgs(CMakeConfigurationKitAspect::toArgumentsList(k));
|
||||||
cmd.addArgs(CMakeConfigurationKitAspect::additionalConfiguration(k), CommandLine::Raw);
|
cmd.addArgs(CMakeConfigurationKitAspect::additionalConfiguration(k), CommandLine::Raw);
|
||||||
|
|
||||||
@@ -1317,13 +1349,21 @@ static void addCMakeConfigurePresetToInitialArguments(QStringList &initialArgume
|
|||||||
}
|
}
|
||||||
|
|
||||||
arg = argItem.toArgument();
|
arg = argItem.toArgument();
|
||||||
} else if (argItem.key == "CMAKE_TOOLCHAIN_FILE") {
|
} else if (argItem.key == CMAKE_TOOLCHAIN_FILE) {
|
||||||
const FilePath argFilePath = FilePath::fromString(argItem.expandedValue(k));
|
const FilePath argFilePath = FilePath::fromString(argItem.expandedValue(k));
|
||||||
const FilePath presetFilePath = FilePath::fromUserInput(
|
const FilePath presetFilePath = FilePath::fromUserInput(
|
||||||
QString::fromUtf8(presetItem.value));
|
QString::fromUtf8(presetItem.value));
|
||||||
|
|
||||||
if (argFilePath != presetFilePath)
|
if (argFilePath != presetFilePath)
|
||||||
arg = presetItem.toArgument();
|
arg = presetItem.toArgument();
|
||||||
|
} else if (argItem.key == CMAKE_CXX_FLAGS_INIT) {
|
||||||
|
// Append the preset value with at the initial parameters value (e.g. QML Debugging)
|
||||||
|
if (argItem.expandedValue(k) != QString::fromUtf8(presetItem.value)) {
|
||||||
|
argItem.value.append(" ");
|
||||||
|
argItem.value.append(presetItem.value);
|
||||||
|
|
||||||
|
arg = argItem.toArgument();
|
||||||
|
}
|
||||||
} else if (argItem.expandedValue(k) != QString::fromUtf8(presetItem.value)) {
|
} else if (argItem.expandedValue(k) != QString::fromUtf8(presetItem.value)) {
|
||||||
arg = presetItem.toArgument();
|
arg = presetItem.toArgument();
|
||||||
}
|
}
|
||||||
@@ -1585,7 +1625,8 @@ CMakeBuildConfiguration::CMakeBuildConfiguration(Target *target, Id id)
|
|||||||
: TriState::Default);
|
: TriState::Default);
|
||||||
|
|
||||||
if (qt && qt->isQmlDebuggingSupported())
|
if (qt && qt->isQmlDebuggingSupported())
|
||||||
cmd.addArg("-DCMAKE_CXX_FLAGS_INIT:STRING=%{" + QLatin1String(QT_QML_DEBUG_FLAG) + "}");
|
cmd.addArg(
|
||||||
|
QLatin1String("-D") + CMAKE_CXX_FLAGS_INIT + ":STRING=%{" + QT_QML_DEBUG_FLAG + "}");
|
||||||
|
|
||||||
// QT_QML_GENERATE_QMLLS_INI, if enabled via the settings checkbox:
|
// QT_QML_GENERATE_QMLLS_INI, if enabled via the settings checkbox:
|
||||||
if (Core::ICore::settings()->value(GENERATE_QMLLS_INI_SETTING).toBool()) {
|
if (Core::ICore::settings()->value(GENERATE_QMLLS_INI_SETTING).toBool()) {
|
||||||
@@ -1646,8 +1687,8 @@ bool CMakeBuildConfiguration::hasQmlDebugging(const CMakeConfig &config)
|
|||||||
// Determine QML debugging flags. This must match what we do in
|
// Determine QML debugging flags. This must match what we do in
|
||||||
// CMakeBuildSettingsWidget::getQmlDebugCxxFlags()
|
// CMakeBuildSettingsWidget::getQmlDebugCxxFlags()
|
||||||
// such that in doubt we leave the QML Debugging setting at "Leave at default"
|
// such that in doubt we leave the QML Debugging setting at "Leave at default"
|
||||||
const QString cxxFlagsInit = config.stringValueOf("CMAKE_CXX_FLAGS_INIT");
|
const QString cxxFlagsInit = config.stringValueOf(CMAKE_CXX_FLAGS_INIT);
|
||||||
const QString cxxFlags = config.stringValueOf("CMAKE_CXX_FLAGS");
|
const QString cxxFlags = config.stringValueOf(CMAKE_CXX_FLAGS);
|
||||||
return cxxFlagsInit.contains(QT_QML_DEBUG_PARAM) && cxxFlags.contains(QT_QML_DEBUG_PARAM);
|
return cxxFlagsInit.contains(QT_QML_DEBUG_PARAM) && cxxFlags.contains(QT_QML_DEBUG_PARAM);
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -2163,9 +2204,20 @@ void InitialCMakeArgumentsAspect::setAllValues(const QString &values, QStringLis
|
|||||||
if (!cmakeGenerator.isEmpty())
|
if (!cmakeGenerator.isEmpty())
|
||||||
arguments.append(cmakeGenerator);
|
arguments.append(cmakeGenerator);
|
||||||
|
|
||||||
m_cmakeConfiguration = CMakeConfig::fromArguments(arguments, additionalOptions);
|
CMakeConfig config = CMakeConfig::fromArguments(arguments, additionalOptions);
|
||||||
for (CMakeConfigItem &ci : m_cmakeConfiguration)
|
// Join CMAKE_CXX_FLAGS_INIT values if more entries are present, or skip the same
|
||||||
|
// values like CMAKE_EXE_LINKER_FLAGS_INIT coming from both C and CXX compilers
|
||||||
|
QHash<QByteArray, CMakeConfigItem> uniqueConfig;
|
||||||
|
for (CMakeConfigItem &ci : config) {
|
||||||
ci.isInitial = true;
|
ci.isInitial = true;
|
||||||
|
if (uniqueConfig.contains(ci.key)) {
|
||||||
|
if (uniqueConfig[ci.key].value != ci.value)
|
||||||
|
uniqueConfig[ci.key].value = uniqueConfig[ci.key].value + " " + ci.value;
|
||||||
|
} else {
|
||||||
|
uniqueConfig.insert(ci.key, ci);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
m_cmakeConfiguration = uniqueConfig.values();
|
||||||
|
|
||||||
// Display the unknown arguments in "Additional CMake Options"
|
// Display the unknown arguments in "Additional CMake Options"
|
||||||
const QString additionalOptionsValue = ProcessArgs::joinArgs(additionalOptions);
|
const QString additionalOptionsValue = ProcessArgs::joinArgs(additionalOptions);
|
||||||
|
@@ -605,7 +605,7 @@ QWidget *CMakeBuildStep::createConfigWidget()
|
|||||||
if (!isCleanStep() && !m_buildPreset.isEmpty())
|
if (!isCleanStep() && !m_buildPreset.isEmpty())
|
||||||
createAndAddEnvironmentWidgets(builder);
|
createAndAddEnvironmentWidgets(builder);
|
||||||
|
|
||||||
builder.noMargin();
|
builder.setNoMargins();
|
||||||
auto widget = builder.emerge();
|
auto widget = builder.emerge();
|
||||||
|
|
||||||
updateDetails();
|
updateDetails();
|
||||||
|
@@ -83,12 +83,17 @@ CMakeBuildSystem::CMakeBuildSystem(CMakeBuildConfiguration *bc)
|
|||||||
|
|
||||||
// Cache mime check result for speed up
|
// Cache mime check result for speed up
|
||||||
if (!isIgnored) {
|
if (!isIgnored) {
|
||||||
auto it = m_mimeBinaryCache.find(mimeType.name());
|
if (auto it = m_mimeBinaryCache.get<std::optional<bool>>(
|
||||||
if (it != m_mimeBinaryCache.end()) {
|
[mimeType](const QHash<QString, bool> &cache) -> std::optional<bool> {
|
||||||
|
auto it = cache.find(mimeType.name());
|
||||||
|
if (it != cache.end())
|
||||||
|
return *it;
|
||||||
|
return {};
|
||||||
|
})) {
|
||||||
isIgnored = *it;
|
isIgnored = *it;
|
||||||
} else {
|
} else {
|
||||||
isIgnored = TreeScanner::isMimeBinary(mimeType, fn);
|
isIgnored = TreeScanner::isMimeBinary(mimeType, fn);
|
||||||
m_mimeBinaryCache[mimeType.name()] = isIgnored;
|
m_mimeBinaryCache.writeLocked()->insert(mimeType.name(), isIgnored);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@@ -10,6 +10,7 @@
|
|||||||
#include <projectexplorer/buildconfiguration.h>
|
#include <projectexplorer/buildconfiguration.h>
|
||||||
#include <projectexplorer/buildsystem.h>
|
#include <projectexplorer/buildsystem.h>
|
||||||
|
|
||||||
|
#include <utils/synchronizedvalue.h>
|
||||||
#include <utils/temporarydirectory.h>
|
#include <utils/temporarydirectory.h>
|
||||||
|
|
||||||
namespace ProjectExplorer {
|
namespace ProjectExplorer {
|
||||||
@@ -221,7 +222,7 @@ private:
|
|||||||
|
|
||||||
ProjectExplorer::TreeScanner m_treeScanner;
|
ProjectExplorer::TreeScanner m_treeScanner;
|
||||||
std::shared_ptr<ProjectExplorer::FolderNode> m_allFiles;
|
std::shared_ptr<ProjectExplorer::FolderNode> m_allFiles;
|
||||||
QHash<QString, bool> m_mimeBinaryCache;
|
Utils::SynchronizedValue<QHash<QString, bool>> m_mimeBinaryCache;
|
||||||
|
|
||||||
bool m_waitingForParse = false;
|
bool m_waitingForParse = false;
|
||||||
bool m_combinedScanAndParseResult = false;
|
bool m_combinedScanAndParseResult = false;
|
||||||
|
@@ -1124,6 +1124,11 @@ const QList<BuildInfo> CMakeProjectImporter::buildInfoList(void *directoryData)
|
|||||||
&& data->hasQmlDebugging)
|
&& data->hasQmlDebugging)
|
||||||
buildType = CMakeBuildConfigurationFactory::BuildTypeProfile;
|
buildType = CMakeBuildConfigurationFactory::BuildTypeProfile;
|
||||||
BuildInfo info = CMakeBuildConfigurationFactory::createBuildInfo(buildType);
|
BuildInfo info = CMakeBuildConfigurationFactory::createBuildInfo(buildType);
|
||||||
|
|
||||||
|
// For CMake Presets use the provided build type if is not mapped to a known type
|
||||||
|
if (!data->cmakePreset.isEmpty() && info.buildType == BuildConfiguration::Unknown)
|
||||||
|
info.typeName = info.displayName = QString::fromUtf8(data->cmakeBuildType);
|
||||||
|
|
||||||
info.buildDirectory = data->buildDirectory;
|
info.buildDirectory = data->buildDirectory;
|
||||||
|
|
||||||
QVariantMap config = info.extraInfo.toMap(); // new empty, or existing one from createBuildInfo
|
QVariantMap config = info.extraInfo.toMap(); // new empty, or existing one from createBuildInfo
|
||||||
|
@@ -209,12 +209,9 @@ static bool isChildOf(const FilePath &path, const FilePaths &prefixes)
|
|||||||
static CMakeBuildTarget toBuildTarget(const TargetDetails &t,
|
static CMakeBuildTarget toBuildTarget(const TargetDetails &t,
|
||||||
const FilePath &sourceDirectory,
|
const FilePath &sourceDirectory,
|
||||||
const FilePath &buildDirectory,
|
const FilePath &buildDirectory,
|
||||||
bool relativeLibs,
|
bool relativeLibs)
|
||||||
const QSet<FilePath> &sharedLibraryArtifacts)
|
|
||||||
{
|
{
|
||||||
const FilePath currentBuildDir = buildDirectory.resolvePath(t.buildDir);
|
const FilePath currentBuildDir = buildDirectory.resolvePath(t.buildDir);
|
||||||
const QSet<FilePath> sharedLibraryArtifactsPaths
|
|
||||||
= transform(sharedLibraryArtifacts, &FilePath::parentDir);
|
|
||||||
|
|
||||||
CMakeBuildTarget ct;
|
CMakeBuildTarget ct;
|
||||||
ct.title = t.name;
|
ct.title = t.name;
|
||||||
@@ -323,18 +320,18 @@ static CMakeBuildTarget toBuildTarget(const TargetDetails &t,
|
|||||||
// "/usr/local/lib" since these are usually in the standard search
|
// "/usr/local/lib" since these are usually in the standard search
|
||||||
// paths. There probably are more, but the naming schemes are arbitrary
|
// paths. There probably are more, but the naming schemes are arbitrary
|
||||||
// so we'd need to ask the linker ("ld --verbose | grep SEARCH_DIR").
|
// so we'd need to ask the linker ("ld --verbose | grep SEARCH_DIR").
|
||||||
if (buildDir.osType() != OsTypeWindows
|
if (buildDir.osType() == OsTypeWindows
|
||||||
&& !isChildOf(tmp,
|
|| !isChildOf(tmp,
|
||||||
{"/lib", "/lib64", "/usr/lib", "/usr/lib64", "/usr/local/lib"}))
|
{"/lib",
|
||||||
|
"/lib64",
|
||||||
|
"/usr/lib",
|
||||||
|
"/usr/lib64",
|
||||||
|
"/usr/local/lib"})) {
|
||||||
librarySeachPaths.append(tmp);
|
librarySeachPaths.append(tmp);
|
||||||
|
|
||||||
if (buildDir.osType() == OsTypeWindows) {
|
|
||||||
if (sharedLibraryArtifactsPaths.contains(tmp))
|
|
||||||
librarySeachPaths.append(tmp);
|
|
||||||
|
|
||||||
// Libraries often have their import libs in ../lib and the
|
// Libraries often have their import libs in ../lib and the
|
||||||
// actual dll files in ../bin on windows. Qt is one example of that.
|
// actual dll files in ../bin on windows. Qt is one example of that.
|
||||||
if (tmp.fileName() == "lib") {
|
if (tmp.fileName() == "lib" && buildDir.osType() == OsTypeWindows) {
|
||||||
const FilePath path = tmp.parentDir().pathAppended("bin");
|
const FilePath path = tmp.parentDir().pathAppended("bin");
|
||||||
if (path.isDir())
|
if (path.isDir())
|
||||||
librarySeachPaths.append(path);
|
librarySeachPaths.append(path);
|
||||||
@@ -355,19 +352,12 @@ static QList<CMakeBuildTarget> generateBuildTargets(const QFuture<void> &cancelF
|
|||||||
const FilePath &buildDirectory,
|
const FilePath &buildDirectory,
|
||||||
bool relativeLibs)
|
bool relativeLibs)
|
||||||
{
|
{
|
||||||
QSet<FilePath> sharedLibraryArtifacts;
|
|
||||||
for (const TargetDetails &t : input.targetDetails)
|
|
||||||
if (t.type == "MODULE_LIBRARY" || t.type == "SHARED_LIBRARY")
|
|
||||||
for (const FilePath &p : t.artifacts)
|
|
||||||
sharedLibraryArtifacts.insert(buildDirectory.resolvePath(p));
|
|
||||||
|
|
||||||
QList<CMakeBuildTarget> result;
|
QList<CMakeBuildTarget> result;
|
||||||
result.reserve(input.targetDetails.size());
|
result.reserve(input.targetDetails.size());
|
||||||
for (const TargetDetails &t : input.targetDetails) {
|
for (const TargetDetails &t : input.targetDetails) {
|
||||||
if (cancelFuture.isCanceled())
|
if (cancelFuture.isCanceled())
|
||||||
return {};
|
return {};
|
||||||
result.append(
|
result.append(toBuildTarget(t, sourceDirectory, buildDirectory, relativeLibs));
|
||||||
toBuildTarget(t, sourceDirectory, buildDirectory, relativeLibs, sharedLibraryArtifacts));
|
|
||||||
}
|
}
|
||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
|
@@ -139,11 +139,13 @@ void expand(const PresetType &preset, Environment &env, const FilePath &sourceDi
|
|||||||
return presetEnv.value(macroName);
|
return presetEnv.value(macroName);
|
||||||
});
|
});
|
||||||
|
|
||||||
bool append = true;
|
enum Operation { set, appendOrSet, prependOrSet };
|
||||||
|
Operation op = set;
|
||||||
if (key.compare("PATH", Qt::CaseInsensitive) == 0) {
|
if (key.compare("PATH", Qt::CaseInsensitive) == 0) {
|
||||||
|
op = appendOrSet;
|
||||||
const int index = value.indexOf("$penv{PATH}", 0, Qt::CaseInsensitive);
|
const int index = value.indexOf("$penv{PATH}", 0, Qt::CaseInsensitive);
|
||||||
if (index != 0)
|
if (index != 0)
|
||||||
append = false;
|
op = prependOrSet;
|
||||||
value.replace("$penv{PATH}", "", Qt::CaseInsensitive);
|
value.replace("$penv{PATH}", "", Qt::CaseInsensitive);
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -154,10 +156,17 @@ void expand(const PresetType &preset, Environment &env, const FilePath &sourceDi
|
|||||||
// Make sure to expand the CMake macros also for environment variables
|
// Make sure to expand the CMake macros also for environment variables
|
||||||
expandAllButEnv(preset, sourceDirectory, value);
|
expandAllButEnv(preset, sourceDirectory, value);
|
||||||
|
|
||||||
if (append)
|
switch (op) {
|
||||||
|
case set:
|
||||||
|
env.set(key, value);
|
||||||
|
break;
|
||||||
|
case appendOrSet:
|
||||||
env.appendOrSet(key, value);
|
env.appendOrSet(key, value);
|
||||||
else
|
break;
|
||||||
|
case prependOrSet:
|
||||||
env.prependOrSet(key, value);
|
env.prependOrSet(key, value);
|
||||||
|
break;
|
||||||
|
}
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@@ -332,7 +332,11 @@ CompilationDatabaseBuildSystem::CompilationDatabaseBuildSystem(Target *target)
|
|||||||
this, &CompilationDatabaseBuildSystem::updateDeploymentData);
|
this, &CompilationDatabaseBuildSystem::updateDeploymentData);
|
||||||
}
|
}
|
||||||
|
|
||||||
CompilationDatabaseBuildSystem::~CompilationDatabaseBuildSystem() = default;
|
CompilationDatabaseBuildSystem::~CompilationDatabaseBuildSystem()
|
||||||
|
{
|
||||||
|
if (m_parser)
|
||||||
|
delete m_parser;
|
||||||
|
}
|
||||||
|
|
||||||
void CompilationDatabaseBuildSystem::triggerParsing()
|
void CompilationDatabaseBuildSystem::triggerParsing()
|
||||||
{
|
{
|
||||||
|
@@ -4,6 +4,7 @@
|
|||||||
#pragma once
|
#pragma once
|
||||||
|
|
||||||
#include <cppeditor/cppprojectfile.h>
|
#include <cppeditor/cppprojectfile.h>
|
||||||
|
#include <utils/synchronizedvalue.h>
|
||||||
|
|
||||||
#include <QHash>
|
#include <QHash>
|
||||||
|
|
||||||
@@ -29,7 +30,7 @@ public:
|
|||||||
QStringList extras;
|
QStringList extras;
|
||||||
};
|
};
|
||||||
|
|
||||||
using MimeBinaryCache = QHash<QString, bool>;
|
using MimeBinaryCache = Utils::SynchronizedValue<QHash<QString, bool>>;
|
||||||
|
|
||||||
QStringList filterFromFileName(const QStringList &flags, const QString &fileName);
|
QStringList filterFromFileName(const QStringList &flags, const QString &fileName);
|
||||||
|
|
||||||
|
@@ -130,6 +130,15 @@ CompilationDbParser::CompilationDbParser(const QString &projectName,
|
|||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
CompilationDbParser::~CompilationDbParser()
|
||||||
|
{
|
||||||
|
if (m_treeScanner && !m_treeScanner->isFinished()) {
|
||||||
|
auto future = m_treeScanner->future();
|
||||||
|
future.cancel();
|
||||||
|
future.waitForFinished();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
void CompilationDbParser::start()
|
void CompilationDbParser::start()
|
||||||
{
|
{
|
||||||
// Check hash first.
|
// Check hash first.
|
||||||
@@ -158,12 +167,17 @@ void CompilationDbParser::start()
|
|||||||
|
|
||||||
// Cache mime check result for speed up
|
// Cache mime check result for speed up
|
||||||
if (!isIgnored) {
|
if (!isIgnored) {
|
||||||
auto it = m_mimeBinaryCache.find(mimeType.name());
|
if (auto it = m_mimeBinaryCache.get<std::optional<bool>>(
|
||||||
if (it != m_mimeBinaryCache.end()) {
|
[mimeType](const QHash<QString, bool> &cache) -> std::optional<bool> {
|
||||||
|
auto it = cache.find(mimeType.name());
|
||||||
|
if (it != cache.end())
|
||||||
|
return *it;
|
||||||
|
return {};
|
||||||
|
})) {
|
||||||
isIgnored = *it;
|
isIgnored = *it;
|
||||||
} else {
|
} else {
|
||||||
isIgnored = TreeScanner::isMimeBinary(mimeType, fn);
|
isIgnored = TreeScanner::isMimeBinary(mimeType, fn);
|
||||||
m_mimeBinaryCache[mimeType.name()] = isIgnored;
|
m_mimeBinaryCache.writeLocked()->insert(mimeType.name(), isIgnored);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@@ -32,6 +32,7 @@ public:
|
|||||||
MimeBinaryCache &mimeBinaryCache,
|
MimeBinaryCache &mimeBinaryCache,
|
||||||
ProjectExplorer::BuildSystem::ParseGuard &&guard,
|
ProjectExplorer::BuildSystem::ParseGuard &&guard,
|
||||||
QObject *parent = nullptr);
|
QObject *parent = nullptr);
|
||||||
|
~CompilationDbParser();
|
||||||
|
|
||||||
|
|
||||||
void setPreviousProjectFileHash(const QByteArray &fileHash) { m_projectFileHash = fileHash; }
|
void setPreviousProjectFileHash(const QByteArray &fileHash) { m_projectFileHash = fileHash; }
|
||||||
|
@@ -258,7 +258,7 @@ SourceEditorWidget::SourceEditorWidget(const std::shared_ptr<SourceSettings> &se
|
|||||||
settings->languageId,
|
settings->languageId,
|
||||||
addCompilerButton,
|
addCompilerButton,
|
||||||
removeSourceButton,
|
removeSourceButton,
|
||||||
customMargin({6, 0, 0, 0}), spacing(0),
|
customMargins(6, 0, 0, 0), spacing(0),
|
||||||
}.attachTo(toolBar);
|
}.attachTo(toolBar);
|
||||||
|
|
||||||
Column {
|
Column {
|
||||||
@@ -403,7 +403,7 @@ CompilerWidget::CompilerWidget(const std::shared_ptr<SourceSettings> &sourceSett
|
|||||||
m_compilerSettings->compiler,
|
m_compilerSettings->compiler,
|
||||||
advButton,
|
advButton,
|
||||||
removeCompilerBtn,
|
removeCompilerBtn,
|
||||||
customMargin({6, 0, 0, 0}), spacing(0),
|
customMargins(6, 0, 0, 0), spacing(0),
|
||||||
}.attachTo(toolBar);
|
}.attachTo(toolBar);
|
||||||
|
|
||||||
Column {
|
Column {
|
||||||
|
@@ -50,18 +50,22 @@ CopilotSettings::CopilotSettings()
|
|||||||
// Vim, Linux/macOS:
|
// Vim, Linux/macOS:
|
||||||
FilePath::fromUserInput("~/.vim/pack/github/start/copilot.vim/dist/agent.js"),
|
FilePath::fromUserInput("~/.vim/pack/github/start/copilot.vim/dist/agent.js"),
|
||||||
FilePath::fromUserInput("~/.vim/pack/github/start/copilot.vim/copilot/dist/agent.js"),
|
FilePath::fromUserInput("~/.vim/pack/github/start/copilot.vim/copilot/dist/agent.js"),
|
||||||
|
FilePath::fromUserInput("~/.vim/pack/github/start/copilot.vim/dist/language-server.js"),
|
||||||
|
|
||||||
// Neovim, Linux/macOS:
|
// Neovim, Linux/macOS:
|
||||||
FilePath::fromUserInput("~/.config/nvim/pack/github/start/copilot.vim/dist/agent.js"),
|
FilePath::fromUserInput("~/.config/nvim/pack/github/start/copilot.vim/dist/agent.js"),
|
||||||
FilePath::fromUserInput("~/.config/nvim/pack/github/start/copilot.vim/copilot/dist/agent.js"),
|
FilePath::fromUserInput("~/.config/nvim/pack/github/start/copilot.vim/copilot/dist/agent.js"),
|
||||||
|
FilePath::fromUserInput("~/.config/nvim/pack/github/start/copilot.vim/dist/language-server.js"),
|
||||||
|
|
||||||
// Vim, Windows (PowerShell command):
|
// Vim, Windows (PowerShell command):
|
||||||
FilePath::fromUserInput("~/vimfiles/pack/github/start/copilot.vim/dist/agent.js"),
|
FilePath::fromUserInput("~/vimfiles/pack/github/start/copilot.vim/dist/agent.js"),
|
||||||
FilePath::fromUserInput("~/vimfiles/pack/github/start/copilot.vim/copilot/dist/agent.js"),
|
FilePath::fromUserInput("~/vimfiles/pack/github/start/copilot.vim/copilot/dist/agent.js"),
|
||||||
|
FilePath::fromUserInput("~/vimfiles/pack/github/start/copilot.vim/dist/language-server.js"),
|
||||||
|
|
||||||
// Neovim, Windows (PowerShell command):
|
// Neovim, Windows (PowerShell command):
|
||||||
FilePath::fromUserInput("~/AppData/Local/nvim/pack/github/start/copilot.vim/dist/agent.js"),
|
FilePath::fromUserInput("~/AppData/Local/nvim/pack/github/start/copilot.vim/dist/agent.js"),
|
||||||
FilePath::fromUserInput("~/AppData/Local/nvim/pack/github/start/copilot.vim/copilot/dist/agent.js")
|
FilePath::fromUserInput("~/AppData/Local/nvim/pack/github/start/copilot.vim/copilot/dist/agent.js"),
|
||||||
|
FilePath::fromUserInput("~/AppData/Local/nvim/pack/github/start/copilot.vim/dist/language-server.js")
|
||||||
};
|
};
|
||||||
// clang-format on
|
// clang-format on
|
||||||
|
|
||||||
@@ -198,7 +202,7 @@ CopilotSettings::CopilotSettings()
|
|||||||
"file from the Copilot neovim plugin.",
|
"file from the Copilot neovim plugin.",
|
||||||
"Markdown text for the copilot instruction label")
|
"Markdown text for the copilot instruction label")
|
||||||
.arg("[README.md](https://github.com/github/copilot.vim)")
|
.arg("[README.md](https://github.com/github/copilot.vim)")
|
||||||
.arg("[agent.js](https://github.com/github/copilot.vim/tree/release/dist)"))
|
.arg("[language-server.js](https://github.com/github/copilot.vim/tree/release/dist)"))
|
||||||
};
|
};
|
||||||
|
|
||||||
return Column {
|
return Column {
|
||||||
|
@@ -30,6 +30,7 @@
|
|||||||
#include <QLineEdit>
|
#include <QLineEdit>
|
||||||
#include <QPointer>
|
#include <QPointer>
|
||||||
#include <QPushButton>
|
#include <QPushButton>
|
||||||
|
#include <QTimer>
|
||||||
#include <QTreeWidgetItem>
|
#include <QTreeWidgetItem>
|
||||||
|
|
||||||
#include <array>
|
#include <array>
|
||||||
@@ -420,6 +421,7 @@ private:
|
|||||||
QGridLayout *m_shortcutLayout;
|
QGridLayout *m_shortcutLayout;
|
||||||
std::vector<std::unique_ptr<ShortcutInput>> m_shortcutInputs;
|
std::vector<std::unique_ptr<ShortcutInput>> m_shortcutInputs;
|
||||||
QPointer<QPushButton> m_addButton = nullptr;
|
QPointer<QPushButton> m_addButton = nullptr;
|
||||||
|
QTimer m_updateTimer;
|
||||||
};
|
};
|
||||||
|
|
||||||
ShortcutSettingsWidget::ShortcutSettingsWidget()
|
ShortcutSettingsWidget::ShortcutSettingsWidget()
|
||||||
@@ -428,7 +430,12 @@ ShortcutSettingsWidget::ShortcutSettingsWidget()
|
|||||||
setTargetHeader(Tr::tr("Shortcut"));
|
setTargetHeader(Tr::tr("Shortcut"));
|
||||||
setResetVisible(true);
|
setResetVisible(true);
|
||||||
|
|
||||||
|
m_updateTimer.setSingleShot(true);
|
||||||
|
m_updateTimer.setInterval(100);
|
||||||
|
|
||||||
connect(ActionManager::instance(), &ActionManager::commandListChanged,
|
connect(ActionManager::instance(), &ActionManager::commandListChanged,
|
||||||
|
&m_updateTimer, qOverload<>(&QTimer::start));
|
||||||
|
connect(&m_updateTimer, &QTimer::timeout,
|
||||||
this, &ShortcutSettingsWidget::initialize);
|
this, &ShortcutSettingsWidget::initialize);
|
||||||
connect(this, &ShortcutSettingsWidget::currentCommandChanged,
|
connect(this, &ShortcutSettingsWidget::currentCommandChanged,
|
||||||
this, &ShortcutSettingsWidget::handleCurrentCommandChanged);
|
this, &ShortcutSettingsWidget::handleCurrentCommandChanged);
|
||||||
|
@@ -133,13 +133,13 @@ EditorView::EditorView(SplitterOrView *parentSplitterOrView, QWidget *parent)
|
|||||||
|
|
||||||
auto currentViewOverlay = new OverlayWidget;
|
auto currentViewOverlay = new OverlayWidget;
|
||||||
currentViewOverlay->attachToWidget(this);
|
currentViewOverlay->attachToWidget(this);
|
||||||
currentViewOverlay->setPaintFunction([this](QWidget *w, QPainter &p, QPaintEvent *) {
|
currentViewOverlay->setAttribute(Qt::WA_OpaquePaintEvent);
|
||||||
const int width = 2;
|
currentViewOverlay->setResizeFunction([this](QWidget *w, const QSize &) {
|
||||||
const QPoint margin{0, width};
|
const QRect toolbarRect = m_toolBar->geometry();
|
||||||
p.setPen({w->palette().color(QPalette::Highlight), width});
|
w->setGeometry(toolbarRect.x(), toolbarRect.bottom() - 1, toolbarRect.width(), 2);
|
||||||
p.drawLine(
|
});
|
||||||
m_toolBar->geometry().bottomLeft() + margin,
|
currentViewOverlay->setPaintFunction([](QWidget *w, QPainter &p, QPaintEvent *) {
|
||||||
m_toolBar->geometry().bottomRight() + margin);
|
p.fillRect(w->rect(), w->palette().color(QPalette::Highlight));
|
||||||
});
|
});
|
||||||
currentViewOverlay->setVisible(false);
|
currentViewOverlay->setVisible(false);
|
||||||
const auto updateCurrentViewOverlay = [this, currentViewOverlay] {
|
const auto updateCurrentViewOverlay = [this, currentViewOverlay] {
|
||||||
|
@@ -3,12 +3,6 @@
|
|||||||
|
|
||||||
#include "findplugin.h"
|
#include "findplugin.h"
|
||||||
|
|
||||||
#include "currentdocumentfind.h"
|
|
||||||
#include "findtoolbar.h"
|
|
||||||
#include "findtoolwindow.h"
|
|
||||||
#include "ifindfilter.h"
|
|
||||||
#include "searchresultwindow.h"
|
|
||||||
#include "textfindconstants.h"
|
|
||||||
#include "../actionmanager/actioncontainer.h"
|
#include "../actionmanager/actioncontainer.h"
|
||||||
#include "../actionmanager/actionmanager.h"
|
#include "../actionmanager/actionmanager.h"
|
||||||
#include "../actionmanager/command.h"
|
#include "../actionmanager/command.h"
|
||||||
@@ -16,6 +10,13 @@
|
|||||||
#include "../coreplugintr.h"
|
#include "../coreplugintr.h"
|
||||||
#include "../icontext.h"
|
#include "../icontext.h"
|
||||||
#include "../icore.h"
|
#include "../icore.h"
|
||||||
|
#include "../session.h"
|
||||||
|
#include "currentdocumentfind.h"
|
||||||
|
#include "findtoolbar.h"
|
||||||
|
#include "findtoolwindow.h"
|
||||||
|
#include "ifindfilter.h"
|
||||||
|
#include "searchresultwindow.h"
|
||||||
|
#include "textfindconstants.h"
|
||||||
|
|
||||||
#include <extensionsystem/pluginmanager.h>
|
#include <extensionsystem/pluginmanager.h>
|
||||||
|
|
||||||
@@ -75,6 +76,10 @@ public:
|
|||||||
|
|
||||||
QVariant data(const QModelIndex &index, int role = Qt::DisplayRole) const override;
|
QVariant data(const QModelIndex &index, int role = Qt::DisplayRole) const override;
|
||||||
|
|
||||||
|
void restore(const Store &s);
|
||||||
|
Store save() const;
|
||||||
|
|
||||||
|
// TODO deprecated since QtC 14.0
|
||||||
void writeSettings(QtcSettings *settings) const;
|
void writeSettings(QtcSettings *settings) const;
|
||||||
void readSettings(QtcSettings *settings);
|
void readSettings(QtcSettings *settings);
|
||||||
|
|
||||||
@@ -105,6 +110,41 @@ static Utils::Key completionSettingsArrayPrefix() { return "FindCompletions"; }
|
|||||||
static Utils::Key completionSettingsTextKey() { return "Text"; }
|
static Utils::Key completionSettingsTextKey() { return "Text"; }
|
||||||
static Utils::Key completionSettingsFlagsKey() { return "Flags"; }
|
static Utils::Key completionSettingsFlagsKey() { return "Flags"; }
|
||||||
|
|
||||||
|
void CompletionModel::restore(const Store &s)
|
||||||
|
{
|
||||||
|
beginResetModel();
|
||||||
|
const QStringList texts = s.value(completionSettingsTextKey()).toStringList();
|
||||||
|
const QList<FindFlags> flags
|
||||||
|
= transform(s.value(completionSettingsFlagsKey()).toList(), [](const QVariant &v) {
|
||||||
|
return FindFlags(v.toInt());
|
||||||
|
});
|
||||||
|
const int size = texts.size();
|
||||||
|
m_entries.clear();
|
||||||
|
m_entries.reserve(size);
|
||||||
|
for (int i = 0; i < size; ++i) {
|
||||||
|
CompletionEntry entry;
|
||||||
|
entry.text = texts.at(i);
|
||||||
|
entry.findFlags = i < flags.size() ? flags.at(i) : FindFlags();
|
||||||
|
if (!entry.text.isEmpty())
|
||||||
|
m_entries.append(entry);
|
||||||
|
}
|
||||||
|
endResetModel();
|
||||||
|
}
|
||||||
|
|
||||||
|
Store CompletionModel::save() const
|
||||||
|
{
|
||||||
|
if (m_entries.isEmpty())
|
||||||
|
return {};
|
||||||
|
const QStringList texts = transform(m_entries, [](const CompletionEntry &e) { return e.text; });
|
||||||
|
const QVariantList flags = transform(m_entries, [](const CompletionEntry &e) {
|
||||||
|
return QVariant::fromValue(int(e.findFlags));
|
||||||
|
});
|
||||||
|
Store s;
|
||||||
|
s.insert(completionSettingsTextKey(), texts);
|
||||||
|
s.insert(completionSettingsFlagsKey(), flags);
|
||||||
|
return s;
|
||||||
|
}
|
||||||
|
|
||||||
void CompletionModel::writeSettings(QtcSettings *settings) const
|
void CompletionModel::writeSettings(QtcSettings *settings) const
|
||||||
{
|
{
|
||||||
if (m_entries.isEmpty()) {
|
if (m_entries.isEmpty()) {
|
||||||
@@ -215,13 +255,20 @@ void Find::initialize()
|
|||||||
d->m_findDialog = new Internal::FindToolWindow;
|
d->m_findDialog = new Internal::FindToolWindow;
|
||||||
d->m_searchResultWindow = new SearchResultWindow(d->m_findDialog);
|
d->m_searchResultWindow = new SearchResultWindow(d->m_findDialog);
|
||||||
ExtensionSystem::PluginManager::addObject(d->m_searchResultWindow);
|
ExtensionSystem::PluginManager::addObject(d->m_searchResultWindow);
|
||||||
|
|
||||||
QObject::connect(ICore::instance(), &ICore::saveSettingsRequested, d, &FindPrivate::writeSettings);
|
QObject::connect(ICore::instance(), &ICore::saveSettingsRequested, d, &FindPrivate::writeSettings);
|
||||||
|
QObject::connect(
|
||||||
|
SessionManager::instance(),
|
||||||
|
&SessionManager::aboutToSaveSession,
|
||||||
|
d,
|
||||||
|
&FindPrivate::writeSettings);
|
||||||
|
QObject::connect(
|
||||||
|
SessionManager::instance(), &SessionManager::sessionLoaded, d, &FindPrivate::readSettings);
|
||||||
}
|
}
|
||||||
|
|
||||||
void Find::extensionsInitialized()
|
void Find::extensionsInitialized()
|
||||||
{
|
{
|
||||||
d->setupFilterMenuItems();
|
d->setupFilterMenuItems();
|
||||||
d->readSettings();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void Find::aboutToShutdown()
|
void Find::aboutToShutdown()
|
||||||
@@ -369,6 +416,8 @@ bool Find::hasFindFlag(FindFlag flag)
|
|||||||
|
|
||||||
void FindPrivate::writeSettings()
|
void FindPrivate::writeSettings()
|
||||||
{
|
{
|
||||||
|
// TODO for backwards compatibility
|
||||||
|
// deprecated since QtC 14.0
|
||||||
QtcSettings *settings = ICore::settings();
|
QtcSettings *settings = ICore::settings();
|
||||||
settings->beginGroup("Find");
|
settings->beginGroup("Find");
|
||||||
settings->setValueWithDefault("Backward", bool(m_findFlags & FindBackward), false);
|
settings->setValueWithDefault("Backward", bool(m_findFlags & FindBackward), false);
|
||||||
@@ -384,26 +433,70 @@ void FindPrivate::writeSettings()
|
|||||||
m_findToolBar->writeSettings();
|
m_findToolBar->writeSettings();
|
||||||
m_findDialog->writeSettings();
|
m_findDialog->writeSettings();
|
||||||
m_searchResultWindow->writeSettings();
|
m_searchResultWindow->writeSettings();
|
||||||
|
|
||||||
|
// save in session
|
||||||
|
Store s;
|
||||||
|
if (m_findFlags & FindBackward)
|
||||||
|
s.insert("Backward", true);
|
||||||
|
if (m_findFlags & FindCaseSensitively)
|
||||||
|
s.insert("CaseSensitively", true);
|
||||||
|
if (m_findFlags & FindWholeWords)
|
||||||
|
s.insert("WholeWords", true);
|
||||||
|
if (m_findFlags & FindRegularExpression)
|
||||||
|
s.insert("RegularExpression", true);
|
||||||
|
if (m_findFlags & FindPreserveCase)
|
||||||
|
s.insert("PreserveCase", true);
|
||||||
|
const Store completion = m_findCompletionModel.save();
|
||||||
|
if (!completion.isEmpty())
|
||||||
|
s.insert("FindCompletions", variantFromStore(completion));
|
||||||
|
if (!m_replaceCompletions.isEmpty())
|
||||||
|
s.insert("ReplaceStrings", m_replaceCompletions);
|
||||||
|
const Store toolbar = m_findToolBar->save();
|
||||||
|
if (!toolbar.isEmpty())
|
||||||
|
s.insert("ToolBar", variantFromStore(toolbar));
|
||||||
|
const Store advanced = m_findDialog->save();
|
||||||
|
if (!advanced.isEmpty())
|
||||||
|
s.insert("AdvancedSearch", variantFromStore(advanced));
|
||||||
|
SessionManager::setValue("Find", variantFromStore(s));
|
||||||
}
|
}
|
||||||
|
|
||||||
void FindPrivate::readSettings()
|
void FindPrivate::readSettings()
|
||||||
{
|
{
|
||||||
QtcSettings *settings = ICore::settings();
|
const Store s = storeFromVariant(SessionManager::value("Find"));
|
||||||
settings->beginGroup("Find");
|
if (s.isEmpty() && SessionManager::isDefaultVirgin()) {
|
||||||
{
|
// TODO compatibility path when opening Qt Creator
|
||||||
QSignalBlocker blocker(m_instance);
|
// TODO deprecated since QtC 14.0
|
||||||
Find::setBackward(settings->value("Backward", false).toBool());
|
QtcSettings *settings = ICore::settings();
|
||||||
Find::setCaseSensitive(settings->value("CaseSensitively", false).toBool());
|
settings->beginGroup("Find");
|
||||||
Find::setWholeWord(settings->value("WholeWords", false).toBool());
|
{
|
||||||
Find::setRegularExpression(settings->value("RegularExpression", false).toBool());
|
QSignalBlocker blocker(m_instance);
|
||||||
Find::setPreserveCase(settings->value("PreserveCase", false).toBool());
|
Find::setBackward(settings->value("Backward", false).toBool());
|
||||||
|
Find::setCaseSensitive(settings->value("CaseSensitively", false).toBool());
|
||||||
|
Find::setWholeWord(settings->value("WholeWords", false).toBool());
|
||||||
|
Find::setRegularExpression(settings->value("RegularExpression", false).toBool());
|
||||||
|
Find::setPreserveCase(settings->value("PreserveCase", false).toBool());
|
||||||
|
}
|
||||||
|
m_findCompletionModel.readSettings(settings);
|
||||||
|
m_replaceCompletions = settings->value("ReplaceStrings").toStringList();
|
||||||
|
m_replaceCompletionModel.setStringList(m_replaceCompletions);
|
||||||
|
settings->endGroup();
|
||||||
|
m_findToolBar->readSettings();
|
||||||
|
m_findDialog->readSettings();
|
||||||
|
} else if (!s.empty()) {
|
||||||
|
{
|
||||||
|
QSignalBlocker blocker(m_instance);
|
||||||
|
Find::setBackward(s.value("Backward", false).toBool());
|
||||||
|
Find::setCaseSensitive(s.value("CaseSensitively", false).toBool());
|
||||||
|
Find::setWholeWord(s.value("WholeWords", false).toBool());
|
||||||
|
Find::setRegularExpression(s.value("RegularExpression", false).toBool());
|
||||||
|
Find::setPreserveCase(s.value("PreserveCase", false).toBool());
|
||||||
|
}
|
||||||
|
m_findCompletionModel.restore(storeFromVariant(s.value("FindCompletions")));
|
||||||
|
m_replaceCompletions = s.value("ReplaceStrings").toStringList();
|
||||||
|
m_replaceCompletionModel.setStringList(m_replaceCompletions);
|
||||||
|
m_findToolBar->restore(storeFromVariant(s.value("ToolBar")));
|
||||||
|
m_findDialog->restore(storeFromVariant(s.value("AdvancedSearch")));
|
||||||
}
|
}
|
||||||
m_findCompletionModel.readSettings(settings);
|
|
||||||
m_replaceCompletions = settings->value("ReplaceStrings").toStringList();
|
|
||||||
m_replaceCompletionModel.setStringList(m_replaceCompletions);
|
|
||||||
settings->endGroup();
|
|
||||||
m_findToolBar->readSettings();
|
|
||||||
m_findDialog->readSettings();
|
|
||||||
emit m_instance->findFlagsChanged(); // would have been done in the setXXX methods above
|
emit m_instance->findFlagsChanged(); // would have been done in the setXXX methods above
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@@ -1047,6 +1047,39 @@ void FindToolBar::resizeEvent(QResizeEvent *event)
|
|||||||
QMetaObject::invokeMethod(this, &FindToolBar::updateToolBar, Qt::QueuedConnection);
|
QMetaObject::invokeMethod(this, &FindToolBar::updateToolBar, Qt::QueuedConnection);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void FindToolBar::restore(const Store &s)
|
||||||
|
{
|
||||||
|
FindFlags flags;
|
||||||
|
if (s.value("Backward", false).toBool())
|
||||||
|
flags |= FindBackward;
|
||||||
|
if (s.value("CaseSensitively", false).toBool())
|
||||||
|
flags |= FindCaseSensitively;
|
||||||
|
if (s.value("WholeWords", false).toBool())
|
||||||
|
flags |= FindWholeWords;
|
||||||
|
if (s.value("RegularExpression", false).toBool())
|
||||||
|
flags |= FindRegularExpression;
|
||||||
|
if (s.value("PreserveCase", false).toBool())
|
||||||
|
flags |= FindPreserveCase;
|
||||||
|
m_findFlags = flags;
|
||||||
|
findFlagsChanged();
|
||||||
|
}
|
||||||
|
|
||||||
|
Store FindToolBar::save() const
|
||||||
|
{
|
||||||
|
Store s;
|
||||||
|
if (m_findFlags & FindBackward)
|
||||||
|
s.insert("Backward", true);
|
||||||
|
if (m_findFlags & FindCaseSensitively)
|
||||||
|
s.insert("CaseSensitively", true);
|
||||||
|
if (m_findFlags & FindWholeWords)
|
||||||
|
s.insert("WholeWords", true);
|
||||||
|
if (m_findFlags & FindRegularExpression)
|
||||||
|
s.insert("RegularExpression", true);
|
||||||
|
if (m_findFlags & FindPreserveCase)
|
||||||
|
s.insert("PreserveCase", true);
|
||||||
|
return s;
|
||||||
|
}
|
||||||
|
|
||||||
void FindToolBar::writeSettings()
|
void FindToolBar::writeSettings()
|
||||||
{
|
{
|
||||||
Utils::QtcSettings *settings = ICore::settings();
|
Utils::QtcSettings *settings = ICore::settings();
|
||||||
|
@@ -6,6 +6,7 @@
|
|||||||
#include "currentdocumentfind.h"
|
#include "currentdocumentfind.h"
|
||||||
|
|
||||||
#include <utils/id.h>
|
#include <utils/id.h>
|
||||||
|
#include <utils/store.h>
|
||||||
#include <utils/styledbar.h>
|
#include <utils/styledbar.h>
|
||||||
|
|
||||||
#include <QTimer>
|
#include <QTimer>
|
||||||
@@ -18,7 +19,9 @@ class QSpacerItem;
|
|||||||
class QToolButton;
|
class QToolButton;
|
||||||
QT_END_NAMESPACE
|
QT_END_NAMESPACE
|
||||||
|
|
||||||
namespace Utils { class FancyLineEdit; }
|
namespace Utils {
|
||||||
|
class FancyLineEdit;
|
||||||
|
} // namespace Utils
|
||||||
|
|
||||||
namespace Core {
|
namespace Core {
|
||||||
|
|
||||||
@@ -43,6 +46,10 @@ public:
|
|||||||
explicit FindToolBar(CurrentDocumentFind *currentDocumentFind);
|
explicit FindToolBar(CurrentDocumentFind *currentDocumentFind);
|
||||||
~FindToolBar() override;
|
~FindToolBar() override;
|
||||||
|
|
||||||
|
void restore(const Utils::Store &s);
|
||||||
|
Utils::Store save() const;
|
||||||
|
|
||||||
|
// TODO deprecated since QtC 14.0
|
||||||
void readSettings();
|
void readSettings();
|
||||||
void writeSettings();
|
void writeSettings();
|
||||||
|
|
||||||
|
@@ -346,6 +346,30 @@ void FindToolWindow::replace()
|
|||||||
filter->replaceAll(term, Find::findFlags());
|
filter->replaceAll(term, Find::findFlags());
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void FindToolWindow::restore(const Utils::Store &s)
|
||||||
|
{
|
||||||
|
const QString currentFilter = s.value("CurrentFilter").toString();
|
||||||
|
for (int i = 0; i < m_filters.size(); ++i) {
|
||||||
|
IFindFilter *filter = m_filters.at(i);
|
||||||
|
filter->restore(storeFromVariant(s.value(filter->id().toUtf8())));
|
||||||
|
if (filter->id() == currentFilter)
|
||||||
|
setCurrentFilterIndex(i);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
Store FindToolWindow::save() const
|
||||||
|
{
|
||||||
|
Store s;
|
||||||
|
if (m_currentFilter && (m_filters.isEmpty() || m_filters.first() != m_currentFilter))
|
||||||
|
s.insert("CurrentFilter", m_currentFilter->id());
|
||||||
|
for (IFindFilter *filter : std::as_const(m_filters)) {
|
||||||
|
const Store store = filter->save();
|
||||||
|
if (!store.isEmpty())
|
||||||
|
s.insert(filter->id().toUtf8(), variantFromStore(store));
|
||||||
|
}
|
||||||
|
return s;
|
||||||
|
}
|
||||||
|
|
||||||
void FindToolWindow::writeSettings()
|
void FindToolWindow::writeSettings()
|
||||||
{
|
{
|
||||||
Utils::QtcSettings *settings = ICore::settings();
|
Utils::QtcSettings *settings = ICore::settings();
|
||||||
|
@@ -3,6 +3,8 @@
|
|||||||
|
|
||||||
#pragma once
|
#pragma once
|
||||||
|
|
||||||
|
#include <utils/store.h>
|
||||||
|
|
||||||
#include <QList>
|
#include <QList>
|
||||||
#include <QWidget>
|
#include <QWidget>
|
||||||
|
|
||||||
@@ -33,6 +35,11 @@ public:
|
|||||||
|
|
||||||
void setFindText(const QString &text);
|
void setFindText(const QString &text);
|
||||||
void setCurrentFilter(IFindFilter *filter);
|
void setCurrentFilter(IFindFilter *filter);
|
||||||
|
|
||||||
|
void restore(const Utils::Store &s);
|
||||||
|
Utils::Store save() const;
|
||||||
|
|
||||||
|
// TODO deprecated since QtC 14.0
|
||||||
void readSettings();
|
void readSettings();
|
||||||
void writeSettings();
|
void writeSettings();
|
||||||
|
|
||||||
|
@@ -6,6 +6,8 @@
|
|||||||
#include "../coreicons.h"
|
#include "../coreicons.h"
|
||||||
#include "../coreplugintr.h"
|
#include "../coreplugintr.h"
|
||||||
|
|
||||||
|
#include <utils/qtcsettings.h>
|
||||||
|
|
||||||
#include <QApplication>
|
#include <QApplication>
|
||||||
#include <QKeySequence>
|
#include <QKeySequence>
|
||||||
#include <QPainter>
|
#include <QPainter>
|
||||||
@@ -177,18 +179,6 @@ using namespace Utils;
|
|||||||
dialog. It will be reparented and deleted by the find plugin.
|
dialog. It will be reparented and deleted by the find plugin.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
/*!
|
|
||||||
\fn void Core::IFindFilter::writeSettings(Utils::QtcSettings *settings)
|
|
||||||
Called at shutdown to write the state of the additional options
|
|
||||||
for this find filter to the \a settings.
|
|
||||||
*/
|
|
||||||
|
|
||||||
/*!
|
|
||||||
\fn void Core::IFindFilter::readSettings(Utils::QtcSettings *settings)
|
|
||||||
Called at startup to read the state of the additional options
|
|
||||||
for this find filter from the \a settings.
|
|
||||||
*/
|
|
||||||
|
|
||||||
/*!
|
/*!
|
||||||
\fn void Core::IFindFilter::enabledChanged(bool enabled)
|
\fn void Core::IFindFilter::enabledChanged(bool enabled)
|
||||||
|
|
||||||
@@ -264,6 +254,60 @@ FindFlags IFindFilter::supportedFindFlags() const
|
|||||||
| FindWholeWords;
|
| FindWholeWords;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/*!
|
||||||
|
Returns a Store with the find filter's settings to store
|
||||||
|
in the session. Default values should not be saved.
|
||||||
|
The default implementation returns an empty store.
|
||||||
|
|
||||||
|
\sa restore()
|
||||||
|
*/
|
||||||
|
Store IFindFilter::save() const
|
||||||
|
{
|
||||||
|
return {};
|
||||||
|
}
|
||||||
|
|
||||||
|
/*!
|
||||||
|
Restores the find filter's settings from the Store \a s.
|
||||||
|
Settings that are not present in the store should be reset to
|
||||||
|
the default.
|
||||||
|
The default implementation does nothing.
|
||||||
|
|
||||||
|
\sa save()
|
||||||
|
*/
|
||||||
|
void IFindFilter::restore([[maybe_unused]] const Utils::Store &s) {}
|
||||||
|
|
||||||
|
/*!
|
||||||
|
Called at shutdown to write the state of the additional options
|
||||||
|
for this find filter to the \a settings.
|
||||||
|
|
||||||
|
\deprecated [14.0] Implement save() instead.
|
||||||
|
*/
|
||||||
|
void IFindFilter::writeSettings(Utils::QtcSettings *settings)
|
||||||
|
{
|
||||||
|
settings->remove(settingsKey()); // make sure defaults are removed
|
||||||
|
storeToSettings(settingsKey(), settings, save());
|
||||||
|
}
|
||||||
|
|
||||||
|
/*!
|
||||||
|
Called at startup to read the state of the additional options
|
||||||
|
for this find filter from the \a settings.
|
||||||
|
|
||||||
|
\deprecated [14.0] Implement restore() instead.
|
||||||
|
*/
|
||||||
|
void IFindFilter::readSettings(Utils::QtcSettings *settings)
|
||||||
|
{
|
||||||
|
restore(storeFromSettings(settingsKey(), settings));
|
||||||
|
}
|
||||||
|
|
||||||
|
/*!
|
||||||
|
\internal
|
||||||
|
\deprecated [14.0]
|
||||||
|
*/
|
||||||
|
QByteArray IFindFilter::settingsKey() const
|
||||||
|
{
|
||||||
|
return id().toUtf8();
|
||||||
|
}
|
||||||
|
|
||||||
/*!
|
/*!
|
||||||
Returns icons for the find flags \a flags.
|
Returns icons for the find flags \a flags.
|
||||||
*/
|
*/
|
||||||
|
@@ -6,6 +6,7 @@
|
|||||||
#include "../core_global.h"
|
#include "../core_global.h"
|
||||||
|
|
||||||
#include <utils/filesearch.h>
|
#include <utils/filesearch.h>
|
||||||
|
#include <utils/store.h>
|
||||||
|
|
||||||
QT_BEGIN_NAMESPACE
|
QT_BEGIN_NAMESPACE
|
||||||
class QWidget;
|
class QWidget;
|
||||||
@@ -42,8 +43,13 @@ public:
|
|||||||
{ Q_UNUSED(txt) Q_UNUSED(findFlags) }
|
{ Q_UNUSED(txt) Q_UNUSED(findFlags) }
|
||||||
|
|
||||||
virtual QWidget *createConfigWidget() { return nullptr; }
|
virtual QWidget *createConfigWidget() { return nullptr; }
|
||||||
virtual void writeSettings(Utils::QtcSettings *settings) { Q_UNUSED(settings) }
|
virtual Utils::Store save() const;
|
||||||
virtual void readSettings(Utils::QtcSettings *settings) { Q_UNUSED(settings) }
|
virtual void restore(const Utils::Store &s);
|
||||||
|
|
||||||
|
// deprecated in 14.0
|
||||||
|
virtual void writeSettings(Utils::QtcSettings *settings);
|
||||||
|
virtual void readSettings(Utils::QtcSettings *settings);
|
||||||
|
virtual QByteArray settingsKey() const;
|
||||||
|
|
||||||
static QPixmap pixmapForFindFlags(Utils::FindFlags flags);
|
static QPixmap pixmapForFindFlags(Utils::FindFlags flags);
|
||||||
static QString descriptionForFindFlags(Utils::FindFlags flags);
|
static QString descriptionForFindFlags(Utils::FindFlags flags);
|
||||||
|
@@ -1068,6 +1068,8 @@ QString uiConfigInformation()
|
|||||||
QTC_ADD_UIELEMENT_FONT(Body2);
|
QTC_ADD_UIELEMENT_FONT(Body2);
|
||||||
QTC_ADD_UIELEMENT_FONT(ButtonMedium);
|
QTC_ADD_UIELEMENT_FONT(ButtonMedium);
|
||||||
QTC_ADD_UIELEMENT_FONT(ButtonSmall);
|
QTC_ADD_UIELEMENT_FONT(ButtonSmall);
|
||||||
|
QTC_ADD_UIELEMENT_FONT(LabelMedium);
|
||||||
|
QTC_ADD_UIELEMENT_FONT(LabelSmall);
|
||||||
QTC_ADD_UIELEMENT_FONT(CaptionStrong);
|
QTC_ADD_UIELEMENT_FONT(CaptionStrong);
|
||||||
QTC_ADD_UIELEMENT_FONT(Caption);
|
QTC_ADD_UIELEMENT_FONT(Caption);
|
||||||
QTC_ADD_UIELEMENT_FONT(IconStandard);
|
QTC_ADD_UIELEMENT_FONT(IconStandard);
|
||||||
|
@@ -563,16 +563,15 @@ static void drawPrimitiveTweakedForDarkTheme(QStyle::PrimitiveElement element,
|
|||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
case QStyle::PE_IndicatorTabClose: {
|
case QStyle::PE_IndicatorTabClose: {
|
||||||
QWindow *window = widget ? widget->window()->windowHandle() : nullptr;
|
const qreal devicePixelRatio = painter->device()->devicePixelRatio();
|
||||||
QRect iconRect = QRect(0, 0, 16, 16);
|
QRect iconRect = QRect(0, 0, 16, 16);
|
||||||
iconRect.moveCenter(option->rect.center());
|
iconRect.moveCenter(option->rect.center());
|
||||||
const QIcon::Mode mode = !isEnabled ? QIcon::Disabled : QIcon::Normal;
|
const QIcon::Mode mode = !isEnabled ? QIcon::Disabled : QIcon::Normal;
|
||||||
const static QIcon closeIcon = Utils::Icons::CLOSE_FOREGROUND.icon();
|
const static QIcon closeIcon = Utils::Icons::CLOSE_FOREGROUND.icon();
|
||||||
if (option->state & QStyle::State_MouseOver && widget)
|
if (option->state & QStyle::State_MouseOver && widget)
|
||||||
widget->style()->drawPrimitive(QStyle::PE_PanelButtonCommand, option, painter, widget);
|
widget->style()->drawPrimitive(QStyle::PE_PanelButtonCommand, option, painter, widget);
|
||||||
const int devicePixelRatio = widget ? widget->devicePixelRatio() : 1;
|
|
||||||
const QPixmap iconPx =
|
const QPixmap iconPx =
|
||||||
closeIcon.pixmap(window, iconRect.size() * devicePixelRatio, mode);
|
closeIcon.pixmap(iconRect.size() * devicePixelRatio, devicePixelRatio, mode);
|
||||||
painter->drawPixmap(iconRect, iconPx);
|
painter->drawPixmap(iconRect, iconPx);
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
@@ -421,7 +421,7 @@ OutputPaneManager::OutputPaneManager(QWidget *parent) :
|
|||||||
}.attachTo(this);
|
}.attachTo(this);
|
||||||
|
|
||||||
Row {
|
Row {
|
||||||
spacing(creatorTheme()->flag(Theme::FlatToolBars) ? 9 : 4), customMargin({5, 0, 0, 0}),
|
spacing(creatorTheme()->flag(Theme::FlatToolBars) ? 9 : 4), customMargins(5, 0, 0, 0),
|
||||||
}.attachTo(m_buttonsWidget);
|
}.attachTo(m_buttonsWidget);
|
||||||
|
|
||||||
StatusBarManager::addStatusBarWidget(m_buttonsWidget, StatusBarManager::Second);
|
StatusBarManager::addStatusBarWidget(m_buttonsWidget, StatusBarManager::Second);
|
||||||
|
@@ -1203,7 +1203,7 @@ ListModel *SectionedGridView::addSection(const Section §ion, const QList<Lis
|
|||||||
st,
|
st,
|
||||||
seeAllLink,
|
seeAllLink,
|
||||||
Space(ExVPaddingGapXl),
|
Space(ExVPaddingGapXl),
|
||||||
customMargin({0, ExPaddingGapL, 0, VPaddingL}),
|
customMargins(0, ExPaddingGapL, 0, VPaddingL),
|
||||||
}.emerge();
|
}.emerge();
|
||||||
m_sectionLabels.append(sectionLabel);
|
m_sectionLabels.append(sectionLabel);
|
||||||
auto scrollArea = qobject_cast<QScrollArea *>(widget(0));
|
auto scrollArea = qobject_cast<QScrollArea *>(widget(0));
|
||||||
@@ -1274,7 +1274,7 @@ void SectionedGridView::zoomInSection(const Section §ion)
|
|||||||
st,
|
st,
|
||||||
backLink,
|
backLink,
|
||||||
Space(ExVPaddingGapXl),
|
Space(ExVPaddingGapXl),
|
||||||
customMargin({0, ExPaddingGapL, 0, VPaddingL}),
|
customMargins(0, ExPaddingGapL, 0, VPaddingL),
|
||||||
}.emerge();
|
}.emerge();
|
||||||
|
|
||||||
auto gridView = new GridView(zoomedInWidget);
|
auto gridView = new GridView(zoomedInWidget);
|
||||||
|
@@ -101,7 +101,7 @@ void CppcheckTool::updateArguments()
|
|||||||
|
|
||||||
arguments.push_back("--template=\"{file},{line},{severity},{id},{message}\"");
|
arguments.push_back("--template=\"{file},{line},{severity},{id},{message}\"");
|
||||||
|
|
||||||
m_runner->reconfigure(s.binary(), arguments.join(' '));
|
m_runner->reconfigure(s.binary.effectiveBinary(), arguments.join(' '));
|
||||||
}
|
}
|
||||||
|
|
||||||
QStringList CppcheckTool::additionalArguments(const CppEditor::ProjectPart &part) const
|
QStringList CppcheckTool::additionalArguments(const CppEditor::ProjectPart &part) const
|
||||||
|
@@ -166,26 +166,30 @@ QWidget *SymbolsFindFilter::createConfigWidget()
|
|||||||
return new SymbolsFindFilterConfigWidget(this);
|
return new SymbolsFindFilterConfigWidget(this);
|
||||||
}
|
}
|
||||||
|
|
||||||
void SymbolsFindFilter::writeSettings(QtcSettings *settings)
|
Store SymbolsFindFilter::save() const
|
||||||
{
|
{
|
||||||
settings->beginGroup(SETTINGS_GROUP);
|
Store s;
|
||||||
settings->setValue(SETTINGS_SYMBOLTYPES, int(m_symbolsToSearch));
|
if (m_symbolsToSearch != SearchSymbols::AllTypes)
|
||||||
settings->setValue(SETTINGS_SEARCHSCOPE, int(m_scope));
|
s.insert(SETTINGS_SYMBOLTYPES, int(m_symbolsToSearch));
|
||||||
settings->endGroup();
|
if (m_scope != SymbolSearcher::SearchProjectsOnly)
|
||||||
|
s.insert(SETTINGS_SEARCHSCOPE, int(m_scope));
|
||||||
|
return s;
|
||||||
}
|
}
|
||||||
|
|
||||||
void SymbolsFindFilter::readSettings(QtcSettings *settings)
|
void SymbolsFindFilter::restore(const Utils::Store &s)
|
||||||
{
|
{
|
||||||
settings->beginGroup(SETTINGS_GROUP);
|
|
||||||
m_symbolsToSearch = static_cast<SearchSymbols::SymbolTypes>(
|
m_symbolsToSearch = static_cast<SearchSymbols::SymbolTypes>(
|
||||||
settings->value(SETTINGS_SYMBOLTYPES, int(SearchSymbols::AllTypes)).toInt());
|
s.value(SETTINGS_SYMBOLTYPES, int(SearchSymbols::AllTypes)).toInt());
|
||||||
m_scope = static_cast<SearchScope>(
|
m_scope = static_cast<SearchScope>(
|
||||||
settings->value(SETTINGS_SEARCHSCOPE,
|
s.value(SETTINGS_SEARCHSCOPE, int(SymbolSearcher::SearchProjectsOnly)).toInt());
|
||||||
int(SymbolSearcher::SearchProjectsOnly)).toInt());
|
|
||||||
settings->endGroup();
|
|
||||||
emit symbolsToSearchChanged();
|
emit symbolsToSearchChanged();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
QByteArray SymbolsFindFilter::settingsKey() const
|
||||||
|
{
|
||||||
|
return SETTINGS_GROUP;
|
||||||
|
}
|
||||||
|
|
||||||
void SymbolsFindFilter::onTaskStarted(Id type)
|
void SymbolsFindFilter::onTaskStarted(Id type)
|
||||||
{
|
{
|
||||||
if (type == Constants::TASK_INDEX) {
|
if (type == Constants::TASK_INDEX) {
|
||||||
|
@@ -37,8 +37,8 @@ public:
|
|||||||
void findAll(const QString &txt, Utils::FindFlags findFlags) override;
|
void findAll(const QString &txt, Utils::FindFlags findFlags) override;
|
||||||
|
|
||||||
QWidget *createConfigWidget() override;
|
QWidget *createConfigWidget() override;
|
||||||
void writeSettings(Utils::QtcSettings *settings) override;
|
Utils::Store save() const override;
|
||||||
void readSettings(Utils::QtcSettings *settings) override;
|
void restore(const Utils::Store &s) override;
|
||||||
|
|
||||||
void setSymbolsToSearch(const SearchSymbols::SymbolTypes &types) { m_symbolsToSearch = types; }
|
void setSymbolsToSearch(const SearchSymbols::SymbolTypes &types) { m_symbolsToSearch = types; }
|
||||||
SearchSymbols::SymbolTypes symbolsToSearch() const { return m_symbolsToSearch; }
|
SearchSymbols::SymbolTypes symbolsToSearch() const { return m_symbolsToSearch; }
|
||||||
@@ -46,6 +46,9 @@ public:
|
|||||||
void setSearchScope(SearchScope scope) { m_scope = scope; }
|
void setSearchScope(SearchScope scope) { m_scope = scope; }
|
||||||
SearchScope searchScope() const { return m_scope; }
|
SearchScope searchScope() const { return m_scope; }
|
||||||
|
|
||||||
|
// deprecated
|
||||||
|
QByteArray settingsKey() const override;
|
||||||
|
|
||||||
signals:
|
signals:
|
||||||
void symbolsToSearchChanged();
|
void symbolsToSearchChanged();
|
||||||
|
|
||||||
|
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user