Merge remote-tracking branch 'origin/15.0'

Conflicts:
	src/plugins/android/androiddeployqtstep.cpp
	src/plugins/debugger/debuggerdialogs.cpp
	src/plugins/projectexplorer/kitaspect.cpp

Change-Id: Iebc1d7a38db4c228282c04c63d7f11ee76072a06
This commit is contained in:
Eike Ziller
2024-11-14 11:47:32 +01:00
90 changed files with 1235 additions and 371 deletions

View File

@@ -2,27 +2,45 @@ type: Group
instructions:
- type: Group
instructions:
# Currently used Qt version for packaging ...
- type: Group
instructions:
- type: SetBuildDirectory
directory: "{{.AgentWorkingDir}}/build"
- type: MakeDirectory
directory: "{{.BuildDir}}"
- type: EnvironmentVariable
variableName: QTC_QT_BASE_URL
variableValue: "https://ci-files02-hki.ci.qt.io/packages/jenkins/qt/6.8.0/release_content/"
- type: EnvironmentVariable
variableName: MACOSX_DEPLOYMENT_TARGET
variableValue: 12.0
enable_if:
condition: property
property: features
not_contains_value: "OldestQt"
# ... or oldest supported Qt version
- type: Group
instructions:
- type: EnvironmentVariable
variableName: QTC_QT_BASE_URL
variableValue: "https://ci-files02-hki.ci.qt.io/packages/jenkins/qt/6.4.3/release_content/"
- type: EnvironmentVariable
variableName: MACOSX_DEPLOYMENT_TARGET
variableValue: 11.0
enable_if:
condition: property
property: features
contains_value: "OldestQt"
- type: SetBuildDirectory
directory: "{{.AgentWorkingDir}}/build"
- type: MakeDirectory
directory: "{{.BuildDir}}"
- type: EnvironmentVariable
variableName: QTC_BUILD_TYPE
variableValue: "RelWithDebInfo"
- type: EnvironmentVariable
variableName: LLVM_BASE_URL
variableValue: https://ci-files02-hki.ci.qt.io/packages/jenkins/qtcreator_libclang/libclang-release_19.1.0-based
- type: EnvironmentVariable
variableName: QTC_QT_BASE_URL
variableValue: "https://ci-files02-hki.ci.qt.io/packages/jenkins/qt/6.8.0/release_content/"
- type: EnvironmentVariable
variableName: QTC_QT_MODULES
variableValue: "qt5compat qtbase qtdeclarative qtimageformats qtquick3d qtquicktimeline qtserialport qtshadertools qtsvg qttools qttranslations qtwebengine"
- type: EnvironmentVariable
variableName: MACOSX_DEPLOYMENT_TARGET
variableValue: 11.0
- type: EnvironmentVariable
variableName: SDKTOOL_MACOSX_DEPLOYMENT_TARGET
variableValue: 11.0
@@ -37,6 +55,17 @@ instructions:
- type: EnvironmentVariable
variableName: QTC_QT_POSTFIX
variableValue: "-Windows-Windows_11_23H2-MSVC2022-Windows-Windows_11_23H2-X86_64.7z"
enable_if:
condition: property
property: features
not_contains_value: "OldestQt"
- type: EnvironmentVariable
variableName: QTC_QT_POSTFIX
variableValue: "-Windows-Windows_11_22H2-MSVC2019-Windows-Windows_11_22H2-X86_64.7z"
enable_if:
condition: property
property: features
contains_value: "OldestQt"
- type: EnvironmentVariable
variableName: QTC_SDKTOOL_QT_EXT
variableValue: ".zip"
@@ -55,9 +84,30 @@ instructions:
equals_value: Windows
- type: Group
instructions:
- type: EnvironmentVariable
variableName: QTC_QT_POSTFIX
variableValue: "-Linux-RHEL_8_8-GCC-Linux-RHEL_8_8-X86_64.7z"
- type: Group
instructions:
- type: EnvironmentVariable
variableName: QTC_QT_POSTFIX
variableValue: "-Linux-RHEL_8_8-GCC-Linux-RHEL_8_8-X86_64.7z"
- type: EnvironmentVariable
variableName: QTC_ICU_URL
variableValue: "https://ci-files02-hki.ci.qt.io/packages/jenkins/development_releases/prebuilt/icu/prebuilt/73.2/icu-linux-g++-Rhel8.6-x64.7z"
enable_if:
condition: property
property: features
not_contains_value: "OldestQt"
- type: Group
instructions:
- type: EnvironmentVariable
variableName: QTC_QT_POSTFIX
variableValue: "-Linux-RHEL_8_4-GCC-Linux-RHEL_8_4-X86_64.7z"
- type: EnvironmentVariable
variableName: QTC_ICU_URL
variableValue: "https://ci-files02-hki.ci.qt.io/packages/jenkins/development_releases/prebuilt/icu/prebuilt/56.1/icu-linux-g++-Rhel7.2-x64.7z"
enable_if:
condition: property
property: features
contains_value: "OldestQt"
- type: EnvironmentVariable
variableName: QTC_SDKTOOL_QT_EXT
variableValue: ".tar.xz"
@@ -67,9 +117,6 @@ instructions:
- type: EnvironmentVariable
variableName: QTC_LLVM_POSTFIX
variableValue: "-linux-Rhel8.8-gcc10.3-x86_64.7z"
- type: EnvironmentVariable
variableName: QTC_ICU_URL
variableValue: "https://ci-files02-hki.ci.qt.io/packages/jenkins/development_releases/prebuilt/icu/prebuilt/56.1/icu-linux-g++-Rhel7.2-x64.7z"
- type: EnvironmentVariable
variableName: PYTHON_EXECUTABLE
variableValue: "python3"
@@ -124,6 +171,17 @@ instructions:
- type: EnvironmentVariable
variableName: QTC_QT_POSTFIX
variableValue: "-MacOS-MacOS_14-Clang-MacOS-MacOS_14-X86_64-ARM64.7z"
enable_if:
condition: property
property: features
not_contains_value: "OldestQt"
- type: EnvironmentVariable
variableName: QTC_QT_POSTFIX
variableValue: "-MacOS-MacOS_12-Clang-MacOS-MacOS_12-X86_64-ARM64.7z"
enable_if:
condition: property
property: features
contains_value: "OldestQt"
- type: EnvironmentVariable
variableName: QTC_SDKTOOL_QT_EXT
variableValue: ".tar.xz"

View File

@@ -1,4 +1,3 @@
dependencies:
../../qt/qt5.git:
ref: "6.8"

View File

