diff --git a/.github/workflows/build_cmake.yml b/.github/workflows/build_cmake.yml
index 6f0223b578b..7cbe1ce5b7f 100644
--- a/.github/workflows/build_cmake.yml
+++ b/.github/workflows/build_cmake.yml
@@ -49,13 +49,12 @@ jobs:
}
- {
name: "macOS Latest Clang", artifact: "macos-universal",
- # TODO: move back to macos-latest when macos-latest is 13 or higher
- os: macos-13,
+ os: macos-latest,
cc: "clang", cxx: "clang++"
}
steps:
- - uses: actions/checkout@v3
+ - uses: actions/checkout@v4
- name: Checkout submodules
id: git
shell: cmake -P {0}
@@ -63,10 +62,10 @@ jobs:
execute_process(COMMAND git submodule set-url -- perfparser https://code.qt.io/qt-creator/perfparser.git)
execute_process(COMMAND git submodule update --init --recursive)
file(MAKE_DIRECTORY release)
- if (${{github.ref}} MATCHES "tags/v([0-9.]+)")
+ if (${{github.ref}} MATCHES "tags/v(([0-9.]+).*)")
file(APPEND "$ENV{GITHUB_OUTPUT}" "tag=${CMAKE_MATCH_1}\n")
- if (EXISTS "dist/changelog/changes-${CMAKE_MATCH_1}.md")
- file(READ "dist/changelog/changes-${CMAKE_MATCH_1}.md" changelog_md)
+ if (EXISTS "dist/changelog/changes-${CMAKE_MATCH_2}.md")
+ file(READ "dist/changelog/changes-${CMAKE_MATCH_2}.md" changelog_md)
endif()
file(WRITE "release/changelog.md" "These packages are not officially supported, for official packages please check out https://download.qt.io/official_releases/qtcreator\n\n")
file(APPEND "release/changelog.md" "${changelog_md}")
@@ -695,41 +694,41 @@ jobs:
endif()
- name: Upload
- uses: actions/upload-artifact@v3
+ uses: actions/upload-artifact@v4
with:
path: build/qtcreator-${{ matrix.config.artifact }}-${{ steps.git.outputs.tag }}.7z
name: qtcreator-${{ matrix.config.artifact }}-${{ steps.git.outputs.tag }}.7z
- name: Upload Devel
- uses: actions/upload-artifact@v3
+ uses: actions/upload-artifact@v4
with:
path: build/qtcreator-${{ matrix.config.artifact }}-${{ steps.git.outputs.tag }}_dev.7z
name: qtcreator-${{ matrix.config.artifact }}-${{ steps.git.outputs.tag }}_dev.7z
- name: Upload wininterrupt
if: runner.os == 'Windows'
- uses: actions/upload-artifact@v3
+ uses: actions/upload-artifact@v4
with:
path: build/wininterrupt-${{ matrix.config.artifact }}-${{ steps.git.outputs.tag }}.7z
name: wininterrupt-${{ matrix.config.artifact }}-${{ steps.git.outputs.tag }}.7z
- name: Upload qtcreatorcdbext
if: runner.os == 'Windows' && matrix.config.is_msvc
- uses: actions/upload-artifact@v3
+ uses: actions/upload-artifact@v4
with:
path: build/qtcreatorcdbext-${{ matrix.config.artifact }}-${{ steps.git.outputs.tag }}.7z
name: qtcreatorcdbext-${{ matrix.config.artifact }}-${{ steps.git.outputs.tag }}.7z
- name: Upload Debian package
if: runner.os == 'Linux'
- uses: actions/upload-artifact@v3
+ uses: actions/upload-artifact@v4
with:
path: build/build/qtcreator-${{ matrix.config.artifact }}-${{ steps.git.outputs.tag }}.deb
name: qtcreator-${{ matrix.config.artifact }}-${{ steps.git.outputs.tag }}.deb
- name: Upload disk image
if: runner.os == 'macOS' && contains(github.ref, 'tags/v')
- uses: actions/upload-artifact@v3
+ uses: actions/upload-artifact@v4
with:
path: build/qt-creator-${{ matrix.config.artifact }}-${{ steps.git.outputs.tag }}.dmg
name: qt-creator-${{ matrix.config.artifact }}-${{ steps.git.outputs.tag }}.dmg
@@ -739,14 +738,14 @@ jobs:
run: cmake -E tar cf ../${{ steps.ccache.outputs.archive_name }}.tar .
- name: Upload ccache archive
- uses: actions/upload-artifact@v3
+ uses: actions/upload-artifact@v4
with:
path: ./${{ steps.ccache.outputs.archive_name }}.tar
name: ${{ steps.ccache.outputs.archive_name }}
- name: Upload Release Changelog
if: contains(github.ref, 'tags/v')
- uses: actions/upload-artifact@v3
+ uses: actions/upload-artifact@v4
with:
path: ./release/changelog.md
name: changelog.md
@@ -758,7 +757,7 @@ jobs:
steps:
- name: Download artifacts
- uses: actions/download-artifact@v3
+ uses: actions/download-artifact@v4
with:
path: release-with-dirs
@@ -770,7 +769,7 @@ jobs:
- name: Create Release
id: create_release
- uses: softprops/action-gh-release@v1
+ uses: softprops/action-gh-release@v2
env:
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
with:
diff --git a/coin/instructions/build.yaml b/coin/instructions/build.yaml
index e4453c9e71b..b98cfbafbcc 100644
--- a/coin/instructions/build.yaml
+++ b/coin/instructions/build.yaml
@@ -20,7 +20,7 @@ instructions:
maxTimeBetweenOutput: 360
userMessageOnFailure: "Failed to download elfutils package, check logs."
- type: ExecuteCommand
- command: "/usr/bin/7z x -y {{.AgentWorkingDir}}/build/qt_temp/elfutils-release_0.175qt-linux-x86_64.7z -o{{.AgentWorkingDir}}/build/qt_temp/elfutils"
+ command: "7z x -y {{.AgentWorkingDir}}/build/qt_temp/elfutils-release_0.175qt-linux-x86_64.7z -o{{.AgentWorkingDir}}/build/qt_temp/elfutils"
maxTimeInSeconds: 3600
maxTimeBetweenOutput: 360
userMessageOnFailure: "Failed to extract elfutils package, check logs."
@@ -30,7 +30,7 @@ instructions:
maxTimeBetweenOutput: 360
userMessageOnFailure: "Failed to download LLVM package, check logs."
- type: ExecuteCommand
- command: "/usr/bin/7z x -y {{.AgentWorkingDir}}/build/qt_temp/libclang.7z -o{{.AgentWorkingDir}}/build/qt_temp/"
+ command: "7z x -y {{.AgentWorkingDir}}/build/qt_temp/libclang.7z -o{{.AgentWorkingDir}}/build/qt_temp/"
maxTimeInSeconds: 3600
maxTimeBetweenOutput: 360
userMessageOnFailure: "Failed to extract LLVM package, check logs."
@@ -42,7 +42,7 @@ instructions:
- type: ChangeDirectory
directory: "{{.AgentWorkingDir}}/build/tqtc-qtsdk/packaging_tools"
- type: ExecuteCommand
- command: "python3 -m pipenv run python -u bld_sdktool.py --qt-url {{.Env.QTC_SDKTOOL_QT_BASE_URL}}{{.Env.QTC_SDKTOOL_QT_EXT}} --qt-build {{.AgentWorkingDir}}/build/sdktool/qt --src {{.AgentWorkingDir}}/qt-creator/qt-creator/src/tools/sdktool --build {{.AgentWorkingDir}}/build/sdktool/build --install {{.AgentWorkingDir}}/build/sdktool/install --make-command make"
+ command: "python3 -m pipenv run python -u bld_sdktool.py --qt-url {{.Env.QTC_SDKTOOL_QT_BASE_URL}}{{.Env.QTC_SDKTOOL_QT_EXT}} --qt-build {{.AgentWorkingDir}}/build/sdktool/qt --src {{.AgentWorkingDir}}/qt-creator/qt-creator/src/tools/sdktool --build {{.AgentWorkingDir}}/build/sdktool/build --install {{.AgentWorkingDir}}/build/sdktool/install --make-command ninja"
maxTimeInSeconds: 36000
maxTimeBetweenOutput: 3600
userMessageOnFailure: "Failed to build sdktool, check logs."
@@ -64,7 +64,7 @@ instructions:
maxTimeBetweenOutput: 360
userMessageOnFailure: "Failed to download LLVM package, check logs."
- type: ExecuteCommand
- command: "/usr/local/bin/7z x -y {{.AgentWorkingDir}}/build/qt_temp/libclang.7z -o{{.AgentWorkingDir}}/build/qt_temp/"
+ command: "7z x -y {{.AgentWorkingDir}}/build/qt_temp/libclang.7z -o{{.AgentWorkingDir}}/build/qt_temp/"
maxTimeInSeconds: 3600
maxTimeBetweenOutput: 360
userMessageOnFailure: "Failed to extract LLVM package, check logs."
@@ -79,7 +79,7 @@ instructions:
variableName: MACOSX_DEPLOYMENT_TARGET
variableValue: "{{.Env.SDKTOOL_MACOSX_DEPLOYMENT_TARGET}}"
- type: ExecuteCommand
- command: "python3 -m pipenv run python -u bld_sdktool.py --qt-url {{.Env.QTC_SDKTOOL_QT_BASE_URL}}{{.Env.QTC_SDKTOOL_QT_EXT}} --qt-build {{.AgentWorkingDir}}/build/sdktool/qt --src {{.AgentWorkingDir}}/qt-creator/qt-creator/src/tools/sdktool --build {{.AgentWorkingDir}}/build/sdktool/build --install {{.AgentWorkingDir}}/build/sdktool/install --make-command make"
+ command: "python3 -m pipenv run python -u bld_sdktool.py --qt-url {{.Env.QTC_SDKTOOL_QT_BASE_URL}}{{.Env.QTC_SDKTOOL_QT_EXT}} --qt-build {{.AgentWorkingDir}}/build/sdktool/qt --src {{.AgentWorkingDir}}/qt-creator/qt-creator/src/tools/sdktool --build {{.AgentWorkingDir}}/build/sdktool/build --install {{.AgentWorkingDir}}/build/sdktool/install --make-command ninja --universal"
maxTimeInSeconds: 36000
maxTimeBetweenOutput: 3600
userMessageOnFailure: "Failed to build sdktool, check logs."
@@ -96,7 +96,7 @@ instructions:
maxTimeBetweenOutput: 360
userMessageOnFailure: "Failed to download elfutils package, check logs."
- type: ExecuteCommand
- command: "C:\\Utils\\sevenzip\\7z.exe x -y {{.AgentWorkingDir}}\\build\\qt_temp\\elfutils-release_0.175qt-windows-x86_64.7z -o{{.AgentWorkingDir}}\\build\\qt_temp\\elfutils"
+ command: "7z.exe x -y {{.AgentWorkingDir}}\\build\\qt_temp\\elfutils-release_0.175qt-windows-x86_64.7z -o{{.AgentWorkingDir}}\\build\\qt_temp\\elfutils"
maxTimeInSeconds: 3600
maxTimeBetweenOutput: 360
userMessageOnFailure: "Failed to extract elfutils package, check logs."
@@ -106,7 +106,7 @@ instructions:
maxTimeBetweenOutput: 360
userMessageOnFailure: "Failed to download python package, check logs."
- type: ExecuteCommand
- command: "C:\\Utils\\sevenzip\\7z.exe x -y {{.AgentWorkingDir}}\\build\\qt_temp\\Python38-win-x64.7z -o{{.AgentWorkingDir}}\\build\\qt_temp\\python"
+ command: "7z.exe x -y {{.AgentWorkingDir}}\\build\\qt_temp\\Python38-win-x64.7z -o{{.AgentWorkingDir}}\\build\\qt_temp\\python"
maxTimeInSeconds: 3600
maxTimeBetweenOutput: 360
userMessageOnFailure: "Failed to extract python package, check logs."
@@ -116,7 +116,7 @@ instructions:
maxTimeBetweenOutput: 360
userMessageOnFailure: "Failed to download LLVM package, check logs."
- type: ExecuteCommand
- command: "C:\\Utils\\sevenzip\\7z.exe x -y {{.AgentWorkingDir}}\\build\\qt_temp\\libclang.7z -o{{.AgentWorkingDir}}\\build\\qt_temp\\"
+ command: "7z.exe x -y {{.AgentWorkingDir}}\\build\\qt_temp\\libclang.7z -o{{.AgentWorkingDir}}\\build\\qt_temp\\"
maxTimeInSeconds: 3600
maxTimeBetweenOutput: 360
userMessageOnFailure: "Failed to extract LLVM package, check logs."
@@ -128,7 +128,7 @@ instructions:
- type: ChangeDirectory
directory: "{{.AgentWorkingDir}}\\build\\tqtc-qtsdk\\packaging_tools"
- type: ExecuteCommand
- command: "python -m pipenv run python -u bld_sdktool.py --qt-url {{.Env.QTC_SDKTOOL_QT_BASE_URL}}{{.Env.QTC_SDKTOOL_QT_EXT}} --qt-build {{.AgentWorkingDir}}\\build\\sdktool\\qt --src {{.AgentWorkingDir}}\\qt-creator\\qt-creator\\src\\tools\\sdktool --build {{.AgentWorkingDir}}\\build\\sdktool\\build --install {{.AgentWorkingDir}}\\build\\sdktool\\install --make-command nmake"
+ command: "python -m pipenv run python -u bld_sdktool.py --qt-url {{.Env.QTC_SDKTOOL_QT_BASE_URL}}{{.Env.QTC_SDKTOOL_QT_EXT}} --qt-build {{.AgentWorkingDir}}\\build\\sdktool\\qt --src {{.AgentWorkingDir}}\\qt-creator\\qt-creator\\src\\tools\\sdktool --build {{.AgentWorkingDir}}\\build\\sdktool\\build --install {{.AgentWorkingDir}}\\build\\sdktool\\install --make-command ninja"
maxTimeInSeconds: 36000
maxTimeBetweenOutput: 3600
userMessageOnFailure: "Failed to build sdktool, check logs."
diff --git a/coin/instructions/common_environment.yaml b/coin/instructions/common_environment.yaml
index bed851d11ed..22d53d03e2a 100644
--- a/coin/instructions/common_environment.yaml
+++ b/coin/instructions/common_environment.yaml
@@ -19,10 +19,10 @@ instructions:
variableValue: 11.0
- type: EnvironmentVariable
variableName: SDKTOOL_MACOSX_DEPLOYMENT_TARGET
- variableValue: 10.14
+ variableValue: 11.0
- type: EnvironmentVariable
variableName: QTC_SDKTOOL_QT_BASE_URL
- variableValue: "https://ci-files02-hki.ci.qt.io/packages/jenkins/archive/qt/5.15/5.15.2-final-released/latest/src/submodules/qtbase-everywhere-src-5.15.2"
+ variableValue: "https://ci-files02-hki.ci.qt.io/packages/jenkins/archive/qt/6.6/6.6.0-released/Qt/src/submodules/qtbase-everywhere-src-6.6.0"
- type: Group
instructions:
- type: EnvironmentVariable
diff --git a/coin/instructions/provision.yaml b/coin/instructions/provision.yaml
index 7b84c6e3baa..a5dad3955c6 100644
--- a/coin/instructions/provision.yaml
+++ b/coin/instructions/provision.yaml
@@ -20,7 +20,7 @@ instructions:
maxTimeInSeconds: 600
maxTimeBetweenOutput: 600
project: qtsdk/tqtc-qtsdk
- ref: master
+ ref: production
directory: "build/tqtc-qtsdk"
userMessageOnFailure: "Failed to install tqtc-qtsdk, check logs"
- type: Group
diff --git a/dist/changelog/changes-14.0.0.md b/dist/changelog/changes-14.0.0.md
index 7d14123acae..e375cb0fa9f 100644
--- a/dist/changelog/changes-14.0.0.md
+++ b/dist/changelog/changes-14.0.0.md
@@ -5,16 +5,16 @@ Qt Creator version 14 contains bug fixes and new features.
The most important changes are listed in this document. For a complete list of
changes, see the Git log for the Qt Creator sources that you can check out from
-the public Git repository. For example:
+the public Git repository or view online at
- git clone git://code.qt.io/qt-creator/qt-creator.git
- git log --cherry-pick --pretty=oneline origin/13.0..v14.0.0
+https://code.qt.io/cgit/qt-creator/qt-creator.git/log/?id=13.0..v14.0.0
General
-------
* Started work on supporting Lua based plugins (registering language servers,
actions, preferences, and wizards)
+ ([Documentation](https://doc-snapshots.qt.io/qtcreator-extending/lua-extensions.html))
* Added `Clear` and `Save Contents` to context menus of all output views
* Locator
* Added the option to show results relative to project root
@@ -42,6 +42,8 @@ Editing
### C++
* Made C++ code model settings configurable per project
+* Added a setting for the naming of include guards
+ ([QTCREATORBUG-25117](https://bugreports.qt.io/browse/QTCREATORBUG-25117))
* Fixed indentation after function calls with subscript operator
([QTCREATORBUG-29225](https://bugreports.qt.io/browse/QTCREATORBUG-29225))
* Refactoring
@@ -58,6 +60,7 @@ Editing
[Documentation](https://doc.qt.io/qtcreator/creator-reference-cpp-quick-fixes.html)
* Clangd
+ * Updated the prebuilt binaries to LLVM 18.1.7
* Increased the minimum version to LLVM 17
* Added the `Per-project index location` and `Per-session index location`
options in `Preferences` > `C++` > `Clangd` for setting the index location
@@ -88,14 +91,19 @@ Editing
([QTCREATORBUG-19226](https://bugreports.qt.io/browse/QTCREATORBUG-19226))
* Added `Qt Design Studio` to `Open With` for `.ui.qml` files
([Documentation](https://doc.qt.io/qtcreator/creator-quick-ui-forms.html))
+* Fixed that the color preview did not work on named colors
+ ([QTCREATORBUG-30594](https://bugreports.qt.io/browse/QTCREATORBUG-30594))
* Language Server
- * Switched on by default
- * Added option for generating `qmlls.ini` files for CMake projects
+ * Switched on by default for Qt 6.8 and later
+ * Added an option for generating `qmlls.ini` files for CMake projects in
+ `Preferences` > `Qt Quick`> `QML/JS Editing`
([QTCREATORBUG-30394](https://bugreports.qt.io/browse/QTCREATORBUG-30394))
([Qt Documentation](https://doc.qt.io/qt-6/cmake-variable-qt-qml-generate-qmlls-ini.html))
* Fixed that tool tips from the built-in model were shown instead of tool tips
from the server
+ [Documentation](https://doc.qt.io/qtcreator/creator-how-to-use-qml-language-server.html)
+
### Python
* Added options for updating Python Language Server
@@ -114,6 +122,10 @@ Editing
`Compiler Explorer`
[Documentation](https://doc.qt.io/qtcreator/creator-how-to-create-compiler-explorer-sessions.html)
+### Markdown
+
+* Fixed the navigation history
+
### Models
* Added more visual attributes for relations
@@ -135,6 +147,8 @@ Projects
from the list in the `Projects` mode
* Added support for user comments in the environment editor
([Documentation](https://doc-snapshots.qt.io/qtcreator-14.0/creator-how-to-edit-environment-settings.html))
+* Added the setting `Time to wait before force-stopping applications`
+ ([QTCREATORBUG-31025](https://bugreports.qt.io/browse/QTCREATORBUG-31025))
* Fixed the parsing of file links when color was used for the output
([QTCREATORBUG-30774](https://bugreports.qt.io/browse/QTCREATORBUG-30774))
* Fixed that the column information was not used when opening files from links
@@ -151,12 +165,18 @@ Projects
* Implemented `Open Online Documentation` for CMake documentation
* Added `Clear CMake Configuration` to the context menu in the `Projects` view
([QTCREATORBUG-24658](https://bugreports.qt.io/browse/QTCREATORBUG-24658))
+* Added support for the `CROSSCOMPILING_EMULATOR` target property
+ ([QTCREATORBUG-29880](https://bugreports.qt.io/browse/QTCREATORBUG-29880))
+ ([CMake Documentation](https://cmake.org/cmake/help/latest/prop_tgt/CROSSCOMPILING_EMULATOR.html#crosscompiling-emulator))
* Fixed that the package manager auto-setup files were not removed with
`Clear CMake Configuration`
([QTCREATORBUG-30771](https://bugreports.qt.io/browse/QTCREATORBUG-30771))
* Fixed that files generated by the Qt QML CMake API were not filtered as
generated files
([QTCREATORBUG-29631](https://bugreports.qt.io/browse/QTCREATORBUG-29631))
+* Fixed a crash when triggering `Follow Symbol` in a CMake file that does not
+ belong to a project
+ ([QTCREATORBUG-31077](https://bugreports.qt.io/browse/QTCREATORBUG-31077))
* Presets
* Made CMake settings configurable
([QTCREATORBUG-25972](https://bugreports.qt.io/browse/QTCREATORBUG-25972),
@@ -200,7 +220,15 @@ Analyzer
### Axivion
-* Made it possible to register multiple servers
+* Added the `Add` and `Remove` buttons to `Preferences` > `Axivion` for
+ registering multiple servers
+ ([Documentation](https://doc-snapshots.qt.io/qtcreator-14.0/creator-preferences-axivion.html))
+
+### Cppcheck
+
+* Fixed that Cppcheck was not working until selecting `Apply` in the settings
+ ([QTCREATORBUG-28951](https://bugreports.qt.io/browse/QTCREATORBUG-28951),
+ [QTCREATORBUG-30615](https://bugreports.qt.io/browse/QTCREATORBUG-30615))
Terminal
--------
@@ -249,11 +277,15 @@ Platforms
* Added support for creating `android-desktop` devices
* Added support for `namespace` in `build.gradle`
([QTBUG-106907](https://bugreports.qt.io/browse/QTBUG-106907))
+* Fixed that errors when creating AVDs were not visible to the user
+ ([QTCREATORBUG-30852](https://bugreports.qt.io/browse/QTCREATORBUG-30852))
### iOS
* Removed Simulator management from the preferences. Use the
`Devices and Simulators` window in Xcode instead.
+* Fixed that starting the debugger could be slow for iOS < 17
+ ([QTCREATORBUG-31044](https://bugreports.qt.io/browse/QTCREATORBUG-31044))
### Remote Linux
@@ -266,6 +298,11 @@ Platforms
* Added support for the `perf` profiler
+### Bare Metal
+
+* Fixed issues with Qbs and the IAR toolchain
+ ([QTCREATORBUG-24040](https://bugreports.qt.io/browse/QTCREATORBUG-24040))
+
Credits for these changes go to:
--------------------------------
Ahmad Samir
diff --git a/dist/changelog/template.md b/dist/changelog/template.md
index cfbdad4677f..66e94906aea 100644
--- a/dist/changelog/template.md
+++ b/dist/changelog/template.md
@@ -83,6 +83,8 @@ Analyzer
### CTF Visualizer
+### Cppcheck
+
Terminal
--------
@@ -127,5 +129,7 @@ Platforms
### QNX
+### Bare Metal
+
Credits for these changes go to:
--------------------------------
diff --git a/doc/qtcreator/images/qtcreator-preferences-axivion.webp b/doc/qtcreator/images/qtcreator-preferences-axivion.webp
index a6b69dd1ff5..6d3ebc35ec4 100644
Binary files a/doc/qtcreator/images/qtcreator-preferences-axivion.webp and b/doc/qtcreator/images/qtcreator-preferences-axivion.webp differ
diff --git a/doc/qtcreator/images/qtcreator-qml-js-editing.webp b/doc/qtcreator/images/qtcreator-qml-js-editing.webp
index c0b56264dd1..f9475414f54 100644
Binary files a/doc/qtcreator/images/qtcreator-qml-js-editing.webp and b/doc/qtcreator/images/qtcreator-qml-js-editing.webp differ
diff --git a/doc/qtcreator/src/cmake/creator-projects-cmake-presets.qdoc b/doc/qtcreator/src/cmake/creator-projects-cmake-presets.qdoc
index 41937eb6b92..4e0160ba9eb 100644
--- a/doc/qtcreator/src/cmake/creator-projects-cmake-presets.qdoc
+++ b/doc/qtcreator/src/cmake/creator-projects-cmake-presets.qdoc
@@ -15,13 +15,14 @@
\c CMakeUserPresets.json has options for your local builds.
Create the presets files in the format described in
- \l{https://cmake.org/cmake/help/latest/manual/cmake-presets.7.html}
+ \l{https://cmake.org/cmake/help/v3.24/manual/cmake-presets.7.html}
{cmake-presets(7)} and store them in the project's root directory.
You can then see them in the \l {Projects} view.
- \QC supports presets up to version 3 (introduced in CMake 3.21), but does not
- enforce version checking. It reads and uses all the fields from version 3 if
- present. It does not support test presets.
+ \QC supports \e configure and \e build presets up to version 5
+ (introduced in CMake 3.24), but does not enforce version checking.
+ It reads and uses all the fields from version 5 if present.
+ It does not support \e test presets.
You can import the presets the first time you \l {Open projects}
{open a project}, when no \c CMakeLists.txt.user file exists or you have
@@ -44,7 +45,7 @@
\c NOT_COMMON_VALUE is displayed in \uicontrol {Initial Parameters}
and \c AN_ENVIRONMENT_FLAG in the environment configuration field.
- \badcode
+ \code
{
"version": 1,
"configurePresets": [
@@ -91,7 +92,7 @@
\li GNU gdb 11.2.0 for MinGW 11.2.0 64-bit debugger
\endlist
- \badcode
+ \code
{
"version": 1,
"configurePresets": [
@@ -131,7 +132,7 @@
generator, add \c Debug and \c Release build steps, and specify the path
to \c ninja.exe as a value of the \c CMAKE_MAKE_PROGRAM variable:
- \badcode
+ \code
{
"version": 2,
"configurePresets": [
@@ -180,7 +181,7 @@
For example:
- \badcode
+ \code
"generator": "Ninja Multi-Config",
"toolset": {
"value": "v142,host=x64",
@@ -196,7 +197,7 @@
in the \c PATH, you might also have to specify the compiler to use in
\c cacheVariables or \c environmentVariables:
- \badcode
+ \code
"generator": "Ninja Multi-Config",
"toolset": {
"value": "v142,host=x64",
@@ -226,7 +227,7 @@
\li \c wine emulator
\endlist
- \badcode
+ \code
{
"version": 4,
"configurePresets": [
@@ -262,7 +263,7 @@
if the \c hostSystemName equals \c Linux, the \c linux presets are used and
if it equals \c Windows, the \c windows presets are used.
- \badcode
+ \code
{
"version": 3,
"configurePresets": [
diff --git a/doc/qtcreator/src/cmake/creator-projects-cmake.qdoc b/doc/qtcreator/src/cmake/creator-projects-cmake.qdoc
index 5fdbd09dd8e..524163a2894 100644
--- a/doc/qtcreator/src/cmake/creator-projects-cmake.qdoc
+++ b/doc/qtcreator/src/cmake/creator-projects-cmake.qdoc
@@ -120,11 +120,14 @@
tooltips
\li Selecting any of the above elements and pressing \key F1 to show
its documentation
- \li Switching to the Help mode
+ \li Switching to the \uicontrol Help mode
\endlist
- \sa {Build with CMake}{How To: Build with CMake}, {CMake},
- {Read Documentation}{How To: Read Documentation}
+ To view the documentation online, open it in the \uicontrol Help mode and
+ select \inlineimage icons/online.png (\uicontrol {Open Online Documentation}).
+
+ \sa {Build with CMake}{How To: Build with CMake},
+ {Read Documentation}{How To: Read Documentation}, {CMake}
*/
/*!
diff --git a/doc/qtcreator/src/editors/creator-only/creator-language-server.qdoc b/doc/qtcreator/src/editors/creator-only/creator-language-server.qdoc
index 281201fb300..7fc22f4b0e8 100644
--- a/doc/qtcreator/src/editors/creator-only/creator-language-server.qdoc
+++ b/doc/qtcreator/src/editors/creator-only/creator-language-server.qdoc
@@ -85,9 +85,8 @@
To enable a language server, select the checkbox next to the language
server name and set server preferences.
- To turn on \l{Turn on \QMLLS}{\QMLLS}, go to
- \preferences > \uicontrol {Qt Quick} > \uicontrol {QML/JS Editing} and
- select \uicontrol {Enable \QMLLS}.
+ To configure \l{Configure \QMLLS}{\QMLLS}, go to
+ \preferences > \uicontrol {Qt Quick} > \uicontrol {QML/JS Editing}.
To remove language servers from the list, select \uicontrol Delete.
@@ -237,35 +236,33 @@
\ingroup creator-how-to-lsp
- \title Turn on \QMLLS
+ \title Configure \QMLLS
- Since Qt 6.4, \QMLLS offers code completion and
- issues warnings for QML. To use it, go to \preferences >
- \uicontrol {Qt Quick} > \uicontrol {QML/JS Editing} and select
- \uicontrol {Enable \QMLLS}.
+ Since Qt 6.4, \QMLLS offers code completion and issues warnings for QML.
- By default, enabling \QMLLS will only enable warning messages
- and code completion, while advanced features such as renaming and finding usages
- will be handled by the embedded code model.
- To disable the embedded code model and use \QMLLS for everything,
- select \uicontrol {Use \QMLLS advanced features}.
+ To turn off \QMLLS, go to \preferences > \uicontrol {Qt Quick} >
+ \uicontrol {QML/JS Editing} and clear \uicontrol {Turn on}.
+
+ By default, \QMLLS issues warning messages and provides code completion,
+ while the embedded code model handles advanced features, such as renaming
+ symbols and finding usages. To disable the embedded code model and use
+ \QMLLS for everything, select \uicontrol {Use advanced features}.
Also, \QC tries to use \QMLLS shipped with the Qt version in your current
\l{Kits}{kit}. To override that behavior and always use
\QMLLS of the highest registered Qt version, select
- \uicontrol {Use \QMLLS from latest Qt version}.
+ \uicontrol {Use from latest Qt version}.
To use older \QMLLS versions, select
\uicontrol{Allow versions below Qt 6.8}.
\image qtcreator-qml-js-editing.webp {QML/JS Editing preferences}
- When using \c qmlls from Qt 6.7 or later, set \l{QT_QML_GENERATE_QMLLS_INI}
- to \c{ON} in \uicontrol Projects > \uicontrol {Build Settings}
- > \uicontrol {Initial Configuration}.
+ To automatically configure new CMake projects, select
+ \uicontrol {Create .qmlls.ini files for new projects}.
\sa {Manage Language Servers}{How To: Manage Language Servers},
- {Enabling and Disabling Messages}, {CMake Build Configuration}, {Kits}
+ {Enabling and Disabling Messages}, {CMake Build Configuration}, {Kits},
{Language Servers}
*/
diff --git a/doc/qtcreator/src/howto/creator-help.qdoc b/doc/qtcreator/src/howto/creator-help.qdoc
index 434ee6fe9b2..f9f3028a022 100644
--- a/doc/qtcreator/src/howto/creator-help.qdoc
+++ b/doc/qtcreator/src/howto/creator-help.qdoc
@@ -23,23 +23,23 @@
\li To view context sensitive help on a Qt class or function as a
tooltip, move the mouse cursor over the class or function. If help
- is not available, the tooltip displays type information for the
+ is not available, the tooltip shows type information for the
symbol.
- \li To display tooltips for function signatures regardless of the
+ \li To show tooltips for function signatures regardless of the
cursor position in the function call, press \key {Ctrl+Shift+D}.
- \li To display the full help on a Qt class or function, press \key F1 or
+ \li To show the full help on a Qt class or function, press \key F1 or
select \uicontrol {Context Help} in the context menu.
- The documentation is displayed in a
+ The documentation is shown in a
view next to the code editor, or, if there is not enough vertical
space, in the fullscreen \uicontrol Help mode.
- \li To select and configure how the documentation is displayed in the
- \uicontrol Help mode, select \preferences > \uicontrol Help.
+ \li To change how the documentation is shown in the
+ \uicontrol Help mode, go to \preferences > \uicontrol Help.
\endlist
- The following image displays the context sensitive help in the \uicontrol Edit
+ The following image shows the context sensitive help in the \uicontrol Edit
mode.
\image qtcreator-context-sensitive-help.png {Context-sensitive help in Edit mode}
@@ -52,43 +52,43 @@
\image qtcreator-preferences-help-general.webp {General tab in Help preferences}
- You can set the default zoom level in the \uicontrol Zoom field. When
- viewing help pages, you can use the mouse scroll wheel to zoom them. To
- disable this feature, deselect the \uicontrol {Enable scroll wheel zooming}
- check box.
+ Set the default zoom level in \uicontrol Zoom. When viewing help pages, use
+ the mouse scroll wheel to zoom them. To turn off this feature, clear
+ \uicontrol {Enable scroll wheel zooming}.
- To disable antialiasing, deselect the \uicontrol Antialiasing check box.
+ To turn off antialiasing, clear \uicontrol Antialias.
\section1 Return to the editor
To switch to the editor context when you close the last help page, select
- the \uicontrol {Return to editor on closing the last page} check box.
+ \uicontrol {Return to editor on closing the last page}.
\section1 Select help viewer backend
- The help viewer backend determines the style sheet that is used to display
+ The help viewer backend determines the style sheet that is used to show
the help files. The default help viewer backend that is based on litehtml
is recommended for viewing Qt documentation. You can choose another help
- viewer backend in the \uicontrol {Viewer backend} field. To take the new
+ viewer backend in the \uicontrol {Viewer backend}. To take the new
backend to use, reload the help page.
\section1 View function tooltips
- To hide function tooltips by default, select \preferences >
- \uicontrol {Text Editor} > \uicontrol Behavior >
- \uicontrol {Show help tooltips using the mouse} >
- \uicontrol {On Shift+Mouseover}. You can still view the tooltips by pressing
- and holding down the \key Shift key.
+ To hide function tooltips by default:
+
+ \list 1
+ \li Go to \preferences > \uicontrol {Text Editor} > \uicontrol Behavior.
+ \image qtcreator-preferences-texteditor-behavior.webp {Text Editor Behavior preferences}
+ \li In \uicontrol {Show help tooltips using the mouse}, select
+ \uicontrol {On Shift+Mouseover}.
+ \endlist
+
+ You can still view the tooltips by pressing and holding down the \key Shift
+ key.
To use a keyboard shortcut for viewing help tooltips, select
\uicontrol {Show help tooltips using keyboard shortcut (Alt)}.
- \sa {Find information in Qt documentation}, {Filter documentation},
- {Search from documentation}
-
- \sa {Add external documentation}, {Detach the help window},
- {Filter documentation}, {Find information in Qt documentation},
- {Select the help start page}
+ \sa {Read Documentation}{How To: Read Documentation}
*/
/*!
@@ -103,15 +103,18 @@
\title Find information in Qt documentation
- \QC, \QSDK and other Qt deliverables have documentation
- as .qch files. All the documentation is accessible in the \uicontrol Help mode.
+ \QC installer, \QOI, and other Qt deliverables install documentation as .qch
+ files. View the documentation in the \uicontrol Help mode. To view the
+ currently open document online, select \inlineimage icons/online.png
+ (\uicontrol {Open Online Documentation}).
By default, \QC registers only the latest available version of the
documentation for each installed Qt module. To register all installed
- documentation, select \preferences > \uicontrol Kits >
- \uicontrol {Qt Versions} > \uicontrol {Register documentation}.
+ documentation, go to \preferences > \uicontrol Kits >
+ \uicontrol {Qt Versions} and select an option in
+ \uicontrol {Register documentation}.
- \image qtcreator-qt-versions.png {Register documentation field in Qt Versions tab in Kit Preferences}
+ \image qtcreator-qt-versions.png {Register documentation in Qt Versions preferences}
\section1 Help mode sidebar views
@@ -137,7 +140,7 @@
\endlist
- \sa {Add bookmarks to help pages}, {Search from documentation}
+ \sa {Read Documentation}{How To: Read Documentation}
*/
/*!
@@ -152,8 +155,8 @@
\title Add bookmarks to help pages
- You can add bookmarks to useful help pages to easily find them later
- in the \uicontrol Bookmarks view. You can either use the page title as the
+ Add bookmarks to useful help pages to easily find them later
+ in the \uicontrol Bookmarks view. Either use the page title as the
bookmark or change it to any text. You can organize the bookmarks in
folders in the view.
@@ -163,21 +166,21 @@
\list 1
- \li Click the \inlineimage icons/bookmark.png
- (\uicontrol {Add Bookmark}) button on the toolbar.
+ \li Select \inlineimage icons/bookmark.png (\uicontrol {Add Bookmark})
+ on the toolbar.
- \li In the \uicontrol {Add Bookmark} dialog, click \uicontrol OK to save the
+ \li In the \uicontrol {Add Bookmark} dialog, select \uicontrol OK to save the
page title as a bookmark in the selected folder.
\endlist
\section1 Import and export bookmarks
- To import and export bookmarks, select \preferences >
- \uicontrol Help > \uicontrol General > \uicontrol {Import Bookmarks} or
+ To import and export bookmarks, go to \preferences > \uicontrol Help >
+ \uicontrol General and select \uicontrol {Import Bookmarks} or
\uicontrol {Export Bookmarks}.
- \sa {Find information in Qt documentation}
+ \sa {Read Documentation}{How To: Read Documentation}
*/
/*!
@@ -192,10 +195,10 @@
\title Search from documentation
- In the \uicontrol Help mode \uicontrol Search pane, you can use full-text
+ In the \uicontrol Help mode \uicontrol Search pane, use full-text
search for finding a
particular word in all the installed documents. Enter the term you are
- looking for, and select the \uicontrol Search button. All documents that
+ looking for, and select \uicontrol Search. All documents that
have the specified term are listed. The list is sorted by document
version (if you have installed several Qt versions, for example) and
the number of search hits that the documents have. Select a document in
@@ -225,16 +228,15 @@
time when you open the \uicontrol Search pane. If you add or remove documents,
\QC recreates the index.
- If you cannot find words that you know are there, indexing might not have
- been completed for some reason. To regenerate the index, click
- \inlineimage icons/reload_gray.png
+ If you cannot find words that you know are there, the index might not be
+ complete. To recreate it, select \inlineimage icons/reload_gray.png
(\uicontrol {Regenerate Index}).
Punctuation is not included in indexed terms. To find terms that have
punctuation, such as domain names, use the asterisk as a wild card. For
example, to find \c {Pastebin.Com}, enter the search term \c {Pastebin*}.
- \sa {Find information in Qt documentation}
+ \sa {Read Documentation}{How To: Read Documentation}
*/
/*!
@@ -249,7 +251,7 @@
\title Add external documentation
- You can display external documentation in the \uicontrol Help mode.
+ You can view external documentation in the \uicontrol Help mode.
To add documentation or replace the documentation that ships with \QC and Qt:
\list 1
@@ -259,14 +261,14 @@
For information on how to prepare your documentation and create a
.qch file, see \l{The Qt Help Framework}.
- \li To add the .qch file to \QC, select \preferences >
+ \li To add the .qch file to \QC, go to \preferences >
\uicontrol Help > \uicontrol Documentation > \uicontrol Add.
\image qtcreator-preferences-help-documentation.webp {Documentation tab in Help Preferences}
\endlist
- \sa {Get help}
+ \sa {Read Documentation}{How To: Read Documentation}
*/
/*!
@@ -281,26 +283,24 @@
\title Detach the help window
- By default, context-sensitive help is opened in a window next to the
+ By default, context-sensitive help opens in a window next to the
code editor when you press \key F1. If there is not enough vertical
space, the help opens in the full-screen help mode.
\image qtcreator-context-sensitive-help.png {Context-sensitive help in Edit mode}
- To specify that the help always opens in full-screen mode or
- is detached to an external window, select \preferences > \uicontrol Help >
- \uicontrol General.
+ To specify that the help always opens in full-screen mode or in an external
+ window, go to \preferences > \uicontrol Help > \uicontrol General.
\image qtcreator-preferences-help-general.webp {General tab in Help preferences}
- Set preferences for displaying context-sensitive help
- in the \uicontrol {On context help} field. To detach the help window, select
+ Set preferences for viewing context-sensitive help
+ in \uicontrol {On context help}. To detach the help window, select
\uicontrol {Always Show in External Window}.
- To change this setting in a help view, select the \inlineimage icons/linkicon.png
- toolbar button.
+ To change this setting in a help view, select \inlineimage icons/linkicon.png.
- \sa {Get help}
+ \sa {Read Documentation}{How To: Read Documentation}
*/
/*!
@@ -315,27 +315,27 @@
\title Select the help start page
- You can select the page to display when you open the \uicontrol Help mode in the
- \preferences > \uicontrol Help > \uicontrol General >
- \uicontrol {On help start} field.
+ To set the page to show when you open the \uicontrol Help mode, go to
+ \preferences > \uicontrol Help > \uicontrol General and select
+ \uicontrol {On help start}.
\image qtcreator-preferences-help-general.webp {General tab in Help preferences}
\list
- \li To display the page and help views that were open when you exited the mode,
+ \li To show the page and help views that were open when you exited the mode,
select the \uicontrol {Show My Tabs from Last Session} option. However, Web pages
are not opened because loading them would slow down opening the \uicontrol Help
mode.
- \li To display a particular page, select \uicontrol {Show My Home Page}, and specify
- the page in the \uicontrol {Home Page} field.
+ \li To show a particular page, select \uicontrol {Show My Home Page}, and specify
+ the page in \uicontrol {Home Page}.
- \li To display a blank page, select the \uicontrol {Show a Blank Page} option. You can
- also select the \uicontrol {Use Blank Page} button to set a blank page as your
+ \li To show a blank page, select the \uicontrol {Show a Blank Page} option.
+ Select \uicontrol {Use Blank Page} to set a blank page as your
home page.
\endlist
- \sa {Get help}
+ \sa {Read Documentation}{How To: Read Documentation}
*/
/*!
@@ -350,40 +350,40 @@
\title Filter documentation
- You can filter the documents displayed in the \uicontrol Help mode to find
+ Filter the documents in the \uicontrol Help mode to find
relevant information faster. Select a filter from a list of filters. The
contents of the \uicontrol Index and \uicontrol Contents
view in the sidebar change accordingly.
- \image qtcreator-help-filters.png {Filters field on the Help mode toolbar}
+ \image qtcreator-help-filters.png {Filters on the Help mode toolbar}
\section1 Add filters
- You can define your own filters to display documentation for a set of
+ Define your own filters to show documentation for a set of
Qt modules and versions.
To add filters:
\list 1
- \li Select \preferences > \uicontrol Help > \uicontrol Filters.
+ \li Go to \preferences > \uicontrol Help > \uicontrol Filters.
\image qtcreator-help-filter-attributes.png {Filters tab in Help preferences}
\li Select \inlineimage icons/plus.png
to add a new filter in the \uicontrol {Add Filter} dialog.
- \li In the \uicontrol {Filter name} field, enter a name for the filter,
+ \li In \uicontrol {Filter name}, enter a name for the filter,
and then select \uicontrol {OK} to return to the \uicontrol Filters
tab.
- \li In the \uicontrol Components field, select the Qt modules to include
+ \li In \uicontrol Components, select the Qt modules to include
in the filter.
- \li In the \uicontrol Versions field, select the Qt versions to include
+ \li In \uicontrol Versions, select the Qt versions to include
in the filter.
- \li Click \uicontrol OK.
+ \li Select \uicontrol OK.
\li In the \uicontrol Help mode, select the filter in the list of
filters to see the filtered documentation in the sidebar.
@@ -392,15 +392,14 @@
\section1 Change filters
- To modify the selected filter, add and remove Qt modules and versions, and
+ To modify the selected filter, add and remove Qt modules and versions and
then select \uicontrol Apply.
To rename the selected filter, select \uicontrol Rename.
\section1 Remove filters
- To remove the selected filter select \inlineimage icons/minus.png
- .
+ To remove the selected filter, select \inlineimage icons/minus.png.
- \sa {Get help}
+ \sa {Read Documentation}{How To: Read Documentation}
*/
diff --git a/doc/qtcreator/src/projects/creator-only/creator-projects-opening.qdoc b/doc/qtcreator/src/projects/creator-only/creator-projects-opening.qdoc
index 67fc416ee7a..b71064f96e0 100644
--- a/doc/qtcreator/src/projects/creator-only/creator-projects-opening.qdoc
+++ b/doc/qtcreator/src/projects/creator-only/creator-projects-opening.qdoc
@@ -14,6 +14,7 @@
\ingroup creator-how-to-projects-configure
\ingroup creator-how-to-manage-kits
+ \ingroup creator-how-to-projects
\title Open projects
@@ -49,6 +50,15 @@
\endlist
\endlist
+ \section1 Open directories as projects
+
+ To open a directory as a project, go to \uicontrol File >
+ \uicontrol {Open Workspace}.
+
+ \QC generates the \e .qtcreator/project.json project file in the directory
+ for setting a project name and file exclusion filters. You can open either
+ the JSON file or the workspace to open the project the next time.
+
\section1 Re-configure projects
\QC stores information that it needs to build projects in a .user file. If
diff --git a/doc/qtcreatordev/src/coding-style.qdoc b/doc/qtcreatordev/src/coding-style.qdoc
index 49e99a8e8bc..33a2189aaf6 100644
--- a/doc/qtcreatordev/src/coding-style.qdoc
+++ b/doc/qtcreatordev/src/coding-style.qdoc
@@ -637,8 +637,8 @@
\li Use Utils::FilePath for any QString that semantically is a file or directory,
see also \l{Passing File Names}.
\li Prefer using Utils::FilePath over any use of QDir and QFileInfo.
- \li Prefer using Utils::QtcProcess over QProcess.
- \li If Utils::FilePath or Utils::QtcProcess functionality is not sufficient
+ \li Prefer using Utils::Process over QProcess.
+ \li If Utils::FilePath or Utils::Process functionality is not sufficient
for your purpose, prefer enhancing them over falling back to QString
or QProcess.
\li Avoid platform #ifdefs unless they are absolutely needed for locally
diff --git a/share/qtcreator/debugger/cdbbridge.py b/share/qtcreator/debugger/cdbbridge.py
index 347d2f89c9e..1ce2a5f96fd 100644
--- a/share/qtcreator/debugger/cdbbridge.py
+++ b/share/qtcreator/debugger/cdbbridge.py
@@ -187,7 +187,7 @@ class Dumper(DumperBase):
self.nativeTypeEnumDisplay(nativeType, intval, form)
return typeid
- def listNativeValueChildren(self, nativeValue: cdbext.Value, include_bases: bool) -> list[DumperBase.Value]:
+ def listNativeValueChildren(self, nativeValue: cdbext.Value, include_bases: bool):
fields = []
index = 0
nativeMember = nativeValue.childFromIndex(index)
@@ -202,13 +202,13 @@ class Dumper(DumperBase):
nativeMember = nativeValue.childFromIndex(index)
return fields
- def listValueChildren(self, value: DumperBase.Value, include_bases=True) -> list[DumperBase.Value]:
+ def listValueChildren(self, value: DumperBase.Value, include_bases=True):
nativeValue = value.nativeValue
if nativeValue is None:
nativeValue = cdbext.createValue(value.address(), self.lookupNativeType(value.type.name, 0))
return self.listNativeValueChildren(nativeValue, include_bases)
- def nativeListMembers(self, value: DumperBase.Value, native_type: cdbext.Type, include_bases: bool) -> list[DumperBase.Value]:
+ def nativeListMembers(self, value: DumperBase.Value, native_type: cdbext.Type, include_bases: bool):
nativeValue = value.nativeValue
if nativeValue is None:
nativeValue = cdbext.createValue(value.address(), native_type)
@@ -629,100 +629,6 @@ class Dumper(DumperBase):
if self.showQObjectNames:
self.tryPutQObjectGuts(value)
-
- def putFormattedPointerX(self, value: DumperBase.Value):
- self.putOriginalAddress(value.address())
- pointer = value.pointer()
- self.putAddress(pointer)
- if pointer == 0:
- self.putType(value.type)
- self.putValue('0x0')
- return
-
- typeName = value.type.name
-
- try:
- self.readRawMemory(pointer, 1)
- except:
- # Failure to dereference a pointer should at least
- # show the value of a pointer.
- #DumperBase.warn('BAD POINTER: %s' % value)
- self.putValue('0x%x' % pointer)
- self.putType(typeName)
- return
-
- if self.currentIName.endswith('.this'):
- self.putDerefedPointer(value)
- return
-
- displayFormat = self.currentItemFormat(value.type.name)
-
- if value.type.targetName == 'void':
- #DumperBase.warn('VOID POINTER: %s' % displayFormat)
- self.putType(typeName)
- self.putSymbolValue(pointer)
- return
-
- if displayFormat == DisplayFormat.Raw:
- # Explicitly requested bald pointer.
- #DumperBase.warn('RAW')
- self.putType(typeName)
- self.putValue('0x%x' % pointer)
- self.putExpandable()
- if self.currentIName in self.expandedINames:
- with Children(self):
- with SubItem(self, '*'):
- self.putItem(value.dereference())
- return
-
- limit = self.displayStringLimit
- if displayFormat in (DisplayFormat.SeparateLatin1String, DisplayFormat.SeparateUtf8String):
- limit = 1000000
- if self.tryPutSimpleFormattedPointer(pointer, typeName,
- value.type.targetName, displayFormat, limit):
- self.putExpandable()
- return
-
- if DisplayFormat.Array10 <= displayFormat and displayFormat <= DisplayFormat.Array10000:
- n = (10, 100, 1000, 10000)[displayFormat - DisplayFormat.Array10]
- self.putType(typeName)
- self.putItemCount(n)
- self.putArrayData(value.pointer(), n, value.type.targetName)
- return
-
- #DumperBase.warn('AUTODEREF: %s' % self.autoDerefPointers)
- #DumperBase.warn('INAME: %s' % self.currentIName)
- if self.autoDerefPointers:
- # Generic pointer type with AutomaticFormat, but never dereference char types:
- if value.type.targetName.strip() not in (
- 'char',
- 'signed char',
- 'int8_t',
- 'qint8',
- 'unsigned char',
- 'uint8_t',
- 'quint8',
- 'wchar_t',
- 'CHAR',
- 'WCHAR',
- 'char8_t',
- 'char16_t',
- 'char32_t'
- ):
- self.putDerefedPointer(value)
- return
-
- #DumperBase.warn('GENERIC PLAIN POINTER: %s' % value.type)
- #DumperBase.warn('ADDR PLAIN POINTER: 0x%x' % value.laddress)
- self.putType(typeName)
- self.putSymbolValue(pointer)
- self.putExpandable()
- if self.currentIName in self.expandedINames:
- with Children(self):
- with SubItem(self, '*'):
- self.putItem(value.dereference())
-
-
def putCStyleArray(self, value: DumperBase.Value):
arrayType = value.type
innerType = arrayType.target()
diff --git a/share/qtcreator/debugger/dumper.py b/share/qtcreator/debugger/dumper.py
index 33c7eb1a846..7f704590664 100644
--- a/share/qtcreator/debugger/dumper.py
+++ b/share/qtcreator/debugger/dumper.py
@@ -1295,8 +1295,6 @@ class DumperBase():
innerType = arrayType.target()
#self.warn("ARRAY TYPE: %s" % arrayType)
#self.warn("INNER TYPE: %s" % innerType)
- if innerType is None:
- innerType = value.type.target()
address = value.address()
if address:
diff --git a/src/app/main.cpp b/src/app/main.cpp
index 4ec11d5e896..43712c6836a 100644
--- a/src/app/main.cpp
+++ b/src/app/main.cpp
@@ -680,11 +680,18 @@ int main(int argc, char **argv)
setPixmapCacheLimit();
loadFonts();
- // On 100% or 200% scaling we can use the default 'Vista' style on Windows
- qreal tmp;
- const bool fractionalDpi = !qFuzzyIsNull(std::modf(qApp->devicePixelRatio(), &tmp));
- if (Utils::HostOsInfo::isWindowsHost() && fractionalDpi && !hasStyleOption)
- QApplication::setStyle(QLatin1String("fusion"));
+ if (Utils::HostOsInfo::isWindowsHost() && !hasStyleOption) {
+ // The Windows 11 default style (Qt 6.7) has major issues, therefore
+ // set the previous default style: "windowsvista"
+ // FIXME: check newer Qt Versions
+ QApplication::setStyle(QLatin1String("windowsvista"));
+
+ // On scaling different than 100% or 200% use the "fusion" style
+ qreal tmp;
+ const bool fractionalDpi = !qFuzzyIsNull(std::modf(qApp->devicePixelRatio(), &tmp));
+ if (fractionalDpi)
+ QApplication::setStyle(QLatin1String("fusion"));
+ }
const int threadCount = QThreadPool::globalInstance()->maxThreadCount();
QThreadPool::globalInstance()->setMaxThreadCount(qMax(4, 2 * threadCount));
diff --git a/src/libs/extensionsystem/pluginview.cpp b/src/libs/extensionsystem/pluginview.cpp
index 0c6aeb2dff3..24ec0a969d5 100644
--- a/src/libs/extensionsystem/pluginview.cpp
+++ b/src/libs/extensionsystem/pluginview.cpp
@@ -89,8 +89,8 @@ static const QIcon &icon(IconIndex icon)
class PluginItem : public TreeItem
{
public:
- PluginItem(PluginSpec *spec, PluginView *view)
- : m_spec(spec), m_view(view)
+ PluginItem(PluginSpec *spec, PluginData *data)
+ : m_spec(spec), m_data(data)
{}
QVariant data(int column, int role) const override
@@ -167,7 +167,7 @@ public:
bool setData(int column, const QVariant &data, int role) override
{
if (column == LoadedColumn && role == Qt::CheckStateRole)
- return m_view->setPluginsEnabled({m_spec}, data.toBool());
+ return m_data->setPluginsEnabled({m_spec}, data.toBool());
return false;
}
@@ -193,19 +193,19 @@ public:
public:
PluginSpec *m_spec; // Not owned.
- PluginView *m_view; // Not owned.
+ PluginData *m_data; // Not owned.
};
class CollectionItem : public TreeItem
{
public:
- CollectionItem(const QString &name, const PluginSpecs &plugins, PluginView *view)
+ CollectionItem(const QString &name, const PluginSpecs &plugins, PluginData *data)
: m_name(name)
, m_plugins(plugins)
- , m_view(view)
+ , m_data(data)
{
for (PluginSpec *spec : plugins)
- appendChild(new PluginItem(spec, view));
+ appendChild(new PluginItem(spec, data));
}
QVariant data(int column, int role) const override
@@ -241,7 +241,7 @@ public:
if (column == LoadedColumn && role == Qt::CheckStateRole) {
const PluginSpecs affectedPlugins
= Utils::filtered(m_plugins, [](PluginSpec *spec) { return !spec->isRequired(); });
- if (m_view->setPluginsEnabled(toSet(affectedPlugins), data.toBool())) {
+ if (m_data->setPluginsEnabled(toSet(affectedPlugins), data.toBool())) {
update();
return true;
}
@@ -260,19 +260,31 @@ public:
public:
QString m_name;
const PluginSpecs m_plugins;
- PluginView *m_view; // Not owned.
+ PluginData *m_data; // Not owned.
};
} // Internal
using namespace ExtensionSystem::Internal;
+PluginData::PluginData(QWidget *parent, PluginView *owner)
+ : m_parent(parent), m_pluginView(owner)
+{
+ m_model = new TreeModel(parent);
+ m_model->setHeader({ Tr::tr("Name"), Tr::tr("Load"), Tr::tr("Version"), Tr::tr("Vendor") });
+
+ m_sortModel = new CategorySortFilterModel(parent);
+ m_sortModel->setSourceModel(m_model);
+ m_sortModel->setSortRole(SortRole);
+ m_sortModel->setFilterKeyColumn(-1/*all*/);
+}
+
/*!
Constructs a plugin view with \a parent that displays a list of plugins
from a plugin manager.
*/
PluginView::PluginView(QWidget *parent)
- : QWidget(parent)
+ : QWidget(parent), m_data(this, this)
{
m_categoryView = new TreeView(this);
m_categoryView->setAlternatingRowColors(true);
@@ -282,14 +294,7 @@ PluginView::PluginView(QWidget *parent)
m_categoryView->setSelectionMode(QAbstractItemView::SingleSelection);
m_categoryView->setSelectionBehavior(QAbstractItemView::SelectRows);
- m_model = new TreeModel(this);
- m_model->setHeader({ Tr::tr("Name"), Tr::tr("Load"), Tr::tr("Version"), Tr::tr("Vendor") });
-
- m_sortModel = new CategorySortFilterModel(this);
- m_sortModel->setSourceModel(m_model);
- m_sortModel->setSortRole(SortRole);
- m_sortModel->setFilterKeyColumn(-1/*all*/);
- m_categoryView->setModel(m_sortModel);
+ m_categoryView->setModel(m_data.m_sortModel);
auto *gridLayout = new QGridLayout(this);
gridLayout->setContentsMargins(2, 2, 2, 2);
@@ -329,7 +334,7 @@ PluginSpec *PluginView::currentPlugin() const
*/
void PluginView::setFilter(const QString &filter)
{
- m_sortModel->setFilterRegularExpression(
+ m_data.m_sortModel->setFilterRegularExpression(
QRegularExpression(QRegularExpression::escape(filter),
QRegularExpression::CaseInsensitiveOption));
m_categoryView->expandAll();
@@ -337,15 +342,15 @@ void PluginView::setFilter(const QString &filter)
PluginSpec *PluginView::pluginForIndex(const QModelIndex &index) const
{
- const QModelIndex &sourceIndex = m_sortModel->mapToSource(index);
- PluginItem *item = m_model->itemForIndexAtLevel<2>(sourceIndex);
+ const QModelIndex &sourceIndex = m_data.m_sortModel->mapToSource(index);
+ PluginItem *item = m_data.m_model->itemForIndexAtLevel<2>(sourceIndex);
return item ? item->m_spec: nullptr;
}
void PluginView::updatePlugins()
{
// Model.
- m_model->clear();
+ m_data.m_model->clear();
const QHash pluginCollections
= PluginManager::pluginCollections();
@@ -353,17 +358,22 @@ void PluginView::updatePlugins()
const auto end = pluginCollections.cend();
for (auto it = pluginCollections.cbegin(); it != end; ++it) {
const QString name = it.key().isEmpty() ? Tr::tr("Utilities") : it.key();
- collections.push_back(new CollectionItem(name, it.value(), this));
+ collections.push_back(new CollectionItem(name, it.value(), &m_data));
}
Utils::sort(collections, &CollectionItem::m_name);
for (CollectionItem *collection : std::as_const(collections))
- m_model->rootItem()->appendChild(collection);
+ m_data.m_model->rootItem()->appendChild(collection);
- emit m_model->layoutChanged();
+ emit m_data.m_model->layoutChanged();
m_categoryView->expandAll();
}
+PluginData &PluginView::data()
+{
+ return m_data;
+}
+
static QString pluginListString(const QSet &plugins)
{
QStringList names = Utils::transform(plugins, &PluginSpec::name);
@@ -371,7 +381,7 @@ static QString pluginListString(const QSet &plugins)
return names.join(QLatin1Char('\n'));
}
-bool PluginView::setPluginsEnabled(const QSet &plugins, bool enable)
+bool PluginData::setPluginsEnabled(const QSet &plugins, bool enable)
{
QSet additionalPlugins;
if (enable) {
@@ -383,7 +393,7 @@ bool PluginView::setPluginsEnabled(const QSet &plugins, bool enabl
}
additionalPlugins.subtract(plugins);
if (!additionalPlugins.isEmpty()) {
- if (QMessageBox::question(this, Tr::tr("Enabling Plugins"),
+ if (QMessageBox::question(m_parent, Tr::tr("Enabling Plugins"),
Tr::tr("Enabling\n%1\nwill also enable the following plugins:\n\n%2")
.arg(pluginListString(plugins), pluginListString(additionalPlugins)),
QMessageBox::Ok | QMessageBox::Cancel,
@@ -400,7 +410,7 @@ bool PluginView::setPluginsEnabled(const QSet &plugins, bool enabl
}
additionalPlugins.subtract(plugins);
if (!additionalPlugins.isEmpty()) {
- if (QMessageBox::question(this, Tr::tr("Disabling Plugins"),
+ if (QMessageBox::question(m_parent, Tr::tr("Disabling Plugins"),
Tr::tr("Disabling\n%1\nwill also disable the following plugins:\n\n%2")
.arg(pluginListString(plugins), pluginListString(additionalPlugins)),
QMessageBox::Ok | QMessageBox::Cancel,
@@ -422,13 +432,16 @@ bool PluginView::setPluginsEnabled(const QSet &plugins, bool enabl
item->updateColumn(LoadedColumn);
item->parent()->updateColumn(LoadedColumn);
}
- emit pluginsChanged(affectedPlugins, enable);
+
+ if (m_pluginView)
+ emit m_pluginView->pluginsChanged(affectedPlugins, enable);
+
return true;
}
void PluginView::cancelChanges()
{
- for (auto element : m_affectedPlugins)
+ for (auto element : m_data.m_affectedPlugins)
element.first->setEnabledBySettings(element.second);
}
diff --git a/src/libs/extensionsystem/pluginview.h b/src/libs/extensionsystem/pluginview.h
index cd0c60b69a7..db144247277 100644
--- a/src/libs/extensionsystem/pluginview.h
+++ b/src/libs/extensionsystem/pluginview.h
@@ -22,12 +22,32 @@ class TreeView;
namespace ExtensionSystem {
class PluginSpec;
+class PluginView;
namespace Internal {
class CollectionItem;
class PluginItem;
} // Internal
+class EXTENSIONSYSTEM_EXPORT PluginData
+{
+public:
+ explicit PluginData(QWidget *parent, PluginView *pluginView = nullptr);
+
+ bool setPluginsEnabled(const QSet &plugins, bool enable);
+
+private:
+ QWidget *m_parent = nullptr;
+ PluginView *m_pluginView = nullptr;
+ Utils::TreeModel *m_model;
+ Utils::CategorySortFilterModel *m_sortModel;
+ std::unordered_map m_affectedPlugins;
+
+ friend class Internal::CollectionItem;
+ friend class Internal::PluginItem;
+ friend class PluginView;
+};
+
class EXTENSIONSYSTEM_EXPORT PluginView : public QWidget
{
Q_OBJECT
@@ -40,6 +60,8 @@ public:
void setFilter(const QString &filter);
void cancelChanges();
+ PluginData &data();
+
signals:
void currentPluginChanged(ExtensionSystem::PluginSpec *spec);
void pluginActivated(ExtensionSystem::PluginSpec *spec);
@@ -48,15 +70,9 @@ signals:
private:
PluginSpec *pluginForIndex(const QModelIndex &index) const;
void updatePlugins();
- bool setPluginsEnabled(const QSet &plugins, bool enable);
+ PluginData m_data;
Utils::TreeView *m_categoryView;
- Utils::TreeModel *m_model;
- Utils::CategorySortFilterModel *m_sortModel;
- std::unordered_map m_affectedPlugins;
-
- friend class Internal::CollectionItem;
- friend class Internal::PluginItem;
};
} // namespace ExtensionSystem
diff --git a/src/libs/solutions/tasking/tasktree.cpp b/src/libs/solutions/tasking/tasktree.cpp
index 55ae3cfb56a..91bdaf2d9e1 100644
--- a/src/libs/solutions/tasking/tasktree.cpp
+++ b/src/libs/solutions/tasking/tasktree.cpp
@@ -18,6 +18,7 @@
#include
#include
+using namespace Qt::StringLiterals;
using namespace std::chrono;
QT_BEGIN_NAMESPACE
@@ -1298,11 +1299,11 @@ const void *Loop::valuePtr() const
using StoragePtr = void *;
-static QString s_activeStorageWarning =
+static constexpr QLatin1StringView s_activeStorageWarning =
"The referenced storage is not reachable in the running tree. "
"A nullptr will be returned which might lead to a crash in the calling code. "
"It is possible that no storage was added to the tree, "
- "or the storage is not reachable from where it is referenced.";
+ "or the storage is not reachable from where it is referenced."_L1;
class StorageThreadData
{
diff --git a/src/libs/utils/icon.cpp b/src/libs/utils/icon.cpp
index 06570e6505a..073ec771531 100644
--- a/src/libs/utils/icon.cpp
+++ b/src/libs/utils/icon.cpp
@@ -211,7 +211,7 @@ QIcon Icon::sideBarIcon(const Icon &classic, const Icon &flat)
}
QIcon Icon::modeIcon(const Icon &classic, const Icon &flat,
- [[__maybe_unused__]] const Icon &flatActive)
+ [[maybe_unused]] const Icon &flatActive)
{
QIcon result = sideBarIcon(classic, flat);
return result;
diff --git a/src/libs/utils/processenums.h b/src/libs/utils/processenums.h
index 903bc8df9bf..e19321fcd04 100644
--- a/src/libs/utils/processenums.h
+++ b/src/libs/utils/processenums.h
@@ -41,6 +41,11 @@ enum class Channel {
Error
};
+enum class DetachedChannelMode {
+ Forward,
+ Discard
+};
+
enum class TextChannelMode {
// Keep | Emit | Emit
// raw | text | content
diff --git a/src/libs/utils/qtcprocess.cpp b/src/libs/utils/qtcprocess.cpp
index 05111ef8efa..2a51e01071f 100644
--- a/src/libs/utils/qtcprocess.cpp
+++ b/src/libs/utils/qtcprocess.cpp
@@ -1317,12 +1317,18 @@ void Process::closeWriteChannel()
d->sendControlSignal(ControlSignal::CloseWriteChannel);
}
-bool Process::startDetached(const CommandLine &cmd, const FilePath &workingDirectory, qint64 *pid)
+bool Process::startDetached(const CommandLine &cmd, const FilePath &workingDirectory,
+ DetachedChannelMode channelMode, qint64 *pid)
{
- return QProcess::startDetached(cmd.executable().toUserOutput(),
- cmd.splitArguments(),
- workingDirectory.toUserOutput(),
- pid);
+ QProcess process;
+ process.setProgram(cmd.executable().toUserOutput());
+ process.setArguments(cmd.splitArguments());
+ process.setWorkingDirectory(workingDirectory.toUserOutput());
+ if (channelMode == DetachedChannelMode::Discard) {
+ process.setStandardOutputFile(QProcess::nullDevice());
+ process.setStandardErrorFile(QProcess::nullDevice());
+ }
+ return process.startDetached(pid);
}
void Process::setLowPriority()
diff --git a/src/libs/utils/qtcprocess.h b/src/libs/utils/qtcprocess.h
index 3f043214f96..cc629fe127b 100644
--- a/src/libs/utils/qtcprocess.h
+++ b/src/libs/utils/qtcprocess.h
@@ -137,6 +137,7 @@ public:
// Some of them could be aggregated in another public utils class.
static bool startDetached(const CommandLine &cmd, const FilePath &workingDirectory = {},
+ DetachedChannelMode channelMode = DetachedChannelMode::Forward,
qint64 *pid = nullptr);
// Starts the command and waits for finish.
diff --git a/src/plugins/android/androiddevice.cpp b/src/plugins/android/androiddevice.cpp
index 7e6e715dc86..4972c653c9d 100644
--- a/src/plugins/android/androiddevice.cpp
+++ b/src/plugins/android/androiddevice.cpp
@@ -974,8 +974,12 @@ expected_str createAvd(const CreateAvdInfo &info, bool force)
GuardLocker locker(s_instance->m_avdPathGuard);
process.runBlocking();
- if (process.result() != ProcessResult::FinishedWithSuccess)
- return Utils::make_unexpected(process.exitMessage());
+ if (process.result() != ProcessResult::FinishedWithSuccess) {
+ const QString stdErr = process.stdErr();
+ const QString errorMessage = stdErr.isEmpty() ? process.exitMessage()
+ : process.exitMessage() + "\n\n" + stdErr;
+ return Utils::make_unexpected(errorMessage);
+ }
return {};
}
diff --git a/src/plugins/android/androidmanager.cpp b/src/plugins/android/androidmanager.cpp
index 9cca27242d0..dac4eb3c8e4 100644
--- a/src/plugins/android/androidmanager.cpp
+++ b/src/plugins/android/androidmanager.cpp
@@ -55,12 +55,12 @@ static std::optional documentElement(const FilePath &fileName)
{
QFile file(fileName.toString());
if (!file.open(QIODevice::ReadOnly)) {
- MessageManager::writeDisrupting(Tr::tr("Cannot open: %1").arg(fileName.toUserOutput()));
+ MessageManager::writeDisrupting(Tr::tr("Cannot open \"%1\".").arg(fileName.toUserOutput()));
return {};
}
QDomDocument doc;
if (!doc.setContent(file.readAll())) {
- MessageManager::writeDisrupting(Tr::tr("Cannot parse: %1").arg(fileName.toUserOutput()));
+ MessageManager::writeDisrupting(Tr::tr("Cannot parse \"%1\".").arg(fileName.toUserOutput()));
return {};
}
return doc.documentElement();
diff --git a/src/plugins/android/androidsdkmanager.cpp b/src/plugins/android/androidsdkmanager.cpp
index 76b4b5db72a..47b1f4b1155 100644
--- a/src/plugins/android/androidsdkmanager.cpp
+++ b/src/plugins/android/androidsdkmanager.cpp
@@ -313,7 +313,7 @@ static GroupItem updateRecipe(const Storage &dialogStorage)
const QStringList args = {"--update", sdkRootArg()};
QuestionProgressDialog *dialog = dialogStorage->m_dialog.get();
setupSdkProcess(args, &process, dialog, 0, 1);
- dialog->appendMessage(Tr::tr("Updating installed packages....") + '\n', NormalMessageFormat);
+ dialog->appendMessage(Tr::tr("Updating installed packages...") + '\n', NormalMessageFormat);
dialog->setProgress(0);
};
const auto onDone = [dialogStorage](DoneWith result) {
diff --git a/src/plugins/appstatisticsmonitor/chart.cpp b/src/plugins/appstatisticsmonitor/chart.cpp
index 260282b39a4..86e99283fa7 100644
--- a/src/plugins/appstatisticsmonitor/chart.cpp
+++ b/src/plugins/appstatisticsmonitor/chart.cpp
@@ -38,7 +38,8 @@ AppStatisticsMonitorChart::AppStatisticsMonitorChart(
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 QBrush brush(creatorColor(Theme::Token_Background_Default)); left for the future
+ const QBrush brush(creatorColor(Theme::BackgroundColorNormal));
const QPen penBack(creatorColor(Theme::Token_Text_Muted));
const QPen penAxis(creatorColor(Theme::Token_Text_Muted));
@@ -160,8 +161,8 @@ void Chart::paintEvent(QPaintEvent *event)
{
Q_UNUSED(event);
QPainter painter(this);
-
- painter.fillRect(rect(), creatorColor(Theme::Token_Background_Default));
+ // painter.fillRect(rect(), creatorColor(Theme::Token_Background_Default)); left for the future
+ painter.fillRect(rect(), creatorColor(Theme::BackgroundColorNormal));
// add the name of the chart in the middle of the widget width and on the top
painter.drawText(
diff --git a/src/plugins/autotest/projectsettingswidget.cpp b/src/plugins/autotest/projectsettingswidget.cpp
index b6347f52a70..01cbb33fd1d 100644
--- a/src/plugins/autotest/projectsettingswidget.cpp
+++ b/src/plugins/autotest/projectsettingswidget.cpp
@@ -69,7 +69,7 @@ ProjectTestSettingsWidget::ProjectTestSettingsWidget(Project *project)
m_pathFilters = new QTreeWidget;
m_pathFilters->setHeaderHidden(true);
m_pathFilters->setRootIsDecorated(false);
- QLabel *filterLabel = new QLabel(Tr::tr("Wildcard expressions for filtering"), this);
+ QLabel *filterLabel = new QLabel(Tr::tr("Wildcard expressions for filtering:"), this);
QPushButton *addFilter = new QPushButton(Tr::tr("Add"), this);
QPushButton *removeFilter = new QPushButton(Tr::tr("Remove"), this);
removeFilter->setEnabled(false);
diff --git a/src/plugins/autotest/testsettings.cpp b/src/plugins/autotest/testsettings.cpp
index 42407ab9034..523a92499aa 100644
--- a/src/plugins/autotest/testsettings.cpp
+++ b/src/plugins/autotest/testsettings.cpp
@@ -35,7 +35,7 @@ TestSettings::TestSettings()
useTimeout.setSettingsKey("UseTimeout");
useTimeout.setDefaultValue(false);
- useTimeout.setLabelText(Tr::tr("Timeout"));
+ useTimeout.setLabelText(Tr::tr("Timeout:"));
useTimeout.setToolTip(Tr::tr("Use a timeout while executing test cases."));
timeout.setSettingsKey("Timeout");
diff --git a/src/plugins/axivion/axivionoutputpane.cpp b/src/plugins/axivion/axivionoutputpane.cpp
index 644db7f5433..fa15362e32d 100644
--- a/src/plugins/axivion/axivionoutputpane.cpp
+++ b/src/plugins/axivion/axivionoutputpane.cpp
@@ -879,17 +879,17 @@ public:
dashboardUrl.setQuery(search.toUrlQuery(QueryMode::FilterQuery));
QMenu *menu = new QMenu;
- auto action = new QAction(Tr::tr("Open issue in Dashboard"), menu);
+ auto action = new QAction(Tr::tr("Open Issue in Dashboard"), menu);
menu->addAction(action);
QObject::connect(action, &QAction::triggered, menu, [issueBaseUrl] {
QDesktopServices::openUrl(issueBaseUrl);
});
- action = new QAction(Tr::tr("Open table in Dashboard"), menu);
+ action = new QAction(Tr::tr("Open Table in Dashboard"), menu);
QObject::connect(action, &QAction::triggered, menu, [dashboardUrl] {
QDesktopServices::openUrl(dashboardUrl);
});
menu->addAction(action);
- action = new QAction(Tr::tr("Copy Dashboard link to clipboard"), menu);
+ action = new QAction(Tr::tr("Copy Dashboard Link to Clipboard"), menu);
QObject::connect(action, &QAction::triggered, menu, [dashboardUrl] {
if (auto clipboard = QGuiApplication::clipboard())
clipboard->setText(dashboardUrl.toString());
diff --git a/src/plugins/axivion/axivionsettings.cpp b/src/plugins/axivion/axivionsettings.cpp
index aaed7b93da1..9100b7c4e99 100644
--- a/src/plugins/axivion/axivionsettings.cpp
+++ b/src/plugins/axivion/axivionsettings.cpp
@@ -308,16 +308,17 @@ AxivionSettingsWidget::AxivionSettingsWidget()
auto addButton = new QPushButton(Tr::tr("Add..."), this);
m_edit = new QPushButton(Tr::tr("Edit..."), this);
m_remove = new QPushButton(Tr::tr("Remove"), this);
- Column {
- Row {
- Form {
- Tr::tr("Default dashboard server"), m_dashboardServers, br
- }, st,
- Column { addButton, m_edit, st, m_remove },
+ Column{
+ Row{
+ Form{Tr::tr("Default dashboard server:"), m_dashboardServers, br},
+ st,
+ Column{addButton, m_edit, st, m_remove},
},
- Space(10), br,
- Row { settings().highlightMarks }, st
- }.attachTo(this);
+ Space(10),
+ br,
+ Row{settings().highlightMarks},
+ st}
+ .attachTo(this);
connect(addButton, &QPushButton::clicked, this, [this] {
// add an empty item unconditionally
@@ -357,10 +358,11 @@ void AxivionSettingsWidget::updateEnabledStates()
void AxivionSettingsWidget::removeCurrentServerConfig()
{
const QString config = m_dashboardServers->currentData().value().displayString();
- if (QMessageBox::question(ICore::dialogParent(), Tr::tr("Remove Server Configuration"),
- Tr::tr("Do you really want to remove the server configuration "
- "\"%1\"?").arg(config))
- != QMessageBox::Yes) {
+ if (QMessageBox::question(
+ ICore::dialogParent(),
+ Tr::tr("Remove Server Configuration"),
+ Tr::tr("Remove the server configuration \"%1\"?").arg(config))
+ != QMessageBox::Yes) {
return;
}
m_dashboardServers->removeItem(m_dashboardServers->currentIndex());
diff --git a/src/plugins/boot2qt/device-detection/devicedetector.cpp b/src/plugins/boot2qt/device-detection/devicedetector.cpp
index abe06bc566b..bc4fbcee665 100644
--- a/src/plugins/boot2qt/device-detection/devicedetector.cpp
+++ b/src/plugins/boot2qt/device-detection/devicedetector.cpp
@@ -80,7 +80,7 @@ void DeviceDetector::handleDeviceEvent(QdbDeviceTracker::DeviceEventType eventTy
DeviceManager * const dm = DeviceManager::instance();
if (eventType == QdbDeviceTracker::NewDevice) {
- const QString name = Tr::tr("Qt Debug Bridge device %1").arg(serial);
+ const QString name = Tr::tr("Boot to Qt device %1").arg(serial);
QdbDevice::Ptr device = QdbDevice::create();
device->setupId(IDevice::AutoDetected, deviceId);
device->settings()->displayName.setValue(name);
diff --git a/src/plugins/boot2qt/qdbdevice.cpp b/src/plugins/boot2qt/qdbdevice.cpp
index d9cbd3ed2aa..581767be99d 100644
--- a/src/plugins/boot2qt/qdbdevice.cpp
+++ b/src/plugins/boot2qt/qdbdevice.cpp
@@ -88,9 +88,9 @@ private:
}
showMessage(errorString, true);
if (!stdOut.isEmpty())
- showMessage(Tr::tr("stdout was: \"%1\"").arg(stdOut));
+ showMessage(Tr::tr("stdout was: \"%1\".").arg(stdOut));
if (!stdErr.isEmpty())
- showMessage(Tr::tr("stderr was: \"%1\"").arg(stdErr));
+ showMessage(Tr::tr("stderr was: \"%1\".").arg(stdErr));
} else {
showMessage(Tr::tr("Commands on device \"%1\" finished successfully.")
.arg(m_deviceName));
@@ -107,7 +107,7 @@ private:
QdbDevice::QdbDevice()
{
- setDisplayType(Tr::tr("Boot2Qt Device"));
+ setDisplayType(Tr::tr("Boot to Qt Device"));
setType(Constants::QdbLinuxOsType);
addDeviceAction({Tr::tr("Reboot Device"), [](const IDevice::Ptr &device, QWidget *) {
@@ -218,7 +218,7 @@ public:
QdbDeviceWizard(QWidget *parent)
: QWizard(parent)
{
- setWindowTitle(Tr::tr("Boot2Qt Network Device Setup"));
+ setWindowTitle(Tr::tr("Boot to Qt Network Device Setup"));
settingsPage.setCommitPage(true);
enum { SettingsPageId };
@@ -253,7 +253,7 @@ public:
QdbLinuxDeviceFactory()
: IDeviceFactory(Constants::QdbLinuxOsType)
{
- setDisplayName(Tr::tr("Boot2Qt Device"));
+ setDisplayName(Tr::tr("Boot to Qt Device"));
setCombinedIcon(":/qdb/images/qdbdevicesmall.png", ":/qdb/images/qdbdevice.png");
setQuickCreationAllowed(true);
setConstructionFunction(&QdbDevice::create);
diff --git a/src/plugins/boot2qt/qdbplugin.cpp b/src/plugins/boot2qt/qdbplugin.cpp
index d3943e94b12..522e9151c76 100644
--- a/src/plugins/boot2qt/qdbplugin.cpp
+++ b/src/plugins/boot2qt/qdbplugin.cpp
@@ -106,7 +106,7 @@ public:
{
setConfigBaseId(Constants::QdbDeployConfigurationId);
addSupportedTargetDeviceType(Constants::QdbLinuxOsType);
- setDefaultDisplayName(Tr::tr("Deploy to Boot2Qt target"));
+ setDefaultDisplayName(Tr::tr("Deploy to Boot to Qt target"));
setUseDeploymentDataView();
addInitialStep(RemoteLinux::Constants::MakeInstallStepId, [](Target *target) {
diff --git a/src/plugins/boot2qt/qdbrunconfiguration.cpp b/src/plugins/boot2qt/qdbrunconfiguration.cpp
index e95c9562c48..66ca757bf9c 100644
--- a/src/plugins/boot2qt/qdbrunconfiguration.cpp
+++ b/src/plugins/boot2qt/qdbrunconfiguration.cpp
@@ -33,7 +33,7 @@ public:
QdbRunConfiguration(Target *target, Id id)
: RunConfiguration(target, id)
{
- setDefaultDisplayName(Tr::tr("Run on Boot2Qt Device"));
+ setDefaultDisplayName(Tr::tr("Run on Boot to Qt Device"));
executable.setDeviceSelector(target, ExecutableAspect::RunDevice);
executable.setSettingsKey("QdbRunConfig.RemoteExecutable");
@@ -87,7 +87,7 @@ private:
Tasks tasks;
if (executable().isEmpty()) {
tasks << BuildSystemTask(Task::Warning, Tr::tr("The remote executable must be set "
- "in order to run on a Boot2Qt device."));
+ "to run on a Boot to Qt device."));
}
return tasks;
}
diff --git a/src/plugins/boot2qt/qdbutils.cpp b/src/plugins/boot2qt/qdbutils.cpp
index 922f0838f7a..e788717829e 100644
--- a/src/plugins/boot2qt/qdbutils.cpp
+++ b/src/plugins/boot2qt/qdbutils.cpp
@@ -65,7 +65,7 @@ QString overridingEnvironmentVariable(QdbTool tool)
void showMessage(const QString &message, bool important)
{
- const QString fullMessage = Tr::tr("Boot2Qt: %1").arg(message);
+ const QString fullMessage = Tr::tr("Boot to Qt: %1").arg(message);
if (important)
Core::MessageManager::writeFlashing(fullMessage);
else
diff --git a/src/plugins/clangcodemodel/clangdcompletion.cpp b/src/plugins/clangcodemodel/clangdcompletion.cpp
index e847e3b0f07..0f0f716eab0 100644
--- a/src/plugins/clangcodemodel/clangdcompletion.cpp
+++ b/src/plugins/clangcodemodel/clangdcompletion.cpp
@@ -358,8 +358,14 @@ void ClangdCompletionItem::apply(TextDocumentManipulator &manipulator,
}
// Avoid inserting characters that are already there
+ // For include file completions, also consider a possibly pre-existing
+ // closing quote or angle bracket.
QTextCursor cursor = manipulator.textCursorAt(rangeStart);
cursor.movePosition(QTextCursor::EndOfWord);
+ if (kind == CompletionItemKind::File && !textToBeInserted.isEmpty()
+ && textToBeInserted.right(1) == manipulator.textAt(cursor.position(), 1)) {
+ cursor.setPosition(cursor.position() + 1);
+ }
const QString textAfterCursor = manipulator.textAt(currentPos, cursor.position() - currentPos);
if (currentPos < cursor.position()
&& textToBeInserted != textAfterCursor
diff --git a/src/plugins/clangformat/clangformatglobalconfigwidget.cpp b/src/plugins/clangformat/clangformatglobalconfigwidget.cpp
index fdcceea62b4..052ed865151 100644
--- a/src/plugins/clangformat/clangformatglobalconfigwidget.cpp
+++ b/src/plugins/clangformat/clangformatglobalconfigwidget.cpp
@@ -110,7 +110,7 @@ ClangFormatGlobalConfigWidget::ClangFormatGlobalConfigWidget(ICodeStylePreferenc
// clang-format off
Group globalSettingsGroupBox {
bindTo(&globalSettingsGroupBoxWidget),
- title(Tr::tr("ClangFormat Settings:")),
+ title(Tr::tr("ClangFormat Settings")),
Column {
m_useGlobalSettings,
Form {
diff --git a/src/plugins/cmakeprojectmanager/cmakebuildconfiguration.cpp b/src/plugins/cmakeprojectmanager/cmakebuildconfiguration.cpp
index fed2112822e..178c2a68bfa 100644
--- a/src/plugins/cmakeprojectmanager/cmakebuildconfiguration.cpp
+++ b/src/plugins/cmakeprojectmanager/cmakebuildconfiguration.cpp
@@ -1585,7 +1585,7 @@ CMakeBuildConfiguration::CMakeBuildConfiguration(Target *target, Id id)
if (info.buildDirectory.isEmpty()) {
setBuildDirectory(shadowBuildDirectory(target->project()->projectFilePath(),
k,
- info.typeName,
+ info.displayName,
info.buildType));
}
@@ -1960,6 +1960,9 @@ CMakeBuildConfigurationFactory::CMakeBuildConfigurationFactory()
k,
info.typeName,
info.buildType);
+ } else {
+ info.displayName.clear(); // ask for a name
+ info.buildDirectory.clear(); // This depends on the displayName
}
result << info;
}
diff --git a/src/plugins/cmakeprojectmanager/cmakebuildsystem.cpp b/src/plugins/cmakeprojectmanager/cmakebuildsystem.cpp
index e0d2b6773fb..c396bde59a1 100644
--- a/src/plugins/cmakeprojectmanager/cmakebuildsystem.cpp
+++ b/src/plugins/cmakeprojectmanager/cmakebuildsystem.cpp
@@ -642,6 +642,25 @@ bool CMakeBuildSystem::addTsFiles(Node *context, const FilePaths &filePaths, Fil
return false;
}
+static bool isGlobbingFunction(const cmListFile &cmakeListFile, const cmListFileFunction &func)
+{
+ // Check if the filename is part of globbing variable result
+ const auto globFunctions = std::get<0>(
+ Utils::partition(cmakeListFile.Functions, [](const auto &f) {
+ return f.LowerCaseName() == "file" && f.Arguments().size() > 2
+ && (f.Arguments().front().Value == "GLOB"
+ || f.Arguments().front().Value == "GLOB_RECURSE");
+ }));
+
+ const auto globVariables = Utils::transform(globFunctions, [](const auto &func) {
+ return std::string("${") + func.Arguments()[1].Value + "}";
+ });
+
+ return Utils::anyOf(func.Arguments(), [globVariables](const auto &arg) {
+ return globVariables.contains(arg.Value);
+ });
+}
+
bool CMakeBuildSystem::addSrcFiles(Node *context, const FilePaths &filePaths, FilePaths *notAdded)
{
if (notAdded)
@@ -670,26 +689,32 @@ bool CMakeBuildSystem::addSrcFiles(Node *context, const FilePaths &filePaths, Fi
return false;
}
- const std::string target_name = function->Arguments().front().Value;
- auto qtAddModule = [target_name](const auto &func) {
- return (func.LowerCaseName() == "qt_add_qml_module"
- || func.LowerCaseName() == "qt6_add_qml_module")
- && func.Arguments().front().Value == target_name;
- };
- // Special case: when qt_add_executable and qt_add_qml_module use the same target name
- // then qt_add_qml_module function should be used
- function = findFunction(*cmakeListFile, qtAddModule).value_or(*function);
+ const bool haveGlobbing = isGlobbingFunction(cmakeListFile.value(), function.value());
+ n->setVisibleAfterAddFileAction(!haveGlobbing);
+ if (haveGlobbing && settings(project()).autorunCMake()) {
+ runCMake();
+ } else {
+ const std::string target_name = function->Arguments().front().Value;
+ auto qtAddModule = [target_name](const auto &func) {
+ return (func.LowerCaseName() == "qt_add_qml_module"
+ || func.LowerCaseName() == "qt6_add_qml_module")
+ && func.Arguments().front().Value == target_name;
+ };
+ // Special case: when qt_add_executable and qt_add_qml_module use the same target name
+ // then qt_add_qml_module function should be used
+ function = findFunction(*cmakeListFile, qtAddModule).value_or(*function);
- const QString newSourceFiles = newFilesForFunction(function->LowerCaseName(),
- filePaths,
- n->filePath().canonicalPath());
+ const QString newSourceFiles = newFilesForFunction(function->LowerCaseName(),
+ filePaths,
+ n->filePath().canonicalPath());
- const SnippetAndLocation snippetLocation = generateSnippetAndLocationForSources(
- newSourceFiles, *cmakeListFile, *function, targetName);
- expected_str inserted = insertSnippetSilently(targetCMakeFile, snippetLocation);
- if (!inserted) {
- qCCritical(cmakeBuildSystemLog) << inserted.error();
- return false;
+ const SnippetAndLocation snippetLocation = generateSnippetAndLocationForSources(
+ newSourceFiles, *cmakeListFile, *function, targetName);
+ expected_str inserted = insertSnippetSilently(targetCMakeFile, snippetLocation);
+ if (!inserted) {
+ qCCritical(cmakeBuildSystemLog) << inserted.error();
+ return false;
+ }
}
if (notAdded)
@@ -770,22 +795,7 @@ CMakeBuildSystem::projectFileArgumentPosition(const QString &targetName, const Q
return ProjectFileArgumentPosition{filePathArgument, targetCMakeFile, fileName};
} else {
// Check if the filename is part of globbing variable result
- const auto globFunctions = std::get<0>(
- Utils::partition(cmakeListFile->Functions, [](const auto &f) {
- return f.LowerCaseName() == "file" && f.Arguments().size() > 2
- && (f.Arguments().front().Value == "GLOB"
- || f.Arguments().front().Value == "GLOB_RECURSE");
- }));
-
- const auto globVariables = Utils::transform(globFunctions, [](const auto &func) {
- return std::string("${") + func.Arguments()[1].Value + "}";
- });
-
- const auto haveGlobbing = Utils::anyOf(func->Arguments(),
- [globVariables](const auto &arg) {
- return globVariables.contains(arg.Value);
- });
-
+ const auto haveGlobbing = isGlobbingFunction(cmakeListFile.value(), func.value());
if (haveGlobbing) {
return ProjectFileArgumentPosition{filePathArgument,
targetCMakeFile,
@@ -833,6 +843,7 @@ RemovedFilesFromProject CMakeBuildSystem::removeFiles(Node *context,
const FilePath projDir = n->filePath().canonicalPath();
const QString targetName = n->buildKey();
+ bool haveGlobbing = false;
for (const auto &file : filePaths) {
const QString fileName
= file.canonicalPath().relativePathFrom(projDir).cleanPath().toString();
@@ -847,6 +858,11 @@ RemovedFilesFromProject CMakeBuildSystem::removeFiles(Node *context,
continue;
}
+ if (filePos.value().fromGlobbing) {
+ haveGlobbing = true;
+ continue;
+ }
+
BaseTextEditor *editor = qobject_cast(
Core::EditorManager::openEditorAt({filePos.value().cmakeFile,
static_cast(filePos.value().argumentPosition.Line),
@@ -869,8 +885,7 @@ RemovedFilesFromProject CMakeBuildSystem::removeFiles(Node *context,
if (filePos->argumentPosition.Delim == cmListFileArgument::Quoted)
extraChars = 2;
- if (!filePos.value().fromGlobbing)
- editor->replace(filePos.value().relativeFileName.length() + extraChars, "");
+ editor->replace(filePos.value().relativeFileName.length() + extraChars, "");
editor->editorWidget()->autoIndent();
if (!Core::DocumentManager::saveDocument(editor->document())) {
@@ -889,6 +904,9 @@ RemovedFilesFromProject CMakeBuildSystem::removeFiles(Node *context,
if (notRemoved && !badFiles.isEmpty())
*notRemoved = badFiles;
+ if (haveGlobbing && settings(project()).autorunCMake())
+ runCMake();
+
return badFiles.isEmpty() ? RemovedFilesFromProject::Ok : RemovedFilesFromProject::Error;
}
@@ -936,10 +954,6 @@ bool CMakeBuildSystem::renameFile(Node *context,
const FilePath newRelPath = newFilePath.canonicalPath().relativePathFrom(projDir).cleanPath();
const QString newRelPathName = newRelPath.toString();
- // FilePath needs the file to exist on disk, the old file has already been renamed
- const QString oldRelPathName
- = newRelPath.parentDir().pathAppended(oldFilePath.fileName()).cleanPath().toString();
-
const QString targetName = n->buildKey();
const QString key
= QStringList{projDir.path(), targetName, oldFilePath.path(), newFilePath.path()}.join(
@@ -953,40 +967,47 @@ bool CMakeBuildSystem::renameFile(Node *context,
return false;
}
+ bool haveGlobbing = false;
do {
- BaseTextEditor *editor = qobject_cast(
- Core::EditorManager::openEditorAt(
- {fileToRename->cmakeFile,
- static_cast(fileToRename->argumentPosition.Line),
- static_cast(fileToRename->argumentPosition.Column - 1)},
- Constants::CMAKE_EDITOR_ID,
- Core::EditorManager::DoNotMakeVisible));
- if (!editor) {
- qCCritical(cmakeBuildSystemLog).noquote()
- << "BaseTextEditor cannot be obtained for" << fileToRename->cmakeFile.path()
- << fileToRename->argumentPosition.Line
- << int(fileToRename->argumentPosition.Column);
- return false;
- }
+ if (!fileToRename->fromGlobbing) {
+ BaseTextEditor *editor = qobject_cast(
+ Core::EditorManager::openEditorAt(
+ {fileToRename->cmakeFile,
+ static_cast(fileToRename->argumentPosition.Line),
+ static_cast(fileToRename->argumentPosition.Column - 1)},
+ Constants::CMAKE_EDITOR_ID,
+ Core::EditorManager::DoNotMakeVisible));
+ if (!editor) {
+ qCCritical(cmakeBuildSystemLog).noquote()
+ << "BaseTextEditor cannot be obtained for" << fileToRename->cmakeFile.path()
+ << fileToRename->argumentPosition.Line
+ << int(fileToRename->argumentPosition.Column);
+ return false;
+ }
- // If quotes were used for the source file, skip the starting quote
- if (fileToRename->argumentPosition.Delim == cmListFileArgument::Quoted)
- editor->setCursorPosition(editor->position() + 1);
+ // If quotes were used for the source file, skip the starting quote
+ if (fileToRename->argumentPosition.Delim == cmListFileArgument::Quoted)
+ editor->setCursorPosition(editor->position() + 1);
- if (!fileToRename->fromGlobbing)
editor->replace(fileToRename->relativeFileName.length(), newRelPathName);
- editor->editorWidget()->autoIndent();
- if (!Core::DocumentManager::saveDocument(editor->document())) {
- qCCritical(cmakeBuildSystemLog).noquote()
- << "Changes to" << fileToRename->cmakeFile.path() << "could not be saved.";
- return false;
+ editor->editorWidget()->autoIndent();
+ if (!Core::DocumentManager::saveDocument(editor->document())) {
+ qCCritical(cmakeBuildSystemLog).noquote()
+ << "Changes to" << fileToRename->cmakeFile.path() << "could not be saved.";
+ return false;
+ }
+ } else {
+ haveGlobbing = true;
}
// Try the next occurrence. This can happen if set_source_file_properties is used
- fileToRename = projectFileArgumentPosition(targetName, oldRelPathName);
+ fileToRename = projectFileArgumentPosition(targetName, fileToRename->relativeFileName);
} while (fileToRename && !fileToRename->fromGlobbing);
+ if (haveGlobbing && settings(project()).autorunCMake())
+ runCMake();
+
return true;
}
diff --git a/src/plugins/cmakeprojectmanager/cmakeeditor.cpp b/src/plugins/cmakeprojectmanager/cmakeeditor.cpp
index 92f63ea04c7..c4e91031015 100644
--- a/src/plugins/cmakeprojectmanager/cmakeeditor.cpp
+++ b/src/plugins/cmakeprojectmanager/cmakeeditor.cpp
@@ -330,7 +330,8 @@ void CMakeEditorWidget::findLinkAt(const QTextCursor &cursor,
if (auto project = ProjectTree::currentProject()) {
buffer.replace("${CMAKE_SOURCE_DIR}", project->projectDirectory().path());
- if (auto bs = ProjectTree::currentBuildSystem(); bs && bs->buildConfiguration()) {
+ auto bs = ProjectTree::currentBuildSystem();
+ if (bs && bs->buildConfiguration()) {
buffer.replace("${CMAKE_BINARY_DIR}", bs->buildConfiguration()->buildDirectory().path());
// Get the path suffix from current source dir to project source dir and apply it
diff --git a/src/plugins/cmakeprojectmanager/cmakeprojectnodes.cpp b/src/plugins/cmakeprojectmanager/cmakeprojectnodes.cpp
index 80c5e58c029..54f28f7b2ad 100644
--- a/src/plugins/cmakeprojectmanager/cmakeprojectnodes.cpp
+++ b/src/plugins/cmakeprojectmanager/cmakeprojectnodes.cpp
@@ -187,9 +187,16 @@ void CMakeTargetNode::setConfig(const CMakeConfig &config)
m_config = config;
}
+void CMakeTargetNode::setVisibleAfterAddFileAction(bool visibleAfterAddFileAction)
+{
+ m_visibleAfterAddFileAction = visibleAfterAddFileAction;
+}
+
std::optional CMakeTargetNode::visibleAfterAddFileAction() const
{
- return filePath().pathAppended(Constants::CMAKE_LISTS_TXT);
+ if (m_visibleAfterAddFileAction)
+ return filePath().pathAppended(Constants::CMAKE_LISTS_TXT);
+ return std::nullopt;
}
void CMakeTargetNode::build()
diff --git a/src/plugins/cmakeprojectmanager/cmakeprojectnodes.h b/src/plugins/cmakeprojectmanager/cmakeprojectnodes.h
index 94cde6dfef1..57b180bbba3 100644
--- a/src/plugins/cmakeprojectmanager/cmakeprojectnodes.h
+++ b/src/plugins/cmakeprojectmanager/cmakeprojectnodes.h
@@ -57,11 +57,14 @@ public:
QVariant data(Utils::Id role) const override;
void setConfig(const CMakeConfig &config);
+ void setVisibleAfterAddFileAction(bool visibleAfterAddFileAction);
+
private:
QString m_tooltip;
Utils::FilePath m_buildDirectory;
Utils::FilePath m_artifact;
CMakeConfig m_config;
+ bool m_visibleAfterAddFileAction = true;
};
} // CMakeProjectManager::Internal
diff --git a/src/plugins/cmakeprojectmanager/cmakespecificsettings.cpp b/src/plugins/cmakeprojectmanager/cmakespecificsettings.cpp
index eeab46f946d..a56a66c533b 100644
--- a/src/plugins/cmakeprojectmanager/cmakespecificsettings.cpp
+++ b/src/plugins/cmakeprojectmanager/cmakespecificsettings.cpp
@@ -142,8 +142,9 @@ void CMakeSpecificSettings::readSettings()
} else {
Store data = storeFromVariant(project->namedSettings(Constants::Settings::GENERAL_ID));
if (data.isEmpty()) {
- CMakeProject *cmakeProject = static_cast(project);
- if (cmakeProject->presetsData().havePresets && cmakeProject->presetsData().vendor) {
+ CMakeProject *cmakeProject = qobject_cast(project);
+ if (cmakeProject && cmakeProject->presetsData().havePresets
+ && cmakeProject->presetsData().vendor) {
useGlobalSettings = false;
data = storeFromMap(cmakeProject->presetsData().vendor.value());
fromMap(data);
diff --git a/src/plugins/cmakeprojectmanager/presetsparser.cpp b/src/plugins/cmakeprojectmanager/presetsparser.cpp
index 6c15f217f09..429c8958694 100644
--- a/src/plugins/cmakeprojectmanager/presetsparser.cpp
+++ b/src/plugins/cmakeprojectmanager/presetsparser.cpp
@@ -518,7 +518,7 @@ bool PresetsParser::parse(const Utils::FilePath &jsonFile, QString &errorMessage
m_presetsData.configurePresets,
jsonFile.parentDir())) {
errorMessage = ::CMakeProjectManager::Tr::tr(
- "Invalid \"configurePresets\" section in %1 file")
+ "Invalid \"configurePresets\" section in file \"%1\".")
.arg(jsonFile.fileName());
return false;
}
@@ -527,14 +527,15 @@ bool PresetsParser::parse(const Utils::FilePath &jsonFile, QString &errorMessage
if (!parseBuildPresets(root.value("buildPresets"),
m_presetsData.buildPresets,
jsonFile.parentDir())) {
- errorMessage = ::CMakeProjectManager::Tr::tr("Invalid \"buildPresets\" section in %1 file")
+ errorMessage = ::CMakeProjectManager::Tr::tr(
+ "Invalid \"buildPresets\" section in file \"%1\".")
.arg(jsonFile.fileName());
return false;
}
// optional
if (!parseVendor(root.value("vendor"), m_presetsData.vendor)) {
- errorMessage = ::CMakeProjectManager::Tr::tr("Invalid \"vendor\" section in %1 file")
+ errorMessage = ::CMakeProjectManager::Tr::tr("Invalid \"vendor\" section in file \"%1\".")
.arg(jsonFile.fileName());
}
diff --git a/src/plugins/coreplugin/editormanager/ieditorfactory.cpp b/src/plugins/coreplugin/editormanager/ieditorfactory.cpp
index 22aa24e7377..0c0fc17a204 100644
--- a/src/plugins/coreplugin/editormanager/ieditorfactory.cpp
+++ b/src/plugins/coreplugin/editormanager/ieditorfactory.cpp
@@ -4,6 +4,7 @@
#include "ieditorfactory.h"
#include "ieditorfactory_p.h"
#include "editormanager.h"
+#include "../coreconstants.h"
#include
#include
@@ -16,15 +17,14 @@ namespace Core {
/* Find the one best matching the mimetype passed in.
* Recurse over the parent classes of the mimetype to find them. */
-template
static void mimeTypeFactoryLookup(const Utils::MimeType &mimeType,
- const QList &allFactories,
- QList *list)
+ const QList &allFactories,
+ QList *list)
{
- QSet matches;
+ QSet matches;
Utils::visitMimeParents(mimeType, [&](const Utils::MimeType &mt) -> bool {
// check for matching factories
- for (EditorTypeLike *factory : allFactories) {
+ for (IEditorFactory *factory : allFactories) {
if (!matches.contains(factory)) {
const QStringList mimeTypes = factory->mimeTypes();
for (const QString &mimeName : mimeTypes) {
@@ -37,6 +37,14 @@ static void mimeTypeFactoryLookup(const Utils::MimeType &mimeType,
}
return true; // continue
});
+ // Always offer the plain text editor as a fallback for the case that the mime type
+ // is not detected correctly.
+ if (auto plainTextEditorFactory = Utils::findOrDefault(
+ allFactories,
+ Utils::equal(&IEditorFactory::id, Utils::Id(Constants::K_DEFAULT_TEXT_EDITOR_ID)))) {
+ if (!matches.contains(plainTextEditorFactory))
+ list->append(plainTextEditorFactory);
+ }
}
/*!
diff --git a/src/plugins/coreplugin/editormanager/openeditorswindow.cpp b/src/plugins/coreplugin/editormanager/openeditorswindow.cpp
index d59f49bf803..172b54570e1 100644
--- a/src/plugins/coreplugin/editormanager/openeditorswindow.cpp
+++ b/src/plugins/coreplugin/editormanager/openeditorswindow.cpp
@@ -161,17 +161,39 @@ void OpenEditorsWindow::setVisible(bool visible)
bool OpenEditorsWindow::eventFilter(QObject *obj, QEvent *e)
{
if (obj == m_editorView) {
- if (e->type() == QEvent::KeyPress) {
+ if (e->type() == QEvent::ShortcutOverride) {
auto ke = static_cast(e);
- if (ke->key() == Qt::Key_Escape) {
- setVisible(false);
+ switch (ke->key()) {
+ case Qt::Key_Up:
+ case Qt::Key_P:
+ e->accept();
+ return true;
+ case Qt::Key_Down:
+ case Qt::Key_N:
+ e->accept();
return true;
}
- if (ke->key() == Qt::Key_Return
- || ke->key() == Qt::Key_Enter) {
+ }
+ if (e->type() == QEvent::KeyPress) {
+ auto ke = static_cast(e);
+ switch (ke->key()) {
+ case Qt::Key_Up:
+ case Qt::Key_P:
+ selectNextEditor();
+ return true;
+ case Qt::Key_Down:
+ case Qt::Key_N:
+ selectPreviousEditor();
+ return true;
+ case Qt::Key_Escape:
+ setVisible(false);
+ return true;
+ case Qt::Key_Return:
+ case Qt::Key_Enter:
selectEditor(m_editorView->currentItem());
return true;
}
+
} else if (e->type() == QEvent::KeyRelease) {
auto ke = static_cast(e);
if (ke->modifiers() == 0
diff --git a/src/plugins/coreplugin/outputwindow.cpp b/src/plugins/coreplugin/outputwindow.cpp
index d5fe9205602..4183a8457ca 100644
--- a/src/plugins/coreplugin/outputwindow.cpp
+++ b/src/plugins/coreplugin/outputwindow.cpp
@@ -74,7 +74,7 @@ public:
QElapsedTimer lastMessage;
QHash> taskPositions;
//: default file name suggested for saving text from output views
- QString outputFileNameHint{Tr::tr("output.txt")};
+ QString outputFileNameHint{::Core::Tr::tr("output.txt")};
};
} // namespace Internal
diff --git a/src/plugins/cppeditor/cppfilesettingspage.cpp b/src/plugins/cppeditor/cppfilesettingspage.cpp
index 70f17e9afe8..b9c64965a68 100644
--- a/src/plugins/cppeditor/cppfilesettingspage.cpp
+++ b/src/plugins/cppeditor/cppfilesettingspage.cpp
@@ -47,7 +47,7 @@ class HeaderGuardExpander : public MacroExpander
public:
HeaderGuardExpander(const FilePath &filePath) : m_filePath(filePath)
{
- setDisplayName(Tr::tr("Header file variables"));
+ setDisplayName(Tr::tr("Header File Variables"));
registerFileVariables("Header", Tr::tr("Header file"), [this] {
return m_filePath;
});
diff --git a/src/plugins/cppeditor/cpphighlighter.cpp b/src/plugins/cppeditor/cpphighlighter.cpp
index 3b4345944e0..16a87df76ef 100644
--- a/src/plugins/cppeditor/cpphighlighter.cpp
+++ b/src/plugins/cppeditor/cpphighlighter.cpp
@@ -82,8 +82,6 @@ void CppHighlighter::highlightBlock(const QString &text)
return;
}
- const int firstNonSpace = tokens.first().utf16charsBegin();
-
// Keep "semantic parentheses".
Parentheses parentheses;
if (TextBlockUserData *userData = TextDocumentLayout::textUserData(currentBlock())) {
@@ -122,9 +120,16 @@ void CppHighlighter::highlightBlock(const QString &text)
if (tk.is(T_LBRACE)) {
++braceDepth;
- // if a folding block opens at the beginning of a line, treat the entire line
- // as if it were inside the folding block
- if (tk.utf16charsBegin() == firstNonSpace) {
+ // if a folding block opens at the beginning of a line, treat the line before
+ // as if it were inside the folding block except if it is a comment or the line does
+ // end with ;
+ const int firstNonSpace = tokens.first().utf16charsBegin();
+ const QString prevBlockText = currentBlock().previous().isValid()
+ ? currentBlock().previous().text().trimmed()
+ : QString();
+ if (!prevBlockText.isEmpty() && !prevBlockText.startsWith("//")
+ && !prevBlockText.endsWith("*/") && !prevBlockText.endsWith(";")
+ && tk.utf16charsBegin() == firstNonSpace) {
++foldingIndent;
TextDocumentLayout::userData(currentBlock())->setFoldingStartIncluded(true);
}
@@ -654,6 +659,32 @@ void CppHighlighterTest::testParentheses()
QCOMPARE(TextDocumentLayout::parentheses(block).count(), expectedParenCount);
}
+void CppHighlighterTest::testFoldingIndent_data()
+{
+ QTest::addColumn("line");
+ QTest::addColumn("expectedFoldingIndent");
+ QTest::addColumn("expectedFoldingIndentNextLine");
+
+ QTest::newRow("braces after one line comment") << 52 << 0 << 1;
+ QTest::newRow("braces after multiline comment") << 59 << 0 << 1;
+ QTest::newRow("braces after completed line") << 67 << 1 << 2;
+}
+
+void CppHighlighterTest::testFoldingIndent()
+{
+ QFETCH(int, line);
+ QFETCH(int, expectedFoldingIndent);
+ QFETCH(int, expectedFoldingIndentNextLine);
+
+ QTextBlock block = m_doc.findBlockByNumber(line - 1);
+ QVERIFY(block.isValid());
+ QCOMPARE(TextDocumentLayout::foldingIndent(block), expectedFoldingIndent);
+
+ QTextBlock nextBlock = m_doc.findBlockByNumber(line);
+ QVERIFY(nextBlock.isValid());
+ QCOMPARE(TextDocumentLayout::foldingIndent(nextBlock), expectedFoldingIndentNextLine);
+}
+
} // namespace Internal
#endif // WITH_TESTS
diff --git a/src/plugins/cppeditor/cpphighlighter.h b/src/plugins/cppeditor/cpphighlighter.h
index 5a6af63adaf..70fe8525c2c 100644
--- a/src/plugins/cppeditor/cpphighlighter.h
+++ b/src/plugins/cppeditor/cpphighlighter.h
@@ -54,6 +54,8 @@ private slots:
void test();
void testParentheses_data();
void testParentheses();
+ void testFoldingIndent_data();
+ void testFoldingIndent();
private:
QTextDocument m_doc;
diff --git a/src/plugins/cppeditor/cppmodelmanager.cpp b/src/plugins/cppeditor/cppmodelmanager.cpp
index 511094b48de..d9a5c7e6f2f 100644
--- a/src/plugins/cppeditor/cppmodelmanager.cpp
+++ b/src/plugins/cppeditor/cppmodelmanager.cpp
@@ -553,7 +553,7 @@ using FindUnusedActionsEnabledSwitcherPtr = std::shared_ptr &search,
- const std::shared_ptr> &findRefsFuture,
+ const std::shared_ptr> &findRefsFuture,
const FindUnusedActionsEnabledSwitcherPtr &actionsSwitcher)
{
if (!search || findRefsFuture->isCanceled())
@@ -650,14 +650,14 @@ void CppModelManager::findUnusedFunctions(const FilePath &folder)
Utils::transform(links, [](const Link &l) { return QVariant::fromValue(l);
}));
search->setUserData(remainingAndActiveLinks);
- const auto findRefsFuture = std::make_shared>();
+ const auto findRefsFuture = std::make_shared>();
FutureProgress *const progress = ProgressManager::addTask(findRefsFuture->future(),
Tr::tr("Finding Unused Functions"),
"CppEditor.FindUnusedFunctions");
connect(progress,
&FutureProgress::canceled,
search,
- [search, future = std::weak_ptr>(findRefsFuture)] {
+ [search, future = std::weak_ptr>(findRefsFuture)] {
search->finishSearch(true);
if (const auto f = future.lock()) {
f->cancel();
diff --git a/src/plugins/cppeditor/testcases/highlightingtestcase.cpp b/src/plugins/cppeditor/testcases/highlightingtestcase.cpp
index a9102ce4578..92b4e21a260 100644
--- a/src/plugins/cppeditor/testcases/highlightingtestcase.cpp
+++ b/src/plugins/cppeditor/testcases/highlightingtestcase.cpp
@@ -47,3 +47,24 @@ static void parenTest()
const char* s7 = R"(
))";
+
+// comment
+{
+
+}
+
+/*
+ *
+ */
+{
+
+}
+
+static void parenTest2()
+{
+
+ parenTest();
+ {
+
+ }
+}
diff --git a/src/plugins/debugger/dap/lldbdapengine.cpp b/src/plugins/debugger/dap/lldbdapengine.cpp
index 8dfd75a75b2..d767ab723ae 100644
--- a/src/plugins/debugger/dap/lldbdapengine.cpp
+++ b/src/plugins/debugger/dap/lldbdapengine.cpp
@@ -115,14 +115,6 @@ LldbDapEngine::LldbDapEngine()
setDebuggerType("DAP");
}
-QJsonArray LldbDapEngine::environment() const
-{
- QJsonArray envArray;
- for (const QString &value : runParameters().inferior.environment.toDictionary().toStringList())
- envArray.append(value);
- return envArray;
-}
-
QJsonArray LldbDapEngine::sourceMap() const
{
QJsonArray sourcePathMapping;
@@ -160,11 +152,12 @@ void LldbDapEngine::handleDapInitialize()
const QJsonArray commands = preRunCommands();
if (!isLocalAttachEngine()) {
- const QJsonArray env = environment();
+ const QJsonArray env = QJsonArray::fromStringList(rp.inferior.environment.toStringList());
+ const QJsonArray args = QJsonArray::fromStringList(rp.inferior.command.splitArguments());
+
QJsonObject launchJson{
{"noDebug", false},
{"program", rp.inferior.command.executable().path()},
- {"args", rp.inferior.command.arguments()},
{"cwd", rp.inferior.workingDirectory.path()},
{"env", env},
{"__restart", ""},
@@ -173,6 +166,8 @@ void LldbDapEngine::handleDapInitialize()
launchJson.insert("sourceMap", map);
if (!commands.isEmpty())
launchJson.insert("preRunCommands", commands);
+ if (!args.isEmpty())
+ launchJson.insert("args", args);
m_dapClient->postRequest("launch", launchJson);
diff --git a/src/plugins/debugger/dap/lldbdapengine.h b/src/plugins/debugger/dap/lldbdapengine.h
index f4f59903820..0ebeb2d2ee1 100644
--- a/src/plugins/debugger/dap/lldbdapengine.h
+++ b/src/plugins/debugger/dap/lldbdapengine.h
@@ -22,7 +22,6 @@ private:
bool acceptsBreakpoint(const BreakpointParameters &bp) const override;
const QLoggingCategory &logCategory() override;
- QJsonArray environment() const;
QJsonArray sourceMap() const;
QJsonArray preRunCommands() const;
};
diff --git a/src/plugins/debugger/gdb/gdbengine.cpp b/src/plugins/debugger/gdb/gdbengine.cpp
index ab173cc0eab..b31ee7130e4 100644
--- a/src/plugins/debugger/gdb/gdbengine.cpp
+++ b/src/plugins/debugger/gdb/gdbengine.cpp
@@ -30,7 +30,9 @@
#include
#include
+#include
#include
+#include
#include
#include
@@ -2074,8 +2076,10 @@ QString GdbEngine::breakpointLocation(const BreakpointParameters &data)
return addressSpec(data.address);
BreakpointPathUsage usage = data.pathUsage;
- if (usage == BreakpointPathUsageEngineDefault)
- usage = BreakpointUseShortPath;
+ if (usage == BreakpointPathUsageEngineDefault) {
+ ProjectExplorer::Project *project = ProjectManager::projectForFile(data.fileName);
+ usage = project ? BreakpointUseFullPath : BreakpointUseShortPath;
+ }
const QString fileName = usage == BreakpointUseFullPath
? data.fileName.path() : breakLocation(data.fileName);
@@ -2088,8 +2092,10 @@ QString GdbEngine::breakpointLocation(const BreakpointParameters &data)
QString GdbEngine::breakpointLocation2(const BreakpointParameters &data)
{
BreakpointPathUsage usage = data.pathUsage;
- if (usage == BreakpointPathUsageEngineDefault)
- usage = BreakpointUseShortPath;
+ if (usage == BreakpointPathUsageEngineDefault) {
+ ProjectExplorer::Project *project = ProjectManager::projectForFile(data.fileName);
+ usage = project ? BreakpointUseFullPath : BreakpointUseShortPath;
+ }
const QString fileName = usage == BreakpointUseFullPath
? data.fileName.path() : breakLocation(data.fileName);
diff --git a/src/plugins/debugger/gdb/gdbsettings.cpp b/src/plugins/debugger/gdb/gdbsettings.cpp
index 9ca93263069..08313c7c6ce 100644
--- a/src/plugins/debugger/gdb/gdbsettings.cpp
+++ b/src/plugins/debugger/gdb/gdbsettings.cpp
@@ -166,7 +166,7 @@ GdbSettings::GdbSettings()
useDebugInfoD.setSettingsKey("UseDebugInfoD");
useDebugInfoD.setLabelText(Tr::tr("Use debug info daemon"));
- useDebugInfoD.setOptionText(TriState::DefaultValue, tr("Use system settings"));
+ useDebugInfoD.setOptionText(TriState::DefaultValue, Tr::tr("Use system settings"));
useDebugInfoD.setToolTip(Tr::tr("Lets GDB attempt to automatically retrieve "
"debug information for system packages."));
diff --git a/src/plugins/extensionmanager/extensionmanager.qrc b/src/plugins/extensionmanager/extensionmanager.qrc
index b6a3554cb1f..b552aaf7b59 100644
--- a/src/plugins/extensionmanager/extensionmanager.qrc
+++ b/src/plugins/extensionmanager/extensionmanager.qrc
@@ -2,10 +2,14 @@
images/download.png
images/download@2x.png
+ images/extensionbig.png
+ images/extensionbig@2x.png
images/extensionsmall.png
images/extensionsmall@2x.png
images/mode_extensionmanager_mask.png
images/mode_extensionmanager_mask@2x.png
+ images/packbig.png
+ images/packbig@2x.png
images/packsmall.png
images/packsmall@2x.png
diff --git a/src/plugins/extensionmanager/extensionmanager_test.qrc b/src/plugins/extensionmanager/extensionmanager_test.qrc
index 4c4d59f002d..e7e934e5316 100644
--- a/src/plugins/extensionmanager/extensionmanager_test.qrc
+++ b/src/plugins/extensionmanager/extensionmanager_test.qrc
@@ -1,6 +1,8 @@
+ testdata/augmentedplugindata.json
testdata/defaultpacks.json
testdata/thirdpartyplugins.json
+ testdata/varieddata.json
diff --git a/src/plugins/extensionmanager/extensionmanagerplugin.cpp b/src/plugins/extensionmanager/extensionmanagerplugin.cpp
index 979a75ad291..e51cb0cbdda 100644
--- a/src/plugins/extensionmanager/extensionmanagerplugin.cpp
+++ b/src/plugins/extensionmanager/extensionmanagerplugin.cpp
@@ -50,7 +50,7 @@ public:
using namespace Layouting;
auto widget = Column {
new StyledBar,
- new ExtensionManagerWidget,
+ createExtensionManagerWidget(),
noMargin, spacing(0),
}.emerge();
diff --git a/src/plugins/extensionmanager/extensionmanagerwidget.cpp b/src/plugins/extensionmanager/extensionmanagerwidget.cpp
index 363b8cb90ee..c2dc396cece 100644
--- a/src/plugins/extensionmanager/extensionmanagerwidget.cpp
+++ b/src/plugins/extensionmanager/extensionmanagerwidget.cpp
@@ -16,6 +16,7 @@
#include
#include
+#include
#include
#include
@@ -33,16 +34,56 @@
#include
#include
+#include
+#include
#include
+#include
+#include
#include
-#include
+#include
+#include
#include
+#include
+#include
using namespace Core;
using namespace Utils;
+using namespace StyleHelper;
+using namespace WelcomePageHelpers;
namespace ExtensionManager::Internal {
+constexpr TextFormat h5TF
+ {Theme::Token_Text_Default, UiElement::UiElementH5};
+constexpr TextFormat h6TF
+ {h5TF.themeColor, UiElement::UiElementH6};
+constexpr TextFormat h6CapitalTF
+ {Theme::Token_Text_Muted, UiElement::UiElementH6Capital};
+constexpr TextFormat contentTF
+ {Theme::Token_Text_Default, UiElement::UiElementBody2};
+
+static QLabel *sectionTitle(const TextFormat &tf, const QString &title)
+{
+ QLabel *label = tfLabel(tf, true);
+ label->setText(title);
+ return label;
+};
+
+static QWidget *toScrollableColumn(QWidget *widget)
+{
+ widget->setContentsMargins(SpacingTokens::ExVPaddingGapXl, SpacingTokens::ExVPaddingGapXl,
+ SpacingTokens::ExVPaddingGapXl, SpacingTokens::ExVPaddingGapXl);
+ widget->setSizePolicy(QSizePolicy::Ignored, QSizePolicy::Minimum);
+
+ auto scrollArea = new QScrollArea;
+ scrollArea->setWidget(widget);
+ scrollArea->setWidgetResizable(true);
+ scrollArea->setHorizontalScrollBarPolicy(Qt::ScrollBarAlwaysOff);
+ scrollArea->setFrameStyle(QFrame::NoFrame);
+
+ return scrollArea;
+};
+
class CollapsingWidget : public QWidget
{
public:
@@ -68,6 +109,169 @@ private:
int m_width = 100;
};
+class HeadingWidget : public QWidget
+{
+ static constexpr QSize iconBgS{68, 68};
+ static constexpr int dividerH = 16;
+
+ Q_OBJECT
+
+public:
+ explicit HeadingWidget(QWidget *parent = nullptr)
+ : QWidget(parent)
+ {
+ m_icon = new QLabel;
+ m_icon->setFixedSize(iconBgS);
+
+ static const TextFormat titleTF
+ {Theme::Token_Text_Default, UiElementH4};
+ static const TextFormat vendorTF
+ {Theme::Token_Text_Accent, UiElementLabelMedium};
+ static const TextFormat dlTF
+ {Theme::Token_Text_Muted, vendorTF.uiElement};
+ static const TextFormat detailsTF
+ {Theme::Token_Text_Default, UiElementBody2};
+
+ m_title = tfLabel(titleTF);
+ m_vendor = new Button({}, Button::SmallLink);
+ m_vendor->setContentsMargins({});
+ m_divider = new QLabel;
+ m_divider->setFixedSize(1, dividerH);
+ WelcomePageHelpers::setBackgroundColor(m_divider, dlTF.themeColor);
+ m_dlIcon = new QLabel;
+ const QPixmap dlIcon = Icon({{":/extensionmanager/images/download.png", dlTF.themeColor}},
+ Icon::Tint).pixmap();
+ m_dlIcon->setPixmap(dlIcon);
+ m_dlCount = tfLabel(dlTF);
+ m_dlCount->setSizePolicy(QSizePolicy::MinimumExpanding, QSizePolicy::Preferred);
+ m_details = tfLabel(detailsTF);
+ installButton = new Button(Tr::tr("Install..."), Button::MediumPrimary);
+ installButton->setSizePolicy(QSizePolicy::Maximum, QSizePolicy::Preferred);
+ installButton->hide();
+
+ using namespace Layouting;
+ Row {
+ m_icon,
+ Column {
+ m_title,
+ st,
+ Row {
+ m_vendor,
+ Widget {
+ bindTo(&m_dlCountItems),
+ Row {
+ Space(SpacingTokens::HGapXs),
+ m_divider,
+ Space(SpacingTokens::HGapXs),
+ m_dlIcon,
+ Space(SpacingTokens::HGapXxs),
+ m_dlCount,
+ noMargin, spacing(0),
+ },
+ },
+ },
+ st,
+ m_details,
+ spacing(0),
+ },
+ Column {
+ installButton,
+ st,
+ },
+ noMargin, spacing(SpacingTokens::ExPaddingGapL),
+ }.attachTo(this);
+
+ setSizePolicy(QSizePolicy::MinimumExpanding, QSizePolicy::Maximum);
+ m_dlCountItems->setVisible(false);
+
+ connect(installButton, &QAbstractButton::pressed,
+ this, &HeadingWidget::pluginInstallationRequested);
+ connect(m_vendor, &QAbstractButton::pressed, this, [this]() {
+ emit vendorClicked(m_currentVendor);
+ });
+
+ update({});
+ }
+
+ void update(const QModelIndex ¤t)
+ {
+ if (!current.isValid())
+ return;
+
+ m_icon->setPixmap(icon(current));
+
+ const QString name = current.data(RoleName).toString();
+ m_title->setText(name);
+
+ m_currentVendor = current.data(RoleVendor).toString();
+ m_vendor->setText(m_currentVendor);
+
+ const int dlCount = current.data(RoleDownloadCount).toInt();
+ const bool showDlCount = dlCount > 0;
+ if (showDlCount)
+ m_dlCount->setText(QString::number(dlCount));
+ m_dlCountItems->setVisible(showDlCount);
+
+ const auto pluginData = current.data(RolePlugins).value();
+ if (current.data(RoleItemType).toInt() == ItemTypePack) {
+ const int pluginsCount = pluginData.count();
+ const QString details = Tr::tr("Pack contains %n plugins.", nullptr, pluginsCount);
+ m_details->setText(details);
+ } else {
+ m_details->setText({});
+ }
+
+ const ItemType itemType = current.data(RoleItemType).value();
+ const bool isPack = itemType == ItemTypePack;
+ const bool isRemotePlugin = !(isPack || pluginSpecForName(name));
+ installButton->setVisible(isRemotePlugin && !pluginData.empty());
+ if (installButton->isVisible())
+ installButton->setToolTip(pluginData.constFirst().second);
+ }
+
+signals:
+ void pluginInstallationRequested();
+ void vendorClicked(const QString &vendor);
+
+private:
+ static QPixmap icon(const QModelIndex &index)
+ {
+ const qreal dpr = qApp->devicePixelRatio();
+ QPixmap pixmap(iconBgS * dpr);
+ pixmap.fill(Qt::transparent);
+ pixmap.setDevicePixelRatio(dpr);
+ const QRect bgR(QPoint(), pixmap.deviceIndependentSize().toSize());
+
+ QPainter p(&pixmap);
+ QLinearGradient gradient(bgR.topRight(), bgR.bottomLeft());
+ gradient.setStops(iconGradientStops(index));
+ constexpr int iconRectRounding = 4;
+ WelcomePageHelpers::drawCardBackground(&p, bgR, gradient, Qt::NoPen, iconRectRounding);
+
+ // Icon
+ constexpr Theme::Color color = Theme::Token_Basic_White;
+ static const QIcon pack = Icon({{":/extensionmanager/images/packbig.png", color}},
+ Icon::Tint).icon();
+ static const QIcon extension = Icon({{":/extensionmanager/images/extensionbig.png",
+ color}}, Icon::Tint).icon();
+ const ItemType itemType = index.data(RoleItemType).value();
+ (itemType == ItemTypePack ? pack : extension).paint(&p, bgR);
+
+ return pixmap;
+ }
+
+ QLabel *m_icon;
+ QLabel *m_title;
+ Button *m_vendor;
+ QLabel *m_divider;
+ QLabel *m_dlIcon;
+ QLabel *m_dlCount;
+ QWidget *m_dlCountItems;
+ QLabel *m_details;
+ QAbstractButton *installButton;
+ QString m_currentVendor;
+};
+
class PluginStatusWidget : public QWidget
{
public:
@@ -75,22 +279,34 @@ public:
: QWidget(parent)
{
m_label = new InfoLabel;
- m_checkBox = new QCheckBox(Tr::tr("Load on Start"));
+ m_checkBox = new QCheckBox(Tr::tr("Load on start"));
+ m_restartButton = new Button(Tr::tr("Restart Now"), Button::MediumPrimary);
+ m_restartButton->setVisible(false);
+ m_pluginView.hide();
using namespace Layouting;
Column {
m_label,
m_checkBox,
+ m_restartButton,
}.attachTo(this);
connect(m_checkBox, &QCheckBox::clicked, this, [this](bool checked) {
- ExtensionSystem::PluginSpec *spec = ExtensionsModel::pluginSpecForName(m_pluginName);
+ ExtensionSystem::PluginSpec *spec = pluginSpecForName(m_pluginName);
if (spec == nullptr)
return;
- spec->setEnabledBySettings(checked);
- ExtensionSystem::PluginManager::writeSettings();
+ const bool doIt = m_pluginView.data().setPluginsEnabled({spec}, checked);
+ if (doIt) {
+ m_restartButton->show();
+ ExtensionSystem::PluginManager::writeSettings();
+ } else {
+ m_checkBox->setChecked(!checked);
+ }
});
+ connect(m_restartButton, &QAbstractButton::clicked,
+ ICore::instance(), &ICore::restart, Qt::QueuedConnection);
+
update();
}
@@ -103,7 +319,7 @@ public:
private:
void update()
{
- const ExtensionSystem::PluginSpec *spec = ExtensionsModel::pluginSpecForName(m_pluginName);
+ const ExtensionSystem::PluginSpec *spec = pluginSpecForName(m_pluginName);
setVisible(spec != nullptr);
if (spec == nullptr)
return;
@@ -125,290 +341,322 @@ private:
InfoLabel *m_label;
QCheckBox *m_checkBox;
+ QAbstractButton *m_restartButton;
QString m_pluginName;
+ ExtensionSystem::PluginView m_pluginView{this};
};
-class ExtensionManagerWidgetPrivate
+class TagList : public QWidget
+{
+ Q_OBJECT
+
+public:
+ explicit TagList(QWidget *parent = nullptr)
+ : QWidget(parent)
+ {
+ QHBoxLayout *layout = new QHBoxLayout(this);
+ setLayout(layout);
+ layout->setContentsMargins({});
+ m_signalMapper = new QSignalMapper(this);
+ connect(m_signalMapper, &QSignalMapper::mappedString, this, &TagList::tagSelected);
+ }
+
+ void setTags(const QStringList &tags)
+ {
+ if (m_container) {
+ delete m_container;
+ m_container = nullptr;
+ }
+
+ if (!tags.empty()) {
+ m_container = new QWidget(this);
+ layout()->addWidget(m_container);
+
+ using namespace Layouting;
+ Flow flow {};
+ flow.setNoMargins();
+ flow.setSpacing(SpacingTokens::HGapXs);
+
+ for (const QString &tag : tags) {
+ QAbstractButton *tagButton = new Button(tag, Button::Tag);
+ connect(tagButton, &QAbstractButton::clicked,
+ m_signalMapper, qOverload<>(&QSignalMapper::map));
+ m_signalMapper->setMapping(tagButton, tag);
+ flow.addItem(tagButton);
+ }
+
+ flow.attachTo(m_container);
+ }
+
+ updateGeometry();
+ }
+
+signals:
+ void tagSelected(const QString &tag);
+
+private:
+ QWidget *m_container = nullptr;
+ QSignalMapper *m_signalMapper;
+};
+
+class ExtensionManagerWidget final : public Core::ResizeSignallingWidget
{
public:
- QString currentItemName;
- ExtensionsBrowser *leftColumn;
- CollapsingWidget *secondaryDescriptionWidget;
- QTextBrowser *primaryDescription;
- QTextBrowser *secondaryDescription;
- PluginStatusWidget *pluginStatus;
- QAbstractButton *installButton;
- PluginsData currentItemPlugins;
- Tasking::TaskTreeRunner taskTreeRunner;
+ ExtensionManagerWidget();
+
+private:
+ void updateView(const QModelIndex ¤t);
+ void fetchAndInstallPlugin(const QUrl &url);
+ void fetchAndDisplayImage(const QUrl &url);
+
+ QString m_currentItemName;
+ ExtensionsBrowser *m_extensionBrowser;
+ CollapsingWidget *m_secondaryDescriptionWidget;
+ HeadingWidget *m_headingWidget;
+ QWidget *m_primaryContent;
+ QWidget *m_secondaryContent;
+ QLabel *m_description;
+ QLabel *m_linksTitle;
+ QLabel *m_links;
+ QLabel *m_imageTitle;
+ QLabel *m_image;
+ QBuffer m_imageDataBuffer;
+ QMovie m_imageMovie;
+ QLabel *m_tagsTitle;
+ TagList *m_tags;
+ QLabel *m_platformsTitle;
+ QLabel *m_platforms;
+ QLabel *m_dependenciesTitle;
+ QLabel *m_dependencies;
+ QLabel *m_packExtensionsTitle;
+ QLabel *m_packExtensions;
+ PluginStatusWidget *m_pluginStatus;
+ PluginsData m_currentItemPlugins;
+ Tasking::TaskTreeRunner m_dlTaskTreeRunner;
+ Tasking::TaskTreeRunner m_imgTaskTreeRunner;
};
-ExtensionManagerWidget::ExtensionManagerWidget(QWidget *parent)
- : ResizeSignallingWidget(parent)
- , d(new ExtensionManagerWidgetPrivate)
+ExtensionManagerWidget::ExtensionManagerWidget()
{
- d->leftColumn = new ExtensionsBrowser;
-
+ m_extensionBrowser = new ExtensionsBrowser;
auto descriptionColumns = new QWidget;
+ m_secondaryDescriptionWidget = new CollapsingWidget;
- d->secondaryDescriptionWidget = new CollapsingWidget;
-
- d->primaryDescription = new QTextBrowser;
- d->primaryDescription->setOpenExternalLinks(true);
- d->primaryDescription->setFrameStyle(QFrame::NoFrame);
-
- d->secondaryDescription = new QTextBrowser;
- d->secondaryDescription->setFrameStyle(QFrame::NoFrame);
-
- d->pluginStatus = new PluginStatusWidget;
-
- d->installButton = new Button(Tr::tr("Install..."), Button::MediumPrimary);
- d->installButton->hide();
+ m_headingWidget = new HeadingWidget;
+ m_description = tfLabel(contentTF, false);
+ m_description->setWordWrap(true);
+ m_linksTitle = sectionTitle(h6CapitalTF, Tr::tr("More information"));
+ m_links = tfLabel(contentTF, false);
+ m_links->setOpenExternalLinks(true);
+ m_imageTitle = sectionTitle(h6CapitalTF, {});
+ m_image = new QLabel;
+ m_imageMovie.setDevice(&m_imageDataBuffer);
using namespace Layouting;
+ auto primary = new QWidget;
+ const auto spL = spacing(SpacingTokens::VPaddingL);
+ Column {
+ m_description,
+ Column { m_linksTitle, m_links, spL },
+ Column { m_imageTitle, m_image, spL },
+ st,
+ noMargin, spacing(SpacingTokens::ExVPaddingGapXl),
+ }.attachTo(primary);
+ m_primaryContent = toScrollableColumn(primary);
+
+ m_tagsTitle = sectionTitle(h6TF, Tr::tr("Tags"));
+ m_tags = new TagList;
+ m_platformsTitle = sectionTitle(h6TF, Tr::tr("Platforms"));
+ m_platforms = tfLabel(contentTF, false);
+ m_dependenciesTitle = sectionTitle(h6TF, Tr::tr("Dependencies"));
+ m_dependencies = tfLabel(contentTF, false);
+ m_packExtensionsTitle = sectionTitle(h6TF, Tr::tr("Extensions in pack"));
+ m_packExtensions = tfLabel(contentTF, false);
+ m_pluginStatus = new PluginStatusWidget;
+
+ auto secondary = new QWidget;
+ const auto spXxs = spacing(SpacingTokens::VPaddingXxs);
+ Column {
+ sectionTitle(h6CapitalTF, Tr::tr("Extension details")),
+ Column {
+ Column { m_tagsTitle, m_tags, spXxs },
+ Column { m_platformsTitle, m_platforms, spXxs },
+ Column { m_dependenciesTitle, m_dependencies, spXxs },
+ Column { m_packExtensionsTitle, m_packExtensions, spXxs },
+ spacing(SpacingTokens::VPaddingL),
+ },
+ st,
+ noMargin, spacing(SpacingTokens::ExVPaddingGapXl),
+ }.attachTo(secondary);
+ m_secondaryContent = toScrollableColumn(secondary);
+
Row {
WelcomePageHelpers::createRule(Qt::Vertical),
Column {
- d->secondaryDescription,
- d->pluginStatus,
- d->installButton,
+ m_secondaryContent,
+ m_pluginStatus,
},
noMargin, spacing(0),
- }.attachTo(d->secondaryDescriptionWidget);
+ }.attachTo(m_secondaryDescriptionWidget);
Row {
WelcomePageHelpers::createRule(Qt::Vertical),
Row {
- d->primaryDescription,
- noMargin,
+ Column {
+ Column {
+ m_headingWidget,
+ customMargins(SpacingTokens::ExVPaddingGapXl, SpacingTokens::ExVPaddingGapXl,
+ SpacingTokens::ExVPaddingGapXl, SpacingTokens::ExVPaddingGapXl),
+ },
+ m_primaryContent,
+ },
},
- d->secondaryDescriptionWidget,
+ m_secondaryDescriptionWidget,
noMargin, spacing(0),
}.attachTo(descriptionColumns);
Row {
- Space(StyleHelper::SpacingTokens::ExVPaddingGapXl),
- d->leftColumn,
+ Space(SpacingTokens::ExVPaddingGapXl),
+ m_extensionBrowser,
descriptionColumns,
noMargin, spacing(0),
}.attachTo(this);
WelcomePageHelpers::setBackgroundColor(this, Theme::Token_Background_Default);
- connect(d->leftColumn, &ExtensionsBrowser::itemSelected,
+ connect(m_extensionBrowser, &ExtensionsBrowser::itemSelected,
this, &ExtensionManagerWidget::updateView);
connect(this, &ResizeSignallingWidget::resized, this, [this](const QSize &size) {
- const int intendedLeftColumnWidth = size.width() - 580;
- d->leftColumn->adjustToWidth(intendedLeftColumnWidth);
+ const int intendedBrowserColumnWidth = size.width() - 580;
+ m_extensionBrowser->adjustToWidth(intendedBrowserColumnWidth);
const bool secondaryDescriptionVisible = size.width() > 970;
const int secondaryDescriptionWidth = secondaryDescriptionVisible ? 264 : 0;
- d->secondaryDescriptionWidget->setWidth(secondaryDescriptionWidth);
+ m_secondaryDescriptionWidget->setWidth(secondaryDescriptionWidth);
});
- connect(d->installButton, &QAbstractButton::pressed, this, [this]() {
- fetchAndInstallPlugin(QUrl::fromUserInput(d->currentItemPlugins.constFirst().second));
+ connect(m_headingWidget, &HeadingWidget::pluginInstallationRequested, this, [this](){
+ fetchAndInstallPlugin(QUrl::fromUserInput(m_currentItemPlugins.constFirst().second));
});
- updateView({});
-}
+ connect(m_tags, &TagList::tagSelected, m_extensionBrowser, &ExtensionsBrowser::setFilter);
+ connect(m_headingWidget, &HeadingWidget::vendorClicked,
+ m_extensionBrowser, &ExtensionsBrowser::setFilter);
-ExtensionManagerWidget::~ExtensionManagerWidget()
-{
- delete d;
+ updateView({});
}
void ExtensionManagerWidget::updateView(const QModelIndex ¤t)
{
- const QString h5Css =
- StyleHelper::fontToCssProperties(StyleHelper::uiFont(StyleHelper::UiElementH5))
- + "; margin-top: 0px;";
- const QString h6Css =
- StyleHelper::fontToCssProperties(StyleHelper::uiFont(StyleHelper::UiElementH6))
- + "; margin-top: 28px;";
- const QString h6CapitalCss =
- StyleHelper::fontToCssProperties(StyleHelper::uiFont(StyleHelper::UiElementH6Capital))
- + QString::fromLatin1("; margin-top: 0px; color: %1;")
- .arg(creatorColor(Theme::Token_Text_Muted).name());
- const QString bodyStyle = QString::fromLatin1("color: %1; background-color: %2; "
- "margin-left: %3px; margin-right: %3px;")
- .arg(creatorColor(Theme::Token_Text_Default).name())
- .arg(creatorColor(Theme::Token_Background_Muted).name())
- .arg(StyleHelper::SpacingTokens::ExVPaddingGapXl);
- const QString htmlStart = QString(R"(
-
-
- )").arg(bodyStyle);
- const QString htmlEnd = QString(R"(
-
- )");
+ m_headingWidget->update(current);
- if (!current.isValid()) {
- const QString emptyHtml = htmlStart + htmlEnd;
- d->primaryDescription->setText(emptyHtml);
- d->secondaryDescription->setText(emptyHtml);
+ const bool showContent = current.isValid();
+ m_primaryContent->setVisible(showContent);
+ m_secondaryContent->setVisible(showContent);
+ m_headingWidget->setVisible(showContent);
+ m_pluginStatus->setVisible(showContent);
+ if (!showContent)
return;
- }
- d->currentItemName = current.data().toString();
+ m_currentItemName = current.data().toString();
const bool isPack = current.data(RoleItemType) == ItemTypePack;
- d->pluginStatus->setPluginName(isPack ? QString() : d->currentItemName);
- const bool isRemotePlugin = !(isPack || ExtensionsModel::pluginSpecForName(d->currentItemName));
- d->currentItemPlugins = current.data(RolePlugins).value();
- d->installButton->setVisible(isRemotePlugin && !d->currentItemPlugins.empty());
- if (!d->currentItemPlugins.empty())
- d->installButton->setToolTip(d->currentItemPlugins.constFirst().second);
+ m_pluginStatus->setPluginName(isPack ? QString() : m_currentItemName);
+ m_currentItemPlugins = current.data(RolePlugins).value();
+
+ auto toContentParagraph = [](const QString &text) {
+ const QString pHtml = QString::fromLatin1("%2
")
+ .arg(contentTF.lineHeight()).arg(text);
+ return pHtml;
+ };
{
- QString description = htmlStart;
-
- QString descriptionHtml;
- {
- const TextData textData = current.data(RoleDescriptionText).value();
+ const TextData textData = current.data(RoleDescriptionText).value();
+ const bool hasDescription = !textData.isEmpty();
+ if (hasDescription) {
+ const QString headerCssTemplate =
+ ";margin-top:%1;margin-bottom:%2;padding-top:0;padding-bottom:0;";
+ const QString h4Css = fontToCssProperties(uiFont(UiElementH4))
+ + headerCssTemplate.arg(0).arg(SpacingTokens::VGapL);
+ const QString h5Css = fontToCssProperties(uiFont(UiElementH5))
+ + headerCssTemplate.arg(SpacingTokens::ExVPaddingGapXl)
+ .arg(SpacingTokens::VGapL);
+ QString descriptionHtml;
for (const TextData::Type &text : textData) {
if (text.second.isEmpty())
continue;
const QString paragraph =
- QString::fromLatin1("%2
%3
")
- .arg(descriptionHtml.isEmpty() ? h5Css : h6Css)
+ QString::fromLatin1("%2
%3")
+ .arg(descriptionHtml.isEmpty() ? h4Css : h5Css)
.arg(text.first)
- .arg(text.second.join("
"));
+ .arg(toContentParagraph(text.second.join("
")));
descriptionHtml.append(paragraph);
}
+ descriptionHtml.prepend(QString::fromLatin1("")
+ .arg(creatorColor(Theme::Token_Text_Default).name()));
+ descriptionHtml.append("");
+ m_description->setText(descriptionHtml);
}
- description.append(descriptionHtml);
+ m_description->setVisible(hasDescription);
- description.append(QString::fromLatin1("%2
")
- .arg(h6Css)
- .arg(Tr::tr("More information")));
const LinksData linksData = current.data(RoleDescriptionLinks).value();
- if (!linksData.isEmpty()) {
+ const bool hasLinks = !linksData.isEmpty();
+ if (hasLinks) {
QString linksHtml;
const QStringList links = transform(linksData, [](const LinksData::Type &link) {
const QString anchor = link.first.isEmpty() ? link.second : link.first;
- return QString::fromLatin1("%2 >")
- .arg(link.second).arg(anchor);
+ return QString::fromLatin1(R"(%3 >)")
+ .arg(link.second)
+ .arg(creatorColor(Theme::Token_Text_Accent).name())
+ .arg(anchor);
});
linksHtml = links.join("
");
- description.append(QString::fromLatin1("%1
").arg(linksHtml));
+ m_links->setText(toContentParagraph(linksHtml));
}
+ m_linksTitle->setVisible(hasLinks);
+ m_links->setVisible(hasLinks);
+ m_imgTaskTreeRunner.reset();
+ m_imageMovie.stop();
+ m_imageDataBuffer.close();
+ m_image->clear();
const ImagesData imagesData = current.data(RoleDescriptionImages).value();
- if (!imagesData.isEmpty()) {
- const QString examplesBoxCss =
- QString::fromLatin1("height: 168px; background-color: %1; ")
- .arg(creatorColor(Theme::Token_Background_Default).name());
- description.append(QString(R"(
-
- %2
-
-
- TODO: Load imagea asynchronously, and show them in a QLabel.
- Also Use QMovie for animated images.
-
-
- )").arg(h6CapitalCss)
- .arg(Tr::tr("Examples"))
- .arg(examplesBoxCss));
+ const bool hasImages = !imagesData.isEmpty();
+ if (hasImages) {
+ const ImagesData::Type &image = imagesData.constFirst(); // Only show one image
+ m_imageTitle->setText(image.first);
+ fetchAndDisplayImage(image.second);
}
-
- // Library details vanished from the Figma designs. The data is available, though.
- const bool showDetails = false;
- if (showDetails) {
- const QString captionStrongCss = StyleHelper::fontToCssProperties(
- StyleHelper::uiFont(StyleHelper::UiElementCaptionStrong));
- const QLocale locale;
- const uint size = current.data(RoleSize).toUInt();
- const QString sizeFmt = locale.formattedDataSize(size);
- const FilePath location = FilePath::fromVariant(current.data(RoleLocation));
- const QString version = current.data(RoleVersion).toString();
- description.append(QString(R"(
- %2
-
-
- | %4 | %5 |
- | %6 | %7 |
- )").arg(h6Css)
- .arg(Tr::tr("Extension library details"))
- .arg(captionStrongCss)
- .arg(Tr::tr("Size"))
- .arg(sizeFmt)
- .arg(Tr::tr("Version"))
- .arg(version));
- if (!location.isEmpty()) {
- const QString locationFmt =
- HostOsInfo::isWindowsHost() ? location.toUserOutput()
- : location.withTildeHomePath();
- description.append(QString(R"(
- | %1 | %2 |
- )").arg(Tr::tr("Location"))
- .arg(locationFmt));
- }
- description.append(QString(R"(
-
-
- )"));
- }
-
- description.append(htmlEnd);
- d->primaryDescription->setText(description);
+ m_imageTitle->setVisible(hasImages);
+ m_image->setVisible(hasImages);
}
{
- QString description = htmlStart;
-
- description.append(QString(R"(
- %2
- )").arg(h6CapitalCss)
- .arg(Tr::tr("Extension details")));
-
const QStringList tags = current.data(RoleTags).toStringList();
- if (!tags.isEmpty()) {
- const QString tagTemplate = QString(R"(
- %2 |
- )").arg(creatorColor(Theme::Token_Stroke_Subtle).name());
- const QStringList tagsFmt = transform(tags, [&tagTemplate](const QString &tag) {
- return tagTemplate.arg(tag);
- });
- description.append(QString(R"(
- %2
- %3
- )").arg(h6Css)
- .arg(Tr::tr("Related tags"))
- .arg(tagsFmt.join(" ")));
- }
+ m_tags->setTags(tags);
+ const bool hasTags = !tags.isEmpty();
+ m_tagsTitle->setVisible(hasTags);
+ m_tags->setVisible(hasTags);
const QStringList platforms = current.data(RolePlatforms).toStringList();
- if (!platforms.isEmpty()) {
- description.append(QString(R"(
- %2
- %3
- )").arg(h6Css)
- .arg(Tr::tr("Platforms"))
- .arg(platforms.join("
")));
- }
+ const bool hasPlatforms = !platforms.isEmpty();
+ if (hasPlatforms)
+ m_platforms->setText(toContentParagraph(platforms.join("
")));
+ m_platformsTitle->setVisible(hasPlatforms);
+ m_platforms->setVisible(hasPlatforms);
const QStringList dependencies = current.data(RoleDependencies).toStringList();
- if (!dependencies.isEmpty()) {
- const QString dependenciesFmt = dependencies.join("
");
- description.append(QString(R"(
- %2
- %3
- )").arg(h6Css)
- .arg(Tr::tr("Dependencies"))
- .arg(dependenciesFmt));
- }
+ const bool hasDependencies = !dependencies.isEmpty();
+ if (hasDependencies)
+ m_dependencies->setText(toContentParagraph(dependencies.join("
")));
+ m_dependenciesTitle->setVisible(hasDependencies);
+ m_dependencies->setVisible(hasDependencies);
- if (isPack) {
- const PluginsData plugins = current.data(RolePlugins).value();
+ const PluginsData plugins = current.data(RolePlugins).value();
+ const bool hasExtensions = isPack && !plugins.isEmpty();
+ if (hasExtensions) {
const QStringList extensions = transform(plugins, &QPair::first);
- const QString extensionsFmt = extensions.join("
");
- description.append(QString(R"(
- %2
- %3
- )").arg(h6Css)
- .arg(Tr::tr("Extensions in pack"))
- .arg(extensionsFmt));
+ m_packExtensions->setText(toContentParagraph(extensions.join("
")));
}
-
- description.append(htmlEnd);
- d->secondaryDescription->setText(description);
+ m_packExtensionsTitle->setVisible(hasExtensions);
+ m_packExtensions->setVisible(hasExtensions);
}
}
@@ -419,9 +667,9 @@ void ExtensionManagerWidget::fetchAndInstallPlugin(const QUrl &url)
struct StorageStruct
{
StorageStruct() {
- progressDialog.reset(new QProgressDialog(Tr::tr("Downloading Plugin..."),
- Tr::tr("Cancel"), 0, 0,
- ICore::dialogParent()));
+ progressDialog.reset(new QProgressDialog(
+ Tr::tr("Downloading..."), Tr::tr("Cancel"), 0, 0, ICore::dialogParent()));
+ progressDialog->setWindowTitle(Tr::tr("Download Extension"));
progressDialog->setWindowModality(Qt::ApplicationModal);
progressDialog->setFixedSize(progressDialog->sizeHint());
progressDialog->setAutoClose(false);
@@ -446,7 +694,7 @@ void ExtensionManagerWidget::fetchAndInstallPlugin(const QUrl &url)
QMessageBox::warning(
ICore::dialogParent(),
Tr::tr("Download Error"),
- Tr::tr("Could not download Plugin") + "\n\n" + storage->url.toString() + "\n\n"
+ Tr::tr("Cannot download extension") + "\n\n" + storage->url.toString() + "\n\n"
+ Tr::tr("Code: %1.").arg(query.reply()->error()));
}
};
@@ -469,7 +717,61 @@ void ExtensionManagerWidget::fetchAndInstallPlugin(const QUrl &url)
onGroupDone(onPluginInstallation),
};
- d->taskTreeRunner.start(group);
+ m_dlTaskTreeRunner.start(group);
+}
+
+void ExtensionManagerWidget::fetchAndDisplayImage(const QUrl &url)
+{
+ using namespace Tasking;
+
+ struct StorageStruct
+ {
+ QByteArray imageData;
+ QUrl url;
+ };
+ Storage storage;
+
+ const auto onFetchSetup = [url, storage](NetworkQuery &query) {
+ storage->url = url;
+ query.setRequest(QNetworkRequest(url));
+ query.setNetworkAccessManager(NetworkAccessManager::instance());
+ };
+ const auto onFetchDone = [storage](const NetworkQuery &query, DoneWith result) {
+ if (result == DoneWith::Success)
+ storage->imageData = query.reply()->readAll();
+ };
+
+ const auto onShowImage = [storage, this]() {
+ if (storage->imageData.isEmpty())
+ return;
+ m_imageDataBuffer.setData(storage->imageData);
+ if (!m_imageDataBuffer.open(QIODevice::ReadOnly))
+ return;
+ QImageReader reader(&m_imageDataBuffer);
+ const bool animated = reader.supportsAnimation();
+ if (animated) {
+ m_image->setMovie(&m_imageMovie);
+ m_imageMovie.start();
+ } else {
+ const QPixmap pixmap = QPixmap::fromImage(reader.read());
+ m_image->setPixmap(pixmap);
+ }
+ };
+
+ Group group{
+ storage,
+ NetworkQueryTask{onFetchSetup, onFetchDone},
+ onGroupDone(onShowImage),
+ };
+
+ m_imgTaskTreeRunner.start(group);
+}
+
+QWidget *createExtensionManagerWidget()
+{
+ return new ExtensionManagerWidget;
}
} // ExtensionManager::Internal
+
+#include "extensionmanagerwidget.moc"
diff --git a/src/plugins/extensionmanager/extensionmanagerwidget.h b/src/plugins/extensionmanager/extensionmanagerwidget.h
index aeaad3db07c..721f5adc956 100644
--- a/src/plugins/extensionmanager/extensionmanagerwidget.h
+++ b/src/plugins/extensionmanager/extensionmanagerwidget.h
@@ -1,21 +1,10 @@
// Copyright (C) 2023 The Qt Company Ltd.
// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only WITH Qt-GPL-exception-1.0
-#include
+#include
namespace ExtensionManager::Internal {
-class ExtensionManagerWidget final : public Core::ResizeSignallingWidget
-{
-public:
- explicit ExtensionManagerWidget(QWidget *parent = nullptr);
- ~ExtensionManagerWidget();
-
-private:
- void updateView(const QModelIndex ¤t);
- void fetchAndInstallPlugin(const QUrl &url);
-
- class ExtensionManagerWidgetPrivate *d = nullptr;
-};
+QWidget *createExtensionManagerWidget();
} // ExtensionManager::Internal
diff --git a/src/plugins/extensionmanager/extensionsbrowser.cpp b/src/plugins/extensionmanager/extensionsbrowser.cpp
index ccf814cd7c8..d88e7f41d3e 100644
--- a/src/plugins/extensionmanager/extensionsbrowser.cpp
+++ b/src/plugins/extensionmanager/extensionsbrowser.cpp
@@ -22,10 +22,12 @@
#include
#include
+#include
#include
#include
#include
+#include
#include
#include
#include
@@ -51,9 +53,9 @@ namespace ExtensionManager::Internal {
Q_LOGGING_CATEGORY(browserLog, "qtc.extensionmanager.browser", QtWarningMsg)
-constexpr int gapSize = ExVPaddingGapXl;
+constexpr int gapSize = HGapL;
constexpr int itemWidth = 330;
-constexpr int cellWidth = itemWidth + HPaddingL;
+constexpr int cellWidth = itemWidth + gapSize;
class ExtensionItemDelegate : public QItemDelegate
{
@@ -79,25 +81,25 @@ public:
void paint(QPainter *painter, const QStyleOptionViewItem &option, const QModelIndex &index)
const override
{
- // +---------------+-------+---------------+----------------------------------------------------------------------+---------------+-----------+
- // | | | | (ExPaddingGapL) | | |
- // | | | +-------------------------------------------------------------+--------+ | |
- // | | | | || | |
- // | | | +-------------------------------------------------------------+--------+ | |
- // | | | | (VGapXxs) | | |
- // | | | +--------+--------+--------------+--------+--------+---------+---------+ | |
- // |(ExPaddingGapL)| |(ExPaddingGapL)||(HGapXs)|(h16)|(HGapXs)||(HGapXxs)||(ExPaddingGapL)|(HPaddingL)|
- // | |(50x50)| +--------+--------+--------------+--------+--------+---------+---------+ | |
- // | | | | (VGapXxs) | | |
- // | | | +----------------------------------------------------------------------+ | |
- // | | | | | | |
- // | | | +----------------------------------------------------------------------+ | |
- // | | | | (ExPaddingGapL) | | |
- // +---------------+-------+---------------+----------------------------------------------------------------------+---------------+-----------+
- // | (ExVPaddingGapXl) |
- // +------------------------------------------------------------------------------------------------------------------------------------------+
+ // +---------------+-------+---------------+----------------------------------------------------------------------+---------------+---------+
+ // | | | | (ExPaddingGapL) | | |
+ // | | | +-------------------------------------------------------------+--------+ | |
+ // | | | | || | |
+ // | | | +-------------------------------------------------------------+--------+ | |
+ // | | | | (VGapXxs) | | |
+ // | | | +--------+--------+--------------+--------+--------+---------+---------+ | |
+ // |(ExPaddingGapL)| |(ExPaddingGapL)||(HGapXs)|(h16)|(HGapXs)||(HGapXxs)||(ExPaddingGapL)|(gapSize)|
+ // | |(50x50)| +--------+--------+--------------+--------+--------+---------+---------+ | |
+ // | | | | (VGapXxs) | | |
+ // | | | +----------------------------------------------------------------------+ | |
+ // | | | | | | |
+ // | | | +----------------------------------------------------------------------+ | |
+ // | | | | (ExPaddingGapL) | | |
+ // +---------------+-------+---------------+----------------------------------------------------------------------+---------------+---------+
+ // | (gapSize) |
+ // +----------------------------------------------------------------------------------------------------------------------------------------+
- const QRect bgRGlobal = option.rect.adjusted(0, 0, -HPaddingL, -gapSize);
+ const QRect bgRGlobal = option.rect.adjusted(0, 0, -gapSize, -gapSize);
const QRect bgR = bgRGlobal.translated(-option.rect.topLeft());
const int middleColumnW = bgR.width() - ExPaddingGapL - iconBgS.width() - ExPaddingGapL
@@ -141,10 +143,7 @@ public:
}
{
QLinearGradient gradient(iconBgR.topRight(), iconBgR.bottomLeft());
- const QColor startColor = creatorColor(Utils::Theme::Token_Gradient01_Start);
- const QColor endColor = creatorColor(Utils::Theme::Token_Gradient01_End);
- gradient.setColorAt(0, startColor);
- gradient.setColorAt(1, endColor);
+ gradient.setStops(iconGradientStops(index));
constexpr int iconRectRounding = 4;
drawCardBackground(painter, iconBgR, gradient, Qt::NoPen, iconRectRounding);
@@ -248,17 +247,44 @@ public:
}
};
+class SortFilterProxyModel : public QSortFilterProxyModel
+{
+public:
+ SortFilterProxyModel(QObject *parent = nullptr);
+
+protected:
+ bool lessThan(const QModelIndex &left, const QModelIndex &right) const override;
+};
+
+SortFilterProxyModel::SortFilterProxyModel(QObject *parent)
+ : QSortFilterProxyModel(parent)
+{
+}
+
+bool SortFilterProxyModel::lessThan(const QModelIndex &left, const QModelIndex &right) const
+{
+ const ItemType leftType = left.data(RoleItemType).value();
+ const ItemType rightType = right.data(RoleItemType).value();
+ if (leftType != rightType)
+ return leftType < rightType;
+
+ const QString leftName = left.data(RoleName).toString();
+ const QString rightName = right.data(RoleName).toString();
+ return leftName < rightName;
+}
+
class ExtensionsBrowserPrivate
{
public:
+ bool dataFetched = false;
ExtensionsModel *model;
QLineEdit *searchBox;
- QAbstractButton *updateButton;
QListView *extensionsView;
QItemSelectionModel *selectionModel = nullptr;
- QSortFilterProxyModel *filterProxyModel;
+ SortFilterProxyModel *filterProxyModel;
int columnsCount = 2;
Tasking::TaskTreeRunner taskTreeRunner;
+ SpinnerSolution::Spinner *m_spinner;
};
ExtensionsBrowser::ExtensionsBrowser(QWidget *parent)
@@ -267,16 +293,17 @@ ExtensionsBrowser::ExtensionsBrowser(QWidget *parent)
{
setSizePolicy(QSizePolicy::Maximum, QSizePolicy::Preferred);
- auto manageLabel = new QLabel(Tr::tr("Manage Extensions"));
- manageLabel->setFont(uiFont(UiElementH1));
+ static const TextFormat titleTF
+ {Theme::Token_Text_Default, UiElementH2};
+ QLabel *titleLabel = tfLabel(titleTF);
+ titleLabel->setText(Tr::tr("Manage Extensions"));
d->searchBox = new SearchBox;
- d->searchBox->setFixedWidth(itemWidth);
- d->updateButton = new Button(Tr::tr("Install..."), Button::MediumPrimary);
+ d->searchBox->setPlaceholderText(Tr::tr("Search"));
d->model = new ExtensionsModel(this);
- d->filterProxyModel = new QSortFilterProxyModel(this);
+ d->filterProxyModel = new SortFilterProxyModel(this);
d->filterProxyModel->setFilterCaseSensitivity(Qt::CaseInsensitive);
d->filterProxyModel->setFilterRole(RoleSearchText);
d->filterProxyModel->setSortRole(RoleItemType);
@@ -294,11 +321,16 @@ ExtensionsBrowser::ExtensionsBrowser(QWidget *parent)
using namespace Layouting;
Column {
- Space(15),
- manageLabel,
- Space(15),
- Row { d->searchBox, st, d->updateButton, Space(extraListViewWidth() + gapSize) },
- Space(gapSize),
+ Column {
+ titleLabel,
+ customMargins(0, VPaddingM, 0, VPaddingM),
+ },
+ Row {
+ d->searchBox,
+ spacing(gapSize),
+ customMargins(0, VPaddingM, extraListViewWidth() + gapSize, VPaddingM),
+ },
+ Space(ExPaddingGapL),
d->extensionsView,
noMargin, spacing(0),
}.attachTo(this);
@@ -308,6 +340,8 @@ ExtensionsBrowser::ExtensionsBrowser(QWidget *parent)
WelcomePageHelpers::setBackgroundColor(d->extensionsView->viewport(),
Theme::Token_Background_Default);
+ d->m_spinner = new SpinnerSolution::Spinner(SpinnerSolution::SpinnerSize::Large, this);
+
auto updateModel = [this] {
d->filterProxyModel->sort(0);
@@ -320,12 +354,7 @@ ExtensionsBrowser::ExtensionsBrowser(QWidget *parent)
}
};
- connect(d->updateButton, &QAbstractButton::pressed, this, []() {
- executePluginInstallWizard();
- });
connect(PluginManager::instance(), &PluginManager::pluginsChanged, this, updateModel);
- connect(PluginManager::instance(), &PluginManager::initializationDone,
- this, &ExtensionsBrowser::fetchExtensions);
connect(d->searchBox, &QLineEdit::textChanged,
d->filterProxyModel, &QSortFilterProxyModel::setFilterWildcard);
}
@@ -335,11 +364,15 @@ ExtensionsBrowser::~ExtensionsBrowser()
delete d;
}
+void ExtensionsBrowser::setFilter(const QString &filter)
+{
+ d->searchBox->setText(filter);
+}
+
void ExtensionsBrowser::adjustToWidth(const int width)
{
const int widthForItems = width - extraListViewWidth();
d->columnsCount = qMax(1, qFloor(widthForItems / cellWidth));
- d->updateButton->setVisible(d->columnsCount > 1);
updateGeometry();
}
@@ -352,40 +385,56 @@ QSize ExtensionsBrowser::sizeHint() const
int ExtensionsBrowser::extraListViewWidth() const
{
// TODO: Investigate "transient" scrollbar, just for this list view.
+ constexpr int extraPadding = qMax(0, ExVPaddingGapXl - gapSize);
return d->extensionsView->style()->pixelMetric(QStyle::PM_ScrollBarExtent)
+ + extraPadding
+ 1; // Needed
}
+void ExtensionsBrowser::showEvent(QShowEvent *event)
+{
+ if (!d->dataFetched) {
+ d->dataFetched = true;
+ fetchExtensions();
+ }
+ QWidget::showEvent(event);
+}
+
void ExtensionsBrowser::fetchExtensions()
{
- // d->model->setExtensionsJson(testData("thirdpartyplugins")); return;
+#ifdef WITH_TESTS
+ // Uncomment for testing with local json data.
+ // Available: "augmentedplugindata", "defaultpacks", "varieddata", "thirdpartyplugins"
+ // d->model->setExtensionsJson(testData("defaultpacks")); return;
+#endif // WITH_TESTS
using namespace Tasking;
- const auto onQuerySetup = [](NetworkQuery &query) {
+ const auto onQuerySetup = [this](NetworkQuery &query) {
const QString host = "https://qc-extensions.qt.io";
const QString url = "%1/api/v1/search?request=";
const QString requestTemplate
= R"({"version":"%1","host_os":"%2","host_os_version":"%3","host_architecture":"%4","page_size":200})";
- const QString request = url.arg(host)
- + requestTemplate
- .arg("2.2") // .arg(QCoreApplication::applicationVersion())
- .arg("macOS") // .arg(QSysInfo::productType())
- .arg("12") // .arg(QSysInfo::productVersion())
- .arg("arm64"); // .arg(QSysInfo::currentCpuArchitecture());
-
+ const QString request = url.arg(host) + requestTemplate
+ .arg(QCoreApplication::applicationVersion())
+ .arg(QSysInfo::productType())
+ .arg(QSysInfo::productVersion())
+ .arg(QSysInfo::currentCpuArchitecture());
query.setRequest(QNetworkRequest(QUrl::fromUserInput(request)));
query.setNetworkAccessManager(NetworkAccessManager::instance());
+ qCDebug(browserLog).noquote() << "Sending request:" << request;
+ d->m_spinner->show();
};
const auto onQueryDone = [this](const NetworkQuery &query, DoneWith result) {
- if (result != DoneWith::Success) {
-#ifdef WITH_TESTS
- d->model->setExtensionsJson(testData("defaultpacks"));
-#endif // WITH_TESTS
- return;
- }
const QByteArray response = query.reply()->readAll();
- d->model->setExtensionsJson(response);
+ qCDebug(browserLog).noquote() << "Got result" << result;
+ if (result == DoneWith::Success) {
+ d->model->setExtensionsJson(response);
+ } else {
+ qCDebug(browserLog).noquote() << response;
+ d->model->setExtensionsJson({});
+ }
+ d->m_spinner->hide();
};
Group group {
@@ -395,4 +444,35 @@ void ExtensionsBrowser::fetchExtensions()
d->taskTreeRunner.start(group);
}
+QLabel *tfLabel(const TextFormat &tf, bool singleLine)
+{
+ QLabel *label = singleLine ? new Utils::ElidingLabel : new QLabel;
+ if (singleLine)
+ label->setFixedHeight(tf.lineHeight());
+ label->setFont(tf.font());
+ label->setAlignment(Qt::Alignment(tf.drawTextFlags));
+
+ QPalette pal = label->palette();
+ pal.setColor(QPalette::WindowText, tf.color());
+ label->setPalette(pal);
+
+ return label;
+}
+
+QGradientStops iconGradientStops(const QModelIndex &index)
+{
+ const PluginSpec *ps = pluginSpecForName(index.data(RoleName).toString());
+ const bool greenGradient = ps != nullptr && ps->isEffectivelyEnabled();
+
+ const QColor startColor = creatorColor(greenGradient ? Theme::Token_Gradient01_Start
+ : Theme::Token_Gradient02_Start);
+ const QColor endColor = creatorColor(greenGradient ? Theme::Token_Gradient01_End
+ : Theme::Token_Gradient02_End);
+ const QGradientStops gradient = {
+ {0, startColor},
+ {1, endColor},
+ };
+ return gradient;
+}
+
} // ExtensionManager::Internal
diff --git a/src/plugins/extensionmanager/extensionsbrowser.h b/src/plugins/extensionmanager/extensionsbrowser.h
index d0467aa2162..4e0b87c5936 100644
--- a/src/plugins/extensionmanager/extensionsbrowser.h
+++ b/src/plugins/extensionmanager/extensionsbrowser.h
@@ -5,6 +5,12 @@
#include
+QT_FORWARD_DECLARE_CLASS(QLabel)
+
+namespace Core::WelcomePageHelpers {
+class TextFormat;
+}
+
namespace ExtensionManager::Internal {
class ExtensionsBrowser final : public QWidget
@@ -15,11 +21,15 @@ public:
ExtensionsBrowser(QWidget *parent = nullptr);
~ExtensionsBrowser();
+ void setFilter(const QString &filter);
+
void adjustToWidth(const int width);
QSize sizeHint() const override;
int extraListViewWidth() const; // Space for scrollbar, etc.
+ void showEvent(QShowEvent *event) override;
+
signals:
void itemSelected(const QModelIndex ¤t, const QModelIndex &previous);
@@ -29,4 +39,7 @@ private:
class ExtensionsBrowserPrivate *d = nullptr;
};
+QLabel *tfLabel(const Core::WelcomePageHelpers::TextFormat &tf, bool singleLine = true);
+QGradientStops iconGradientStops(const QModelIndex &index);
+
} // ExtensionManager::Internal
diff --git a/src/plugins/extensionmanager/extensionsmodel.cpp b/src/plugins/extensionmanager/extensionsmodel.cpp
index 56fcc54ad8b..2500f8f73f6 100644
--- a/src/plugins/extensionmanager/extensionsmodel.cpp
+++ b/src/plugins/extensionmanager/extensionsmodel.cpp
@@ -36,8 +36,8 @@ using Dependencies = QList;
struct Plugin
{
- Dependencies dependencies;
QString copyright;
+ Dependencies dependencies;
bool isInternal = false;
QString name;
QString packageUrl;
@@ -69,23 +69,29 @@ struct Extension {
};
using Extensions = QList;
+static const Dependencies dependenciesFromJson(const QJsonObject &obj)
+{
+ const QJsonArray dependenciesArray = obj.value("Dependencies").toArray();
+ Dependencies dependencies;
+ for (const QJsonValueConstRef &dependencyVal : dependenciesArray) {
+ const QJsonObject dependencyObj = dependencyVal.toObject();
+ const QJsonObject metaDataObj = dependencyObj.value("meta_data").toObject();
+ dependencies.append({
+ .name = metaDataObj.value("Name").toString(),
+ .version = metaDataObj.value("Version").toString(),
+ });
+ }
+
+ return dependencies;
+}
+
static Plugin pluginFromJson(const QJsonObject &obj)
{
const QJsonObject metaDataObj = obj.value("meta_data").toObject();
- const QJsonArray dependenciesArray = metaDataObj.value("Dependencies").toArray();
- Dependencies dependencies;
- for (const QJsonValueConstRef &dependencyVal : dependenciesArray) {
- const QJsonObject dependencyObj = dependencyVal.toObject();
- dependencies.append(Dependency{
- .name = dependencyObj.value("Name").toString(),
- .version = dependencyObj.value("Version").toString(),
- });
- }
-
return {
- .dependencies = dependencies,
.copyright = metaDataObj.value("Copyright").toString(),
+ .dependencies = dependenciesFromJson(metaDataObj),
.isInternal = obj.value("is_internal").toBool(false),
.name = metaDataObj.value("Name").toString(),
.packageUrl = obj.value("url").toString(),
@@ -192,30 +198,80 @@ static Extensions parseExtensionsRepoReply(const QByteArray &jsonData)
return parsedExtensions;
}
+static Extension extensionFromPluginSpec(const PluginSpec *pluginSpec)
+{
+ const Dependencies dependencies = transform(pluginSpec->dependencies(),
+ [](const PluginDependency &pd) -> Dependency {
+ return {
+ .name = pd.name,
+ .version = pd.version,
+ };
+ });
+ const Plugin plugin = {
+ .copyright = pluginSpec->copyright(),
+ .dependencies = dependencies,
+ .name = pluginSpec->name(),
+ .packageUrl = {},
+ .vendor = pluginSpec->vendor(),
+ .version = pluginSpec->version(),
+ };
+
+ const QStringList lines = pluginSpec->description().split('\n', Qt::SkipEmptyParts)
+ + pluginSpec->longDescription().split('\n', Qt::SkipEmptyParts);
+ const TextData text = {{ pluginSpec->name(), lines }};
+ LinksData links;
+ if (const QString url = pluginSpec->url(); !url.isEmpty())
+ links.append({{}, url});
+ const Description description = {
+ .images = {},
+ .links = links,
+ .text = text,
+ };
+
+ const QString platformsPattern = pluginSpec->platformSpecification().pattern();
+ const QStringList platforms = platformsPattern.isEmpty()
+ ? QStringList({"macOS", "Windows", "Linux"})
+ : QStringList(platformsPattern);
+
+ const Extension extension = {
+ .copyright = pluginSpec->copyright(),
+ .description = description,
+ .id = {},
+ .license = pluginSpec->license(),
+ .name = pluginSpec->name(),
+ .platforms = platforms,
+ .plugins = {plugin},
+ .tags = {},
+ .type = ItemTypeExtension,
+ .vendor = pluginSpec->vendor(),
+ .version = pluginSpec->version(),
+ };
+ return extension;
+}
+
class ExtensionsModelPrivate
{
public:
void setExtensions(const Extensions &extensions);
- void removeLocalExtensions();
+ void addUnlistedLocalExtensions();
- Extensions allExtensions; // Original, complete extensions entries
- Extensions absentExtensions; // All packs + plugin extensions that are not (yet) installed
+ Extensions extensions;
};
void ExtensionsModelPrivate::setExtensions(const Extensions &extensions)
{
- allExtensions = extensions;
- removeLocalExtensions();
+ this->extensions = extensions;
+ qCDebug(modelLog) << "Number of extensions from json:" << this->extensions.count();
+ addUnlistedLocalExtensions();
+ qCDebug(modelLog) << "Number of extensions with added local ones:" << this->extensions.count();
}
-void ExtensionsModelPrivate::removeLocalExtensions()
+void ExtensionsModelPrivate::addUnlistedLocalExtensions()
{
- const QStringList installedPlugins = transform(PluginManager::plugins(), &PluginSpec::name);
- absentExtensions.clear();
- for (const Extension &extension : allExtensions) {
- if (extension.type == ItemTypePack || !installedPlugins.contains(extension.name))
- absentExtensions.append(extension);
- }
+ const QStringList listedModelExtensions = transform(extensions, &Extension::name);
+ for (const PluginSpec *plugin : PluginManager::plugins())
+ if (!listedModelExtensions.contains(plugin->name()))
+ extensions.append(extensionFromPluginSpec(plugin));
}
ExtensionsModel::ExtensionsModel(QObject *parent)
@@ -231,66 +287,7 @@ ExtensionsModel::~ExtensionsModel()
int ExtensionsModel::rowCount([[maybe_unused]] const QModelIndex &parent) const
{
- const int remoteExtnsionsCount = d->absentExtensions.count();
- const int installedPluginsCount = PluginManager::plugins().count();
- return remoteExtnsionsCount + installedPluginsCount;
-}
-
-static QVariant dataFromPluginSpec(const PluginSpec *pluginSpec, int role)
-{
- switch (role) {
- case Qt::DisplayRole:
- case RoleName:
- return pluginSpec->name();
- case RoleCopyright:
- return pluginSpec->copyright();
- case RoleDependencies: {
- QStringList dependencies = transform(pluginSpec->dependencies(),
- &PluginDependency::toString);
- dependencies.sort();
- return dependencies;
- }
- case RoleDescriptionImages:
- break;
- case RoleDescriptionLinks: {
- const QString url = pluginSpec->url();
- if (!url.isEmpty()) {
- const LinksData links = {{{}, url}};
- return QVariant::fromValue(links);
- }
- break;
- }
- case RoleDescriptionText: {
- QStringList lines = pluginSpec->description().split('\n', Qt::SkipEmptyParts);
- lines.append(pluginSpec->longDescription().split('\n', Qt::SkipEmptyParts));
- const TextData text = {{ pluginSpec->name(), lines }};
- return QVariant::fromValue(text);
- }
- case RoleItemType:
- return ItemTypeExtension;
- case RoleLicense:
- return pluginSpec->license();
- case RoleLocation:
- return pluginSpec->filePath().toVariant();
- case RolePlatforms: {
- const QString pattern = pluginSpec->platformSpecification().pattern();
- const QStringList platforms = pattern.isEmpty()
- ? QStringList({"macOS", "Windows", "Linux"})
- : QStringList(pattern);
- return platforms;
- }
- case RoleSize:
- return pluginSpec->filePath().fileSize();
- case RoleTags:
- break;
- case RoleVendor:
- return pluginSpec->vendor();
- case RoleVersion:
- return pluginSpec->version();
- default:
- break;
- }
- return {};
+ return d->extensions.count();
}
static QStringList dependenciesFromExtension(const Extension &extension)
@@ -299,7 +296,7 @@ static QStringList dependenciesFromExtension(const Extension &extension)
for (const Plugin &plugin : extension.plugins) {
for (const Dependency &dependency : plugin.dependencies) {
const QString withVersion = QString::fromLatin1("%1 (%2)").arg(dependency.name)
- .arg(dependency.version);
+ .arg(dependency.version);
dependencies.append(withVersion);
}
}
@@ -371,27 +368,18 @@ QVariant ExtensionsModel::data(const QModelIndex &index, int role) const
if (role == RoleSearchText)
return searchText(index);
- const bool itemIsLocalPlugin = index.row() >= d->absentExtensions.count();
- if (itemIsLocalPlugin) {
- const PluginSpecs &pluginSpecs = PluginManager::plugins();
- const int pluginIndex = index.row() - d->absentExtensions.count();
- QTC_ASSERT(pluginIndex >= 0 && pluginIndex <= pluginSpecs.size(), return {});
- const PluginSpec *plugin = pluginSpecs.at(pluginIndex);
- return dataFromPluginSpec(plugin, role);
- } else {
- const Extension &extension = d->absentExtensions.at(index.row());
- const QVariant extensionData = dataFromExtension(extension, role);
-
- // If data is unavailable, retrieve it from the first contained plugin
- if (extensionData.isNull() && !extension.plugins.isEmpty()) {
- const PluginSpec *pluginSpec = ExtensionsModel::pluginSpecForName(
- extension.plugins.constFirst().name);
- if (pluginSpec)
- return dataFromPluginSpec(pluginSpec, role);
- }
- return extensionData;
+ const Extension &extension = d->extensions.at(index.row());
+ const QVariant extensionData = dataFromExtension(extension, role);
+ // If data is unavailable, retrieve it from the first contained plugin
+ if (extensionData.isNull() && !extension.plugins.isEmpty()) {
+ const QString firstPluginName = extension.plugins.constFirst().name;
+ const Extension firstPluginExtension =
+ findOrDefault(d->extensions, Utils::equal(&Extension::name, firstPluginName));
+ if (firstPluginExtension.name.isEmpty())
+ return {};
+ return dataFromExtension(firstPluginExtension, role);
}
- return {};
+ return extensionData;
}
void ExtensionsModel::setExtensionsJson(const QByteArray &json)
@@ -402,7 +390,7 @@ void ExtensionsModel::setExtensionsJson(const QByteArray &json)
endResetModel();
}
-PluginSpec *ExtensionsModel::pluginSpecForName(const QString &pluginName)
+PluginSpec *pluginSpecForName(const QString &pluginName)
{
return findOrDefault(PluginManager::plugins(), equal(&PluginSpec::name, pluginName));
}
diff --git a/src/plugins/extensionmanager/extensionsmodel.h b/src/plugins/extensionmanager/extensionsmodel.h
index 1fc86d3afde..68e7f9ea846 100644
--- a/src/plugins/extensionmanager/extensionsmodel.h
+++ b/src/plugins/extensionmanager/extensionsmodel.h
@@ -54,12 +54,13 @@ public:
QVariant data(const QModelIndex &index, int role) const;
void setExtensionsJson(const QByteArray &json);
- static ExtensionSystem::PluginSpec *pluginSpecForName(const QString &pluginName);
private:
class ExtensionsModelPrivate *d = nullptr;
};
+ExtensionSystem::PluginSpec *pluginSpecForName(const QString &pluginName);
+
#ifdef WITH_TESTS
QObject *createExtensionsModelTest();
#endif
diff --git a/src/plugins/extensionmanager/images/extensionbig.png b/src/plugins/extensionmanager/images/extensionbig.png
new file mode 100644
index 00000000000..6600ff9fb06
Binary files /dev/null and b/src/plugins/extensionmanager/images/extensionbig.png differ
diff --git a/src/plugins/extensionmanager/images/extensionbig@2x.png b/src/plugins/extensionmanager/images/extensionbig@2x.png
new file mode 100644
index 00000000000..f44905ebc56
Binary files /dev/null and b/src/plugins/extensionmanager/images/extensionbig@2x.png differ
diff --git a/src/plugins/extensionmanager/images/packbig.png b/src/plugins/extensionmanager/images/packbig.png
new file mode 100644
index 00000000000..b69acad9770
Binary files /dev/null and b/src/plugins/extensionmanager/images/packbig.png differ
diff --git a/src/plugins/extensionmanager/images/packbig@2x.png b/src/plugins/extensionmanager/images/packbig@2x.png
new file mode 100644
index 00000000000..7fb684a9c2a
Binary files /dev/null and b/src/plugins/extensionmanager/images/packbig@2x.png differ
diff --git a/src/plugins/extensionmanager/testdata/augmentedplugindata.json b/src/plugins/extensionmanager/testdata/augmentedplugindata.json
new file mode 100644
index 00000000000..32efe15b708
--- /dev/null
+++ b/src/plugins/extensionmanager/testdata/augmentedplugindata.json
@@ -0,0 +1,71 @@
+{
+ "items": [
+ {
+ "name": "ScreenRecorder",
+ "description": {
+ "paragraphs": [
+ {
+ "header": "Screen Recorder plugin",
+ "text": [
+ "With FFmpeg, you can record your screens and save the recordings as animated images or videos.",
+ "To record screens:",
+ "",
+ "- Select Tools > Screen Recording.",
+ "- Select to select the screen to record from and to set the recorded screen area.",
+ "- Select to start recording.",
+ "- Select when you are done recording.",
+ "- Select Crop and Trim to edit the recording.",
+ "- Select Export to save the recording as an animated image or a video."
+ ]
+ },
+ {
+ "header": "Set the screen and area to record",
+ "text": [
+ "Set the screen and the area to record in the Screen Recording Options dialog.",
+ "To select a screen and area:",
+ "",
+ "- In Display, select the display to record.",
+ "- In Recorded screen area, drag the guides to set the x and y coordinates of the starting point for the recording area, as well as the width and height of the area.",
+ "- Select OK to return to the Record Screen dialog."
+ ]
+ }
+ ],
+ "images": [
+ {
+ "image_label": "Create animated imges like this",
+ "url": "https://bugreports.qt.io/secure/attachment/156058/156058_DragAndCopyOnLinux.gif"
+ }
+ ],
+ "links": [
+ {
+ "link_text": "Documentation",
+ "url": "https://doc.qt.io/qtcreator/creator-how-to-record-screens.html"
+ },
+ {
+ "link_text": "Homepage",
+ "url": "https://www.qt.io/"
+ }
+ ]
+ },
+ "is_pack": false,
+ "plugins": [
+ {
+ "meta_data": {
+ "Name": "ScreenRecorder",
+ "Dependencies": [
+ {
+ "meta_data": {
+ "Name": "Core",
+ "Version": "13.0.2"
+ }
+ }
+ ],
+ "Version": "13.0.2"
+ }
+ }
+ ],
+ "tags": [ "Utility", "Docs" ],
+ "vendor": "The Qt Company Ltd"
+ }
+ ]
+}
diff --git a/src/plugins/extensionmanager/testdata/defaultpacks.json b/src/plugins/extensionmanager/testdata/defaultpacks.json
index 0323b08d27e..d26b0a42c60 100644
--- a/src/plugins/extensionmanager/testdata/defaultpacks.json
+++ b/src/plugins/extensionmanager/testdata/defaultpacks.json
@@ -121,41 +121,6 @@
"plugins": [
{ "meta_data": { "Name": "Designer" } }
]
- },
-
- {
- "name": "SpellChecker",
- "tags": [ "Editor" ],
- "platforms": [ "macOS", "Windows", "Linux" ],
- "license": "os",
- "is_pack": false,
- "description": {
- "paragraphs": [
- {
- "text": [
- "Spellcheck comments in source files."
- ],
- "header": "Get started"
- }
- ],
- "links": [
- {
- "url": "https://github.com/CJCombrink/SpellChecker-Plugin",
- "link_text": "GitHub page"
- }
- ]
- },
- "plugins": [
- {
- "meta_data": {
- "Name": "SpellChecker",
- "Copyright": "(C) 2015 - 2024 Carel Combrink"
- },
- "url": "https://github.com/CJCombrink/SpellChecker-Plugin/releases/download/v3.6.0/SpellChecker-Plugin_QtC13.0.0_macos_x64.tar.gz"
- }
- ],
- "vendor": "Carel Combrink",
- "copyright": "(C) 2015 - 2024 Carel Combrink"
}
]
}
diff --git a/src/plugins/extensionmanager/testdata/varieddata.json b/src/plugins/extensionmanager/testdata/varieddata.json
new file mode 100644
index 00000000000..245d08ad844
--- /dev/null
+++ b/src/plugins/extensionmanager/testdata/varieddata.json
@@ -0,0 +1,76 @@
+{
+ "items": [
+ {
+ "name": "Few tags",
+ "tags": [ "Tag one", "Tag two"]
+ },
+
+ {
+ "name": "Many tags",
+ "tags": [ "Tag_01", "Tag_02", "Tag_03", "Tag_04", "Tag_05", "Tag_06", "Tag_07", "Tag_08", "Tag_09", "Tag_10", "Tag_11", "Tag_12", "Tag_13", "Tag_14", "Tag_15", "Tag_16", "Tag_17", "Tag_18", "Tag_19", "Tag_20", "Tag_21", "Tag_22", "Tag_23", "Tag_24", "Tag_25", "Tag_26", "Tag_27", "Tag_28", "Tag_29", "Tag_30", "And_a_very_long_tag_without_spaces", "Ok, a last long tag without spaces, but that sgould be enough"],
+ "description": {
+ "paragraphs": [
+ {
+ "text": [
+ "... and a few long ones"
+ ]
+ }
+ ]
+ }
+ },
+
+ {
+ "name": "One static image",
+ "description": {
+ "paragraphs": [
+ {
+ "text": [
+ "png"
+ ]
+ }
+ ],
+ "images": [
+ {
+ "image_label": "Screenshot",
+ "url": "https://bugreports.qt.io/secure/attachment/147354/VirtualNodesShownAsNotExisting.png"
+ }
+ ]
+ }
+ },
+
+ {
+ "name": "One animated image",
+ "description": {
+ "paragraphs": [
+ {
+ "text": [
+ "gif (animated)"
+ ]
+ }
+ ],
+ "images": [
+ {
+ "image_label": "Screencast",
+ "url": "https://bugreports.qt.io/secure/attachment/156058/156058_DragAndCopyOnLinux.gif"
+ }
+ ]
+ }
+ },
+
+ {
+ "name": "Vendor, no download count",
+ "vendor": "Vendor name"
+ },
+
+ {
+ "name": "No vendor, but download count",
+ "download_count": 12345
+ },
+
+ {
+ "name": "Vendor and download count",
+ "vendor": "Vendor name",
+ "download_count": 12345
+ }
+ ]
+}
diff --git a/src/plugins/languageclient/callandtypehierarchy.cpp b/src/plugins/languageclient/callandtypehierarchy.cpp
index d759ea35341..8cfc3578c37 100644
--- a/src/plugins/languageclient/callandtypehierarchy.cpp
+++ b/src/plugins/languageclient/callandtypehierarchy.cpp
@@ -76,7 +76,12 @@ protected:
}
private:
- bool canFetchMore() const override { return m_client && !m_fetchedChildren; }
+ bool canFetchMore() const override
+ {
+ if (m_client && !m_fetchedChildren)
+ const_cast(this)->fetchMore();
+ return false;
+ }
void fetchMore() override
{
@@ -96,8 +101,6 @@ private:
appendChild(new HierarchyItem(getSourceItem(item), m_client));
}
}
- if (!hasChildren())
- update();
});
m_client->sendMessage(request);
}
@@ -267,6 +270,7 @@ public:
m_view->setModel(&m_model);
m_view->setActivationMode(SingleClickActivation);
m_view->setItemDelegate(&m_delegate);
+ m_view->setUniformRowHeights(true);
theWidget->setLayout(new QVBoxLayout);
theWidget->layout()->addWidget(m_view);
@@ -432,7 +436,7 @@ public:
Icons::RELOAD_TOOLBAR.icon();
auto button = new QToolButton;
button->setIcon(Icons::RELOAD_TOOLBAR.icon());
- button->setToolTip(LanguageClient::Tr::tr(
+ button->setToolTip(::LanguageClient::Tr::tr(
"Reloads the call hierarchy for the symbol under cursor position."));
connect(button, &QToolButton::clicked, this, [h] { h->updateHierarchyAtCursorPosition(); });
return {h, {button}};
diff --git a/src/plugins/languageclient/client.cpp b/src/plugins/languageclient/client.cpp
index 2ec4d41dbf3..412430171dc 100644
--- a/src/plugins/languageclient/client.cpp
+++ b/src/plugins/languageclient/client.cpp
@@ -1789,6 +1789,11 @@ const DynamicCapabilities &Client::dynamicCapabilities() const
return d->m_dynamicCapabilities;
}
+DynamicCapabilities &Client::dynamicCapabilities()
+{
+ return d->m_dynamicCapabilities;
+}
+
DocumentSymbolCache *Client::documentSymbolCache()
{
return &d->m_documentSymbolCache;
diff --git a/src/plugins/languageclient/client.h b/src/plugins/languageclient/client.h
index c80e458a472..28360c71a6f 100644
--- a/src/plugins/languageclient/client.h
+++ b/src/plugins/languageclient/client.h
@@ -97,6 +97,7 @@ public:
QString serverName() const;
QString serverVersion() const;
const DynamicCapabilities &dynamicCapabilities() const;
+ DynamicCapabilities &dynamicCapabilities();
void registerCapabilities(const QList ®istrations);
void unregisterCapabilities(const QList &unregistrations);
diff --git a/src/plugins/languageclient/dynamiccapabilities.h b/src/plugins/languageclient/dynamiccapabilities.h
index 076d578d8f3..13f8be74a6f 100644
--- a/src/plugins/languageclient/dynamiccapabilities.h
+++ b/src/plugins/languageclient/dynamiccapabilities.h
@@ -3,6 +3,8 @@
#pragma once
+#include "languageclient_global.h"
+
#include
namespace LanguageClient {
@@ -21,7 +23,7 @@ public:
void disable()
{
- m_enabled = true;
+ m_enabled = false;
m_id.clear();
m_options = QJsonValue();
}
@@ -37,7 +39,7 @@ private:
};
-class DynamicCapabilities
+class LANGUAGECLIENT_EXPORT DynamicCapabilities
{
public:
DynamicCapabilities() = default;
diff --git a/src/plugins/languageclient/languageclientmanager.cpp b/src/plugins/languageclient/languageclientmanager.cpp
index 8ee2254c746..11ce6b4618e 100644
--- a/src/plugins/languageclient/languageclientmanager.cpp
+++ b/src/plugins/languageclient/languageclientmanager.cpp
@@ -387,6 +387,7 @@ void LanguageClientManager::enableClientSettings(const QString &settingsId, bool
QList LanguageClientManager::clientsForSetting(const BaseSettings *setting)
{
QTC_ASSERT(managerInstance, return {});
+ QTC_ASSERT(setting, return {});
auto instance = managerInstance;
return instance->m_clientsForSetting.value(setting->m_id);
}
diff --git a/src/plugins/languageclient/lualanguageclient/lualanguageclient.cpp b/src/plugins/languageclient/lualanguageclient/lualanguageclient.cpp
index c9a12900230..47b2f7599dc 100644
--- a/src/plugins/languageclient/lualanguageclient/lualanguageclient.cpp
+++ b/src/plugins/languageclient/lualanguageclient/lualanguageclient.cpp
@@ -175,7 +175,7 @@ public:
std::optional m_startFailedCallback;
QMap m_messageCallbacks;
- QList m_clients;
+ LuaClientSettings *m_settings{nullptr};
public:
static BaseSettings::StartBehavior startBehaviorFromString(const QString &str)
@@ -190,6 +190,8 @@ public:
throw sol::error("Unknown start behavior: " + str.toStdString());
}
+ void setSettings(LuaClientSettings *settings) { m_settings = settings; }
+
LuaClientWrapper(const sol::table &options)
{
m_cmdLineCallback = addValue(
@@ -267,8 +269,6 @@ public:
auto luaClient = qobject_cast(c);
if (luaClient && luaClient->m_settingsId == m_settingsTypeId && m_onInstanceStart) {
QTC_CHECK(::Lua::LuaEngine::void_safe_call(*m_onInstanceStart, c));
-
- m_clients.push_back(c);
updateMessageCallbacks();
}
});
@@ -286,22 +286,11 @@ public:
if (!luaClient || luaClient->m_settingsId != m_settingsTypeId)
return;
- if (m_clients.contains(c))
- m_clients.removeOne(c);
-
if (unexpected && m_startFailedCallback) {
QTC_CHECK_EXPECTED(::Lua::LuaEngine::void_safe_call(*m_startFailedCallback));
}
}
- ~LuaClientWrapper()
- {
- for (auto client : m_clients)
- LanguageClientManager::shutdownClient(client);
-
- // TODO: Unregister Client settings from LanguageClientManager
- }
-
TransportType transportType() { return m_transportType; }
void applySettings()
@@ -340,7 +329,9 @@ public:
void updateMessageCallbacks()
{
- for (Client *c : m_clients) {
+ for (Client *c : LanguageClientManager::clientsForSetting(m_settings)) {
+ if (!c)
+ continue;
for (const auto &[msg, func] : m_messageCallbacks.asKeyValueRange()) {
c->registerCustomMethod(
msg,
@@ -367,8 +358,10 @@ public:
if (!messageValue.isObject())
throw sol::error("Message is not an object");
const LanguageServerProtocol::JsonRpcMessage jsonrpcmessage(messageValue.toObject());
- for (Client *c : m_clients)
- c->sendMessage(jsonrpcmessage);
+ for (Client *c : LanguageClientManager::clientsForSetting(m_settings)) {
+ if (c)
+ c->sendMessage(jsonrpcmessage);
+ }
}
void updateOptions()
@@ -536,6 +529,7 @@ static void registerLuaApi()
[](const sol::table &options) -> std::shared_ptr {
auto luaClient = std::make_shared(options);
auto client = new LuaClientSettings(luaClient);
+ luaClient->setSettings(client);
// The order is important!
// First restore the settings ...
diff --git a/src/plugins/lua/bindings/fetch.cpp b/src/plugins/lua/bindings/fetch.cpp
index 22d1bc64cbd..6f5fd535612 100644
--- a/src/plugins/lua/bindings/fetch.cpp
+++ b/src/plugins/lua/bindings/fetch.cpp
@@ -59,7 +59,7 @@ void addFetchModule()
LuaOptionsPage(Module *module)
{
setId("BB.Lua.Fetch");
- setDisplayName(Tr::tr("Network access"));
+ setDisplayName(Tr::tr("Network Access"));
setCategory("ZY.Lua");
setDisplayCategory("Lua");
setCategoryIconPath(":/lua/images/settingscategory_lua.png");
@@ -176,8 +176,8 @@ void addFetchModule()
// so we have to use a QMessageBox instead of the info bar
auto msgBox = new QMessageBox(
QMessageBox::Question,
- Tr::tr("Allow Internet access"),
- Tr::tr("The plugin \"%1\" would like to fetch from the following url:\n%2")
+ Tr::tr("Allow Internet Access"),
+ Tr::tr("Allow the extension \"%1\" to fetch from the following URL:\n%2")
.arg(pluginName)
.arg(url),
QMessageBox::Yes | QMessageBox::No,
@@ -205,14 +205,13 @@ void addFetchModule()
Utils::InfoBarEntry entry{
Utils::Id::fromString("Fetch" + pluginName),
- Tr::tr("The plugin \"%1\" would like to fetch data from the internet. Do "
- "you want to allow this?")
+ Tr::tr("Allow the extension \"%1\" to fetch data from the internet?")
.arg(pluginName)};
entry.setDetailsWidgetCreator([pluginName, url] {
- const QString markdown = Tr::tr("The plugin \"**%1**\" would like to fetch "
- "from the following url:\n\n")
- .arg(pluginName)
- + QString("* [%3](%3)").arg(url);
+ const QString markdown = Tr::tr("Allow the extension \"%1\" to fetch data"
+ "from the following URL:\n\n")
+ .arg("**" + pluginName + "**")
+ + QString("* [%1](%1)").arg(url);
QLabel *list = new QLabel();
list->setTextFormat(Qt::TextFormat::MarkdownText);
@@ -225,7 +224,7 @@ void addFetchModule()
Core::ICore::infoBar()->removeInfo(Utils::Id::fromString("Fetch" + pluginName));
fetch();
});
- entry.addCustomButton(Tr::tr("Allow once"), [pluginName, fetch]() {
+ entry.addCustomButton(Tr::tr("Allow Once"), [pluginName, fetch]() {
Core::ICore::infoBar()->removeInfo(Utils::Id::fromString("Fetch" + pluginName));
fetch();
});
@@ -311,8 +310,8 @@ void addFetchModule()
};
checkPermission(url, actualFetch, [callback, pluginName]() {
- callback(Tr::tr("Fetching is not allowed for the plugin \"%1\" (You can edit "
- "permissions in Preferences => Lua)")
+ callback(Tr::tr("Fetching is not allowed for the extension \"%1\". (You can edit "
+ "permissions in Preferences > Lua.)")
.arg(pluginName));
});
};
diff --git a/src/plugins/lua/bindings/install.cpp b/src/plugins/lua/bindings/install.cpp
index a044ff2fb8d..076cf63b9fa 100644
--- a/src/plugins/lua/bindings/install.cpp
+++ b/src/plugins/lua/bindings/install.cpp
@@ -50,7 +50,7 @@ expected_str getPackageInfo(const FilePath &appDataPath)
return make_unexpected(error.errorString());
if (!doc.isObject())
- return make_unexpected(Tr::tr("Package info is not an object"));
+ return make_unexpected(Tr::tr("Package info is not an object."));
return doc;
}
@@ -66,7 +66,7 @@ expected_str getInstalledPackageInfo(const FilePath &appDataPath, c
if (root.contains(name)) {
QJsonValue v = root[name];
if (!v.isObject())
- return make_unexpected(Tr::tr("Installed package info is not an object"));
+ return make_unexpected(Tr::tr("Installed package info is not an object."));
return v.toObject();
}
@@ -86,12 +86,12 @@ expected_str getOrCreatePackageInfo(const FilePath &appDataPath)
expected_str savePackageInfo(const FilePath &appDataPath, const QJsonDocument &doc)
{
if (!appDataPath.ensureWritableDir())
- return make_unexpected(Tr::tr("Could not create app data directory"));
+ return make_unexpected(Tr::tr("Cannot create app data directory."));
const FilePath packageInfoPath = appDataPath / "package.json";
return packageInfoPath.writeFileContents(doc.toJson())
.transform_error([](const QString &error) {
- return Tr::tr("Could not write to package info: %1").arg(error);
+ return Tr::tr("Cannot write to package info: %1").arg(error);
})
.transform([](qint64) { return; });
}
@@ -147,7 +147,7 @@ static Group installRecipe(
const auto size = reply->size();
const auto written = storage->write(reply->readAll());
if (written != size)
- return emitResult(Tr::tr("Could not write to temporary file"));
+ return emitResult(Tr::tr("Cannot write to temporary file."));
storage->close();
return DoneResult::Success;
};
@@ -169,7 +169,7 @@ static Group installRecipe(
const auto onUnarchiverDone = [appDataPath, installOptionsIt, emitResult](DoneWith result) {
if (result == DoneWith::Error)
- return emitResult(Tr::tr("Unarchiving failed"));
+ return emitResult(Tr::tr("Unarchiving failed."));
if (result == DoneWith::Cancel)
return DoneResult::Error;
@@ -212,7 +212,7 @@ static Group installRecipe(
}
if (!storage->open(QIODevice::WriteOnly)) {
- emitResult(Tr::tr("Could not open temporary file"));
+ emitResult(Tr::tr("Cannot open temporary file."));
return SetupResult::StopWithError;
}
return SetupResult::Continue;
@@ -326,16 +326,17 @@ void addInstallModule()
if (QApplication::activeModalWidget()) {
auto msgBox = new QMessageBox(
QMessageBox::Question,
- Tr::tr("Install package"),
+ Tr::tr("Install Package"),
msg,
QMessageBox::Yes | QMessageBox::No,
Core::ICore::dialogParent());
const QString details
- = Tr::tr("The plugin \"%1\" would like to install the following "
+ = Tr::tr("The extension \"%1\" wants to install the following "
"package(s):\n\n")
.arg(pluginSpec->name)
+ Utils::transform(installOptionsList, [](const InstallOptions &options) {
+ //: %1 = package name, %2 = version, %3 = URL
return QString("* %1 - %2 (from: %3)")
.arg(options.name, options.version, options.url.toString());
}).join("\n");
@@ -363,11 +364,12 @@ void addInstallModule()
entry.setCancelButtonInfo(denied);
const QString details
- = Tr::tr("The plugin \"**%1**\" would like to install the following "
+ = Tr::tr("The extension \"%1\" wants to install the following "
"package(s):\n\n")
- .arg(pluginSpec->name)
+ .arg("**" + pluginSpec->name + "**") // markdown bold
+ Utils::transform(installOptionsList, [](const InstallOptions &options) {
- return QString("* %1 - %2 (from: [%3](%3))")
+ //: Markdown list item: %1 = package name, %2 = version, %3 = URL
+ return Tr::tr("* %1 - %2 (from: [%3](%3))")
.arg(options.name, options.version, options.url.toString());
}).join("\n");
diff --git a/src/plugins/lua/luaengine.cpp b/src/plugins/lua/luaengine.cpp
index 8872e85bce3..af1741fea2a 100644
--- a/src/plugins/lua/luaengine.cpp
+++ b/src/plugins/lua/luaengine.cpp
@@ -136,7 +136,7 @@ std::unique_ptr LuaEngine::runScript(
sol::error err = result;
qWarning() << "Failed to run script" << name << ":" << QString::fromUtf8(err.what());
Core::MessageManager::writeFlashing(
- tr("Failed to run script %1: %2").arg(name, QString::fromUtf8(err.what())));
+ Tr::tr("Failed to run script %1: %2").arg(name, QString::fromUtf8(err.what())));
}
return opaque;
@@ -168,7 +168,7 @@ expected_str LuaEngine::connectHooks(
QString hookName = QStringList{path, k.as()}.join(".");
auto it = d->m_hooks.find(hookName);
if (it == d->m_hooks.end())
- return make_unexpected(QString("No hook named '%1' found").arg(hookName));
+ return make_unexpected(Tr::tr("No hook with the name \"%1\" found.").arg(hookName));
else
it.value()(v.as());
}
@@ -269,7 +269,7 @@ expected_str LuaEngine::prepareSetup(
auto pluginTable = result.get>();
if (!pluginTable)
- return make_unexpected(Tr::tr("Script did not return a table"));
+ return make_unexpected(Tr::tr("Script did not return a table."));
auto hookTable = pluginTable->get>("hooks");
@@ -282,7 +282,7 @@ expected_str LuaEngine::prepareSetup(
auto setupFunction = pluginTable->get_or("setup", {});
if (!setupFunction)
- return make_unexpected(Tr::tr("Plugin info table did not contain a setup function"));
+ return make_unexpected(Tr::tr("Extension info table did not contain a setup function."));
return setupFunction;
}
diff --git a/src/plugins/lua/luapluginspec.cpp b/src/plugins/lua/luapluginspec.cpp
index 3e6b1eb3edd..f00e48936bc 100644
--- a/src/plugins/lua/luapluginspec.cpp
+++ b/src/plugins/lua/luapluginspec.cpp
@@ -108,19 +108,19 @@ bool LuaPluginSpec::initializePlugin()
= LuaEngine::instance().prepareSetup(*activeLuaState, *this);
if (!setupResult) {
- setError(Lua::Tr::tr("Failed to prepare plugin setup: %1").arg(setupResult.error()));
+ setError(Lua::Tr::tr("Cannot prepare extension setup: %1").arg(setupResult.error()));
return false;
}
auto result = setupResult->call();
if (result.get_type() == sol::type::boolean && result.get() == false) {
- setError(Lua::Tr::tr("Plugin setup function returned false"));
+ setError(Lua::Tr::tr("Extension setup function returned false."));
return false;
} else if (result.get_type() == sol::type::string) {
std::string error = result.get().what();
if (!error.empty()) {
- setError(Lua::Tr::tr("Plugin setup function returned error: %1")
+ setError(Lua::Tr::tr("Extension setup function returned error: %1")
.arg(QString::fromStdString(error)));
return false;
}
diff --git a/src/plugins/mcusupport/mcubuildstep.cpp b/src/plugins/mcusupport/mcubuildstep.cpp
index 102ee306fef..786b363d38f 100644
--- a/src/plugins/mcusupport/mcubuildstep.cpp
+++ b/src/plugins/mcusupport/mcubuildstep.cpp
@@ -67,12 +67,12 @@ DeployMcuProcessStep::DeployMcuProcessStep(ProjectExplorer::BuildStepList *bc, I
, m_tmpDir()
{
if (!buildSystem()) {
- showError(QmlProjectManager::Tr::tr("Failed to find valid build system"));
+ showError(QmlProjectManager::Tr::tr("Cannot find a valid build system."));
return;
}
if (!m_tmpDir.isValid()) {
- showError(QmlProjectManager::Tr::tr("Failed to create valid build directory"));
+ showError(QmlProjectManager::Tr::tr("Cannot create a valid build directory."));
return;
}
@@ -193,7 +193,7 @@ void MCUBuildStepFactory::updateDeployStep(ProjectExplorer::Target *target, bool
stepList->appendStep(DeployMcuProcessStep::id);
} else {
DeployMcuProcessStep::showError(
- QmlProjectManager::Tr::tr("Failed to find valid Qt for MCUs kit"));
+ QmlProjectManager::Tr::tr("Cannot find a valid Qt for MCUs kit."));
}
} else {
if (!step)
diff --git a/src/plugins/mcusupport/mcusupportoptionspage.cpp b/src/plugins/mcusupport/mcusupportoptionspage.cpp
index 1383c737e71..d2269a40b51 100644
--- a/src/plugins/mcusupport/mcusupportoptionspage.cpp
+++ b/src/plugins/mcusupport/mcusupportoptionspage.cpp
@@ -320,7 +320,7 @@ void McuSupportOptionsWidget::apply()
QMessageBox warningPopup(QMessageBox::Icon::Warning,
Tr::tr("Warning"),
- Tr::tr("Unable to apply changes in Devices > MCU."),
+ Tr::tr("Cannot apply changes in Devices > MCU."),
QMessageBox::Ok,
this);
diff --git a/src/plugins/modeleditor/elementtasks.cpp b/src/plugins/modeleditor/elementtasks.cpp
index 039964ccb83..cc49180d133 100644
--- a/src/plugins/modeleditor/elementtasks.cpp
+++ b/src/plugins/modeleditor/elementtasks.cpp
@@ -448,8 +448,10 @@ void ElementTasks::openLinkedFile(const qmt::MElement *element)
(void) Core::EditorManager::openEditor(filepath);
}
} else {
- QMessageBox::critical(Core::ICore::dialogParent(), Tr::tr("Opening File"),
- Tr::tr("File %1 does not exist.").arg(filepath.toUserOutput()));
+ QMessageBox::critical(
+ Core::ICore::dialogParent(),
+ Tr::tr("Opening File"),
+ Tr::tr("File \"%1\" does not exist.").arg(filepath.toUserOutput()));
}
}
}
diff --git a/src/plugins/modeleditor/extpropertiesmview.cpp b/src/plugins/modeleditor/extpropertiesmview.cpp
index b105554e6fc..27fcca34f34 100644
--- a/src/plugins/modeleditor/extpropertiesmview.cpp
+++ b/src/plugins/modeleditor/extpropertiesmview.cpp
@@ -257,8 +257,10 @@ void ExtPropertiesMView::onImagePathChanged(const QString &path)
assignModelElement(m_diagramElements, SelectionSingle, image,
&qmt::DObject::image, &qmt::DObject::setImage);
} else {
- QMessageBox::critical(Core::ICore::dialogParent(), Tr::tr("Selecting Image"),
- Tr::tr("Unable to read image file %1").arg(path));
+ QMessageBox::critical(
+ Core::ICore::dialogParent(),
+ Tr::tr("Selecting Image"),
+ Tr::tr("Unable to read image file \"%1\".").arg(path));
}
}
}
diff --git a/src/plugins/projectexplorer/CMakeLists.txt b/src/plugins/projectexplorer/CMakeLists.txt
index ea7a079d908..0c62d2177a1 100644
--- a/src/plugins/projectexplorer/CMakeLists.txt
+++ b/src/plugins/projectexplorer/CMakeLists.txt
@@ -140,7 +140,6 @@ add_qtc_plugin(ProjectExplorer
projectmanager.cpp projectmanager.h
projectmodels.cpp projectmodels.h
projectnodes.cpp projectnodes.h
- projectnodeshelper.h
projectpanelfactory.cpp projectpanelfactory.h
projectsettingswidget.cpp projectsettingswidget.h
projecttree.cpp projecttree.h
diff --git a/src/plugins/projectexplorer/buildpropertiessettings.cpp b/src/plugins/projectexplorer/buildpropertiessettings.cpp
index ebfe8782151..d5eb9bfc3aa 100644
--- a/src/plugins/projectexplorer/buildpropertiessettings.cpp
+++ b/src/plugins/projectexplorer/buildpropertiessettings.cpp
@@ -57,7 +57,7 @@ BuildPropertiesSettings::BuildPropertiesSettings()
buildDirectoryTemplate.setToolTip(
Tr::tr("Template used to construct the default build directory.
"
"The default value can be set using the environment variable "
- "%1")
+ "%1.")
.arg(Constants::QTC_DEFAULT_BUILD_DIRECTORY_TEMPLATE));
buildDirectoryTemplate.setUseResetButton();
diff --git a/src/plugins/projectexplorer/devicesupport/sshparameters.cpp b/src/plugins/projectexplorer/devicesupport/sshparameters.cpp
index 2b2ebdabc00..c266055003c 100644
--- a/src/plugins/projectexplorer/devicesupport/sshparameters.cpp
+++ b/src/plugins/projectexplorer/devicesupport/sshparameters.cpp
@@ -75,12 +75,11 @@ QStringList SshParameters::connectionOptions(const FilePath &binary) const
return args;
}
-bool SshParameters::setupSshEnvironment(Process *process)
+void SshParameters::setupSshEnvironment(Process *process)
{
Environment env = process->controlEnvironment();
if (!env.hasChanges())
env = Environment::systemEnvironment();
- const bool hasDisplay = env.hasKey("DISPLAY") && (env.value("DISPLAY") != QString(":0"));
if (SshSettings::askpassFilePath().exists()) {
env.set("SSH_ASKPASS", SshSettings::askpassFilePath().toUserOutput());
env.set("SSH_ASKPASS_REQUIRE", "force");
@@ -93,7 +92,6 @@ bool SshParameters::setupSshEnvironment(Process *process)
// Otherwise, ssh will ignore SSH_ASKPASS and read from /dev/tty directly.
process->setDisableUnixTerminal();
- return hasDisplay;
}
bool operator==(const SshParameters &p1, const SshParameters &p2)
diff --git a/src/plugins/projectexplorer/devicesupport/sshparameters.h b/src/plugins/projectexplorer/devicesupport/sshparameters.h
index 5a5f32da268..da57f2c5aa2 100644
--- a/src/plugins/projectexplorer/devicesupport/sshparameters.h
+++ b/src/plugins/projectexplorer/devicesupport/sshparameters.h
@@ -46,7 +46,7 @@ public:
AuthenticationType authenticationType = AuthenticationTypeAll;
SshHostKeyCheckingMode hostKeyCheckingMode = SshHostKeyCheckingAllowNoMatch;
- static bool setupSshEnvironment(Utils::Process *process);
+ static void setupSshEnvironment(Utils::Process *process);
friend PROJECTEXPLORER_EXPORT bool operator==(const SshParameters &p1, const SshParameters &p2);
friend bool operator!=(const SshParameters &p1, const SshParameters &p2) { return !(p1 == p2); }
diff --git a/src/plugins/projectexplorer/projectexplorer.qbs b/src/plugins/projectexplorer/projectexplorer.qbs
index 19b9221de2b..bce24dc1361 100644
--- a/src/plugins/projectexplorer/projectexplorer.qbs
+++ b/src/plugins/projectexplorer/projectexplorer.qbs
@@ -115,7 +115,6 @@ QtcPlugin {
"projectmanager.cpp", "projectmanager.h",
"projectmodels.cpp", "projectmodels.h",
"projectnodes.cpp", "projectnodes.h",
- "projectnodeshelper.h",
"projectpanelfactory.cpp", "projectpanelfactory.h",
"projectsettingswidget.cpp", "projectsettingswidget.h",
"projecttree.cpp",
diff --git a/src/plugins/projectexplorer/projectexplorersettings.cpp b/src/plugins/projectexplorer/projectexplorersettings.cpp
index 3e36b84ab75..a45872eeff3 100644
--- a/src/plugins/projectexplorer/projectexplorersettings.cpp
+++ b/src/plugins/projectexplorer/projectexplorersettings.cpp
@@ -310,10 +310,11 @@ ProjectExplorerSettingsWidget::ProjectExplorerSettingsWidget()
{
m_reaperTimeoutSpinBox = new QSpinBox;
m_reaperTimeoutSpinBox->setMinimum(1);
+ //: Suffix for "seconds"
m_reaperTimeoutSpinBox->setSuffix(Tr::tr("s"));
m_reaperTimeoutSpinBox->setToolTip(
Tr::tr("The amount of seconds to wait between a \"soft kill\" and a \"hard kill\" of a "
- "running application"));
+ "running application."));
m_currentDirectoryRadioButton = new QRadioButton(Tr::tr("Current directory"));
m_directoryRadioButton = new QRadioButton(Tr::tr("Directory"));
diff --git a/src/plugins/projectexplorer/projectmodels.cpp b/src/plugins/projectexplorer/projectmodels.cpp
index 5f5aa0150e1..b7be5e1546b 100644
--- a/src/plugins/projectexplorer/projectmodels.cpp
+++ b/src/plugins/projectexplorer/projectmodels.cpp
@@ -284,8 +284,9 @@ bool FlatModel::setData(const QModelIndex &index, const QVariant &value, int rol
QTC_ASSERT(node, return false);
std::vector> toRename;
- const Utils::FilePath orgFilePath = node->filePath();
- const Utils::FilePath newFilePath = orgFilePath.parentDir().pathAppended(value.toString());
+ const FilePath orgFilePath = node->filePath();
+ const FilePath newFilePath = orgFilePath.parentDir().pathAppended(value.toString());
+ const FilePath valuePath = FilePath::fromString(value.toString());
const QFileInfo orgFileInfo = orgFilePath.toFileInfo();
toRename.emplace_back(std::make_tuple(node, orgFilePath, newFilePath));
@@ -309,12 +310,13 @@ bool FlatModel::setData(const QModelIndex &index, const QVariant &value, int rol
case QMessageBox::Yes:
for (Node * const n : candidateNodes) {
QString targetFilePath = orgFileInfo.absolutePath() + '/'
- + newFilePath.completeBaseName();
+ + valuePath.parentDir().path() + '/'
+ + valuePath.completeBaseName();
const QString suffix = n->filePath().suffix();
if (!suffix.isEmpty())
targetFilePath.append('.').append(suffix);
toRename.emplace_back(std::make_tuple(n, n->filePath(),
- FilePath::fromString(targetFilePath)));
+ FilePath::fromString(targetFilePath).cleanPath()));
}
break;
case QMessageBox::Cancel:
diff --git a/src/plugins/projectexplorer/projectnodeshelper.h b/src/plugins/projectexplorer/projectnodeshelper.h
deleted file mode 100644
index 37b015ec321..00000000000
--- a/src/plugins/projectexplorer/projectnodeshelper.h
+++ /dev/null
@@ -1,141 +0,0 @@
-// Copyright (C) 2021 The Qt Company Ltd.
-// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only WITH Qt-GPL-exception-1.0
-
-#pragma once
-
-#include "projectnodes.h"
-
-#include
-#include
-
-#include
-
-#include
-#include
-#include
-#include
-
-#include
-
-namespace ProjectExplorer {
-namespace Internal {
-
-struct DirectoryScanResult
-{
- QList nodes;
- Utils::FilePaths subDirectories;
-};
-
-static DirectoryScanResult scanForFiles(
- const QFuture &future,
- const Utils::FilePath &directory,
- QDir::Filters filter,
- const std::function &factory,
- const QList &versionControls)
-{
- DirectoryScanResult result;
-
- const Utils::FilePaths entries = directory.dirEntries(filter);
- for (const Utils::FilePath &entry : entries) {
- if (future.isCanceled())
- return result;
-
- if (Utils::anyOf(versionControls, [entry](const Core::IVersionControl *vc) {
- return vc->isVcsFileOrDirectory(entry);
- })) {
- continue;
- }
-
- if (entry.isDir())
- result.subDirectories.append(entry);
- else if (FileNode *node = factory(entry))
- result.nodes.append(node);
- }
- return result;
-}
-
-template
-QList scanForFilesRecursively(
- QPromise &promise,
- int progressRange,
- const Utils::FilePath &directory,
- QDir::Filters filter,
- const std::function &factory,
- const QList &versionControls)
-{
- const QFuture future(promise.future());
-
- QSet visited;
- const DirectoryScanResult result
- = scanForFiles(future, directory, filter, factory, versionControls);
- QList fileNodes = result.nodes;
- const int progressIncrement = int(
- progressRange / static_cast(fileNodes.count() + result.subDirectories.count()));
- promise.setProgressValue(int(fileNodes.count() * progressIncrement));
- QList> subDirectories;
- auto addSubDirectories = [&](const Utils::FilePaths &subdirs, int progressIncrement) {
- for (const Utils::FilePath &subdir : subdirs) {
- if (Utils::insert(visited, subdir.canonicalPath()))
- subDirectories.append(qMakePair(subdir, progressIncrement));
- else
- promise.setProgressValue(promise.future().progressValue() + progressIncrement);
- }
- };
- addSubDirectories(result.subDirectories, progressIncrement);
-
- while (!subDirectories.isEmpty()) {
- using namespace Tasking;
- const LoopList iterator(subDirectories);
- subDirectories.clear();
-
- auto onSetup = [&, iterator](Utils::Async &task) {
- task.setConcurrentCallData(
- scanForFiles, future, iterator->first, filter, factory, versionControls);
- };
-
- auto onDone = [&, iterator](const Utils::Async &task) {
- const int progressRange = iterator->second;
- const DirectoryScanResult result = task.result();
- fileNodes.append(result.nodes);
- const qsizetype subDirCount = result.subDirectories.count();
- if (subDirCount == 0) {
- promise.setProgressValue(promise.future().progressValue() + progressRange);
- } else {
- const qsizetype fileCount = result.nodes.count();
- const int increment = int(
- progressRange / static_cast(fileCount + subDirCount));
- promise.setProgressValue(
- promise.future().progressValue() + increment * fileCount);
- addSubDirectories(result.subDirectories, increment);
- }
- };
-
- const Group group{
- Utils::HostOsInfo::isLinuxHost() ? parallelLimit(2) : parallelIdealThreadCountLimit,
- iterator,
- Utils::AsyncTask(onSetup, onDone)
- };
- TaskTree::runBlocking(group);
- }
- return fileNodes;
-}
-
-} // namespace Internal
-
-template
-QList scanForFiles(
- QPromise &promise,
- const Utils::FilePath &directory,
- QDir::Filters filter,
- const std::function &factory)
-{
- promise.setProgressRange(0, 1000000);
- return Internal::scanForFilesRecursively(promise,
- 1000000,
- directory,
- filter,
- factory,
- Core::VcsManager::versionControls());
-}
-
-} // namespace ProjectExplorer
diff --git a/src/plugins/projectexplorer/treescanner.cpp b/src/plugins/projectexplorer/treescanner.cpp
index 49680621ec2..4411184c923 100644
--- a/src/plugins/projectexplorer/treescanner.cpp
+++ b/src/plugins/projectexplorer/treescanner.cpp
@@ -3,15 +3,17 @@
#include "treescanner.h"
-#include "projectnodeshelper.h"
#include "projecttree.h"
#include
#include
-#include
-#include
+#include
+
#include
+#include
+#include
+#include
#include
@@ -146,14 +148,113 @@ static std::unique_ptr createFolderNode(const Utils::FilePath &direc
return fileSystemNode;
}
+struct DirectoryScanResult
+{
+ QList nodes;
+ Utils::FilePaths subDirectories;
+};
+
+static DirectoryScanResult scanForFilesImpl(
+ const QFuture &future,
+ const Utils::FilePath &directory,
+ QDir::Filters filter,
+ const std::function &factory,
+ const QList &versionControls)
+{
+ DirectoryScanResult result;
+
+ const Utils::FilePaths entries = directory.dirEntries(filter);
+ for (const Utils::FilePath &entry : entries) {
+ if (future.isCanceled())
+ return result;
+
+ if (Utils::anyOf(versionControls, [entry](const Core::IVersionControl *vc) {
+ return vc->isVcsFileOrDirectory(entry);
+ })) {
+ continue;
+ }
+
+ if (entry.isDir())
+ result.subDirectories.append(entry);
+ else if (FileNode *node = factory(entry))
+ result.nodes.append(node);
+ }
+ return result;
+}
+
+static QList scanForFilesHelper(
+ TreeScanner::Promise &promise,
+ const Utils::FilePath &directory,
+ QDir::Filters filter,
+ const std::function &factory)
+{
+ const QFuture future(promise.future());
+
+ const int progressRange = 1000000;
+ const QList &versionControls = Core::VcsManager::versionControls();
+ promise.setProgressRange(0, progressRange);
+
+ QSet visited;
+ const DirectoryScanResult result = scanForFilesImpl(future, directory, filter, factory, versionControls);
+ QList fileNodes = result.nodes;
+ const int progressIncrement = int(
+ progressRange / static_cast(fileNodes.count() + result.subDirectories.count()));
+ promise.setProgressValue(int(fileNodes.count() * progressIncrement));
+ QList> subDirectories;
+ auto addSubDirectories = [&](const Utils::FilePaths &subdirs, int progressIncrement) {
+ for (const Utils::FilePath &subdir : subdirs) {
+ if (Utils::insert(visited, subdir.canonicalPath()))
+ subDirectories.append(qMakePair(subdir, progressIncrement));
+ else
+ promise.setProgressValue(future.progressValue() + progressIncrement);
+ }
+ };
+ addSubDirectories(result.subDirectories, progressIncrement);
+
+ while (!subDirectories.isEmpty()) {
+ using namespace Tasking;
+ const LoopList iterator(subDirectories);
+ subDirectories.clear();
+
+ auto onSetup = [&, iterator](Utils::Async &task) {
+ task.setConcurrentCallData(
+ scanForFilesImpl, future, iterator->first, filter, factory, versionControls);
+ };
+
+ auto onDone = [&, iterator](const Utils::Async &task) {
+ const int progressRange = iterator->second;
+ const DirectoryScanResult result = task.result();
+ fileNodes.append(result.nodes);
+ const qsizetype subDirCount = result.subDirectories.count();
+ if (subDirCount == 0) {
+ promise.setProgressValue(future.progressValue() + progressRange);
+ } else {
+ const qsizetype fileCount = result.nodes.count();
+ const int increment = int(
+ progressRange / static_cast(fileCount + subDirCount));
+ promise.setProgressValue(future.progressValue() + increment * fileCount);
+ addSubDirectories(result.subDirectories, increment);
+ }
+ };
+
+ const Group group{
+ Utils::HostOsInfo::isLinuxHost() ? parallelLimit(2) : parallelIdealThreadCountLimit,
+ iterator,
+ Utils::AsyncTask(onSetup, onDone)
+ };
+ TaskTree::runBlocking(group);
+ }
+ return fileNodes;
+}
+
void TreeScanner::scanForFiles(
Promise &promise,
const Utils::FilePath &directory,
const FileFilter &filter,
- const QDir::Filters &dirFilter,
+ QDir::Filters dirFilter,
const FileTypeFactory &factory)
{
- QList nodes = ProjectExplorer::scanForFiles(
+ QList nodes = scanForFilesHelper(
promise, directory, dirFilter, [&filter, &factory](const Utils::FilePath &fn) -> FileNode * {
const Utils::MimeType mimeType = Utils::mimeTypesForFileName(fn.path()).value(0);
diff --git a/src/plugins/projectexplorer/treescanner.h b/src/plugins/projectexplorer/treescanner.h
index 6de26e399ad..bc4dbe0b069 100644
--- a/src/plugins/projectexplorer/treescanner.h
+++ b/src/plugins/projectexplorer/treescanner.h
@@ -75,7 +75,7 @@ private:
static void scanForFiles(Promise &fi,
const Utils::FilePath &directory,
const FileFilter &filter,
- const QDir::Filters &dirFilter,
+ QDir::Filters dirFilter,
const FileTypeFactory &factory);
private:
diff --git a/src/plugins/python/pipsupport.cpp b/src/plugins/python/pipsupport.cpp
index 673dbdccf33..d7a2dbd645b 100644
--- a/src/plugins/python/pipsupport.cpp
+++ b/src/plugins/python/pipsupport.cpp
@@ -66,21 +66,16 @@ void PipInstallTask::run()
emit finished(false);
return;
}
- QString operation = Tr::tr("Install");
- QString operant;
QStringList arguments = {"-m", "pip", "install"};
if (!m_requirementsFile.isEmpty()) {
- operant = Tr::tr("Requirements");
arguments << "-r" << m_requirementsFile.toString();
} else {
-
for (const PipPackage &package : m_packages) {
QString pipPackage = package.packageName;
if (!package.version.isEmpty())
pipPackage += "==" + package.version;
arguments << pipPackage;
}
- operant = m_packages.count() == 1 ? m_packages.first().displayName : Tr::tr("Packages");
}
if (!m_targetPath.isEmpty()) {
@@ -90,17 +85,27 @@ void PipInstallTask::run()
arguments << "--user"; // add --user to global pythons, but skip it for venv pythons
}
- if (m_upgrade) {
+ if (m_upgrade)
arguments << "--upgrade";
- operation = Tr::tr("Update");
+
+ QString operation;
+ if (!m_requirementsFile.isEmpty()) {
+ operation = m_upgrade ? Tr::tr("Update Requirements") : Tr::tr("Install Requirements");
+ } else if (m_packages.count() == 1) {
+ //: %1 = package name
+ operation = m_upgrade ? Tr::tr("Update %1")
+ //: %1 = package name
+ : Tr::tr("Install %1");
+ operation = operation.arg(m_packages.first().displayName);
+ } else {
+ operation = m_upgrade ? Tr::tr("Update Packages") : Tr::tr("Install Packages");
}
m_process.setCommand({m_python, arguments});
m_process.setTerminalMode(m_silent ? TerminalMode::Off : TerminalMode::Run);
m_process.start();
- const QString taskTitle = Tr::tr("%1 %2").arg(operation).arg(operant);
- Core::ProgressManager::addTask(m_future.future(), taskTitle, pipInstallTaskId);
+ Core::ProgressManager::addTask(m_future.future(), operation, pipInstallTaskId);
Core::MessageManager::writeSilently(
Tr::tr("Running \"%1\" to install %2.")
.arg(m_process.commandLine().toUserOutput(), packagesDisplayName()));
diff --git a/src/plugins/qmljseditor/qmljseditordocument.cpp b/src/plugins/qmljseditor/qmljseditordocument.cpp
index 445abaa4321..30fe36b6010 100644
--- a/src/plugins/qmljseditor/qmljseditordocument.cpp
+++ b/src/plugins/qmljseditor/qmljseditordocument.cpp
@@ -728,10 +728,11 @@ void QmlJSEditorDocumentPrivate::setSourcesWithCapabilities(
setSemanticWarningSource(QmllsStatus::Source::Qmlls);
else
setSemanticWarningSource(QmllsStatus::Source::EmbeddedCodeModel);
- if (cap.semanticTokensProvider())
- setSemanticHighlightSource(QmllsStatus::Source::Qmlls);
- else
- setSemanticHighlightSource(QmllsStatus::Source::EmbeddedCodeModel);
+ // TODO: uncomment when qmlls semantic tokens reach a stable state
+ // if (cap.semanticTokensProvider())
+ // setSemanticHighlightSource(QmllsStatus::Source::Qmlls);
+ // else
+ setSemanticHighlightSource(QmllsStatus::Source::EmbeddedCodeModel);
}
static Utils::FilePath qmllsForFile(const Utils::FilePath &file,
diff --git a/src/plugins/qmljseditor/qmljseditorsettings.cpp b/src/plugins/qmljseditor/qmljseditorsettings.cpp
index 9073a2109e6..aadcf7c6c01 100644
--- a/src/plugins/qmljseditor/qmljseditorsettings.cpp
+++ b/src/plugins/qmljseditor/qmljseditorsettings.cpp
@@ -447,7 +447,7 @@ public:
uiQmlOpenComboBox->setSizePolicy(QSizePolicy::Maximum, QSizePolicy::Preferred);
uiQmlOpenComboBox->setSizeAdjustPolicy(QComboBox::QComboBox::AdjustToContents);
- useQmlls = new QCheckBox(Tr::tr("Enable QML Language Server"));
+ useQmlls = new QCheckBox(Tr::tr("Turn on"));
useQmlls->setChecked(s.useQmlls());
ignoreMinimumQmllsVersion = new QCheckBox(
@@ -457,16 +457,15 @@ public:
ignoreMinimumQmllsVersion->setEnabled(s.useQmlls());
disableBuiltInCodemodel = new QCheckBox(
- Tr::tr("Use QML Language Server advanced features (renaming, find usages and co.) "
- "(EXPERIMENTAL!)"));
+ Tr::tr("Use advanced features (renaming, find usages, and so on) "
+ "(experimental)"));
disableBuiltInCodemodel->setChecked(s.disableBuiltinCodemodel());
disableBuiltInCodemodel->setEnabled(s.useQmlls());
- useLatestQmlls = new QCheckBox(Tr::tr("Use QML Language Server from latest Qt version"));
+ useLatestQmlls = new QCheckBox(Tr::tr("Use from latest Qt version"));
useLatestQmlls->setChecked(s.useLatestQmlls());
useLatestQmlls->setEnabled(s.useQmlls());
- generateQmllsIniFiles = new QCheckBox(
- Tr::tr("Generate QML Language Server .qmlls.ini configurations for new projects."));
+ generateQmllsIniFiles = new QCheckBox(Tr::tr("Create .qmlls.ini files for new projects"));
generateQmllsIniFiles->setChecked(s.generateQmllsIniFiles());
generateQmllsIniFiles->setEnabled(s.useQmlls());
QObject::connect(useQmlls, &QCheckBox::stateChanged, this, [this](int checked) {
diff --git a/src/plugins/qmljseditor/qmllsclient.cpp b/src/plugins/qmljseditor/qmllsclient.cpp
index 6ec46774f30..9fe50a5af7e 100644
--- a/src/plugins/qmljseditor/qmllsclient.cpp
+++ b/src/plugins/qmljseditor/qmllsclient.cpp
@@ -66,6 +66,10 @@ QmllsClient *QmllsClient::clientForQmlls(const FilePath &qmlls)
QmllsClient::QmllsClient(StdIOClientInterface *interface)
: Client(interface)
{
+ LanguageServerProtocol::Unregistration unregister;
+ unregister.setMethod("textDocument/semanticTokens");
+ unregister.setId({});
+ dynamicCapabilities().unregisterCapability({unregister});
}
QmllsClient::~QmllsClient()
diff --git a/src/plugins/qtsupport/externaleditors.cpp b/src/plugins/qtsupport/externaleditors.cpp
index 371623f6cf7..47200a6aeb3 100644
--- a/src/plugins/qtsupport/externaleditors.cpp
+++ b/src/plugins/qtsupport/externaleditors.cpp
@@ -118,12 +118,6 @@ static QString locateBinary(const QString &path, const QString &binary)
return {};
}
-static QString msgStartFailed(const QString &binary, QStringList arguments)
-{
- arguments.push_front(binary);
- return Tr::tr("Unable to start \"%1\"").arg(arguments.join(QLatin1Char(' ')));
-}
-
static QString designerBinary(const QtSupport::QtVersion *qtVersion)
{
if (qtVersion)
@@ -227,12 +221,11 @@ static bool startEditorProcess(const LaunchData &data, QString *errorMessage)
{
if (debug)
qDebug() << Q_FUNC_INFO << '\n' << data.binary << data.arguments << data.workingDirectory;
- qint64 pid = 0;
- if (!Process::startDetached({FilePath::fromString(data.binary), data.arguments}, data.workingDirectory, &pid)) {
- *errorMessage = msgStartFailed(data.binary, data.arguments);
- return false;
- }
- return true;
+ const CommandLine cmd{FilePath::fromString(data.binary), data.arguments};
+ if (Process::startDetached(cmd, data.workingDirectory))
+ return true;
+ *errorMessage = Tr::tr("Unable to start \"%1\".").arg(cmd.toUserOutput());
+ return false;
}
// ExternalDesignerEditorFactory with Designer Tcp remote control.
diff --git a/src/plugins/remotelinux/linuxdevice.cpp b/src/plugins/remotelinux/linuxdevice.cpp
index d51df10bef4..3fd4f0db738 100644
--- a/src/plugins/remotelinux/linuxdevice.cpp
+++ b/src/plugins/remotelinux/linuxdevice.cpp
@@ -711,8 +711,11 @@ void SshProcessInterfacePrivate::start()
auto linuxDevice = std::dynamic_pointer_cast(m_device);
QTC_ASSERT(linuxDevice, handleDone(); return);
if (linuxDevice->isDisconnected()) {
- emit q->done({-1, QProcess::CrashExit, QProcess::FailedToStart,
- Tr::tr("Device \"%1\" is disconnected").arg(linuxDevice->displayName())});
+ emit q->done(
+ {-1,
+ QProcess::CrashExit,
+ QProcess::FailedToStart,
+ Tr::tr("Device \"%1\" is disconnected.").arg(linuxDevice->displayName())});
return;
}
linuxDevice->connectionAccess()
@@ -1646,7 +1649,7 @@ private:
const expected_str result = async.result();
if (result)
emit progress(
- Tr::tr("Created directory: %1\n").arg(iteratorParentDirs->toUserOutput()));
+ Tr::tr("Created directory: \"%1\".\n").arg(iteratorParentDirs->toUserOutput()));
else
emit progress(result.error());
};
@@ -1665,7 +1668,8 @@ private:
++counter;
if (result) {
- emit progress(Tr::tr("Copied %1/%2: %3 -> %4\n")
+ //: %1/%2 = progress in the form 4/15, %3 and %4 = source and target file paths
+ emit progress(Tr::tr("Copied %1/%2: \"%3\" -> \"%4\".\n")
.arg(counter)
.arg(m_setup.m_files.size())
.arg(iterator->m_source.toUserOutput())
diff --git a/src/plugins/texteditor/texteditorplugin.cpp b/src/plugins/texteditor/texteditorplugin.cpp
index 5db6a17e0d5..5df9de54701 100644
--- a/src/plugins/texteditor/texteditorplugin.cpp
+++ b/src/plugins/texteditor/texteditorplugin.cpp
@@ -304,12 +304,22 @@ void TextEditorPlugin::createStandardContextMenu()
add(Constants::SWITCH_UTF8BOM, Constants::G_BOM);
}
+class TextActionBuilder : public ActionBuilder
+{
+public:
+ TextActionBuilder(QObject *contextActionParent, const Utils::Id actionId)
+ : ActionBuilder(contextActionParent, actionId)
+ {
+ setContext(Context(Constants::C_TEXTEDITOR));
+ }
+};
+
void TextEditorPlugin::createEditorCommands()
{
using namespace Core::Constants;
// Add shortcut for invoking automatic completion
Command *command = nullptr;
- ActionBuilder(this, Constants::COMPLETE_THIS)
+ TextActionBuilder(this, Constants::COMPLETE_THIS)
.setText(Tr::tr("Trigger Completion"))
.bindCommand(&command)
.setDefaultKeySequence(Tr::tr("Meta+Space"), Tr::tr("Ctrl+Space"));
@@ -320,253 +330,253 @@ void TextEditorPlugin::createEditorCommands()
FancyLineEdit::setCompletionShortcut(command->keySequence());
// Add shortcut for invoking function hint completion
- ActionBuilder(this, Constants::FUNCTION_HINT)
+ TextActionBuilder(this, Constants::FUNCTION_HINT)
.setText(Tr::tr("Display Function Hint"))
.setDefaultKeySequence(Tr::tr("Meta+Shift+D"), Tr::tr("Ctrl+Shift+D"));
// Add shortcut for invoking quick fix options
- ActionBuilder(this, Constants::QUICKFIX_THIS)
+ TextActionBuilder(this, Constants::QUICKFIX_THIS)
.setText(Tr::tr("Trigger Refactoring Action"))
.setDefaultKeySequence(Tr::tr("Alt+Return"));
- ActionBuilder(this, Constants::SHOWCONTEXTMENU)
+ TextActionBuilder(this, Constants::SHOWCONTEXTMENU)
.setText(Tr::tr("Show Context Menu"));
- ActionBuilder(this, DELETE_LINE).setText(Tr::tr("Delete &Line"));
- ActionBuilder(this, DELETE_END_OF_LINE).setText(Tr::tr("Delete Line from Cursor On"));
- ActionBuilder(this, DELETE_END_OF_WORD).setText(Tr::tr("Delete Word from Cursor On"));
- ActionBuilder(this, DELETE_END_OF_WORD_CAMEL_CASE)
+ TextActionBuilder(this, DELETE_LINE).setText(Tr::tr("Delete &Line"));
+ TextActionBuilder(this, DELETE_END_OF_LINE).setText(Tr::tr("Delete Line from Cursor On"));
+ TextActionBuilder(this, DELETE_END_OF_WORD).setText(Tr::tr("Delete Word from Cursor On"));
+ TextActionBuilder(this, DELETE_END_OF_WORD_CAMEL_CASE)
.setText(Tr::tr("Delete Word Camel Case from Cursor On"));
- ActionBuilder(this, DELETE_START_OF_LINE)
+ TextActionBuilder(this, DELETE_START_OF_LINE)
.setText(Tr::tr("Delete Line up to Cursor"))
.setDefaultKeySequence(Tr::tr("Ctrl+Backspace"), {});
- ActionBuilder(this, DELETE_START_OF_WORD).setText(Tr::tr("Delete Word up to Cursor"));
- ActionBuilder(this, DELETE_START_OF_WORD_CAMEL_CASE)
+ TextActionBuilder(this, DELETE_START_OF_WORD).setText(Tr::tr("Delete Word up to Cursor"));
+ TextActionBuilder(this, DELETE_START_OF_WORD_CAMEL_CASE)
.setText(Tr::tr("Delete Word Camel Case up to Cursor"));
- ActionBuilder(this, GOTO_BLOCK_START_WITH_SELECTION)
+ TextActionBuilder(this, GOTO_BLOCK_START_WITH_SELECTION)
.setText(Tr::tr("Go to Block Start with Selection"))
.setDefaultKeySequence(QKeySequence(Tr::tr("Ctrl+{")));
- ActionBuilder(this, GOTO_BLOCK_END_WITH_SELECTION)
+ TextActionBuilder(this, GOTO_BLOCK_END_WITH_SELECTION)
.setText(Tr::tr("Go to Block End with Selection"))
.setDefaultKeySequence(QKeySequence(Tr::tr("Ctrl+}")));
- ActionBuilder(this, MOVE_LINE_UP)
+ TextActionBuilder(this, MOVE_LINE_UP)
.setText(Tr::tr("Move Line Up"))
.setDefaultKeySequence(QKeySequence(Tr::tr("Ctrl+Shift+Up")));
- ActionBuilder(this, MOVE_LINE_DOWN)
+ TextActionBuilder(this, MOVE_LINE_DOWN)
.setText(Tr::tr("Move Line Down"))
.setDefaultKeySequence(QKeySequence(Tr::tr("Ctrl+Shift+Down")));
- ActionBuilder(this, COPY_LINE_UP)
+ TextActionBuilder(this, COPY_LINE_UP)
.setText(Tr::tr("Copy Line Up"))
.setDefaultKeySequence(QKeySequence(Tr::tr("Ctrl+Alt+Up")));
- ActionBuilder(this, COPY_LINE_DOWN)
+ TextActionBuilder(this, COPY_LINE_DOWN)
.setText(Tr::tr("Copy Line Down"))
.setDefaultKeySequence(QKeySequence(Tr::tr("Ctrl+Alt+Down")));
- ActionBuilder(this, JOIN_LINES)
+ TextActionBuilder(this, JOIN_LINES)
.setText(Tr::tr("Join Lines"))
.setDefaultKeySequence(QKeySequence(Tr::tr("Ctrl+J")));
- ActionBuilder(this, INSERT_LINE_ABOVE)
+ TextActionBuilder(this, INSERT_LINE_ABOVE)
.setText(Tr::tr("Insert Line Above Current Line"))
.setDefaultKeySequence(QKeySequence(Tr::tr("Ctrl+Shift+Return")));
- ActionBuilder(this, INSERT_LINE_BELOW)
+ TextActionBuilder(this, INSERT_LINE_BELOW)
.setText(Tr::tr("Insert Line Below Current Line"))
.setDefaultKeySequence(QKeySequence(Tr::tr("Ctrl+Return")));
- ActionBuilder(this, SWITCH_UTF8BOM).setText(Tr::tr("Toggle UTF-8 BOM"));
- ActionBuilder(this, INDENT).setText(Tr::tr("Indent"));
- ActionBuilder(this, UNINDENT).setText(Tr::tr("Unindent"));
- ActionBuilder(this, FOLLOW_SYMBOL_UNDER_CURSOR)
+ TextActionBuilder(this, SWITCH_UTF8BOM).setText(Tr::tr("Toggle UTF-8 BOM"));
+ TextActionBuilder(this, INDENT).setText(Tr::tr("Indent"));
+ TextActionBuilder(this, UNINDENT).setText(Tr::tr("Unindent"));
+ TextActionBuilder(this, FOLLOW_SYMBOL_UNDER_CURSOR)
.setText(Tr::tr("Follow Symbol Under Cursor"))
.setDefaultKeySequence(QKeySequence(Qt::Key_F2));
- ActionBuilder(this, FOLLOW_SYMBOL_UNDER_CURSOR_IN_NEXT_SPLIT)
+ TextActionBuilder(this, FOLLOW_SYMBOL_UNDER_CURSOR_IN_NEXT_SPLIT)
.setText(Tr::tr("Follow Symbol Under Cursor in Next Split"))
.setDefaultKeySequence(Tr::tr("Meta+E, F2"), Tr::tr("Ctrl+E, F2"));
- ActionBuilder(this, FOLLOW_SYMBOL_TO_TYPE)
+ TextActionBuilder(this, FOLLOW_SYMBOL_TO_TYPE)
.setText(Tr::tr("Follow Type Under Cursor"))
.setDefaultKeySequence(QKeySequence(Tr::tr("Ctrl+Shift+F2")));
- ActionBuilder(this, FOLLOW_SYMBOL_TO_TYPE_IN_NEXT_SPLIT)
+ TextActionBuilder(this, FOLLOW_SYMBOL_TO_TYPE_IN_NEXT_SPLIT)
.setText(Tr::tr("Follow Type Under Cursor in Next Split"))
.setDefaultKeySequence(Tr::tr("Meta+E, Shift+F2"), Tr::tr("Ctrl+E, Ctrl+Shift+F2"));
- ActionBuilder(this, FIND_USAGES)
+ TextActionBuilder(this, FIND_USAGES)
.setText(Tr::tr("Find References to Symbol Under Cursor"))
.setDefaultKeySequence(QKeySequence(Tr::tr("Ctrl+Shift+U")));
- ActionBuilder(this, RENAME_SYMBOL)
+ TextActionBuilder(this, RENAME_SYMBOL)
.setText(Tr::tr("Rename Symbol Under Cursor"))
.setDefaultKeySequence(QKeySequence(Tr::tr("Ctrl+Shift+R")));
- ActionBuilder(this, JUMP_TO_FILE_UNDER_CURSOR)
+ TextActionBuilder(this, JUMP_TO_FILE_UNDER_CURSOR)
.setText(Tr::tr("Jump to File Under Cursor"))
.setDefaultKeySequence(QKeySequence(Qt::Key_F2));
- ActionBuilder(this, JUMP_TO_FILE_UNDER_CURSOR_IN_NEXT_SPLIT)
+ TextActionBuilder(this, JUMP_TO_FILE_UNDER_CURSOR_IN_NEXT_SPLIT)
.setText(Tr::tr("Jump to File Under Cursor in Next Split"))
.setDefaultKeySequence(Tr::tr("Meta+E, F2"), Tr::tr("Ctrl+E, F2"));
- ActionBuilder(this, OPEN_CALL_HIERARCHY).setText(Tr::tr("Open Call Hierarchy"));
- ActionBuilder(this, OPEN_TYPE_HIERARCHY)
+ TextActionBuilder(this, OPEN_CALL_HIERARCHY).setText(Tr::tr("Open Call Hierarchy"));
+ TextActionBuilder(this, OPEN_TYPE_HIERARCHY)
.setText(Tr::tr("Open Type Hierarchy"))
.setDefaultKeySequence(Tr::tr("Meta+Shift+T"), Tr::tr("Ctrl+Shift+T"));
- ActionBuilder(this, VIEW_PAGE_UP)
+ TextActionBuilder(this, VIEW_PAGE_UP)
.setText(Tr::tr("Move the View a Page Up and Keep the Cursor Position"))
.setDefaultKeySequence(QKeySequence(Tr::tr("Ctrl+PgUp")));
- ActionBuilder(this, VIEW_PAGE_DOWN)
+ TextActionBuilder(this, VIEW_PAGE_DOWN)
.setText(Tr::tr("Move the View a Page Down and Keep the Cursor Position"))
.setDefaultKeySequence(QKeySequence(Tr::tr("Ctrl+PgDown")));
- ActionBuilder(this, VIEW_LINE_UP)
+ TextActionBuilder(this, VIEW_LINE_UP)
.setText(Tr::tr("Move the View a Line Up and Keep the Cursor Position"))
.setDefaultKeySequence(QKeySequence(Tr::tr("Ctrl+Up")));
- ActionBuilder(this, VIEW_LINE_DOWN)
+ TextActionBuilder(this, VIEW_LINE_DOWN)
.setText(Tr::tr("Move the View a Line Down and Keep the Cursor Position"))
.setDefaultKeySequence(QKeySequence(Tr::tr("Ctrl+Down")));
ActionManager::actionContainer(M_EDIT);
- ActionBuilder(this, SELECT_ENCODING)
+ TextActionBuilder(this, SELECT_ENCODING)
.setText(Tr::tr("Select Encoding..."))
.addToContainer(M_EDIT, G_EDIT_OTHER);
- ActionBuilder(this, CIRCULAR_PASTE)
+ TextActionBuilder(this, CIRCULAR_PASTE)
.setText(Tr::tr("Paste from Clipboard History"))
.setDefaultKeySequence(QKeySequence(Tr::tr("Ctrl+Shift+V")))
.addToContainer(M_EDIT, G_EDIT_COPYPASTE);
- ActionBuilder(this, NO_FORMAT_PASTE)
+ TextActionBuilder(this, NO_FORMAT_PASTE)
.setText(Tr::tr("Paste Without Formatting"))
.setDefaultKeySequence(Tr::tr("Ctrl+Alt+Shift+V"), QString())
.addToContainer(M_EDIT, G_EDIT_COPYPASTE);
ActionManager::actionContainer(M_EDIT_ADVANCED);
- ActionBuilder(this, AUTO_INDENT_SELECTION)
+ TextActionBuilder(this, AUTO_INDENT_SELECTION)
.setText(Tr::tr("Auto-&indent Selection"))
.setDefaultKeySequence(QKeySequence(Tr::tr("Ctrl+I")))
.addToContainer(M_EDIT_ADVANCED, G_EDIT_FORMAT);
- ActionBuilder(this, AUTO_FORMAT_SELECTION)
+ TextActionBuilder(this, AUTO_FORMAT_SELECTION)
.setText(Tr::tr("Auto-&format Selection"))
.setDefaultKeySequence(QKeySequence(Tr::tr("Ctrl+;")))
.addToContainer(M_EDIT_ADVANCED, G_EDIT_FORMAT);
- ActionBuilder(this, REWRAP_PARAGRAPH)
+ TextActionBuilder(this, REWRAP_PARAGRAPH)
.setText(Tr::tr("&Rewrap Paragraph"))
.setDefaultKeySequence(Tr::tr("Meta+E, R"), Tr::tr("Ctrl+E, R"))
.addToContainer(M_EDIT_ADVANCED, G_EDIT_FORMAT);
- ActionBuilder(this, VISUALIZE_WHITESPACE)
+ TextActionBuilder(this, VISUALIZE_WHITESPACE)
.setText(Tr::tr("&Visualize Whitespace"))
.setDefaultKeySequence(Tr::tr("Meta+E, Meta+V"), Tr::tr("Ctrl+E, Ctrl+V"))
.addToContainer(M_EDIT_ADVANCED, G_EDIT_FORMAT);
- ActionBuilder(this, CLEAN_WHITESPACE)
+ TextActionBuilder(this, CLEAN_WHITESPACE)
.setText(Tr::tr("Clean Whitespace"))
.addToContainer(M_EDIT_ADVANCED, G_EDIT_FORMAT);
- ActionBuilder(this, TEXT_WRAPPING)
+ TextActionBuilder(this, TEXT_WRAPPING)
.setText(Tr::tr("Enable Text &Wrapping"))
.setDefaultKeySequence(Tr::tr("Meta+E, Meta+W"), Tr::tr("Ctrl+E, Ctrl+W"))
.addToContainer(M_EDIT_ADVANCED, G_EDIT_FORMAT)
.setCheckable(true);
- ActionBuilder(this, UN_COMMENT_SELECTION)
+ TextActionBuilder(this, UN_COMMENT_SELECTION)
.setText(Tr::tr("Toggle Comment &Selection"))
.setDefaultKeySequence(QKeySequence(Tr::tr("Ctrl+/")))
.addToContainer(M_EDIT_ADVANCED, G_EDIT_FORMAT);
- ActionBuilder(this, CUT_LINE)
+ TextActionBuilder(this, CUT_LINE)
.setText(Tr::tr("Cut &Line"))
.setDefaultKeySequence(QKeySequence(Tr::tr("Shift+Del")))
.addToContainer(M_EDIT_ADVANCED, G_EDIT_TEXT);
- ActionBuilder(this, COPY_LINE)
+ TextActionBuilder(this, COPY_LINE)
.setText(Tr::tr("Copy &Line"))
.setDefaultKeySequence(QKeySequence(Tr::tr("Ctrl+Ins")))
.addToContainer(M_EDIT_ADVANCED, G_EDIT_TEXT);
- ActionBuilder(this, COPY_WITH_HTML)
+ TextActionBuilder(this, COPY_WITH_HTML)
.setText(Tr::tr("Copy With Highlighting"))
.addToContainer(M_EDIT_ADVANCED, G_EDIT_TEXT);
- ActionBuilder(this, ADD_CURSORS_TO_LINE_ENDS)
+ TextActionBuilder(this, ADD_CURSORS_TO_LINE_ENDS)
.setText(Tr::tr("Create Cursors at Selected Line Ends"))
.setDefaultKeySequence(QKeySequence(Tr::tr("Alt+Shift+I")))
.addToContainer(M_EDIT_ADVANCED, G_EDIT_TEXT);
- ActionBuilder(this, ADD_SELECT_NEXT_FIND_MATCH)
+ TextActionBuilder(this, ADD_SELECT_NEXT_FIND_MATCH)
.setText(Tr::tr("Add Next Occurrence to Selection"))
.setDefaultKeySequence(QKeySequence(Tr::tr("Ctrl+D")))
.addToContainer(M_EDIT_ADVANCED, G_EDIT_TEXT);
- ActionBuilder(this, DUPLICATE_SELECTION)
+ TextActionBuilder(this, DUPLICATE_SELECTION)
.setText(Tr::tr("&Duplicate Selection"))
.addToContainer(M_EDIT_ADVANCED, G_EDIT_TEXT);
- ActionBuilder(this, DUPLICATE_SELECTION_AND_COMMENT)
+ TextActionBuilder(this, DUPLICATE_SELECTION_AND_COMMENT)
.setText(Tr::tr("&Duplicate Selection and Comment"))
.addToContainer(M_EDIT_ADVANCED, G_EDIT_TEXT);
- ActionBuilder(this, UPPERCASE_SELECTION)
+ TextActionBuilder(this, UPPERCASE_SELECTION)
.setText(Tr::tr("Uppercase Selection"))
.setDefaultKeySequence(Tr::tr("Meta+Shift+U"), Tr::tr("Alt+Shift+U"))
.addToContainer(M_EDIT_ADVANCED, G_EDIT_TEXT);
- ActionBuilder(this, LOWERCASE_SELECTION)
+ TextActionBuilder(this, LOWERCASE_SELECTION)
.setText(Tr::tr("Lowercase Selection"))
.setDefaultKeySequence(Tr::tr("Meta+U"), Tr::tr("Alt+U"))
.addToContainer(M_EDIT_ADVANCED, G_EDIT_TEXT);
- ActionBuilder(this, SORT_LINES)
+ TextActionBuilder(this, SORT_LINES)
.setText(Tr::tr("Sort Lines"))
.setDefaultKeySequence(Tr::tr("Meta+Shift+S"), Tr::tr("Alt+Shift+S"))
.addToContainer(M_EDIT_ADVANCED, G_EDIT_TEXT);
- ActionBuilder(this, FOLD)
+ TextActionBuilder(this, FOLD)
.setText(Tr::tr("Fold"))
.setDefaultKeySequence(QKeySequence(Tr::tr("Ctrl+<")))
.addToContainer(M_EDIT_ADVANCED, G_EDIT_COLLAPSING);
- ActionBuilder(this, UNFOLD)
+ TextActionBuilder(this, UNFOLD)
.setText(Tr::tr("Unfold"))
.setDefaultKeySequence(QKeySequence(Tr::tr("Ctrl+>")))
.addToContainer(M_EDIT_ADVANCED, G_EDIT_COLLAPSING);
- ActionBuilder(this, UNFOLD_ALL)
+ TextActionBuilder(this, UNFOLD_ALL)
.setText(Tr::tr("Toggle &Fold All"))
.addToContainer(M_EDIT_ADVANCED, G_EDIT_COLLAPSING);
- ActionBuilder(this, INCREASE_FONT_SIZE)
+ TextActionBuilder(this, INCREASE_FONT_SIZE)
.setText(Tr::tr("Increase Font Size"))
.setDefaultKeySequence(QKeySequence(Tr::tr("Ctrl++")))
.addToContainer(M_EDIT_ADVANCED, G_EDIT_FONT);
- ActionBuilder(this, DECREASE_FONT_SIZE)
+ TextActionBuilder(this, DECREASE_FONT_SIZE)
.setText(Tr::tr("Decrease Font Size"))
.setDefaultKeySequence(QKeySequence(Tr::tr("Ctrl+-")))
.addToContainer(M_EDIT_ADVANCED, G_EDIT_FONT);
- ActionBuilder(this, RESET_FONT_SIZE)
+ TextActionBuilder(this, RESET_FONT_SIZE)
.setText(Tr::tr("Reset Font Size"))
.setDefaultKeySequence(QKeySequence(Tr::tr("Ctrl+0")))
.addToContainer(M_EDIT_ADVANCED, G_EDIT_FONT);
- ActionBuilder(this, GOTO_BLOCK_START)
+ TextActionBuilder(this, GOTO_BLOCK_START)
.setText(Tr::tr("Go to Block Start"))
.setDefaultKeySequence(QKeySequence(Tr::tr("Ctrl+[")))
.addToContainer(M_EDIT_ADVANCED, G_EDIT_BLOCKS);
- ActionBuilder(this, GOTO_BLOCK_END)
+ TextActionBuilder(this, GOTO_BLOCK_END)
.setText(Tr::tr("Go to Block End"))
.setDefaultKeySequence(QKeySequence(Tr::tr("Ctrl+]")))
.addToContainer(M_EDIT_ADVANCED, G_EDIT_BLOCKS);
- ActionBuilder(this, SELECT_BLOCK_UP)
+ TextActionBuilder(this, SELECT_BLOCK_UP)
.setText(Tr::tr("Select Block Up"))
.setDefaultKeySequence(QKeySequence(Tr::tr("Ctrl+U")))
.addToContainer(M_EDIT_ADVANCED, G_EDIT_BLOCKS);
- ActionBuilder(this, SELECT_BLOCK_DOWN)
+ TextActionBuilder(this, SELECT_BLOCK_DOWN)
.setText(Tr::tr("Select Block Down"))
.setDefaultKeySequence(QKeySequence(Tr::tr("Ctrl+Shift+Alt+U")))
.addToContainer(M_EDIT_ADVANCED, G_EDIT_BLOCKS);
- ActionBuilder(this, SELECT_WORD_UNDER_CURSOR).setText(Tr::tr("Select Word Under Cursor"));
+ TextActionBuilder(this, SELECT_WORD_UNDER_CURSOR).setText(Tr::tr("Select Word Under Cursor"));
- ActionBuilder(this, GOTO_DOCUMENT_START).setText(Tr::tr("Go to Document Start"));
- ActionBuilder(this, GOTO_DOCUMENT_END).setText(Tr::tr("Go to Document End"));
- ActionBuilder(this, GOTO_LINE_START).setText(Tr::tr("Go to Line Start"));
- ActionBuilder(this, GOTO_LINE_END).setText(Tr::tr("Go to Line End"));
- ActionBuilder(this, GOTO_NEXT_LINE).setText(Tr::tr("Go to Next Line"));
- ActionBuilder(this, GOTO_PREVIOUS_LINE).setText(Tr::tr("Go to Previous Line"));
- ActionBuilder(this, GOTO_PREVIOUS_CHARACTER).setText(Tr::tr("Go to Previous Character"));
- ActionBuilder(this, GOTO_NEXT_CHARACTER).setText(Tr::tr("Go to Next Character"));
- ActionBuilder(this, GOTO_PREVIOUS_WORD).setText(Tr::tr("Go to Previous Word"));
- ActionBuilder(this, GOTO_NEXT_WORD).setText(Tr::tr("Go to Next Word"));
- ActionBuilder(this, GOTO_PREVIOUS_WORD_CAMEL_CASE)
+ TextActionBuilder(this, GOTO_DOCUMENT_START).setText(Tr::tr("Go to Document Start"));
+ TextActionBuilder(this, GOTO_DOCUMENT_END).setText(Tr::tr("Go to Document End"));
+ TextActionBuilder(this, GOTO_LINE_START).setText(Tr::tr("Go to Line Start"));
+ TextActionBuilder(this, GOTO_LINE_END).setText(Tr::tr("Go to Line End"));
+ TextActionBuilder(this, GOTO_NEXT_LINE).setText(Tr::tr("Go to Next Line"));
+ TextActionBuilder(this, GOTO_PREVIOUS_LINE).setText(Tr::tr("Go to Previous Line"));
+ TextActionBuilder(this, GOTO_PREVIOUS_CHARACTER).setText(Tr::tr("Go to Previous Character"));
+ TextActionBuilder(this, GOTO_NEXT_CHARACTER).setText(Tr::tr("Go to Next Character"));
+ TextActionBuilder(this, GOTO_PREVIOUS_WORD).setText(Tr::tr("Go to Previous Word"));
+ TextActionBuilder(this, GOTO_NEXT_WORD).setText(Tr::tr("Go to Next Word"));
+ TextActionBuilder(this, GOTO_PREVIOUS_WORD_CAMEL_CASE)
.setText(Tr::tr("Go to Previous Word (Camel Case)"));
- ActionBuilder(this, GOTO_NEXT_WORD_CAMEL_CASE).setText(Tr::tr("Go to Next Word (Camel Case)"));
+ TextActionBuilder(this, GOTO_NEXT_WORD_CAMEL_CASE).setText(Tr::tr("Go to Next Word (Camel Case)"));
- ActionBuilder(this, GOTO_LINE_START_WITH_SELECTION)
+ TextActionBuilder(this, GOTO_LINE_START_WITH_SELECTION)
.setText(Tr::tr("Go to Line Start with Selection"));
- ActionBuilder(this, GOTO_LINE_END_WITH_SELECTION)
+ TextActionBuilder(this, GOTO_LINE_END_WITH_SELECTION)
.setText(Tr::tr("Go to Line End with Selection"));
- ActionBuilder(this, GOTO_NEXT_LINE_WITH_SELECTION)
+ TextActionBuilder(this, GOTO_NEXT_LINE_WITH_SELECTION)
.setText(Tr::tr("Go to Next Line with Selection"));
- ActionBuilder(this, GOTO_PREVIOUS_LINE_WITH_SELECTION)
+ TextActionBuilder(this, GOTO_PREVIOUS_LINE_WITH_SELECTION)
.setText(Tr::tr("Go to Previous Line with Selection"));
- ActionBuilder(this, GOTO_PREVIOUS_CHARACTER_WITH_SELECTION)
+ TextActionBuilder(this, GOTO_PREVIOUS_CHARACTER_WITH_SELECTION)
.setText(Tr::tr("Go to Previous Character with Selection"));
- ActionBuilder(this, GOTO_NEXT_CHARACTER_WITH_SELECTION)
+ TextActionBuilder(this, GOTO_NEXT_CHARACTER_WITH_SELECTION)
.setText(Tr::tr("Go to Next Character with Selection"));
- ActionBuilder(this, GOTO_PREVIOUS_WORD_WITH_SELECTION)
+ TextActionBuilder(this, GOTO_PREVIOUS_WORD_WITH_SELECTION)
.setText(Tr::tr("Go to Previous Word with Selection"));
- ActionBuilder(this, GOTO_NEXT_WORD_WITH_SELECTION)
+ TextActionBuilder(this, GOTO_NEXT_WORD_WITH_SELECTION)
.setText(Tr::tr("Go to Next Word with Selection"));
- ActionBuilder(this, GOTO_PREVIOUS_WORD_CAMEL_CASE_WITH_SELECTION)
+ TextActionBuilder(this, GOTO_PREVIOUS_WORD_CAMEL_CASE_WITH_SELECTION)
.setText(Tr::tr("Go to Previous Word (Camel Case) with Selection"));
- ActionBuilder(this, GOTO_NEXT_WORD_CAMEL_CASE_WITH_SELECTION)
+ TextActionBuilder(this, GOTO_NEXT_WORD_CAMEL_CASE_WITH_SELECTION)
.setText(Tr::tr("Go to Next Word (Camel Case) with Selection"));
}
diff --git a/src/shared/qbs b/src/shared/qbs
index 2e54309c02a..c99763b462a 160000
--- a/src/shared/qbs
+++ b/src/shared/qbs
@@ -1 +1 @@
-Subproject commit 2e54309c02a56c602909ee3f4fef6c654a616c85
+Subproject commit c99763b462a93b547f4f3f41ab84e9e793276d4c
diff --git a/src/tools/icons/qtcreatoricons.svg b/src/tools/icons/qtcreatoricons.svg
index 01ec12e64ba..714b37601b6 100644
--- a/src/tools/icons/qtcreatoricons.svg
+++ b/src/tools/icons/qtcreatoricons.svg
@@ -3818,6 +3818,20 @@
style="fill:none;stroke:#000000;stroke-width:2;stroke-linejoin:round"
sodipodi:nodetypes="cccccccccccc" />
+
+
+
+
+
+
+
+
+