@@ -47,6 +47,8 @@ Editing
* Added `Fold Recursively` and `Unfold Recursively`
* Fixed the display of multi-line annotations
([QTCREATORBUG-29951](https://bugreports.qt.io/browse/QTCREATORBUG-29951))
* Fixed the tab order in `Advanced Search`
([QTCREATORBUG-31771](https://bugreports.qt.io/browse/QTCREATORBUG-31771))
### C++
@@ -67,6 +69,8 @@ Editing
([QTCREATORBUG-31256](https://bugreports.qt.io/browse/QTCREATORBUG-31256))
* Fixed the display of annotations with array operators
([QTCREATORBUG-31670](https://bugreports.qt.io/browse/QTCREATORBUG-31670))
* Fixed code formatting after `Apply Changes to Declaration / Definition`
([QTCREATORBUG-31293](https://bugreports.qt.io/browse/QTCREATORBUG-31293))
* ClangFormat
* Implemented `Export` and `Import` for the settings
@@ -182,6 +186,8 @@ Projects
* Fixed the option `Build Only the Application to Be Run` for the
`Build before deploying` preferences
([QTCREATORBUG-31416](https://bugreports.qt.io/browse/QTCREATORBUG-31416))
* Fixed the `vcpkg` support for Android
([QTCREATORBUG-31883](https://bugreports.qt.io/browse/QTCREATORBUG-31883))
### Workspace
@@ -274,6 +280,11 @@ Extension Manager
Platforms
---------
### Windows
* Fixed that it wasn't possible to select a remote `qmake` executable
([QTCREATORBUG-31939](https://bugreports.qt.io/browse/QTCREATORBUG-31939))
### macOS
* Added support for back and forward gestures
@@ -284,6 +295,8 @@ Platforms
* Improved the responsiveness of Qt Creator during Android related operations
* Fixed that the setup wizard could use the wrong NDK and build tools version
([QTCREATORBUG-31311](https://bugreports.qt.io/browse/QTCREATORBUG-31311))
* Fixed a freeze in the preferences while an emulator is running
([QTCREATORBUG-31912](https://bugreports.qt.io/browse/QTCREATORBUG-31912))
### iOS
@@ -314,11 +327,13 @@ Alexandru Croitor
Ali Kianian
Andre Hartmann
André Pönitz
Andrii Batyiev
Andrii Semkiv
Artem Sokolovskii
Artur Twardy
Assam Boudjelthia
Audun Sutterud
BogDan Vatra
Burak Hancerli
Christian Kandeler
Christian Stenger
@@ -332,6 +347,7 @@ Henning Gruendl
Jaroslaw Kobus
Jussi Witick
Justyna Hudziak
Kai Köhne
Karim Pinter
Knud Dollereder
Kwangsub Kim
@@ -346,6 +362,7 @@ Mariusz Szczepanik
Mathias Hasselmann
Mats Honkamaa
Mehdi Salem
Michael Weghorn
Miikka Heikkinen
Orgad Shaneh
Pino Toscano
@@ -366,5 +383,6 @@ Tim Jenßen
Toni Saario
Ulf Hermann
Vikas Pachdha
Ville Lavonius
Xavier Besson
Zoltan Gera

Binary file not shown.

Before

Width:  |  Height:  |  Size: 21 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 11 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 4.1 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 16 KiB

View File

@@ -15,7 +15,7 @@
\uicontrol Debugger. In the \uicontrol General tab, you can specify settings
that are common to all debuggers.
\image qtcreator-debugger-general-options.png "Debugger General preferences"
\image qtcreator-preferences-debugger-general.webp {Debugger General preferences}
You can customize the appearance and behavior of the debug views and
setting breakpoints, as well as map source paths to target paths.

View File

@@ -838,7 +838,7 @@
To change the appearance and behavior of the debug views, set preferences
in \preferences > \uicontrol Debugger > \uicontrol General.
\image qtcreator-debugger-general-options.png {General tab in Debugger preferences}
\image qtcreator-preferences-debugger-general.webp {General tab in Debugger preferences}
For example, you can:
@@ -1270,7 +1270,7 @@
at which the libraries were built, you can map source paths to target
paths in \preferences > \uicontrol Debugger > \uicontrol General.
\image qtcreator-debugger-general-options.png {General tab in Debugger preferences}
\image qtcreator-preferences-debugger-general.webp {General tab in Debugger preferences}
For more information, see \l{Source Paths Mapping}.

View File

@@ -74,8 +74,8 @@
To use a context-specific margin when available, select the
\uicontrol {Use context-specific margin} check box.
\if defined(qtcreator)
Then, use the ClangFormat \c ColumnLimit option to set the margin, for
example.
Then, use the \l{ClangFormat Style Options}{ClangFormat} \c ColumnLimit
option to set the margin, for example.
\sa {C++ Code Style}
\endif

View File

@@ -23,7 +23,7 @@
\li \l{http://astyle.sourceforge.net}{Artistic Style}
\li \l{http://clang.llvm.org/docs/ClangFormat.html}{ClangFormat}
\li \l{ClangFormat: Documentation}{ClangFormat}
\li \l{http://uncrustify.sourceforge.net}{Uncrustify}
@@ -41,7 +41,7 @@
\list
\li \l{http://sourceforge.net/projects/astyle/files/astyle}
{Artistic Style}
\li \l{http://llvm.org/releases/download.html}{ClangFormat}
\li \l{ClangFormat: Download}{ClangFormat}
\li \l{http://sourceforge.net/projects/uncrustify/files/uncrustify}
{Uncrustify}
\endlist

View File

@@ -11,7 +11,7 @@
\brief Set global code style for C++ files.
\QC uses the Clang \l{https://clang.llvm.org/docs/LibFormat.html}{LibFormat}
\QC uses the Clang \l{LibFormat: Documentation}{LibFormat}
library to automatically format and indent C++ code. It enforces a coding
style for a project or the whole organization.
@@ -25,7 +25,8 @@
\li \uicontrol {Indenting Only} to only indent code.
\li \uicontrol {Full Formatting} to use the \key {Ctrl+I}
keyboard shortcut to format code instead of indenting.
\li \uicontrol {Use Built-In Indenter} to turn off ClangFormat.
\li \uicontrol {Use Built-In Indenter} to turn off
\l{ClangFormat: Documentation}{ClangFormat}.
\endlist
\li Select \uicontrol {Ignore files greater than} to make parsing faster
by ignoring big files. Specify the maximum size of files to parse.
@@ -38,10 +39,8 @@
\li In \uicontrol {Custom settings}, select the settings to change, and
then select \uicontrol Copy.
\li Give a name to the settings, and select \uicontrol OK.
\li In \uicontrol ClangFormat, edit the
\l{https://clang.llvm.org/docs/ClangFormatStyleOptions.html}
{ClangFormat Style Options}. The live preview shows how the
preferences change the indentation.
\li In \uicontrol ClangFormat, edit the \l {ClangFormat Style Options}.
The live preview shows how the preferences change the indentation.
If you enter invalid values, you see warning messages.
\endlist

View File

@@ -253,3 +253,19 @@
\externalpage https://code.qt.io/cgit/qt-creator/qt-creator.git/tree/share/qtcreator/jsonschemas/project.json
\title project.json
*/
/*!
\externalpage https://clang.llvm.org/docs/ClangFormat.html
\title ClangFormat: Documentation
*/
/*!
\externalpage https://llvm.org/releases/download.html
\title ClangFormat: Download
*/
/*!
\externalpage https://clang.llvm.org/docs/ClangFormatStyleOptions.html
\title ClangFormat Style Options
*/
/*!
\externalpage https://clang.llvm.org/docs/LibFormat.html
\title LibFormat: Documentation
*/

View File

@@ -0,0 +1,38 @@
// Copyright (C) 2024 The Qt Company Ltd.
// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GFDL-1.3-no-invariants-only
/*!
\page creator-how-to-collect-usage-statistics.html
\previouspage creator-how-tos.html
\ingroup creator-how-to-use
\title Collect usage statistics
When you install \QC with \QOI, you can allow it to collect pseudonymous
information about your system and \QC use. If you decline, the telemetry
plugin is not installed and no usage statistics are collected.
\section1 Principles of data collection
No personal data, such as names, IP addresses, MAC addresses, or project
and path names are collected. However, QUuid objects are used to identify
data records that belong to one user. The objects cannot be converted
back to the actual values from which they were generated.
For more information about Qt privacy policy, see
\l{https://www.qt.io/terms-conditions/privacy-and-security}
{Qt Appendix for Privacy and Security}.
\QC respects the same privacy rules.
\section1 Turn on data collection
To allow the telemetry plugin to collect data, go to \preferences >
\uicontrol Telemetry > \uicontrol {Usage Statistics}, and then select
\uicontrol {Send pseudonymous usage statistics}.
\image qtcreator-preferences-telemetry-usage-statistics.webp {Usage Statistics}
\sa {Installation}
*/

View File

@@ -1,106 +0,0 @@
// Copyright (C) 2023 The Qt Company Ltd.
// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GFDL-1.3-no-invariants-only
/*!
\page creator-telemetry.html
\if defined(qtdesignstudio)
\previouspage creator-quick-ui-forms.html
\nextpage collecting-usage-statistics.html
\else
\previouspage creator-how-tos.html
\endif
\ingroup creator-how-to-use
\title Manage data collection
\if defined (qtcreator)
When you install \QC as a part of Qt installation, you are asked whether
you allow it to collect pseudonymous information about your system and \QC
use. If you decline, the plugin is not installed and no analytics data is
collected.
If you accept, all collected and transmitted data is fully transparent to
you. You can change the settings for collecting and transmitting data any
time. By default, no data is collected and you have to select a telemetry
mode for data collection to begin.
See \l {Collect usage statistics} for more information about the data
transmitted by the telemetry plugin and \l {Specify telemetry settings}
{specifying telemetry settings}.
\else
To enable the use of the telemetry plugin, you need to select \uicontrol
{Enable Usage Statistics} in the splash screen that appears when you first
launch \QDS. If the splash screen does not appear, you can enable the
telemetry plugin by selecting \uicontrol Help > \uicontrol {About Plugins} >
\uicontrol Utilities > \uicontrol UsageStatistic on Linux and Windows (or
\uicontrol {\QDS} > \uicontrol {About Plugins} > \uicontrol Utilities >
\uicontrol UsageStatistic on \macos).
\image studio-usage-statistics.png "Enabling Usage Statistics"
\endif
\if defined(qtdesignstudio)
See below for more information about the collected data:
\list
\li \l {Collect usage statistics}
\li \l {Collecting User Feedback}
\li \l {Reporting Crashes}
\endlist
\endif
\section1 Principles of data collection
No personal data, such as names, IP addresses, MAC addresses, or project
and path names are collected. However, QUuid objects are used to identify
data records that belong to one user. The objects cannot be converted
back to the actual values from which they were generated.
For more information about Qt privacy policy, select
\l{https://www.qt.io/terms-conditions/#privacy}
{Legal Notice and Privacy Policy}.
\sa {Collect usage statistics}
*/
/*!
\page collecting-usage-statistics.html
\if defined(qtdesignstudio)
\previouspage creator-telemetry.html
\nextpage studio-user-feedback.html
\else
\previouspage creator-how-tos.html
\endif
\ingroup creator-how-to-use
\title Collect usage statistics
The telemetry plugin uses the
\l{https://api.kde.org/frameworks/kuserfeedback/html/index.html}
{KUserFeedback} framework to collect the usage data. The library
has been designed from the user data privacy point of view and
\QC respects the same privacy rules.
The data is transmitted to the backend storage using an encrypted
connection. The storage is located in the same Heroku backend as the
\QOI backend. Physically, data is stored in the Amazon cloud.
\section1 Specify telemetry settings
To determine what data is transmitted to the backend storage:
\list 1
\li Select \preferences > \uicontrol Telemetry
> \uicontrol {Usage Statistics}.
\image qtcreator-telemetry-settings.png "Telemetry settings"
\li In the \uicontrol {Telemetry mode} list, select the mode that
determines what kind of data is collected.
\li In the \uicontrol {Data sources} list, select entries to view
exactly what data is collected. Deselect check boxes for data
that you do not want to transmit to the backend storage.
\endlist
\sa {Manage data collection}
*/

View File

@@ -258,17 +258,29 @@
system libraries or your own libraries. Further, your own libraries might
link to other libraries. To compile your project and benefit from services
such as code completion and syntax highlighting, add the libraries to your
project. The process of adding a library to a project depends on the build
system that you use.
project.
\section1 CMake projects
\section1 Create subprojects
To add CMakeLists.txt files to any project, use the
\l{https://cmake.org/cmake/help/latest/command/add_subdirectory.html}
{add_subdirectory} command. The files can define complete projects that
you include into the top-level project or any other CMake commands.
To create subprojects and add them to a project:
\section1 qmake projects
\list 1
\li Right-click the project name in the \l Projects view to open the
context menu, and select \uicontrol {New Subproject}.
\li Follow the instructions of the wizard to create a subproject.
\image qtcreator-project-qt-quick.webp {New Project dialog}
\endlist
\section1 Add existing projects as subprojects
To add an existing project as a subproject:
\list 1
\li Select \uicontrol {Add Existing Projects} in the context menu.
\li In the file browser dialog, locate your subproject.
\endlist
\section1 Create SUBDIRS projects for qmake
When you create a new project and select qmake as the build system,
you can add it to another project as a subproject in the
@@ -292,28 +304,15 @@
and the subproject that you add as a value of the \l{Variables#subdirs}
{SUBDIRS variable}. It also adds all the necessary files for the subproject.
\section2 Add subprojects to the root project
\section2 Specify dependencies
To create more subprojects, right-click the project name in the
\l Projects view to open the context menu, and select
\uicontrol {New Subproject}. Follow the steps in the
\uicontrol {New Subproject} wizard to create a subproject.
\image qtcreator-project-qt-quick.webp {New Project dialog}
To add an existing project as a subproject, select
\uicontrol {Add Existing Projects} in the context menu.
In the file browser dialog, locate your subproject.
To specify dependencies, use the \uicontrol{Add Library} wizard.
\section2 Remove subprojects
To remove subprojects, right-click the project name in the \uicontrol Projects
view, and select \uicontrol {Remove Subproject} in the context menu.
\section2 Specify dependencies
To specify dependencies, use the \uicontrol{Add Library} wizard.
\sa {Creating Projects}, {Use project wizards},
{Add libraries to qmake projects}, {Add libraries to CMake projects}
*/

View File

@@ -53,9 +53,9 @@
project.
\endlist
In rare cases, ClangFormat can trip over a code construct and
trigger a \QC crash. If that happens for your project, select
\uicontrol {Use Built-In Indenter} in \uicontrol {Formatting mode} to
In rare cases, \l{ClangFormat: Documentation}{ClangFormat} can trip over a
code construct and trigger a \QC crash. If that happens for your project,
select \uicontrol {Use Built-In Indenter} in \uicontrol {Formatting mode} to
turn off ClangFormat for the project. If you can reproduce the crash,
go to \uicontrol Help > \uicontrol {Report Bug} to report
the bug and attach the code that triggers the crash to the bug report.

Binary file not shown.

After

Width:  |  Height:  |  Size: 3.9 KiB

View File

@@ -0,0 +1,59 @@
// Copyright (C) 2024 The Qt Company Ltd.
// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GFDL-1.3-no-invariants-only
/*!
\page studio-telemetry.html
\previouspage creator-quick-ui-forms.html
\nextpage studio-collecting-usage-statistics.html
\title Managing Data Collection
See below for more information about the collected data:
\list
\li \l {Collecting Usage Statistics}
\li \l {Collecting User Feedback}
\li \l {Reporting Crashes}
\endlist
\section1 Principles of Data Collection
No personal data, such as names, IP addresses, MAC addresses, or project
and path names are collected. However, QUuid objects are used to identify
data records that belong to one user. The objects cannot be converted
back to the actual values from which they were generated.
For more information about Qt privacy policy, see
\l{https://www.qt.io/terms-conditions/privacy-and-security}
{Qt Appendix for Privacy and Security}.
\sa {Collecting Usage Statistics}
*/
/*!
\page studio-collecting-usage-statistics.html
\previouspage studio-telemetry.html
\nextpage studio-user-feedback.html
\title Collecting Usage Statistics
The telemetry plugin uses the
\l{https://api.kde.org/frameworks/kuserfeedback/html/index.html}
{KUserFeedback} framework to collect the usage data. The library
has been designed from the user data privacy point of view and
\QC respects the same privacy rules.
The data is transmitted to the backend storage using an encrypted
connection. The storage is located in the same Heroku backend as the
\QOI backend. Physically, data is stored in the Amazon cloud.
\section1 Turning on Telemetry
To determine what data is transmitted to the backend storage, go to
\preferences > \uicontrol Telemetry > \uicontrol {Usage Statistics},
and then select \uicontrol {Enable telemetry}.
\image studio-preferences-telemetry-usage-statistics.webp {Usage Statistics}
\sa {Managing Data Collection}
*/

View File

@@ -23,7 +23,7 @@
Some of the wizard templates create projects that contain UI files.
You should always edit UI files in the \l {2D}
and \l Properties view, to avoid breaking the code.
\li \l{Manage Data Collection}
\li \l{Managing Data Collection}
You can enable \QDS to report crashes automatically. If you enable
the telemetry plugin, you can turn on the pseudonymous user

View File

@@ -217,9 +217,9 @@
\li Extending Component Functionality
\endomit
\li \l{UI Files}
\li \l{Manage Data Collection}
\li \l{Managing Data Collection}
\list
\li \l {Collect Usage Statistics}
\li \l {Collecting Usage Statistics}
\li \l {Collecting User Feedback}
\li \l {Reporting Crashes}
\endlist

View File

@@ -272,12 +272,7 @@ def package_qtcreator(args, paths):
if not args.no_cdb:
common.check_print_call(command + [paths.qtcreatorcdbext_install])
# use -mf=off to avoid usage of the ARM executable compression filter,
# which cannot be extracted by p7zip
# use -snl to preserve symlinks even if their target doesn't exist
# which is important for the _dev package on Linux
# (only works with official/upstream 7zip)
zip = ['7z', 'a', '-mmt' + args.zip_threads, '-mf=off', '-snl']
zip = common.sevenzip_command(args.zip_threads)
if not args.no_zip:
if not args.no_qtcreator:
common.check_print_call(zip

View File

@@ -147,12 +147,7 @@ def package(args, paths):
if common.is_windows_platform() and args.sign_command:
command = shlex.split(args.sign_command)
common.check_print_call(command + [paths.install])
# use -mf=off to avoid usage of the ARM executable compression filter,
# which cannot be extracted by p7zip
# use -snl to preserve symlinks even if their target doesn't exist
# which is important for the _dev package on Linux
# (only works with official/upstream 7zip)
zip = ['7z', 'a', '-mmt' + args.zip_threads, '-mf=off', '-snl']
zip = common.sevenzip_command(args.zip_threads)
common.check_print_call(zip + [os.path.join(paths.result, args.name + '.7z'), '*'],
paths.install)
if os.path.exists(paths.dev_install): # some plugins might not provide anything in Devel

View File

@@ -4,13 +4,13 @@
from __future__ import annotations
import argparse
from itertools import islice
import os
from pathlib import Path
from typing import NamedTuple
from common import (is_linux_platform, is_mac_platform, is_windows_platform,
download_and_extract, check_print_call)
download_and_extract, check_print_call, sevenzip_command,
get_single_subdir)
class BuildParams(NamedTuple):
@@ -105,13 +105,6 @@ def sign_sdktool(params: BuildParams,
env=environment)
def get_single_subdir(path: Path):
entries = list(islice(path.iterdir(), 2))
if len(entries) == 1:
return path / entries[0]
return path
def build_sdktool(
qt_src_url: str,
qt_build_base: Path,
@@ -150,7 +143,7 @@ def zip_sdktool(
) -> None:
glob = "*.exe" if is_windows_platform() else "*"
check_print_call(
cmd=["7z", "a", str(out_7zip), glob],
cmd=sevenzip_command() + [str(out_7zip), glob],
cwd=sdktool_target_path
)

View File

@@ -4,6 +4,7 @@
from __future__ import annotations
import argparse
import asyncio
from itertools import islice
import os
import locale
from pathlib import Path
@@ -61,6 +62,26 @@ def get_commit_SHA(path):
git_sha = f.read().strip()
return git_sha
def get_single_subdir(path: Path):
entries = list(islice(path.iterdir(), 2))
if len(entries) == 1:
return path / entries[0]
return path
def sevenzip_command(threads=None):
# use -mf=off to avoid usage of the ARM executable compression filter,
# which cannot be extracted by p7zip
# use -snl to preserve symlinks even if their target doesn't exist
# which is important for the _dev package on Linux
# (only works with official/upstream 7zip)
command = ['7z', 'a', '-mf=off', '-snl']
if threads:
command.extend(['-mmt' + threads])
return command
# copy of shutil.copytree that does not bail out if the target directory already exists
# and that does not create empty directories
def copytree(src, dst, symlinks=False, ignore=None):
@@ -142,22 +163,26 @@ async def download(url: str, target: Path) -> None:
def download_and_extract(urls: list[str], target: Path, temp: Path) -> None:
download_and_extract_tuples([(url, target) for url in urls], temp)
def download_and_extract_tuples(urls_and_targets: list[tuple[str, Path]], temp: Path) -> None:
temp.mkdir(parents=True, exist_ok=True)
target_files = []
target_tuples : list[tuple[Path, Path]] = []
# TODO make this work with file URLs, which then aren't downloaded
# but just extracted
async def impl():
tasks : list[asyncio.Task] = []
for url in urls:
for (url, target_path) in urls_and_targets:
u = urlparse(url)
filename = Path(u.path).name
target_file = temp / filename
target_files.append(target_file)
target_tuples.append((target_file, target_path))
tasks.append(asyncio.create_task(download(url, target_file)))
for task in tasks:
await task
asyncio.run(impl())
for file in target_files:
for (file, target) in target_tuples:
extract_file(file, target)

View File

@@ -4,7 +4,7 @@
from __future__ import annotations
import argparse
from common import download_and_extract
from common import download_and_extract_tuples
from pathlib import Path
import subprocess
import sys
@@ -73,10 +73,10 @@ def install_qt(
with TemporaryDirectory() as temporary_dir:
if need_to_install_qt:
urls = qt_modules
url_target_tuples = [(url, qt_path) for url in qt_modules]
if icu_url:
qt_modules.append(icu_url)
download_and_extract(urls, qt_path, Path(temporary_dir))
url_target_tuples.append((icu_url, qt_path / 'lib'))
download_and_extract_tuples(url_target_tuples, Path(temporary_dir))
patch_qt(qt_path)

View File

@@ -202,6 +202,46 @@ def qdump__CPlusPlus__Internal__Value(d, value):
d.putPlainChildren(value)
def is_windows_drive_letter(ch):
return (ch >= ord('A') and ch <= ord('Z')) or (ch >= ord('a') and ch <= ord('z'))
def is_relative_filepath_enc(path_enc):
# Note: path is hex-encoded UTF-16 here, i.e. 4 byte per original QChar
"""
This needs to stay in sync with the implementation on the C++ side
in filepath.cpp.
bool isWindowsDriveLetter(QChar ch)
{
return (ch >= 'A' && ch <= 'Z') || (ch >= 'a' && ch <= 'z');
}
bool startsWithWindowsDriveLetterAndSlash(QStringView path)
{
return path.size() > 2 && path[1] == ':' && path[2] == '/
&& isWindowsDriveLetter(path[0]);
}
bool FilePath::isRelativePath() const
{
const QStringView p = pathView();
if (p.startsWith('/'))
return false;
if (startsWithWindowsDriveLetterAndSlash(p))
return false;
if (p.startsWith(u":/")) // QRC
return false;
return true;
}
"""
colon = "3A00"
slash = "2F00"
if path_enc.startswith(slash):
return False
if path_enc[4:12] == colon + slash and is_windows_drive_letter(int(path_enc[0:2], 16)):
return False
if path_enc.startswith(colon + slash):
return False
return True
def qdump__Utils__FilePath(d, value):
data, path_len, scheme_len, host_len = d.split("{@QString}IHH", value)
length, enc = d.encodeStringHelper(data, d.displayStringLimit)
@@ -216,8 +256,10 @@ def qdump__Utils__FilePath(d, value):
dot = "2E00"
colon = "3A00"
val = scheme_enc + colon + slash + slash + host_enc
if not path_enc.startswith(slash):
if is_relative_filepath_enc(path_enc):
val += slash + dot + slash
elif is_windows_drive_letter(int(path_enc[0:2], 16)):
val += slash
val += path_enc
else:
val = enc

View File

@@ -988,7 +988,7 @@ class Dumper(DumperBase):
connect_options = lldb.SBPlatformConnectOptions(self.remoteChannel_)
res = self.target.GetPlatform().ConnectRemote(connect_options)
DumperBase.warn("CONNECT: %s %s platform: %s %s" % (res,
DumperBase.warn("CONNECT: %s %s platform: %s connected: %s" % (res,
self.remoteChannel_,
self.target.GetPlatform().GetName(),
self.target.GetPlatform().IsConnected()))

View File

@@ -46,6 +46,9 @@ local function tst_embedWidget()
}
embed = editor:addEmbeddedWidget(layout, cursor:mainCursor():position())
embed:onShouldClose(function()
embed:close()
end)
end
local function setup()

View File

@@ -1451,10 +1451,10 @@ void PluginManagerPrivate::loadPlugins()
void PluginManagerPrivate::loadPluginsAtRuntime(const QSet<PluginSpec *> &plugins)
{
const bool allSoftloadable = allOf(plugins, &PluginSpec::isSoftLoadable);
const bool allSoftloadable = allOf(plugins, &PluginSpec::isEffectivelySoftloadable);
if (!allSoftloadable) {
const QStringList notSoftLoadablePlugins = Utils::transform<QStringList>(
Utils::filtered(plugins, std::not_fn(&PluginSpec::isSoftLoadable)),
Utils::filtered(plugins, std::not_fn(&PluginSpec::isEffectivelySoftloadable)),
&PluginSpec::displayName);
qWarning().noquote()
<< "PluginManagerPrivate::loadPluginsAtRuntime(): trying to load non-softloadable"
@@ -1464,7 +1464,7 @@ void PluginManagerPrivate::loadPluginsAtRuntime(const QSet<PluginSpec *> &plugin
// load the plugins and their dependencies (if possible) ordered by dependency
const QList<PluginSpec *> queue = filtered(loadQueue(), [&plugins](PluginSpec *spec) {
// Is the current plugin already running, or not soft loadable?
if (spec->state() == PluginSpec::State::Running || !spec->isSoftLoadable())
if (spec->state() == PluginSpec::State::Running || !spec->isEffectivelySoftloadable())
return false;
// Is the current plugin in the list of plugins to load?

View File

@@ -497,6 +497,22 @@ bool PluginSpec::isForceDisabled() const
return d->forceDisabled;
}
bool PluginSpec::isEffectivelySoftloadable() const
{
if (state() == Running)
return true;
if (!d->softLoadable)
return false;
if (state() < PluginSpec::Resolved)
return false; // We won't know yet.
return !Utils::anyOf(dependencySpecs(), [](PluginSpec *dependency) {
return !dependency->isEffectivelySoftloadable();
});
}
/*!
Returns whether the plugin is allowed to be loaded during runtime
without a restart.

View File

@@ -131,6 +131,7 @@ public:
virtual bool isForceEnabled() const;
virtual bool isForceDisabled() const;
virtual bool isSoftLoadable() const;
virtual bool isEffectivelySoftloadable() const;
virtual QVector<PluginDependency> dependencies() const;
virtual QJsonObject metaData() const;

View File

@@ -239,8 +239,10 @@ Result DeviceFileAccess::copyRecursively(const FilePath &src, const FilePath &ta
targetProcess.writeRaw(srcProcess.readAllRawStandardOutput());
});
srcProcess.setCommand({sourceTar, {"-C", src.path(), "-cf", "-", "."}});
targetProcess.setCommand({targetTar, {"xf", "-", "-C", target.path()}});
srcProcess.setCommand({sourceTar, {"-cf", "-", "."}});
srcProcess.setWorkingDirectory(src);
targetProcess.setCommand({targetTar, {"xf", "-"}});
targetProcess.setWorkingDirectory(target);
targetProcess.start();
targetProcess.waitForStarted();

View File

@@ -869,6 +869,13 @@ static bool startsWithWindowsDriveLetterAndSlash(QStringView path)
return path.size() > 2 && path[1] == ':' && path[2] == '/' && isWindowsDriveLetter(path[0]);
}
static bool startsWithWindowsDriveLetter(QStringView path)
{
if (path.size() > 2 && startsWithWindowsDriveLetterAndSlash(path))
return true;
return path.size() == 2 && path[1] == ':' && isWindowsDriveLetter(path[0]);
}
int FilePath::rootLength(const QStringView path)
{
if (path.size() == 0)
@@ -888,6 +895,8 @@ int FilePath::rootLength(const QStringView path)
if (startsWithWindowsDriveLetterAndSlash(path))
return 3; // FIXME-ish: same assumption as elsewhere: we assume "x:/" only ever appears as root
if (path.size() == 2 && startsWithWindowsDriveLetter(path))
return 2;
if (path[0] == '/')
return 1;
@@ -1252,9 +1261,14 @@ void FilePath::setFromString(QStringView fileNameView)
if (schemeEnd != -1 && schemeEnd < firstSlash) {
// This is a pseudo Url, we can't use QUrl here sadly.
const QStringView scheme = fileNameView.left(schemeEnd);
const int hostEnd = fileNameView.indexOf(slash, schemeEnd + 3);
int hostEnd = fileNameView.indexOf(slash, schemeEnd + 3);
const QString host = decodeHost(
fileNameView.mid(schemeEnd + 3, hostEnd - schemeEnd - 3).toString());
QStringView path = fileNameView.mid(hostEnd);
if (!path.isEmpty() && path[0] == '/' && startsWithWindowsDriveLetter(path.mid(1)))
hostEnd++;
setParts(scheme, host, hostEnd != -1 ? fileNameView.mid(hostEnd) : QStringView());
return;
}
@@ -1553,9 +1567,6 @@ bool FilePath::contains(const QString &s) const
bool FilePath::startsWithDriveLetter() const
{
QStringView p = pathView();
if (needsDevice() && !p.isEmpty())
p = p.mid(1);
return p.size() >= 2 && isWindowsDriveLetter(p[0]) && p.at(1) == ':';
}

View File

@@ -15,6 +15,7 @@
#include <QFormLayout>
#include <QGridLayout>
#include <QGroupBox>
#include <QKeyEvent>
#include <QLabel>
#include <QPushButton>
#include <QScrollArea>
@@ -785,6 +786,11 @@ void Widget::setContentsMargins(int left, int top, int right, int bottom)
access(this)->setContentsMargins(left, top, right, bottom);
}
void Widget::setCursor(Qt::CursorShape shape)
{
access(this)->setCursor(shape);
}
void Widget::activateWindow()
{
access(this)->activateWindow();
@@ -1149,9 +1155,24 @@ void tight(Layout *layout)
layout->setSpacing(0);
}
class LineEditImpl : public Utils::FancyLineEdit
{
public:
using FancyLineEdit::FancyLineEdit;
void keyPressEvent(QKeyEvent *event) override
{
FancyLineEdit::keyPressEvent(event);
if (acceptReturnKeys && (event->key() == Qt::Key_Enter || event->key() == Qt::Key_Return))
event->accept();
}
bool acceptReturnKeys = false;
};
LineEdit::LineEdit(std::initializer_list<I> ps)
{
ptr = new Implementation;
ptr = new LineEditImpl;
apply(this, ps);
}
@@ -1192,6 +1213,7 @@ void LineEdit::setMinimumHeight(int height)
void LineEdit::onReturnPressed(const std::function<void()> &func, QObject *guard)
{
static_cast<LineEditImpl *>(access(this))->acceptReturnKeys = true;
QObject::connect(access(this), &Utils::FancyLineEdit::returnPressed, guard, func);
}

View File

@@ -258,6 +258,8 @@ public:
void setNoMargins(int = 0);
void setNormalMargins(int = 0);
void setContentsMargins(int left, int top, int right, int bottom);
void setCursor(Qt::CursorShape shape);
void activateWindow();
void close();
};

View File

@@ -382,7 +382,13 @@ QString MacroExpander::expand(const QString &stringWithVariables) const
FilePath MacroExpander::expand(const FilePath &fileNameWithVariables) const
{
// We want single variables to expand to fully qualified strings.
// This is intentionally unsymmetric: We have already sanitized content
// in fileNameWithVariables, so using .toString() is fine.
// The macro expansion may introduce arbitrary new contents, so
// sanitization using fromUserInput() needs to repeated.
// We also cannot just operate on the scheme, host and path component
// individually as we want to allow single variables to expand to fully
// remote-qualified paths.
return FilePath::fromUserInput(expand(fileNameWithVariables.toString()));
}

View File

@@ -394,6 +394,11 @@ QSize MarkdownBrowser::minimumSizeHint() const
return boundingRect.size().toSize() + QTextBrowser::minimumSizeHint();
}
void MarkdownBrowser::setMargins(const QMargins &margins)
{
setViewportMargins(margins);
}
void MarkdownBrowser::setAllowRemoteImages(bool allow)
{
static_cast<AnimatedDocument *>(document())->setAllowRemoteImages(allow);

View File

@@ -25,6 +25,8 @@ public:
QSize sizeHint() const override;
QSize minimumSizeHint() const override;
void setMargins(const QMargins &margins);
protected:
void changeEvent(QEvent *event) override;

View File

@@ -58,6 +58,22 @@
# include <QTest>
#endif // WITH_TESTS
/*
Suggested NDK and Debugger version per Qt version:
| Qt5 | Qt6 | NDK | GDB | LLDB |
| ---------------- | --------- | ------------- | ------ | ------ |
| 5.12.0 - 5.13.1 | | 19.2.5345600 | 7.11.0 | |
| 5.13.2 - 5.15.8 | 6.0 - 6.1 | 21.3.6528147 | 8.3.0 | |
| 5.15.9 - 5.15.16 | 6.2 - 6.3 | 22.1.7171670 | 8.3.0 | 11.0.5 |
| | 6.4 | 23.1.7779620 | 8.3.0 | 12.0.8 |
| | 6.5 - 6.6 | 25.1.8937393 | | 14.0.6 |
| | 6.7 - 6.8 | 26.1.10909125 | | 17.0.2 |
< Qt 6.5: Mapping read from sdk_definitions.json
>= Qt 6.5: Mapping read from <QtDir>/modules/Core.json
*/
using namespace ProjectExplorer;
using namespace QtSupport;
using namespace Tasking;

View File

@@ -14,6 +14,7 @@
#include <projectexplorer/projectmanager.h>
#include <utils/algorithm.h>
#include <utils/qtcassert.h>
using namespace Utils;
@@ -303,23 +304,30 @@ ITestConfiguration *QtTestTreeItem::debugConfiguration() const
QList<ITestConfiguration *> QtTestTreeItem::getAllTestConfigurations() const
{
QList<ITestConfiguration *> result;
QList<QSet<QString>> allTargets;
ProjectExplorer::Project *project = ProjectExplorer::ProjectManager::startupProject();
if (!project || type() != Root)
return result;
forFirstLevelChildren([&result](ITestTreeItem *child) {
if (child->type() == TestCase) {
ITestConfiguration *tc = child->testConfiguration();
QTC_ASSERT(tc, return);
result << tc;
} else if (child->type() == GroupNode) {
child->forFirstLevelChildren([&result](ITestTreeItem *groupChild) {
ITestConfiguration *tc = groupChild->testConfiguration();
QTC_ASSERT(tc, return);
result << tc;
});
// avoid executing tests with multiple test classes multiple times
auto appendConfiguration = [&result, &allTargets](ITestTreeItem *item) {
ITestConfiguration *config = item->testConfiguration();
QTC_ASSERT(config, return);
const QSet<QString> targets = static_cast<TestConfiguration *>(config)->internalTargets();
if (allTargets.contains(targets)) {
delete config;
} else {
result << config;
allTargets << targets;
}
};
forFirstLevelChildren([appendConfiguration](ITestTreeItem *child) {
if (child->type() == TestCase)
appendConfiguration(child);
else if (child->type() == GroupNode)
child->forFirstLevelChildren(appendConfiguration);
});
return result;
}

View File

@@ -116,8 +116,8 @@ bool ITestTreeItem::lessThan(const ITestTreeItem *other, ITestTreeItem::SortMode
return filePath().path().compare(other->filePath().path(), Qt::CaseInsensitive) > 0;
}
const Link &leftLink = data(0, LinkRole).value<Link>();
const Link &rightLink = other->data(0, LinkRole).value<Link>();
const Link leftLink{m_filePath, m_line};
const Link rightLink{other->m_filePath, other->m_line};
const int comparison = leftLink.targetFilePath.path()
.compare(rightLink.targetFilePath.path(), Qt::CaseInsensitive);
if (comparison == 0) {

View File

@@ -92,10 +92,6 @@ static std::optional<PathMapping> findPathMappingMatch(const QString &projectNam
for (const PathMapping &mapping : settings().validPathMappings()) {
if (mapping.projectName != projectName)
continue;
if (mapping.localPath.isRelativePath()) // TODO mark inside settings
continue;
if (mapping.analysisPath.isAbsolutePath()) // TODO mark inside settings
continue;
if (mapping.analysisPath.isEmpty())
return mapping;

View File

@@ -86,6 +86,31 @@ bool PathMapping::operator!=(const PathMapping &other) const
return !(*this == other);
}
static bool analysisPathValid(const FilePath &analysisPath, QString *error)
{
if (analysisPath.isEmpty())
return true;
if (analysisPath.needsDevice() || analysisPath.isAbsolutePath()) {
if (error)
*error = QString("Path must be relative.");
return false;
}
static const QRegularExpression invalid("^(.*/)?\\.\\.?(/.*)?$");
if (invalid.match(analysisPath.path()).hasMatch()) {
if (error)
*error = QString("Invalid path elements (. or ..)");
return false;
}
return true;
}
bool PathMapping::isValid() const
{
return !projectName.isEmpty() && !localPath.isEmpty()
&& !localPath.needsDevice() && localPath.isAbsolutePath()
&& analysisPathValid(analysisPath, nullptr);
}
static FilePath axivionJsonFilePath()
{
return FilePath::fromString(ICore::settings()->fileName()).parentDir()
@@ -549,8 +574,22 @@ public:
{
m_projectName.setLabelText(Tr::tr("Project name:"));
m_projectName.setDisplayStyle(StringAspect::LineEditDisplay);
m_projectName.setValidationFunction([](FancyLineEdit *edit, QString *error) {
QTC_ASSERT(edit, return false);
if (!edit->text().isEmpty())
return true;
if (error)
*error = QString("Project name must be non-empty.");
return false;
});
m_analysisPath.setLabelText(Tr::tr("Analysis path:"));
m_analysisPath.setDisplayStyle(StringAspect::LineEditDisplay);
m_analysisPath.setValidationFunction([](FancyLineEdit *edit, QString *error) {
QTC_ASSERT(edit, return false);
// do NOT use fromUserInput() as this also cleans the path
const FilePath fp = FilePath::fromString(edit->text().replace('\\', '/'));
return analysisPathValid(fp, error);
});
m_localPath.setLabelText(Tr::tr("Local path:"));
m_localPath.setExpectedKind(PathChooser::ExistingDirectory);
m_localPath.setAllowPathFromDevice(false);

View File

@@ -43,7 +43,7 @@ public:
bool operator==(const PathMapping &other) const;
bool operator!=(const PathMapping &other) const;
bool isValid() const {return !projectName.isEmpty() && !localPath.isEmpty(); }
bool isValid() const;
QString projectName;
Utils::FilePath analysisPath;
Utils::FilePath localPath;

View File

@@ -10,10 +10,12 @@
#include <utils/layoutbuilder.h>
#include <utils/utilsicons.h>
#include <QGuiApplication>
#include <QLabel>
#include <QMouseEvent>
#include <QPainter>
#include <QPushButton>
#include <QScreen>
#include <QToolButton>
namespace Axivion::Internal {
@@ -37,6 +39,22 @@ static QString infoText()
"\"\" matches issues having an empty value in this column\n"
"!\"\" matches issues having any non-empty value in this column");
}
static void fixGlobalPosOnScreen(QPoint *globalPos, const QSize &size)
{
QScreen *qscreen = QGuiApplication::screenAt(*globalPos);
if (!qscreen)
qscreen = QGuiApplication::primaryScreen();
const QRect screen = qscreen->availableGeometry();
if (globalPos->x() + size.width() > screen.width())
globalPos->setX(screen.width() - size.width());
if (globalPos->y() + size.height() > screen.height())
globalPos->setY(screen.height() - size.height());
if (globalPos->y() < 0)
globalPos->setY(0);
}
class FilterPopupWidget : public QFrame
{
public:
@@ -262,8 +280,10 @@ void IssueHeaderView::mouseReleaseEvent(QMouseEvent *event)
popup->setOnApply(onApply);
const int right = sectionViewportPosition(logical) + sectionSize(logical);
const QSize size = popup->sizeHint();
popup->move(mapToGlobal(QPoint{x() + right - size.width(),
this->y() - size.height()}));
QPoint globalPos = mapToGlobal(QPoint{std::max(0, x() + right - size.width()),
this->y() - size.height()});
fixGlobalPosOnScreen(&globalPos, size);
popup->move(globalPos);
popup->show();
}
}

View File

@@ -41,7 +41,10 @@ clang::format::FormatStyle calculateQtcStyle()
style.Language = FormatStyle::LK_Cpp;
style.AccessModifierOffset = -4;
style.AlignAfterOpenBracket = FormatStyle::BAS_Align;
#if LLVM_VERSION_MAJOR >= 15
#if LLVM_VERSION_MAJOR >= 18
style.AlignConsecutiveAssignments = {false, false, false, false, false, false};
style.AlignConsecutiveDeclarations = {false, false, false, false, false, false};
#elif LLVM_VERSION_MAJOR >= 15
style.AlignConsecutiveAssignments = {false, false, false, false, false};
style.AlignConsecutiveDeclarations = {false, false, false, false, false};
#else

View File

@@ -720,7 +720,9 @@ static void addCompileGroups(ProjectNode *targetRoot,
targetRoot);
if (showSourceFolders) {
FilePath baseDir = sourceDirectory.pathAppended(td.sourceGroups[i]);
if (!baseDir.exists())
const bool caseSensitiveMatch = baseDir.nativePath()
== baseDir.canonicalPath().nativePath();
if (!baseDir.exists() || !caseSensitiveMatch)
baseDir = sourceDirectory;
insertNode->addNestedNodes(std::move(current), baseDir);
} else {

View File

@@ -484,9 +484,11 @@ static void drawPrimitiveTweakedForDarkTheme(QStyle::PrimitiveElement element,
case QStyle::PE_FrameGroupBox: {
QRect groupBoxFrame = option->rect;
int topMargin = 0;
if (widget) {
if (auto control = dynamic_cast<const QGroupBox *>(widget)) {
const bool emptyTitle = !control->isCheckable() && control->title().isEmpty();
// Before Qt 6.6.3, QStyle::subControlRect() returned wrong QRect for SC_GroupBoxFrame
static const bool validSCRect = QLibraryInfo::version() >= QVersionNumber(6, 6, 3);
const bool validSCRect = QLibraryInfo::version() >= QVersionNumber(6, 6, 3)
&& !emptyTitle; // QTCREATORBUG-31960
if (validSCRect) {
QStyleOptionGroupBox opt;
opt.initFrom(widget);
@@ -497,8 +499,7 @@ static void drawPrimitiveTweakedForDarkTheme(QStyle::PrimitiveElement element,
} else {
// Snippet from pre-6.6.3 FusionStyle::drawPrimitive - BEGIN
static const int groupBoxTopMargin = 3;
auto control = dynamic_cast<const QGroupBox *>(widget);
if (!control->isCheckable() && control->title().isEmpty()) {
if (emptyTitle) {
// Shrinking the topMargin if Not checkable AND title is empty
topMargin = groupBoxTopMargin;
} else {
@@ -630,8 +631,10 @@ void ManhattanStyle::drawPrimitiveForPanelWidget(PrimitiveElement element,
if (!enabled)
painter->setOpacity(0.75);
QBrush baseBrush = option->palette.base();
if (widget && qobject_cast<const QSpinBox *>(widget->parentWidget()))
if (widget && qobject_cast<const QSpinBox *>(widget->parentWidget())
&& StyleHelper::isQDSTheme()) {
baseBrush = creatorColor(Theme::DScontrolBackgroundDisabled);
}
painter->fillRect(backgroundRect, baseBrush);
painter->restore();
} else {

View File

@@ -84,7 +84,7 @@ PluginDialog::PluginDialog()
connect(m_view, &ExtensionSystem::PluginView::pluginsChanged,
this, [this](const QSet<PluginSpec *> &plugins, bool enable) {
for (PluginSpec *plugin : plugins) {
if (enable && plugin->isSoftLoadable()) {
if (enable && plugin->isEffectivelySoftloadable()) {
m_softLoad.insert(plugin);
} else {
m_softLoad.remove(plugin); // In case it was added, harmless otherwise.

View File

@@ -207,7 +207,7 @@ void SecretAspect::addToLayoutImpl(Layouting::Layout &parent)
d->wasEdited = true;
});
addLabeledItem(parent, Layouting::Row{edit, warningLabel, showPasswordButton}.emerge());
addLabeledItem(parent, Layouting::Row{Layouting::noMargin, edit, warningLabel, showPasswordButton}.emerge());
}
void SecretAspect::requestValue(

View File

@@ -30,6 +30,7 @@
#include <QGroupBox>
#include <QGuiApplication>
#include <QLabel>
#include <QMessageBox>
#include <QPlainTextEdit>
#include <QPushButton>
#include <QRadioButton>
@@ -402,6 +403,11 @@ void StartApplicationDialog::run(bool attachRemote)
}
IDevice::ConstPtr dev = RunDeviceKitAspect::device(k);
if (!dev) {
QMessageBox::critical(
&dialog, Tr::tr("Cannot debug"), Tr::tr("Cannot debug application: Kit has no device"));
return;
}
ProcessRunData inferior = newParameters.runnable;
const QString inputAddress = dialog.d->channelOverrideEdit->text();
if (!inputAddress.isEmpty())
@@ -419,7 +425,7 @@ void StartApplicationDialog::run(bool attachRemote)
if (!newParameters.sysRoot.isEmpty())
debugger->setSysRoot(newParameters.sysRoot);
bool isLocal = !dev || (dev->type() == ProjectExplorer::Constants::DESKTOP_DEVICE_TYPE);
bool isLocal = dev->type() == ProjectExplorer::Constants::DESKTOP_DEVICE_TYPE;
if (isLocal) // FIXME: Restriction needed?
debugger->setInferiorEnvironment(k->runEnvironment());

View File

@@ -279,6 +279,8 @@ public:
QString m_container;
std::unique_ptr<Process> m_startProcess;
std::optional<Environment> m_cachedEnviroment;
bool m_isShutdown = false;
SynchronizedValue<std::unique_ptr<DeviceFileAccess>> m_fileAccess;
@@ -771,13 +773,11 @@ void DockerDevicePrivate::stopCurrentContainer()
}
}
Process proc;
proc.setCommand({settings().dockerBinaryPath(), {"container", "kill", m_container}});
if (m_startProcess && m_startProcess->isRunning())
m_startProcess->kill(); // Kill instead of stop so we don't wait for the process to finish.
m_container.clear();
proc.runBlocking();
m_cachedEnviroment.reset();
}
@@ -972,18 +972,45 @@ expected_str<QString> DockerDevicePrivate::createContainer()
expected_str<void> DockerDevicePrivate::startContainer()
{
using namespace std::chrono_literals;
auto createResult = createContainer();
if (!createResult)
return make_unexpected(createResult.error());
Process startProcess;
startProcess.setCommand({settings().dockerBinaryPath(), {"container", "start", m_container}});
startProcess.runBlocking();
if (startProcess.result() != ProcessResult::FinishedWithSuccess) {
return make_unexpected(Tr::tr("Failed starting Docker container. Exit code: %1, output: %2")
.arg(startProcess.exitCode())
.arg(startProcess.allOutput()));
if (m_startProcess)
m_startProcess->stop();
m_startProcess = std::make_unique<Process>();
m_startProcess->setCommand(
{settings().dockerBinaryPath(), {"container", "start", "-a", "-i", m_container}});
m_startProcess->setProcessMode(ProcessMode::Writer);
m_startProcess->start();
if (!m_startProcess->waitForStarted(5s)) {
if (m_startProcess->state() == QProcess::NotRunning) {
return make_unexpected(
Tr::tr("Failed starting Docker container. Exit code: %1, output: %2")
.arg(m_startProcess->exitCode())
.arg(m_startProcess->allOutput()));
}
// Lets assume it will start soon
qCWarning(dockerDeviceLog)
<< "Docker container start process took more than 5 seconds to start.";
}
QDeadlineTimer deadline(5s);
while (!DockerApi::instance()->isContainerRunning(m_container) && !deadline.hasExpired()) {
QThread::msleep(100);
}
if (deadline.hasExpired() && !DockerApi::instance()->isContainerRunning(m_container)) {
m_startProcess->stop();
return make_unexpected(Tr::tr("Failed to start container: %1").arg(m_container));
}
qCDebug(dockerDeviceLog) << "Started container: " << m_startProcess->commandLine();
return {};
}

View File

@@ -389,7 +389,6 @@ private:
QStackedWidget *m_detailsStack;
CollapsingWidget *m_secondaryDescriptionWidget;
HeadingWidget *m_headingWidget;
QWidget *m_primaryContent;
QWidget *m_secondaryContent;
MarkdownBrowser *m_description;
QLabel *m_dateUpdatedTitle;
@@ -457,17 +456,8 @@ ExtensionManagerWidget::ExtensionManagerWidget()
QPalette browserPal = m_description->palette();
browserPal.setColor(QPalette::Base, creatorColor(Theme::Token_Background_Default));
m_description->setPalette(browserPal);
using namespace Layouting;
auto primary = new QWidget;
const auto spL = spacing(SpacingTokens::VPaddingL);
// clang-format off
Column {
m_description,
noMargin, spacing(SpacingTokens::ExVPaddingGapXl),
}.attachTo(primary);
// clang-format on
m_primaryContent = toScrollableColumn(primary);
const int verticalPadding = SpacingTokens::ExVPaddingGapXl - SpacingTokens::VPaddingM;
m_description->setMargins({verticalPadding, 0, verticalPadding, 0});
m_dateUpdatedTitle = sectionTitle(h6TF, Tr::tr("Last Update"));
m_dateUpdated = tfLabel(contentTF, false);
@@ -482,7 +472,11 @@ ExtensionManagerWidget::ExtensionManagerWidget()
m_pluginStatus = new PluginStatusWidget;
auto secondary = new QWidget;
using namespace Layouting;
const auto spL = spacing(SpacingTokens::VPaddingL);
const auto spXxs = spacing(SpacingTokens::VPaddingXxs);
// clang-format off
Column {
sectionTitle(h6CapitalTF, Tr::tr("Extension details")),
Column {
@@ -515,7 +509,7 @@ ExtensionManagerWidget::ExtensionManagerWidget()
customMargins(SpacingTokens::ExVPaddingGapXl, SpacingTokens::ExVPaddingGapXl,
SpacingTokens::ExVPaddingGapXl, SpacingTokens::ExVPaddingGapXl),
},
m_primaryContent,
m_description,
},
},
m_secondaryDescriptionWidget,
@@ -536,6 +530,7 @@ ExtensionManagerWidget::ExtensionManagerWidget()
},
noMargin, spacing(0),
}.attachTo(this);
// clang-format on
WelcomePageHelpers::setBackgroundColor(this, Theme::Token_Background_Default);
@@ -580,6 +575,7 @@ void ExtensionManagerWidget::updateView(const QModelIndex &current)
{
const QString description = current.data(RoleDescriptionLong).toString();
m_description->setMarkdown(description);
m_description->document()->setDocumentMargin(SpacingTokens::VPaddingM);
}
{

View File

@@ -986,17 +986,21 @@ void GitPluginPrivate::logFile()
*/
QStringList GitPluginPrivate::lineRange(int &firstLine, bool allowSingleLine) const
{
auto buildLineRange = [](int firstLine, int lastLine = -1) {
int stop = (lastLine == -1) ? firstLine : lastLine;
return QStringList{"-L " + QString::number(firstLine) + ',' + QString::number(stop)};
};
if (BaseTextEditor *textEditor = BaseTextEditor::currentTextEditor()) {
QTextCursor cursor = textEditor->textCursor();
if (cursor.hasSelection()) {
QString argument = "-L ";
int selectionStart = cursor.selectionStart();
int selectionEnd = cursor.selectionEnd();
cursor.setPosition(selectionStart);
const int startBlock = cursor.blockNumber();
cursor.setPosition(selectionEnd);
int endBlock = cursor.blockNumber();
if (startBlock != endBlock) {
if (startBlock != endBlock || allowSingleLine) {
firstLine = startBlock + 1;
if (cursor.atBlockStart())
--endBlock;
@@ -1005,13 +1009,18 @@ QStringList GitPluginPrivate::lineRange(int &firstLine, bool allowSingleLine) co
if (previousFirstLine > 0)
firstLine = previousFirstLine;
}
argument += QString::number(firstLine) + ',';
argument += QString::number(endBlock + firstLine - startBlock);
return {argument};
return buildLineRange(firstLine, firstLine + endBlock - startBlock);
} else if (startBlock == endBlock) {
QTextCursor lineCursor = textEditor->textCursor();
lineCursor.movePosition(QTextCursor::StartOfLine);
const bool startsAtLineStart = (lineCursor.position() == selectionStart);
lineCursor.movePosition(QTextCursor::EndOfLine);
const bool endsAtLineEnd = (lineCursor.position() == selectionEnd);
if (startsAtLineStart && endsAtLineEnd)
return buildLineRange(lineCursor.blockNumber() + 1);
}
} else if (allowSingleLine) {
firstLine = cursor.blockNumber() + 1;
return {"-L " + QString::number(firstLine) + ',' + QString::number(firstLine)};
return buildLineRange(cursor.blockNumber() + 1);
}
}
return {};

View File

@@ -1829,6 +1829,7 @@ LanguageClientValue<MessageActionItem> ClientPrivate::showMessageBox(
const ShowMessageRequestParams &message)
{
QMessageBox box;
box.setWindowTitle(q->name());
box.setText(message.toString());
switch (message.type()) {
case Error:

View File

@@ -43,7 +43,11 @@ QString LanguageClientCompletionItem::text() const
{ return m_item.label(); }
bool LanguageClientCompletionItem::implicitlyApplies() const
{ return false; }
{
// only implicitly apply this item if there is no textEdit otherwise the user has to confirm
// the completion
return !m_item.textEdit();
}
bool LanguageClientCompletionItem::prematurelyApplies(const QChar &typedCharacter) const
{

View File

@@ -166,6 +166,7 @@ void LspCapabilitiesWidget::setCapabilities(const Capabilities &serverCapabiliti
{
m_capabilitiesView->setModel(
createJsonModel(Tr::tr("Server Capabilities"), QJsonObject(serverCapabilities.capabilities)));
m_dynamicCapabilities = serverCapabilities.dynamicCapabilities;
const QStringList &methods = m_dynamicCapabilities.registeredMethods();
if (methods.isEmpty()) {
@@ -502,7 +503,7 @@ LspInspectorWidget::LspInspectorWidget(LspInspector *inspector)
TabWidget {
bindTo(&m_tabWidget),
Tab(Tr::tr("Log"), Column { m_logWidget }),
Tab(Tr::tr("Capabilities"), Column {new LspCapabilitiesWidget}),
Tab(Tr::tr("Capabilities"), Column { m_capWidget }),
},
buttonBox,
}.attachTo(this);

View File

@@ -490,6 +490,7 @@ public:
m_initializationOptions = options.as<QString>();
emit optionsChanged();
LanguageClientManager::applySettings();
m_isUpdatingAsyncOptions = false;
});
@@ -703,7 +704,7 @@ static void registerLuaApi()
"sendMessageWithIdForDocument_cb",
&LuaClientWrapper::sendMessageWithIdForDocument_cb,
"create",
[](const sol::table &options) -> std::shared_ptr<LuaClientWrapper> {
[](const sol::main_table &options) -> std::shared_ptr<LuaClientWrapper> {
auto luaClientWrapper = std::make_shared<LuaClientWrapper>(options);
auto clientSettings = new LuaClientSettings(luaClientWrapper);

View File

@@ -111,10 +111,24 @@ CREATE_HAS_FUNC(setTextInteractionFlags, Qt::TextInteractionFlags())
CREATE_HAS_FUNC(setFixedSize, QSize())
CREATE_HAS_FUNC(setVisible, bool())
CREATE_HAS_FUNC(setIcon, Utils::Icon());
CREATE_HAS_FUNC(setContentsMargins, int(), int(), int(), int());
CREATE_HAS_FUNC(setCursor, Qt::CursorShape())
template<class T>
void setProperties(std::unique_ptr<T> &item, const sol::table &children, QObject *guard)
{
if constexpr (has_setContentsMargins<T>) {
sol::optional<QMargins> margins = children.get<sol::optional<QMargins>>("contentMargins");
if (margins)
item->setContentsMargins(margins->left(), margins->top(), margins->right(), margins->bottom());
}
if constexpr (has_setCursor<T>) {
const auto cursor = children.get<sol::optional<Qt::CursorShape>>("cursor");
if (cursor)
item->setCursor(*cursor);
}
if constexpr (has_setVisible<T>) {
const auto visible = children.get<sol::optional<bool>>("visible");
if (visible)
@@ -243,8 +257,8 @@ void setProperties(std::unique_ptr<T> &item, const sol::table &children, QObject
}
if constexpr (has_onTextChanged<T>) {
sol::optional<sol::protected_function> onTextChanged
= children.get<sol::optional<sol::protected_function>>("onTextChanged");
sol::optional<sol::main_function> onTextChanged
= children.get<sol::optional<sol::main_function>>("onTextChanged");
if (onTextChanged) {
item->onTextChanged(
[f = *onTextChanged](const QString &text) {
@@ -255,8 +269,8 @@ void setProperties(std::unique_ptr<T> &item, const sol::table &children, QObject
}
}
if constexpr (has_onClicked<T>) {
sol::optional<sol::protected_function> onClicked
= children.get<sol::optional<sol::protected_function>>("onClicked");
sol::optional<sol::main_function> onClicked
= children.get<sol::optional<sol::main_function>>("onClicked");
if (onClicked) {
item->onClicked(
[f = *onClicked]() {
@@ -525,6 +539,10 @@ void setupGuiModule()
sol::property(&Widget::isVisible, &Widget::setVisible),
"enabled",
sol::property(&Widget::isEnabled, &Widget::setEnabled),
"focus",
sol::property([](Widget *self) { return self->emerge()->hasFocus(); }),
"setFocus",
[](Widget *self) { self->emerge()->setFocus(); },
sol::base_classes,
sol::bases<Object, Thing>());
@@ -532,6 +550,7 @@ void setupGuiModule()
mirrorEnum(gui, QMetaEnum::fromType<Qt::WindowType>());
mirrorEnum(gui, QMetaEnum::fromType<Qt::TextFormat>());
mirrorEnum(gui, QMetaEnum::fromType<Qt::TextInteractionFlag>());
mirrorEnum(gui, QMetaEnum::fromType<Qt::CursorShape>());
gui.new_usertype<Stack>(
"Stack",

View File

@@ -36,7 +36,7 @@ void setupQtModule()
&QCompleter::completionMode,
[](QCompleter *c, QCompleter::CompletionMode mode) { c->setCompletionMode(mode); }),
"onActivated",
sol::property([guard = pluginSpec](QCompleter &obj, sol::function callback) {
sol::property([guard = pluginSpec](QCompleter &obj, sol::main_function callback) {
QObject::connect(
&obj,
QOverload<const QString &>::of(&QCompleter::activated),

View File

@@ -294,7 +294,7 @@ sol::usertype<T> addTypedAspect(sol::table &lua, const QString &name)
return lua.new_usertype<T>(
name,
"create",
[](const sol::table &options) {
[](const sol::main_table &options) {
return createAspectFromTable<T>(options, &typedAspectCreate<T>);
},
sol::base_classes,
@@ -355,7 +355,7 @@ void setupSettingsModule()
settings.new_usertype<SecretAspect>(
"SecretAspect",
"create",
[](const sol::table &options) {
[](const sol::main_table &options) {
return createAspectFromTable<SecretAspect>(
options,
[](SecretAspect *aspect, const std::string &key, const sol::object &value) {
@@ -392,7 +392,7 @@ void setupSettingsModule()
settings.new_usertype<SelectionAspect>(
"SelectionAspect",
"create",
[](const sol::table &options) {
[](const sol::main_table &options) {
return createAspectFromTable<SelectionAspect>(
options,
[](SelectionAspect *aspect, const std::string &key, const sol::object &value) {
@@ -473,7 +473,7 @@ void setupSettingsModule()
settings.new_usertype<ToggleAspect>(
"ToggleAspect",
"create",
[](const sol::table &options) {
[](const sol::main_table &options) {
return createAspectFromTable<ToggleAspect>(
options,
[](ToggleAspect *aspect, const std::string &key, const sol::object &value) {
@@ -521,7 +521,7 @@ void setupSettingsModule()
settings.new_usertype<TriStateAspect>(
"TriStateAspect",
"create",
[](const sol::table &options) {
[](const sol::main_table &options) {
return createAspectFromTable<TriStateAspect>(
options,
[](TriStateAspect *aspect, const std::string &key, const sol::object &value) {
@@ -553,7 +553,7 @@ void setupSettingsModule()
settings.new_usertype<TextDisplay>(
"TextDisplay",
"create",
[](const sol::table &options) {
[](const sol::main_table &options) {
return createAspectFromTable<TextDisplay>(
options,
[](TextDisplay *aspect, const std::string &key, const sol::object &value) {
@@ -587,7 +587,7 @@ void setupSettingsModule()
settings.new_usertype<AspectList>(
"AspectList",
"create",
[](const sol::table &options) {
[](const sol::main_table &options) {
return createAspectFromTable<AspectList>(
options,
[](AspectList *aspect, const std::string &key, const sol::object &value) {
@@ -682,7 +682,7 @@ void setupSettingsModule()
settings.new_usertype<OptionsPage>(
"OptionsPage",
"create",
[&pool, pluginSpec](const sol::table &options) {
[&pool, pluginSpec](const sol::main_table &options) {
return pool.makePage<OptionsPage>(pluginSpec, options);
},
"show",

View File

@@ -4,8 +4,11 @@
#include "../luaengine.h"
#include "../luatr.h"
#include "utils.h"
#include <texteditor/basehoverhandler.h>
#include <texteditor/fontsettings.h>
#include <texteditor/refactoroverlay.h>
#include <texteditor/textdocument.h>
#include <texteditor/textdocumentlayout.h>
#include <texteditor/texteditor.h>
@@ -47,14 +50,61 @@ TextEditor::TextEditorWidget *getSuggestionReadyEditorWidget(TextEditor::TextDoc
}
std::unique_ptr<EmbeddedWidgetInterface> addEmbeddedWidget(
BaseTextEditor *editor, QWidget *widget, int cursorPosition)
BaseTextEditor *editor, QWidget *widget, std::variant<int, Position> cursorPosition)
{
if (!editor->textDocument() || !editor->textDocument()->document())
throw sol::error("No text document set");
widget->setParent(editor->editorWidget()->viewport());
TextEditorWidget *editorWidget = editor->editorWidget();
std::unique_ptr<EmbeddedWidgetInterface> embed
= editorWidget->insertWidget(widget, cursorPosition);
int pos = cursorPosition.index() == 0
? std::get<int>(cursorPosition)
: std::get<Position>(cursorPosition)
.positionInDocument(editor->textDocument()->document());
std::unique_ptr<EmbeddedWidgetInterface> embed = editorWidget->insertWidget(widget, pos);
return embed;
}
void clearRefactorMarkers(BaseTextEditor *editor, const Utils::Id &id)
{
TextEditorWidget *editorWidget = editor->editorWidget();
QTC_ASSERT(editorWidget, throw sol::error("TextEditorWidget is not valid"));
editorWidget->clearRefactorMarkers(id);
}
void setRefactorMarker(
BaseTextEditor *editor,
const Utils::Icon &icon,
int position,
const Utils::Id &id,
bool anchorLeft,
sol::main_function callback)
{
TextEditorWidget *editorWidget = editor->editorWidget();
QTC_ASSERT(editorWidget, throw sol::error("TextEditorWidget is not valid"));
TextDocument *textDocument = editor->textDocument();
QTextCursor cursor = QTextCursor(textDocument->document());
cursor.setPosition(position);
// Move cursor to start of line
if (anchorLeft)
cursor.movePosition(QTextCursor::MoveOperation::StartOfBlock);
TextEditor::RefactorMarker marker;
marker.cursor = cursor;
marker.icon = icon.icon();
marker.callback = [callback](TextEditorWidget *) {
expected_str<void> res = Lua::void_safe_call(callback);
QTC_CHECK_EXPECTED(res);
};
marker.type = id;
editorWidget->setRefactorMarkers({std::move(marker)}, id);
}
} // namespace
namespace Lua::Internal {
@@ -148,6 +198,9 @@ void setupTextEditorModule()
TextEditorRegistry::instance();
registerProvider("TextEditor", [](sol::state_view lua) -> sol::object {
const ScriptPluginSpec *pluginSpec = lua.get<ScriptPluginSpec *>("PluginSpec");
QObject *guard = pluginSpec->connectionGuard.get();
sol::table result = lua.create_table();
result["currentEditor"] = []() -> TextEditorPtr {
@@ -168,18 +221,18 @@ void setupTextEditorModule()
"Position",
sol::no_constructor,
"line",
sol::property([](Position &pos) { return pos.line; }),
sol::property(&Position::line, &Position::line),
"column",
sol::property([](Position &pos) { return pos.column; }));
sol::property(&Position::column, &Position::column));
// In range can't use begin/end as "end" is a reserved word for LUA scripts
result.new_usertype<Range>(
"Range",
sol::no_constructor,
"from",
sol::property([](Range &range) { return range.begin; }),
sol::property(&Range::begin, &Range::begin),
"to",
sol::property([](Range &range) { return range.end; }));
sol::property(&Range::end, &Range::end));
result.new_usertype<QTextCursor>(
"TextCursor",
@@ -246,7 +299,26 @@ void setupTextEditorModule()
"resize",
&EmbeddedWidgetInterface::resize,
"close",
&EmbeddedWidgetInterface::close);
&EmbeddedWidgetInterface::close,
"onShouldClose",
[guard](EmbeddedWidgetInterface *widget, sol::main_function func) {
QObject::connect(widget, &EmbeddedWidgetInterface::shouldClose, guard, [func]() {
expected_str<void> res = void_safe_call(func);
QTC_CHECK_EXPECTED(res);
});
});
std::shared_ptr<QMap<TextEditorPtr, QSet<Utils::Id>>> activeMarkers
= std::make_shared<QMap<TextEditorPtr, QSet<Utils::Id>>>();
QObject::connect(guard, &QObject::destroyed, [activeMarkers] {
for (const auto &[k, v] : activeMarkers->asKeyValueRange()) {
if (k) {
for (const auto &id : v)
k->editorWidget()->clearRefactorMarkers(id);
}
}
});
result.new_usertype<BaseTextEditor>(
"TextEditor",
@@ -257,10 +329,39 @@ void setupTextEditorModule()
return textEditor->textDocument();
},
"addEmbeddedWidget",
[](const TextEditorPtr &textEditor, LayoutOrWidget widget, int position) {
[](const TextEditorPtr &textEditor,
LayoutOrWidget widget,
std::variant<int, Position> position) {
QTC_ASSERT(textEditor, throw sol::error("TextEditor is not valid"));
return addEmbeddedWidget(textEditor, toWidget(widget), position);
},
"setRefactorMarker",
[pluginSpec, activeMarkers](
const TextEditorPtr &textEditor,
const IconFilePathOrString &icon,
int position,
const QString &id,
bool anchorLeft,
sol::main_function callback) {
QTC_ASSERT(textEditor, throw sol::error("TextEditor is not valid"));
QTC_ASSERT(!id.isEmpty(), throw sol::error("Id is empty"));
QTC_ASSERT(!icon.valueless_by_exception(), throw sol::error("Icon is invalid"));
Id finalId = Utils::Id::fromString(QString(pluginSpec->id + "." + id));
(*activeMarkers)[textEditor].insert(finalId);
setRefactorMarker(textEditor, *toIcon(icon), position, finalId, anchorLeft, callback);
},
"clearRefactorMarkers",
[pluginSpec, activeMarkers](const TextEditorPtr &textEditor, const QString &id) {
QTC_ASSERT(textEditor, throw sol::error("TextEditor is not valid"));
QTC_ASSERT(!id.isEmpty(), throw sol::error("Id is empty"));
Id finalId = Utils::Id::fromString(QString(pluginSpec->id + "." + id));
(*activeMarkers)[textEditor].remove(finalId);
clearRefactorMarkers(textEditor, finalId);
},
"cursor",
[](const TextEditorPtr &textEditor) {
QTC_ASSERT(textEditor, throw sol::error("TextEditor is not valid"));

View File

@@ -251,7 +251,7 @@ void setupUtilsModule()
utils.new_usertype<QTimer>(
"Timer",
"create",
[guard = pluginSpec](int timeout, bool singleShort, sol::function callback)
[guard = pluginSpec](int timeout, bool singleShort, sol::main_function callback)
-> std::unique_ptr<QTimer> {
auto timer = std::make_unique<QTimer>();
timer->setInterval(timeout);

View File

@@ -1,7 +1,9 @@
---@meta Action
local action = {}
---@module 'Utils'
local Utils
---@enum CommandAttributes
action.CommandAttribute = {
---Hide the command from the menu.
@@ -17,7 +19,7 @@ action.CommandAttribute = {
---@class ActionOptions
---@field context? string The context in which the action is available.
---@field text? string The text to display for the action.
---@field icon? FilePath|string The icon to display for the action.
---@field icon? Utils.Icon|FilePath|string The icon to display for the action.
---@field iconText? string The icon text to display for the action.
---@field toolTip? string The toolTip to display for the action.
---@field onTrigger? function The callback to call when the action is triggered.

View File

@@ -38,6 +38,8 @@ gui.baseWidgetOptions = {}
---@field flat? boolean A boolean, representing whether the widget should be flat, if applicable.
---@field [1]? Layout The layout of the widget, if applicable.
---@field fixedSize? integer[] Two integers representing the width and height
---@field contentMargins? integer[] Four integers represending left, top, right and bottom margins.
---@field cursor? CursorShape The cursor shape for the widget.
gui.widgetOptions = {}
---@param options WidgetOptions
@@ -430,6 +432,37 @@ gui.WidgetAttribute = {
WA_ContentsMarginsRespectsSafeArea = 0,
WA_StyleSheetTarget = 0
}
--- Enum representing cursor shape for the widget
---@enum CursorShape
gui.CursorShape = {
ArrowCursor = 0 = 0,
UpArrowCursor = 0,
CrossCursor = 0,
WaitCursor = 0,
IBeamCursor = 0,
SizeVerCursor = 0,
SizeHorCursor = 0,
SizeBDiagCursor = 0,
SizeFDiagCursor = 0,
SizeAllCursor = 0,
BlankCursor = 0,
SplitVCursor = 0,
SplitHCursor = 0,
PointingHandCursor = 0,
ForbiddenCursor = 0,
WhatsThisCursor = 0,
BusyCursor = 0,
OpenHandCursor = 0,
ClosedHandCursor = 0,
DragCopyCursor = 0,
DragMoveCursor = 0,
DragLinkCursor = 0,
LastCursor = DragLinkCursor,
BitmapCursor = 0,
CustomCursor = 0
}
---@class Space : Layout
gui.space = {}

View File

@@ -1,6 +1,10 @@
---@meta TextEditor
local textEditor = {}
---@module 'Utils'
local Utils
---@class Position
---@field line integer The line number.
---@field column integer The column number.
@@ -116,12 +120,28 @@ function EmbeddedWidget:close() end
---Resizes the floating widget according to its layout.
function EmbeddedWidget:resize() end
---Set the callback to be called when the widget should close. (E.g. if the user presses the escape key)
---@param fn function The function to be called when the embed should close.
function EmbeddedWidget:onShouldClose(fn) end
---Embeds a widget at the specified cursor position in the text editor.
---@param widget Widget|Layout The widget to be added as a floating widget.
---@param position integer The position in the document where the widget should appear.
---@param position integer|Position The position in the document where the widget should appear.
---@return EmbeddedWidget interface An interface to control the floating widget.
function TextEditor:addEmbeddedWidget(widget, position) end
---Adds an refactor marker in the text editor at given cursor position.
---@param icon Utils.Icon|FilePath|string Icon to be used. If specified icon is invalid the default QtCreator for markers is used.
---@param position integer The position in the document where the marker should appear.
---@param id string The identifier of the marker.
---@param anchorLeft boolean Specifies if the marker should appear at the beginning of the TextCursor block.
---@param callback function A function to be called once the marker is pressed.
function TextEditor:setRefactorMarker(icon, position, id, anchorLeft, callback) end
---Removes the refactor markers with given id.
---param id string The identifier of the marker.
function TextEditor:clearRefactorMarkers(icon, position, id, anchorLeft, callback) end
---Checks if the current suggestion is locked. The suggestion is locked when the user can use it.
---@return boolean True if the suggestion is locked, false otherwise.
function TextEditor:hasLockedSuggestion() end

View File

@@ -26,5 +26,18 @@
],
"Url" : "https://www.mesonbuild.com",
"DocumentationUrl" : "https://doc.qt.io/qtcreator/creator-project-meson.html",
${IDE_PLUGIN_DEPENDENCIES}
${IDE_PLUGIN_DEPENDENCIES},
"Mimetypes" : [
"<?xml version='1.0' encoding='UTF-8'?>",
"<mime-info xmlns='http://www.freedesktop.org/standards/shared-mime-info'>",
" <mime-type type='text/x-meson'>",
" <sub-class-of type='text/plain'/>",
" <comment>Meson build description</comment>",
" <glob pattern='meson.build'/>",
" <glob pattern='meson.options'/>",
" <glob pattern='meson_options.txt'/>",
" </mime-type>",
"</mime-info>"
]
}

View File

@@ -198,8 +198,6 @@ void KitAspect::addToInnerLayout(Layouting::Layout &parentItem)
void KitAspect::addListAspectSpec(const ListAspectSpec &listAspectSpec)
{
const auto comboBox = createSubWidget<QComboBox>();
comboBox->setSizePolicy(QSizePolicy::Preferred, comboBox->sizePolicy().verticalPolicy());
comboBox->setEnabled(true);
const auto sortModel = new KitAspectSortModel(this);
sortModel->setSourceModel(listAspectSpec.model);
comboBox->setModel(sortModel);

View File

@@ -865,7 +865,10 @@ void MiniProjectTargetSelector::doLayout()
m_kitAreaWidget->move(0, 0);
int kitAreaHeight = m_kitAreaWidget->isVisibleTo(this) ? m_kitAreaWidget->sizeHint().height() : 0;
const int kitAreaHeight = m_kitAreaWidget->isVisibleTo(this)
? m_kitAreaWidget->sizeHint().height() : 0;
const int kitAreaWidth = m_kitAreaWidget->isVisibleTo(this)
? m_kitAreaWidget->sizeHint().width() : 0;
// 1. Calculate the summary label height
int summaryLabelY = 1 + kitAreaHeight;
@@ -900,6 +903,7 @@ void MiniProjectTargetSelector::doLayout()
QRect newGeometry;
const int minWidth = std::max({m_summaryLabel->sizeHint().width(), kitAreaWidth, 250});
if (!onlySummary) {
// list widget height
int maxItemCount = m_projectListWidget->maxCount();
@@ -920,8 +924,6 @@ void MiniProjectTargetSelector::doLayout()
int listHeight = heightWithoutKitArea + kitAreaHeight - bottomMargin - listY + 1;
// list widget widths
int minWidth = qMax(m_summaryLabel->sizeHint().width(), 250);
minWidth = qMax(minWidth, m_kitAreaWidget->sizeHint().width());
QVector<int> widths = listWidgetWidths(minWidth, Core::ICore::mainWindow()->width() * 0.9);
const int runColumnWidth = widths[RUN] == -1 ? 0 : RunColumnWidth;
@@ -952,7 +954,7 @@ void MiniProjectTargetSelector::doLayout()
heightWithoutKitArea = qMax(summaryLabelHeight + bottomMargin, alignedWithActionHeight);
m_summaryLabel->resize(m_summaryLabel->sizeHint().width(), heightWithoutKitArea - bottomMargin);
m_kitAreaWidget->resize(m_kitAreaWidget->sizeHint());
newGeometry.setSize({m_summaryLabel->width() + 1, heightWithoutKitArea + kitAreaHeight});
newGeometry.setSize({minWidth + 1, heightWithoutKitArea + kitAreaHeight});
}
newGeometry.translate(statusBar->mapToGlobal(QPoint{0, 0}));

View File

@@ -578,6 +578,7 @@ void ToolChainOptionsWidget::apply()
removedTcs << Utils::transform(notRegistered, &Toolchain::displayName);
}
for (ExtendedToolchainTreeItem * const item : std::as_const(m_toAddList)) {
m_model.takeItem(item);
item->bundle->deleteToolchains();
delete item;
}

View File

@@ -1373,17 +1373,23 @@ FilePath QtVersion::examplesPath() const // QT_INSTALL_EXAMPLES
return d->data().examplesPath;
}
/*!
\internal
Returns a list of directories containing Qt related shared objects
*/
FilePaths QtVersion::qtSoPaths() const
{
FilePaths paths;
const FilePaths qtPaths = {libraryPath(), pluginPath(), qmlPath(), importsPath()};
const FilePath qtPaths[] = {libraryPath(), pluginPath(), qmlPath(), importsPath()};
for (const FilePath &qtPath : qtPaths) {
if (qtPath.isEmpty())
continue;
// FIXME: Could be sped up, we need just the info whether there is one such entry
const FilePaths soPaths =
qtPath.dirEntries({{"*.so"}, QDir::Files, QDirIterator::Subdirectories});
paths.append(soPaths);
for (const FilePath &soPath : soPaths)
paths.append(soPath.parentDir());
}
FilePath::removeDuplicates(paths);
return paths;

Binary file not shown.

Before

Width:  |  Height:  |  Size: 5.3 KiB

After

Width:  |  Height:  |  Size: 1.5 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 12 KiB

After

Width:  |  Height:  |  Size: 4.3 KiB

View File

@@ -750,6 +750,7 @@ public:
qreal charWidth() const;
std::unique_ptr<EmbeddedWidgetInterface> insertWidget(QWidget *widget, int line);
void forceUpdateScrollbarSize();
// actions
void registerActions();
@@ -947,6 +948,7 @@ public:
void updateSuggestion();
void clearCurrentSuggestion();
QTextBlock m_suggestionBlock;
int m_numEmbeddedWidgets = 0;
Context m_editorContext;
QAction *m_undoAction = nullptr;
@@ -1839,6 +1841,7 @@ void TextEditorWidgetPrivate::insertSuggestion(std::unique_ptr<TextSuggestion> &
auto options = suggestion->replacementDocument()->defaultTextOption();
m_suggestionBlock = cursor.block();
m_document->insertSuggestion(std::move(suggestion));
forceUpdateScrollbarSize();
}
void TextEditorWidgetPrivate::updateSuggestion()
@@ -3500,7 +3503,10 @@ bool TextEditorWidget::event(QEvent *e)
if (ke->key() == Qt::Key_Escape
&& (d->m_snippetOverlay->isVisible()
|| multiTextCursor().hasMultipleCursors()
|| d->m_suggestionBlock.isValid())) {
|| d->m_suggestionBlock.isValid()
|| d->m_numEmbeddedWidgets > 0)) {
if (d->m_numEmbeddedWidgets > 0)
emit embeddedWidgetsShouldClose();
e->accept();
} else {
// hack copied from QInputControl::isCommonTextEditShortcut
@@ -3920,10 +3926,8 @@ qreal TextEditorWidgetPrivate::charWidth() const
{
return QFontMetricsF(q->font()).horizontalAdvance(QLatin1Char('x'));
}
class CarrierWidget : public QWidget
{
Q_OBJECT
public:
CarrierWidget(TextEditorWidget *textEditorWidget, QWidget *embed)
: QWidget(textEditorWidget->viewport())
@@ -3942,7 +3946,7 @@ public:
});
}
int embedHeight() { return m_embed->minimumSizeHint().height(); }
int embedHeight() { return m_embed->sizeHint().height(); }
private:
QWidget *m_embed;
@@ -3964,12 +3968,27 @@ void EmbeddedWidgetInterface::close()
emit closed();
}
void TextEditorWidgetPrivate::forceUpdateScrollbarSize()
{
// We use resizeEvent here as a workaround as we can't get access to the
// scrollarea which is a private part of the QPlainTextEdit.
// During the resizeEvent the plain text edit will resize its scrollbars.
// The TextEditorWidget will also update its scrollbar overlays.
q->resizeEvent(new QResizeEvent(q->size(), q->size()));
}
std::unique_ptr<EmbeddedWidgetInterface> TextEditorWidgetPrivate::insertWidget(
QWidget *widget, int line)
{
QPointer<CarrierWidget> carrier = new CarrierWidget(q, widget);
std::unique_ptr<EmbeddedWidgetInterface> result(new EmbeddedWidgetInterface());
connect(
q,
&TextEditorWidget::embeddedWidgetsShouldClose,
result.get(),
&EmbeddedWidgetInterface::shouldClose);
struct State
{
int height = 0;
@@ -4032,9 +4051,14 @@ std::unique_ptr<EmbeddedWidgetInterface> TextEditorWidgetPrivate::insertWidget(
QTextBlock block = pState->cursor.block();
auto userData = TextDocumentLayout::userData(block);
userData->removeEmbeddedWidget(carrier);
m_numEmbeddedWidgets--;
forceUpdateScrollbarSize();
});
connect(q->document()->documentLayout(), &QAbstractTextDocumentLayout::update, carrier, position);
connect(result.get(), &EmbeddedWidgetInterface::resized, carrier, position);
connect(result.get(), &EmbeddedWidgetInterface::resized, carrier, [position, this]() {
position();
forceUpdateScrollbarSize();
});
connect(result.get(), &EmbeddedWidgetInterface::closed, this, [this, carrier] {
if (carrier)
carrier->deleteLater();
@@ -4042,7 +4066,11 @@ std::unique_ptr<EmbeddedWidgetInterface> TextEditorWidgetPrivate::insertWidget(
QTimer::singleShot(0, layout, [layout] { layout->update(); });
});
m_numEmbeddedWidgets++;
carrier->show();
forceUpdateScrollbarSize();
return result;
}
@@ -7078,6 +7106,15 @@ void TextEditorWidget::mouseReleaseEvent(QMouseEvent *e)
if (!HostOsInfo::isLinuxHost() && handleForwardBackwardMouseButtons(e))
return;
// If the refactor marker was pressed then don't propagate release event to editor
RefactorMarker refactorMarker = d->m_refactorOverlay->markerAt(e->pos());
if (refactorMarker.isValid()) {
if (refactorMarker.callback) {
e->accept();
return;
}
}
QPlainTextEdit::mouseReleaseEvent(e);
d->setClipboardSelection();

View File

@@ -113,6 +113,7 @@ public:
signals:
void resized();
void closed();
void shouldClose();
};
class TEXTEDITOR_EXPORT BaseTextEditor : public Core::IEditor
@@ -561,6 +562,7 @@ signals:
void addCurrentStateToNavigationHistory();
void resized();
void embeddedWidgetsShouldClose();
protected:
QTextBlock blockForVisibleRow(int row) const;

View File

@@ -207,7 +207,7 @@ macro(qtc_auto_setup_vcpkg)
option(QT_CREATOR_SKIP_VCPKG_SETUP "Skip Qt Creator's vcpkg package manager auto-setup" OFF)
find_program(vcpkg_program vcpkg
PATHS $ENV{VCPKG_ROOT} ${CMAKE_SOURCE_DIR}/vcpkg
PATHS $ENV{VCPKG_ROOT} ${CMAKE_SOURCE_DIR}/vcpkg ${CMAKE_SOURCE_DIR}/3rdparty/vcpkg
NO_DEFAULT_PATH
)
if (NOT vcpkg_program)
@@ -247,7 +247,23 @@ macro(qtc_auto_setup_vcpkg)
if (VCPKG_TARGET_TRIPLET)
set(vcpkg_triplet ${VCPKG_TARGET_TRIPLET})
else()
if (WIN32)
if (ANDROID_ABI)
if (ANDROID_ABI STREQUAL "armeabi-v7a")
set(vcpkg_triplet arm-neon-android)
elseif (ANDROID_ABI STREQUAL "arm64-v8a")
set(vcpkg_triplet arm64-android)
elseif (ANDROID_ABI STREQUAL "x86")
set(vcpkg_triplet x86-android)
elseif (ANDROID_ABI STREQUAL "x86_64")
set(vcpkg_triplet x64-android)
else()
message(FATAL_ERROR "Unsupported Android ABI: ${ANDROID_ABI}")
endif()
# Needed by vcpkg/scripts/toolchains/android.cmake
file(APPEND "${CMAKE_BINARY_DIR}/vcpkg-dependencies/toolchain.cmake" "
set(ENV{ANDROID_NDK_HOME} \"${ANDROID_NDK}\")
")
elseif (WIN32)
set(vcpkg_triplet x64-mingw-static)
if (CMAKE_CXX_COMPILER MATCHES ".*/(.*)/cl.exe")
set(vcpkg_triplet ${CMAKE_MATCH_1}-windows)

View File

@@ -55,7 +55,7 @@ function(_get_msvc_ide_version result)
set(${result} 15 PARENT_SCOPE)
elseif(NOT MSVC_VERSION VERSION_LESS 1920 AND MSVC_VERSION VERSION_LESS 1930)
set(${result} 16 PARENT_SCOPE)
elseif(NOT MSVC_VERSION VERSION_LESS 1930 AND MSVC_VERSION VERSION_LESS 1940)
elseif(NOT MSVC_VERSION VERSION_LESS 1930 AND MSVC_VERSION VERSION_LESS 1950)
set(${result} 17 PARENT_SCOPE)
else()
message(FATAL_ERROR "Conan: Unknown MSVC compiler version [${MSVC_VERSION}]")

View File

@@ -9,6 +9,7 @@ qtc_add_public_header(qtcreator_pch.h)
qtc_add_public_header(qtcreator_gui_pch.h)
option(BUILD_QBS "Build Qbs together with Qt Creator" OFF)
option(WITH_QBS_DOCS "Build Qbs documentation" ${WITH_DOCS})
add_feature_info("Build Qbs" BUILD_QBS "")
if (BUILD_QBS)
@@ -30,6 +31,6 @@ if (BUILD_QBS)
set(INSTALL_PUBLIC_HEADERS OFF CACHE BOOL "")
set(WITH_TESTS OFF)
set(WITH_PROJECT_FILE_UPDATES ON CACHE BOOL "")
set(QBS_INSTALL_QCH_DOCS ${WITH_DOCS} CACHE BOOL "")
set(QBS_INSTALL_QCH_DOCS ${WITH_QBS_DOCS} CACHE BOOL "")
add_subdirectory(qbs)
endif()

View File

@@ -198,9 +198,10 @@ public:
const auto end = system_clock::now();
const auto freeze = duration_cast<milliseconds>(end - start);
if (freeze > m_threshold) {
m_total += freeze;
const QString time = QTime::currentTime().toString(Qt::ISODateWithMs);
qDebug().noquote() << QString("FREEZE [%1]").arg(time)
<< "of" << freeze.count() << "ms, on:" << event;
qDebug().noquote() << QString("FREEZE [%1]").arg(time) << "of" << freeze.count()
<< "ms, total" << m_total.count() << "ms, on:" << event;
const QString receiverMessage = name.isEmpty()
? QString("receiver class: %1").arg(className)
: QString("receiver class: %1, object name: %2").arg(className, name);
@@ -215,6 +216,7 @@ private:
bool m_inNotify = false;
const QString m_align;
milliseconds m_threshold{100};
milliseconds m_total{0};
};
QtSingleApplication *createApplication(const QString &id, int &argc, char **argv)

View File

@@ -460,27 +460,6 @@
effect="fill_between_many"
linkedpaths="#path2259-2-0-6,0"
id="path-effect2469-8" />
<linearGradient
gradientUnits="userSpaceOnUse"
gradientTransform="matrix(75,0,0,-70,-74,7774.97)"
y2="111"
x2="1.45"
y1="109.58"
x1="2.76"
id="linear-gradient-7">
<stop
id="stop2568"
stop-color="#6ffe80"
offset="0" />
<stop
id="stop2570"
stop-color="#43ce58"
offset="0.37" />
<stop
id="stop2572"
stop-color="#425fcf"
offset="1" />
</linearGradient>
<linearGradient
inkscape:collect="always"
xlink:href="#linearGradient2550"
@@ -738,17 +717,52 @@
x="0"
y="0"
style="fill:#ffffff" />
<path
style="fill:url(#linear-gradient-7)"
d="m 145.67,81.5 a 1.34,1.34 0 0 0 -1.34,1.33 v 0.44 l -16,6.59 V 87.5 l 17.85,-7.38 a 1.36,1.36 0 0 0 0.82,-1.24 1.34,1.34 0 0 0 -0.82,-1.23 l -38.67,-16 a 1.38,1.38 0 0 0 -1,0 l -38.67,16 a 1.34,1.34 0 0 0 -0.84,1.18 1.36,1.36 0 0 0 0.82,1.24 l 38.67,16 a 1.24,1.24 0 0 0 1,0 l 14,-5.78 a 1.33,1.33 0 0 0 -1,-2.46 L 107,93.39 71.82,78.83 107,64.28 l 35.18,14.55 -15.31,6.34 -14.66,-5.48 a 3,3 0 0 0 0.12,-0.86 c 0,-2.24 -2.34,-4 -5.33,-4 -2.99,0 -5.33,1.76 -5.33,4 0,2.24 2.34,4 5.33,4 a 6.41,6.41 0 0 0 3.45,-0.95 l 15.22,5.68 v 4.28 0 28.57 a 4,4 0 1 0 2.66,0 v -7.57 a 16.19,16.19 0 0 0 5.26,-6.9 1.32,1.32 0 0 0 0.08,-0.44 v -9.33 a 1.34,1.34 0 1 0 -2.67,0 v 9.08 a 13.49,13.49 0 0 1 -2.67,4 V 92.74 L 146.17,85.4 A 1.34,1.34 0 0 0 147,84.17 v -1.34 a 1.34,1.34 0 0 0 -1.33,-1.33 z m -41.34,-2.67 c 0,-0.54 1,-1.33 2.67,-1.33 1.67,0 2.67,0.79 2.67,1.33 0,0.54 -1,1.34 -2.67,1.34 -1.67,0 -2.67,-0.79 -2.67,-1.34 z M 127,125.5 a 1.34,1.34 0 1 1 1.33,-1.33 1.33,1.33 0 0 1 -1.33,1.33 z M 106.49,101.4 67.82,85.4 A 1.34,1.34 0 0 1 67,84.17 v -1.34 a 1.34,1.34 0 0 1 2.67,0 v 0.45 L 107,98.72 121.15,92.86 a 1.36,1.36 0 0 1 1.75,0.73 1.33,1.33 0 0 1 -0.72,1.74 l -14.67,6.07 a 1.35,1.35 0 0 1 -1,0 z m 15.77,15.54 A 34.28,34.28 0 0 1 107,120.17 c -20.67,0 -26.34,-13.6 -26.57,-14.17 a 1.44,1.44 0 0 1 -0.1,-0.5 v -9.33 a 1.34,1.34 0 1 1 2.67,0 v 9 c 0.77,1.67 6.11,11.7 22.67,12.23 v -11.9 a 1.33,1.33 0 0 1 2.66,0 v 12 a 31,31 0 0 0 12.75,-2.91 1.3327134,1.3327134 0 0 1 1.18,2.39 z m 6.07,13.89 v 4 a 1.33,1.33 0 1 1 -2.66,0 v -4 a 1.33,1.33 0 1 1 2.66,0 z m -4,-1 -1.33,5.33 a 1.33,1.33 0 0 1 -1.29,1 1.86,1.86 0 0 1 -0.33,0 1.34,1.34 0 0 1 -1,-1.62 l 1.34,-5.33 a 1.33,1.33 0 0 1 2.58,0.64 z m 9.34,4.69 a 1.34,1.34 0 0 1 -1,1.62 1.86,1.86 0 0 1 -0.33,0 1.33,1.33 0 0 1 -1.29,-1 l -1.33,-5.34 a 1.33,1.33 0 1 1 2.58,-0.64 l 1.34,5.33 z"
class="cls-2"
id="graduation-hat"
inkscape:connector-curvature="0" />
<path
id="path2598"
style="fill:#222840"
d="M 133.5,41.74 V 29 h 2 v 12.74 z m -2.57,-6.22 v 4.1 a 0.86,0.86 0 0 0 0.2,0.58 1,1 0 0 0 0.59,0.25 v 1.49 a 3.81,3.81 0 0 1 -2.4,-0.66 6.91,6.91 0 0 1 -2.9,0.66 c -1.79,0 -2.68,-1 -2.68,-2.86 a 2.44,2.44 0 0 1 0.73,-2 4,4 0 0 1 2.24,-0.74 l 2.32,-0.2 V 35.5 a 1.33,1.33 0 0 0 -0.31,-1 1.35,1.35 0 0 0 -0.93,-0.29 c -0.77,0 -1.73,0 -2.88,0.14 h -0.57 L 124.21,33 a 15.72,15.72 0 0 1 3.61,-0.46 3.31,3.31 0 0 1 2.38,0.71 3.05,3.05 0 0 1 0.73,2.27 z m -4,2.23 a 1.21,1.21 0 0 0 -1.25,1.35 c 0,0.83 0.37,1.24 1.1,1.24 a 7,7 0 0 0 1.91,-0.29 l 0.32,-0.11 v -2.39 z m -7,-6.54 v -2.07 h 2 v 2.07 z m 0,10.53 v -9 h 2 v 9 z m -6.5,0 v -9 h 1.95 v 1.08 a 8.42,8.42 0 0 1 3.06,-1.27 v 2 a 12.5,12.5 0 0 0 -2.65,0.79 l -0.4,0.16 v 6.28 z m -9.04,-8.02 a 4.65,4.65 0 0 1 6.17,0 5.57,5.57 0 0 1 0.94,3.51 5.76,5.76 0 0 1 -0.9,3.52 4.67,4.67 0 0 1 -6.23,0 5.76,5.76 0 0 1 -0.9,-3.52 5.57,5.57 0 0 1 0.92,-3.51 z m 1.46,5.85 a 1.71,1.71 0 0 0 1.62,0.72 1.69,1.69 0 0 0 1.62,-0.72 4.93,4.93 0 0 0 0.41,-2.36 4.53,4.53 0 0 0 -0.44,-2.32 1.76,1.76 0 0 0 -1.56,-0.69 1.74,1.74 0 0 0 -1.59,0.69 4.53,4.53 0 0 0 -0.44,2.32 5.08,5.08 0 0 0 0.38,2.36 z m -3.56,-5.15 h -2.48 v 4 a 4.19,4.19 0 0 0 0.16,1.46 c 0.11,0.24 0.38,0.36 0.83,0.36 l 1.47,-0.06 0.09,1.57 a 10.91,10.91 0 0 1 -1.83,0.23 2.59,2.59 0 0 1 -2.1,-0.7 4.41,4.41 0 0 1 -0.57,-2.65 v -4.21 h -1.15 v -1.68 h 1.15 v -2.61 h 2 v 2.61 h 2.48 z m -9.16,-1.68 h 1.94 v 9 h -1.94 v -0.55 a 5,5 0 0 1 -2.43,0.75 2.72,2.72 0 0 1 -2.49,-1 7,7 0 0 1 -0.63,-3.5 v -4.7 h 2 v 4.72 a 5.78,5.78 0 0 0 0.27,2.18 c 0.18,0.37 0.6,0.56 1.26,0.56 a 4.36,4.36 0 0 0 1.78,-0.36 l 0.27,-0.11 z M 78.5,31.2 v -1.79 h 9 V 31.2 H 84 V 41.74 H 82 V 31.2 Z"
inkscape:connector-curvature="0" />
<g
id="g11668"
transform="translate(17,-13)">
<rect
style="fill:#2cde85;fill-opacity:0.6"
id="rect2143"
width="47"
height="53"
x="56"
y="80"
ry="4" />
<rect
style="fill:#00414a"
id="rect3291"
width="47"
height="53"
x="66"
y="67"
ry="4" />
<g
id="g5219"
transform="translate(-22,-57)">
<use
x="0"
y="0"
xlink:href="#rect2143"
id="use5085"
transform="translate(42,31)" />
<path
id="path5274"
style="fill:none;stroke:#ffffff"
d="m 109,139.5 h 13 m -13,-6 h 28 m -28,-6 h 28 m -28,-6 h 28"
sodipodi:nodetypes="cccccccc" />
</g>
<path
id="Rectangle"
d="m -7.0710678,-175.43154 v -11.34132 c 0,-2.29705 -1.8489181,-4.14597 -4.1459662,-4.14597 h -1.607563 c -2.297048,0 -4.145966,1.84892 -4.145966,4.14597 v 11.34132 c 3.181981,-0.9916 7.7781748,-0.63805 9.8994952,0 z"
transform="rotate(135)"
sodipodi:nodetypes="csssscc" />
<circle
style="opacity:1;fill:none;stroke:#2cde85;stroke-width:10;stroke-opacity:0.9"
id="path27226"
cx="118.5"
cy="101.5"
r="15.5" />
</g>
</g>
</g>
<g

Before

Width:  |  Height:  |  Size: 378 KiB

After

Width:  |  Height:  |  Size: 376 KiB

View File

@@ -17,6 +17,8 @@ using namespace std::chrono_literals;
using TaskObject = milliseconds;
using TestTask = TimeoutTask;
constexpr milliseconds s_endlessTime = 1000000s;
namespace PrintableEnums {
Q_NAMESPACE
@@ -347,17 +349,6 @@ void tst_Tasking::runtimeCheck()
}
}
class Tick : public QObject
{
Q_OBJECT
public:
Tick(const milliseconds &interval) { QTimer::singleShot(interval, this, &Tick::tick); }
signals:
void tick();
};
class TickAndDone : public QObject
{
Q_OBJECT
@@ -3171,7 +3162,7 @@ void tst_Tasking::testTree_data()
// This test ensures the task done handlers are invoked in a different order
// than the corresponding setup handlers.
const QList<milliseconds> tasks { 1000000ms, 0ms };
const QList<milliseconds> tasks { s_endlessTime, 0ms };
const LoopList iterator(tasks);
const auto onSetup = [storage, iterator](TaskObject &taskObject) {
@@ -3790,25 +3781,28 @@ void tst_Tasking::testTree_data()
{
// withCancel / withAccept
const Storage<std::unique_ptr<Tick>> tickStorage;
const Storage<std::unique_ptr<QTimer>> tickStorage;
const auto onSetup = [tickStorage](milliseconds timeout) {
return [tickStorage, timeout] { tickStorage->reset(new Tick(timeout)); };
return [tickStorage, timeout] {
tickStorage->reset(new QTimer);
tickStorage->get()->start(timeout);
};
};
const auto onTickSetup = [tickStorage] {
return std::make_pair(tickStorage->get(), &Tick::tick);
return std::make_pair(tickStorage->get(), &QTimer::timeout);
};
const Group cancelRecipe {
storage,
tickStorage,
onGroupSetup(onSetup(0ms)),
onGroupSetup(onSetup(0ms)), // 1st queued call
Group {
groupSetup(1),
createSuccessTask(2, 1ms),
createSuccessTask(2, s_endlessTime),
groupDone(1)
}.withCancel(onTickSetup)
}.withCancel(onTickSetup) // 2nd queued call
};
const Log cancelLog {

View File

@@ -126,6 +126,9 @@ private slots:
void dontBreakPathOnWierdWindowsPaths();
void isRelativePath();
void isRelativePath_data();
private:
QTemporaryDir tempDir;
QString rootPath;
@@ -506,6 +509,10 @@ void tst_filepath::rootLength_data()
QTest::newRow("unc-localhost-drive") << "//localhost/c$" << 12;
QTest::newRow("unc-localhost-drive-slash") << "//localhost//c$/" << 12;
QTest::newRow("unc-localhost-drive-slash-rest") << "//localhost//c$/x" << 12;
QTest::newRow("windows-1") << "C:" << 2;
QTest::newRow("windows-2") << "C:/" << 3;
QTest::newRow("windows-3") << "C:/foor" << 3;
}
void tst_filepath::rootLength()
@@ -1323,7 +1330,7 @@ void tst_filepath::startsWithDriveLetter_data()
QTest::newRow("remote-slash") << FilePath::fromString("docker://1234/") << false;
QTest::newRow("remote-single-letter") << FilePath::fromString("docker://1234/c") << false;
QTest::newRow("remote-drive") << FilePath::fromString("docker://1234/c:") << true;
QTest::newRow("remote-invalid-drive") << FilePath::fromString("docker://1234/c:a") << true;
QTest::newRow("remote-invalid-drive") << FilePath::fromString("docker://1234/c:a") << false;
QTest::newRow("remote-with-path") << FilePath::fromString("docker://1234/c:/a") << true;
QTest::newRow("remote-z") << FilePath::fromString("docker://1234/z:") << true;
QTest::newRow("remote-1") << FilePath::fromString("docker://1234/1:") << false;
@@ -1810,15 +1817,66 @@ void tst_filepath::makeTemporaryFile()
}
}
void tst_filepath::isRelativePath_data()
{
QTest::addColumn<QString>("path");
QTest::addColumn<bool>("expected");
QTest::newRow("empty") << "" << true;
QTest::newRow("root") << "/" << false;
QTest::newRow("relative") << "foo" << true;
QTest::newRow("relative-path") << "foo/bar" << true;
QTest::newRow("absolute") << "/foo" << false;
QTest::newRow("absolute-path") << "/foo/bar" << false;
QTest::newRow("remote") << "device://host/foo" << false;
QTest::newRow("remote-path") << "device://host/foo/bar" << false;
QTest::newRow("windows-current-dir") << "c:" << true;
QTest::newRow("windows-path") << "c:/" << false;
QTest::newRow("windows-path-with-dir") << "c:/foo" << false;
QTest::newRow("windows-remote-current-dir") << "device://host/C:" << true;
QTest::newRow("windows-remote-path") << "device://host/C:/" << false;
QTest::newRow("windows-remote-path-with-dir") << "device://host/C:/foo" << false;
}
void tst_filepath::isRelativePath()
{
QFETCH(QString, path);
QFETCH(bool, expected);
QCOMPARE(FilePath::fromUserInput(path).isRelativePath(), expected);
}
void tst_filepath::dontBreakPathOnWierdWindowsPaths()
{
FilePath path = FilePath::fromString(
"device://host/./C:/Users/ckandeler/Documents/"
"device://host/./C:/Users/johndoe/Documents/"
"build-iartest-IAR-Debugx/Debug_IAR_55df6f02d5b3d06d/iartest.a152245e/iartest.out");
QCOMPARE(
path.toString(),
"device://host/C:/Users/ckandeler/Documents/"
"device://host/C:/Users/johndoe/Documents/"
"build-iartest-IAR-Debugx/Debug_IAR_55df6f02d5b3d06d/iartest.a152245e/iartest.out");
FilePath pathWithBackslash = FilePath::fromUserInput(
"device://host/C:\\Users\\johndoe\\Documents\\test.elf");
QCOMPARE(pathWithBackslash.toString(), "device://host/C:/Users/johndoe/Documents/test.elf");
QCOMPARE(pathWithBackslash.path(), "C:/Users/johndoe/Documents/test.elf");
const FilePath bin = FilePath::fromString(pathWithBackslash.path());
QCOMPARE(bin.toString(), "C:/Users/johndoe/Documents/test.elf");
// Make sure the optimization still works
FilePath path2 = FilePath::fromString("/./");
QCOMPARE(path2.toString(), "");
// Make sure unix paths are not affected
FilePath path3 = FilePath::fromString("/./foo/bar");
QCOMPARE(path3.toString(), "foo/bar");
// Make sure unix paths with device also work
FilePath path4 = FilePath::fromString("device://host/./foo/bar");
QCOMPARE(path4.toString(), "device://host/./foo/bar");
}
} // Utils

View File

@@ -0,0 +1,31 @@
FROM ubuntu:22.04
ENV DEBIAN_FRONTEND=noninteractive
RUN apt-get update && \
apt-get install -y \
libgl1-mesa-dev \
qt6-base-dev \
qt6-base-private-dev \
qt6-declarative-dev \
qt6-declarative-private-dev \
libqt6core5compat6-dev \
build-essential \
clang-format clang-tidy clang-tools clang clangd libc++-dev libc++1 libc++abi-dev libc++abi1 libclang-dev libclang1 liblldb-dev libllvm-ocaml-dev libomp-dev libomp5 lld lldb llvm-dev llvm-runtime llvm python3-clang python3-lldb \
cmake \
nano \
ninja-build \
ca-certificates \
curl \
gnupg \
lsb-release \
qtcreator \
gdb \
&& curl -fsSL https://download.docker.com/linux/ubuntu/gpg | gpg --dearmor -o /usr/share/keyrings/docker-archive-keyring.gpg \
&& echo "deb [arch=$(dpkg --print-architecture) signed-by=/usr/share/keyrings/docker-archive-keyring.gpg] https://download.docker.com/linux/ubuntu $(lsb_release -cs) stable" | tee /etc/apt/sources.list.d/docker.list > /dev/null \
&& apt-get update \
&& apt-get install -y docker-ce-cli \
&& rm -rf /var/lib/apt/lists/* # buildkit
# Fix lldb python installation
RUN ln -s /usr/lib/llvm-14/lib/python3.10/dist-packages/lldb/* /usr/lib/python3/dist-packages/lldb/

View File

@@ -0,0 +1,22 @@
FROM ubuntu:22.04
RUN apt-get update && \
apt-get install -y \
libgl1-mesa-dev \
qt6-base-dev \
qt6-base-private-dev \
qt6-declarative-dev \
qt6-declarative-private-dev \
libqt6core5compat6-dev \
build-essential \
cmake \
nano \
ninja-build \
ca-certificates \
curl \
gnupg \
lsb-release \
gdb \
xterm \
&& rm -rf /var/lib/apt/lists/*

View File

@@ -0,0 +1,20 @@
FROM ubuntu:22.04
RUN apt-get update && \
apt-get install -y \
build-essential curl cmake libssl-dev python3 nano ninja-build \
libglu1-mesa-dev libgl1-mesa-dev libopengl-dev libgl-dev libfontconfig1-dev libfreetype6-dev libx11-dev libx11-xcb-dev libxext-dev libxfixes-dev libxi-dev libxrender-dev libxcb1-dev libxcb-glx0-dev libxcb-keysyms1-dev libxcb-image0-dev libxcb-shm0-dev libxcb-icccm4-dev libxcb-sync-dev libxcb-xfixes0-dev libxcb-shape0-dev libxcb-randr0-dev libxcb-render-util0-dev libxcb-util-dev libxcb-xinerama0-dev libxcb-xkb-dev libxkbcommon-dev libxkbcommon-x11-dev && \
rm -rf /var/lib/apt/lists/*
RUN curl -L https://download.qt.io/official_releases/qt/6.4/6.4.2/single/qt-everywhere-src-6.4.2.tar.xz -o /tmp/qt.tar.xz && \
cd /tmp && tar -xf qt.tar.xz && \
cd /tmp/qt-everywhere-src-6.4.2 && \
./configure -nomake tests -debug -skip qtlocation -skip qtpositioning -no-warnings-are-errors && \
cmake --build . --parallel 4 && \
cmake --install . && \
rm -rf /tmp/*
ENV PATH="/usr/local/Qt-6.4.2/bin:$PATH"

View File

@@ -0,0 +1,29 @@
FROM ubuntu:22.04
RUN apt-get update && \
apt-get install -y \
libgl1-mesa-dev \
qt6-base-dev \
qt6-base-private-dev \
qt6-declarative-dev \
qt6-declarative-private-dev \
libqt6core5compat6-dev \
build-essential \
clang-format clang-tidy clang-tools clang clangd libc++-dev libc++1 libc++abi-dev libc++abi1 libclang-dev libclang1 liblldb-dev libllvm-ocaml-dev libomp-dev libomp5 lld lldb llvm-dev llvm-runtime llvm python3-clang python3-lldb \
cmake \
nano \
ninja-build \
ca-certificates \
curl \
gnupg \
lsb-release \
gdb \
xterm \
&& curl -fsSL https://download.docker.com/linux/ubuntu/gpg | gpg --dearmor -o /usr/share/keyrings/docker-archive-keyring.gpg \
&& echo "deb [arch=$(dpkg --print-architecture) signed-by=/usr/share/keyrings/docker-archive-keyring.gpg] https://download.docker.com/linux/ubuntu $(lsb_release -cs) stable" | tee /etc/apt/sources.list.d/docker.list > /dev/null \
&& apt-get update \
&& apt-get install -y docker-ce-cli \
&& rm -rf /var/lib/apt/lists/* # buildkit
# Fix lldb python installation
RUN ln -s /usr/lib/llvm-14/lib/python3.10/dist-packages/lldb/* /usr/lib/python3/dist-packages/lldb/

View File

@@ -0,0 +1,32 @@
FROM ubuntu:22.04
RUN apt-get update && \
apt-get install -y \
libgl1-mesa-dev \
qt6-base-dev \
qt6-base-private-dev \
qt6-declarative-dev \
qt6-declarative-private-dev \
libqt6core5compat6-dev \
build-essential \
clang-format clang-tidy clang-tools clang clangd libc++-dev libc++1 libc++abi-dev libc++abi1 libclang-dev libclang1 liblldb-dev libllvm-ocaml-dev libomp-dev libomp5 lld lldb llvm-dev llvm-runtime llvm python3-clang python3-lldb \
cmake \
nano \
ninja-build \
ca-certificates \
curl \
gnupg \
lsb-release \
gdb \
&& curl -fsSL https://download.docker.com/linux/ubuntu/gpg | gpg --dearmor -o /usr/share/keyrings/docker-archive-keyring.gpg \
&& echo "deb [arch=$(dpkg --print-architecture) signed-by=/usr/share/keyrings/docker-archive-keyring.gpg] https://download.docker.com/linux/ubuntu $(lsb_release -cs) stable" | tee /etc/apt/sources.list.d/docker.list > /dev/null \
&& apt-get update \
&& apt-get install -y docker-ce-cli \
&& rm -rf /var/lib/apt/lists/* # buildkit
# Fix lldb python installation
RUN ln -s /usr/lib/llvm-14/lib/python3.10/dist-packages/lldb/* /usr/lib/python3/dist-packages/lldb/
RUN curl https://bootstrap.pypa.io/get-pip.py -o get-pip.py && python3 get-pip.py && rm get-pip.py
RUN pip install conan && conan --version && mkdir /.conan && chmod 777 /.conan

View File

@@ -0,0 +1,36 @@
FROM ubuntu:22.04
RUN apt-get update && \
apt-get install -y \
libgl1-mesa-dev \
qt6-base-dev \
qt6-base-private-dev \
qt6-declarative-dev \
qt6-declarative-private-dev \
libqt6core5compat6-dev \
build-essential \
clang-format clang-tidy clang-tools clang clangd libc++-dev libc++1 libc++abi-dev libc++abi1 libclang-dev libclang1 liblldb-dev libllvm-ocaml-dev libomp-dev libomp5 lld lldb llvm-dev llvm-runtime llvm python3-clang python3-lldb \
cmake \
nano \
ninja-build \
ca-certificates \
curl \
gnupg \
lsb-release \
git \
zip unzip tar \
gdb \
&& curl -fsSL https://download.docker.com/linux/ubuntu/gpg | gpg --dearmor -o /usr/share/keyrings/docker-archive-keyring.gpg \
&& echo "deb [arch=$(dpkg --print-architecture) signed-by=/usr/share/keyrings/docker-archive-keyring.gpg] https://download.docker.com/linux/ubuntu $(lsb_release -cs) stable" | tee /etc/apt/sources.list.d/docker.list > /dev/null \
&& apt-get update \
&& apt-get install -y docker-ce-cli \
&& rm -rf /var/lib/apt/lists/* # buildkit
# Fix lldb python installation
RUN ln -s /usr/lib/llvm-14/lib/python3.10/dist-packages/lldb/* /usr/lib/python3/dist-packages/lldb/
RUN cd / && git clone --depth 1 https://github.com/Microsoft/vcpkg.git && cd vcpkg && ./bootstrap-vcpkg.sh
RUN chmod -R 777 /vcpkg
RUN ln -s /vcpkg/vcpkg /usr/local/bin/vcpkg

View File

@@ -0,0 +1,43 @@
all: help
help:
@grep -E '^[0-9a-zA-Z._-]+:.*?## .*$$' $(MAKEFILE_LIST) | awk 'BEGIN {FS = ":.*?## "}; {printf "\033[36m%-30s\033[0m %s\n", $$1, $$2}'
default_run_args = --env="DISPLAY=host.docker.internal:0" --cap-add=SYS_PTRACE --security-opt seccomp=unconfined -v $(HOME):$(HOME) --workdir=$(HOME)
base: Dockerfile-base ## Build Ubuntu 22.04, docker-cli image, build Qt manually
docker build . -f Dockerfile-base -t qt-linux-base -t qt-linux-base:6
base-run: ## Build & run the base image
docker run -it --rm -v /var/run/docker.sock:/var/run/docker.sock $(default_run_args) qt-linux-base /bin/bash
qt-linux: Dockerfile ## Build Ubuntu 22.04, Qt 6, docker-cli image
docker build . -t qt-linux -t qt-linux:6
qt-linux-run: qt-linux ## Build & run the image
docker run -it --rm -v /var/run/docker.sock:/var/run/docker.sock $(default_run_args) qt-linux:6 /bin/bash
qt-linux-with-qtc: DockerFile-with-creator ## Build Ubuntu 22.04, Qt 6, docker-cli image, Includes Qt Creator
docker build . -f DockerFile-with-creator -t qt-linux-qtc -t qt-linux-qtc:6
qt-linux-with-qtc-run: qt-linux-with-qtc ## Build & run the image, Includes Qt Creator
docker run -it --rm $(default_run_args) qt-linux-qtc:6 /bin/bash
qt-linux-with-llvm: Dockerfile-llvm ## Build Ubuntu 22.04, Qt 6, docker-cli image, With Clang
docker build . -f Dockerfile-llvm -t qt-linux-llvm -t qt-linux-llvm:6
qt-linux-with-llvm-run: qt-linux-with-llvm ## Build & run the image, With Clang
docker run -it --rm $(default_run_args) qt-linux-llvm:6 /bin/bash
qt-linux-with-llvm-conan: Dockerfile-llvm-conan ## Build Ubuntu 22.04, Qt 6, docker-cli image, With Clang, Conan
docker build . -f Dockerfile-llvm-conan -t qt-linux-llvm-conan -t qt-linux-llvm-conan:6
qt-linux-with-llvm-conan-run: qt-linux-with-llvm-conan ## Build & run the image, With Clang, Conan
docker run -it --rm $(default_run_args) qt-linux-llvm-conan:6 /bin/bash
qt-linux-with-llvm-vcpkg: Dockerfile-llvm-vcpkg ## Build Ubuntu 22.04, Qt 6, docker-cli image, With Clang, Vcpkg
docker build . -f Dockerfile-llvm-vcpkg -t qt-linux-llvm-vcpkg -t qt-linux-llvm-vcpkg:6
qt-linux-with-llvm-vcpkg-run: qt-linux-with-llvm-vcpkg ## Build & run the image, With Clang, Vcpkg
docker run -it --rm $(default_run_args) qt-linux-llvm-vcpkg:6 /bin/bash