diff --git a/coin/instructions/build.yaml b/coin/instructions/build.yaml index 6c276b1b27e..5f7c305ea44 100644 --- a/coin/instructions/build.yaml +++ b/coin/instructions/build.yaml @@ -23,7 +23,7 @@ instructions: maxTimeBetweenOutput: 360 userMessageOnFailure: "Failed to extract LLVM package, check logs." - type: ExecuteCommand - command: "python -u {{.AgentWorkingDir}}/qt-creator/qt-creator/scripts/build.py --build-type {{.Env.QTC_BUILD_TYPE}} --src {{.AgentWorkingDir}}/qt-creator/qt-creator --build {{.AgentWorkingDir}}/qt-creator/qt-creator_build --qt-path {{.AgentWorkingDir}}/build/qt_install_dir --elfutils-path {{.AgentWorkingDir}}/build/qt_temp/elfutils --llvm-path {{.AgentWorkingDir}}/build/qt_temp/libclang --with-tests --no-zip --add-config=-DCMAKE_C_COMPILER_LAUNCHER=sccache --add-config=-DCMAKE_CXX_COMPILER_LAUNCHER=sccache" + command: "python3 -u {{.AgentWorkingDir}}/qt-creator/qt-creator/scripts/build.py --build-type {{.Env.QTC_BUILD_TYPE}} --src {{.AgentWorkingDir}}/qt-creator/qt-creator --build {{.AgentWorkingDir}}/qt-creator/qt-creator_build --qt-path {{.AgentWorkingDir}}/build/qt_install_dir --elfutils-path {{.AgentWorkingDir}}/build/qt_temp/elfutils --llvm-path {{.AgentWorkingDir}}/build/qt_temp/libclang --with-tests --no-zip --add-config=-DCMAKE_C_COMPILER_LAUNCHER=sccache --add-config=-DCMAKE_CXX_COMPILER_LAUNCHER=sccache" maxTimeInSeconds: 36000 maxTimeBetweenOutput: 3600 userMessageOnFailure: "Failed to run build.py, check logs." @@ -50,7 +50,7 @@ instructions: maxTimeBetweenOutput: 360 userMessageOnFailure: "Failed to extract LLVM package, check logs." - type: ExecuteCommand - command: "python -u {{.AgentWorkingDir}}/qt-creator/qt-creator/scripts/build.py --build-type {{.Env.QTC_BUILD_TYPE}} --src {{.AgentWorkingDir}}/qt-creator/qt-creator --build {{.AgentWorkingDir}}/qt-creator/qt-creator_build --qt-path {{.AgentWorkingDir}}/build/qt_install_dir --llvm-path {{.AgentWorkingDir}}/build/qt_temp/libclang --keychain-unlock-script /Users/qt/unlock-keychain.sh --with-tests --no-zip --add-config=-DCMAKE_C_COMPILER_LAUNCHER=sccache --add-config=-DCMAKE_CXX_COMPILER_LAUNCHER=sccache" + command: "python3 -u {{.AgentWorkingDir}}/qt-creator/qt-creator/scripts/build.py --build-type {{.Env.QTC_BUILD_TYPE}} --src {{.AgentWorkingDir}}/qt-creator/qt-creator --build {{.AgentWorkingDir}}/qt-creator/qt-creator_build --qt-path {{.AgentWorkingDir}}/build/qt_install_dir --llvm-path {{.AgentWorkingDir}}/build/qt_temp/libclang --keychain-unlock-script /Users/qt/unlock-keychain.sh --with-tests --no-zip --add-config=-DCMAKE_C_COMPILER_LAUNCHER=sccache --add-config=-DCMAKE_CXX_COMPILER_LAUNCHER=sccache" maxTimeInSeconds: 36000 maxTimeBetweenOutput: 3600 userMessageOnFailure: "Failed to run build.py, check logs." diff --git a/coin/instructions/common_environment.yaml b/coin/instructions/common_environment.yaml index a2f189f473b..19f8d3a61d1 100644 --- a/coin/instructions/common_environment.yaml +++ b/coin/instructions/common_environment.yaml @@ -96,7 +96,7 @@ instructions: - type: PrependToEnvironmentVariable variableName: PATH - variableValue: "{{.InstallDir}}\\bin;" + variableValue: "{{.Env.PYTHON3_PATH}};{{.Env.PIP3_PATH}};C:\\Utils\\gnuwin21\\bin;{{.InstallDir}}\\bin;" enable_if: condition: property property: target.os diff --git a/coin/instructions/provision.yaml b/coin/instructions/provision.yaml index 9de3cf487e1..5d0431a273b 100644 --- a/coin/instructions/provision.yaml +++ b/coin/instructions/provision.yaml @@ -32,7 +32,7 @@ instructions: property: host.os in_values: [MacOS, Linux, Windows] - type: ExecuteCommand - command: "python -u {{.AgentWorkingDir}}/build/qtsdk/packaging-tools/install_qt.py --qt-path {{.AgentWorkingDir}}/build/qt_install_dir --temp-path {{.AgentWorkingDir}}/build/qt_temp --base-url {{.Env.QTC_QT_BASE_URL}} --base-url-postfix={{.Env.QTC_QT_POSTFIX}} --icu7z http://master.qt.io/development_releases/prebuilt/icu/prebuilt/56.1/icu-linux-g++-Rhel7.2-x64.7z {{.Env.QTC_QT_MODULES}}" + command: "python3 -u {{.AgentWorkingDir}}/build/qtsdk/packaging-tools/install_qt.py --qt-path {{.AgentWorkingDir}}/build/qt_install_dir --temp-path {{.AgentWorkingDir}}/build/qt_temp --base-url {{.Env.QTC_QT_BASE_URL}} --base-url-postfix={{.Env.QTC_QT_POSTFIX}} --icu7z http://master.qt.io/development_releases/prebuilt/icu/prebuilt/56.1/icu-linux-g++-Rhel7.2-x64.7z {{.Env.QTC_QT_MODULES}}" executeCommandArgumentSplitingBehavior: SplitAfterVariableSubstitution maxTimeInSeconds: 3600 maxTimeBetweenOutput: 360 @@ -42,7 +42,7 @@ instructions: property: host.os equals_value: Linux - type: ExecuteCommand - command: "python -u {{.AgentWorkingDir}}/build/qtsdk/packaging-tools/install_qt.py --qt-path {{.AgentWorkingDir}}/build/qt_install_dir --temp-path {{.AgentWorkingDir}}/build/qt_temp --base-url {{.Env.QTC_QT_BASE_URL}} --base-url-postfix={{.Env.QTC_QT_POSTFIX}} {{.Env.QTC_QT_MODULES}}" + command: "python3 -u {{.AgentWorkingDir}}/build/qtsdk/packaging-tools/install_qt.py --qt-path {{.AgentWorkingDir}}/build/qt_install_dir --temp-path {{.AgentWorkingDir}}/build/qt_temp --base-url {{.Env.QTC_QT_BASE_URL}} --base-url-postfix={{.Env.QTC_QT_POSTFIX}} {{.Env.QTC_QT_MODULES}}" executeCommandArgumentSplitingBehavior: SplitAfterVariableSubstitution maxTimeInSeconds: 3600 maxTimeBetweenOutput: 360 @@ -52,7 +52,7 @@ instructions: property: host.os equals_value: MacOS - type: ExecuteCommand - command: "C:\\Python27\\Scripts\\pip.exe install pywin32" + command: "pip.exe install pywin32" maxTimeInSeconds: 1200 maxTimeBetweenOutput: 120 userMessageOnFailure: "Failed to install win32api, check logs." diff --git a/doc/qtcreator/src/analyze/cpu-usage-analyzer.qdoc b/doc/qtcreator/src/analyze/cpu-usage-analyzer.qdoc index f95f7dda851..03b4c35bb8f 100644 --- a/doc/qtcreator/src/analyze/cpu-usage-analyzer.qdoc +++ b/doc/qtcreator/src/analyze/cpu-usage-analyzer.qdoc @@ -452,11 +452,10 @@ The Performance Analyzer can read Perf data files generated in either frame pointer or dwarf mode. However, to generate the files correctly, numerous preconditions have to be met. All system images for the - \l{http://doc.qt.io/QtForDeviceCreation/qtee-supported-platforms.html} - {Qt for Device Creation reference devices}, except for Freescale iMX53 Quick - Start Board and SILICA Architect Tibidabo, are correctly set up for - profiling in the dwarf mode. For other devices, check whether Perf can read - back its own data in a sensible way by checking the output of + \l{https://doc.qt.io/Boot2Qt/qtdc-supported-platforms.html} + {Boot2Qt:Supported Target Devices and Development Hosts} are correctly set + up for profiling in the dwarf mode. For other devices, check whether Perf + can read back its own data in a sensible way by checking the output of \c {perf report} or \c {perf script} for the recorded Perf data files. \section1 Loading and Saving Trace Files diff --git a/doc/qtcreator/src/external-resources/external-resources.qdoc b/doc/qtcreator/src/external-resources/external-resources.qdoc index b755f99cf15..cc7dd4341d6 100644 --- a/doc/qtcreator/src/external-resources/external-resources.qdoc +++ b/doc/qtcreator/src/external-resources/external-resources.qdoc @@ -157,3 +157,15 @@ \externalpage https://microsoft.github.io/language-server-protocol/ \title Language Server Protocol */ +/*! + \externalpage https://docs.microsoft.com/en-us/java/openjdk/download + \title Download OpenJDK +*/ +/*! + \externalpage https://developer.android.com/studio + \title Download Android Studio +*/ +/*! + \externalpage https://developer.android.com/studio/install + \title Android Studio Installation Guide +*/ diff --git a/doc/qtcreator/src/linux-mobile/b2qtdev.qdoc b/doc/qtcreator/src/linux-mobile/b2qtdev.qdoc index e9d4e470f9f..ba71b49ab2e 100644 --- a/doc/qtcreator/src/linux-mobile/b2qtdev.qdoc +++ b/doc/qtcreator/src/linux-mobile/b2qtdev.qdoc @@ -63,8 +63,8 @@ \note On Ubuntu Linux, the development user account must have access to plugged in devices. To allow the development user access to the device via USB, create a new \c udev rule, as described in - \l{https://doc.qt.io/QtForDeviceCreation/b2qt-requirements-x11.html#setting-up-usb-access-to-embedded-devices} - {Setting Up USB Access to Embedded Devices}. + \l{https://doc.qt.io/Boot2Qt/b2qt-requirements-x11.html#setting-up-usb-access-to-embedded-devices} + {Boot2Qt: Setting Up USB Access to Embedded Devices}. You can edit the settings later in \uicontrol Tools > \uicontrol Options > \uicontrol Devices > \uicontrol Devices. diff --git a/doc/qtcreator/src/linux-mobile/creator-embedded-platforms.qdoc b/doc/qtcreator/src/linux-mobile/creator-embedded-platforms.qdoc index d920d13e906..8d0f5d25e0c 100644 --- a/doc/qtcreator/src/linux-mobile/creator-embedded-platforms.qdoc +++ b/doc/qtcreator/src/linux-mobile/creator-embedded-platforms.qdoc @@ -65,24 +65,22 @@ license holders, tooling is provided to customize the contents of the stack as well as to take it into desired production hardware. - Either Windows 7 or later or Ubuntu Linux 64-bit 12.04 LTS + Either Windows 10 64-bit or later or Ubuntu Linux 64-bit 20.04 LTS or later is required to install and use Boot2Qt. The following topics contain more information about developing applications for Boot2Qt devices: \list - \li \l{https://doc.qt.io/QtForDeviceCreation/qtee-supported-platforms.html} - {Reference Target Devices and Development Hosts} - \li \l{https://doc.qt.io/QtForDeviceCreation/b2qt-installation-guides.html} - {Installation Guides} + \li \l{https://doc.qt.io/Boot2Qt/qtdc-supported-platforms.html} + {Boot2Qt: Supported Target Devices and Development Hosts} + \li \l{https://doc.qt.io/Boot2Qt/b2qt-installation-guides.html} + {Boot2Qt: Installation Guides} \li \l{Connecting Boot2Qt Devices} \li \l{Specifying Run Settings for Boot2Qt Devices} \li \l{Deploying Applications to Boot2Qt Devices} \li \l{https://doc.qt.io/qtcreator/creator-overview-qtasam.html} {Qt Creator Plugin for Qt Application Manager} - \li \l{https://doc.qt.io/QtForDeviceCreation/index.html} - {Qt for Device Creation} \endlist \section1 Generic Remote Linux diff --git a/doc/qtcreator/src/linux-mobile/creator-projects-settings-run-b2qt.qdocinc b/doc/qtcreator/src/linux-mobile/creator-projects-settings-run-b2qt.qdocinc index 864a449bcc6..175dfe49c36 100644 --- a/doc/qtcreator/src/linux-mobile/creator-projects-settings-run-b2qt.qdocinc +++ b/doc/qtcreator/src/linux-mobile/creator-projects-settings-run-b2qt.qdocinc @@ -32,10 +32,8 @@ must create connections from the development host to the device and add the device configurations to \l{glossary-buildandrun-kit}{kits}. Select \uicontrol {Manage Kits} to add devices to kits. For more information, see - the \l{http://doc.qt.io/QtForDeviceCreation/qtee-installation-guide.html} - {Installation Guide} in the - \l{http://doc.qt.io/QtForDeviceCreation/index.html}{Qt for Device Creation} - documentation. + \l{http://doc.qt.io/Boot2Qt/b2qt-installation-guides.html} + {Boot2Qt: Installation Guide}. The run settings display the path to the executable file on the development host and on the device. diff --git a/doc/qtcreator/src/overview/creator-only/creator-commercial-overview.qdoc b/doc/qtcreator/src/overview/creator-only/creator-commercial-overview.qdoc index acb4548fb3c..015c30825ca 100644 --- a/doc/qtcreator/src/overview/creator-only/creator-commercial-overview.qdoc +++ b/doc/qtcreator/src/overview/creator-only/creator-commercial-overview.qdoc @@ -40,9 +40,8 @@ \l{http://qt.io/licensing/}{Qt license}: \list - \li \l{http://doc.qt.io/QtForDeviceCreation/index.html}{Developing for - embedded devices} - \li \l{http://doc.qt.io/qtcreator/creator-overview-qtasam.html} + \li \l{https://doc.qt.io/Boot2Qt/index.html}{Boot2Qt} + \li \l{https://doc.qt.io/qtcreator/creator-overview-qtasam.html} {Qt Application Manager} integration \endlist */ diff --git a/doc/qtcreator/src/projects/creator-only/creator-projects-build-run-tutorial.qdoc b/doc/qtcreator/src/projects/creator-only/creator-projects-build-run-tutorial.qdoc index 93949aa6584..e69d92ffa56 100644 --- a/doc/qtcreator/src/projects/creator-only/creator-projects-build-run-tutorial.qdoc +++ b/doc/qtcreator/src/projects/creator-only/creator-projects-build-run-tutorial.qdoc @@ -44,12 +44,10 @@ \l{Connecting Android Devices} and \l{Connecting iOS Devices}. To run an example application on a Boot2Qt device, you must set up - Qt for Device Creation on the development host and create connections + Boot2Qt on the development host and create connections between the host and devices. For more information, see - \l{https://doc.qt.io/QtForDeviceCreation/b2qt-installation-guides.html} - {Installation Guides} in the - \l{http://doc.qt.io/QtForDeviceCreation/index.html}{Qt for Device Creation} - documentation. + \l{https://doc.qt.io/Boot2Qt/b2qt-installation-guides.html} + {Boot2Qt: Installation Guides} If you have \l{Qt Design Studio Manual}{\QDS} installed, you can open \QDS examples from \QC in \QDS. diff --git a/doc/qtcreator/src/projects/creator-only/creator-projects-targets.qdoc b/doc/qtcreator/src/projects/creator-only/creator-projects-targets.qdoc index 1a1f0a19a29..b6106cb7cf3 100644 --- a/doc/qtcreator/src/projects/creator-only/creator-projects-targets.qdoc +++ b/doc/qtcreator/src/projects/creator-only/creator-projects-targets.qdoc @@ -49,7 +49,7 @@ \list \li \l{Connecting Android Devices}{Android Device} \li \l{Connecting Bare Metal Devices}{Bare Metal Device} - \li \l{https://doc.qt.io/QtForDeviceCreation/b2qt-installation-guides.html} + \li \l{https://doc.qt.io/Boot2Qt/b2qt-installation-guides.html} {Boot2Qt Device} (commercial only) \li \l{Emulator}{Boot2Qt Emulator Device} (commercial only) \li \l{Connecting Generic Remote Linux Devices}{Generic Remote Linux Device} diff --git a/doc/qtcreator/src/qtquick/qt-design-viewer.qdoc b/doc/qtcreator/src/qtquick/qt-design-viewer.qdoc index ab23eb15810..818ad7ed5eb 100644 --- a/doc/qtcreator/src/qtquick/qt-design-viewer.qdoc +++ b/doc/qtcreator/src/qtquick/qt-design-viewer.qdoc @@ -24,11 +24,12 @@ ****************************************************************************/ /*! - \previouspage creator-live-preview-devices.html \page qt-design-viewer.html \if defined(qtdesignstudio) + \previouspage creator-live-preview-android.html \nextpage studio-exporting-and-importing.html \else + \previouspage creator-live-preview-devices.html \nextpage creator-building-targets.html \endif diff --git a/doc/qtcreator/src/qtquick/qtquick-live-preview-devices.qdoc b/doc/qtcreator/src/qtquick/qtquick-live-preview-devices.qdoc index 9505b6a15fb..c8ef7a11c83 100644 --- a/doc/qtcreator/src/qtquick/qtquick-live-preview-devices.qdoc +++ b/doc/qtcreator/src/qtquick/qtquick-live-preview-devices.qdoc @@ -26,8 +26,11 @@ /*! \previouspage creator-live-preview-desktop.html \page creator-live-preview-devices.html + \if defined(qtdesignstudio) + \nextpage creator-live-preview-android.html + \else \nextpage qt-design-viewer.html - + \endif \title Previewing on Devices To preview UIs on Android devices, you need to enable USB debugging on them @@ -78,19 +81,17 @@ \section2 Previewing on Boot2Qt Devices - You can preview UIs on Boot2Qt devices that are supported by - \l{Qt for Device Creation}. For a list of supported devices, see - \l{https://doc.qt.io/QtForDeviceCreation/qtdc-supported-platforms.html} - {Reference Target Devices and Development Hosts}. + You can preview UIs on Boot2Qt devices. For a list of supported devices, see + \l{https://doc.qt.io/Boot2Qt/qtdc-supported-platforms.html} + {Boot2Qt: Supported Target Devices and Development Hosts}. You must configure the device as instructed in the - \l{https://doc.qt.io/QtForDeviceCreation/b2qt-installation-guides.html} - {Installation Guides}. + \l{https://doc.qt.io/Boot2Qt/b2qt-installation-guides.html} + {Boot2Qt: Installation Guides}. \note At the time of this writing, \macos is not supported as a development - host for Qt for Device Creation. This means that you cannot preview UIs on - devices if you are using \QC on \macos. For more information about - supported development hosts, see - \l {https://doc.qt.io/QtForDeviceCreation/qtdc-supported-platforms.html#supported-development-hosts} - {Supported Development Hosts}. + host for Boot2Qt. This means that you cannot preview UIs on + devices if you are using \QC on \macos. For more information, see + \l {https://doc.qt.io/Boot2Qt/qtdc-supported-platforms.html#supported-development-hosts} + {Boot2Qt: Supported Development Hosts}. */ diff --git a/doc/qtcreator/src/qtquick/qtquick-live-preview.qdoc b/doc/qtcreator/src/qtquick/qtquick-live-preview.qdoc index 47028e00a23..cf4abeb59cd 100644 --- a/doc/qtcreator/src/qtquick/qtquick-live-preview.qdoc +++ b/doc/qtcreator/src/qtquick/qtquick-live-preview.qdoc @@ -72,6 +72,14 @@ devices is set up automatically. You only need to connect your devices to your system. \endif + + \if defined(qtdesignstudio) + \li \l{Previewing Android applications} + + You can preview Android applications live using an Android + emulator. + + \endif \li \l{Previewing in Browsers} You can open \l{https://qt-webassembly.io/designviewer/}{\QDV} diff --git a/doc/qtdesignstudio/images/android-studio-avd-manager.png b/doc/qtdesignstudio/images/android-studio-avd-manager.png new file mode 100644 index 00000000000..e37a4db1698 Binary files /dev/null and b/doc/qtdesignstudio/images/android-studio-avd-manager.png differ diff --git a/doc/qtdesignstudio/images/android-studio-sdk-manager.png b/doc/qtdesignstudio/images/android-studio-sdk-manager.png new file mode 100644 index 00000000000..c3f2601fcd9 Binary files /dev/null and b/doc/qtdesignstudio/images/android-studio-sdk-manager.png differ diff --git a/doc/qtdesignstudio/images/android-studio-sdk-tools.png b/doc/qtdesignstudio/images/android-studio-sdk-tools.png new file mode 100644 index 00000000000..b754093ac42 Binary files /dev/null and b/doc/qtdesignstudio/images/android-studio-sdk-tools.png differ diff --git a/doc/qtdesignstudio/images/menu-build-qml-preview.png b/doc/qtdesignstudio/images/menu-build-qml-preview.png new file mode 100644 index 00000000000..1f519c31e50 Binary files /dev/null and b/doc/qtdesignstudio/images/menu-build-qml-preview.png differ diff --git a/doc/qtdesignstudio/images/qtds-android-sdk-changes-dialog.png b/doc/qtdesignstudio/images/qtds-android-sdk-changes-dialog.png new file mode 100644 index 00000000000..fd5ff937bdf Binary files /dev/null and b/doc/qtdesignstudio/images/qtds-android-sdk-changes-dialog.png differ diff --git a/doc/qtdesignstudio/images/qtds-android-sdk-licenses-dialog.png b/doc/qtdesignstudio/images/qtds-android-sdk-licenses-dialog.png new file mode 100644 index 00000000000..200fa88d92f Binary files /dev/null and b/doc/qtdesignstudio/images/qtds-android-sdk-licenses-dialog.png differ diff --git a/doc/qtdesignstudio/images/qtds-options-accept-licenses.png b/doc/qtdesignstudio/images/qtds-options-accept-licenses.png new file mode 100644 index 00000000000..91dff8c700e Binary files /dev/null and b/doc/qtdesignstudio/images/qtds-options-accept-licenses.png differ diff --git a/doc/qtdesignstudio/images/qtds-options-devices.png b/doc/qtdesignstudio/images/qtds-options-devices.png new file mode 100644 index 00000000000..9744dd333ec Binary files /dev/null and b/doc/qtdesignstudio/images/qtds-options-devices.png differ diff --git a/doc/qtdesignstudio/images/qtds-options-dialog-missing-packages.png b/doc/qtdesignstudio/images/qtds-options-dialog-missing-packages.png new file mode 100644 index 00000000000..640e8794003 Binary files /dev/null and b/doc/qtdesignstudio/images/qtds-options-dialog-missing-packages.png differ diff --git a/doc/qtdesignstudio/images/qtds-options-kits.png b/doc/qtdesignstudio/images/qtds-options-kits.png new file mode 100644 index 00000000000..3b349d53f7c Binary files /dev/null and b/doc/qtdesignstudio/images/qtds-options-kits.png differ diff --git a/doc/qtdesignstudio/images/qtds-run-settings.png b/doc/qtdesignstudio/images/qtds-run-settings.png new file mode 100644 index 00000000000..14d5a85c22d Binary files /dev/null and b/doc/qtdesignstudio/images/qtds-run-settings.png differ diff --git a/doc/qtdesignstudio/images/qtds-running-emulator.png b/doc/qtdesignstudio/images/qtds-running-emulator.png new file mode 100644 index 00000000000..ecd3054db3b Binary files /dev/null and b/doc/qtdesignstudio/images/qtds-running-emulator.png differ diff --git a/doc/qtdesignstudio/images/studio-3d-particles-sprite-template.png b/doc/qtdesignstudio/images/studio-3d-particles-sprite-template.png new file mode 100644 index 00000000000..dd0ce67de45 Binary files /dev/null and b/doc/qtdesignstudio/images/studio-3d-particles-sprite-template.png differ diff --git a/doc/qtdesignstudio/images/studio-3d-particles.png b/doc/qtdesignstudio/images/studio-3d-particles.png index 48f963ede66..14711846f32 100644 Binary files a/doc/qtdesignstudio/images/studio-3d-particles.png and b/doc/qtdesignstudio/images/studio-3d-particles.png differ diff --git a/doc/qtdesignstudio/images/toolbar-show-live-preview.png b/doc/qtdesignstudio/images/toolbar-show-live-preview.png new file mode 100644 index 00000000000..b942fcf5c1b Binary files /dev/null and b/doc/qtdesignstudio/images/toolbar-show-live-preview.png differ diff --git a/doc/qtdesignstudio/src/prototyping/qtquick-live-preview-android.qdoc b/doc/qtdesignstudio/src/prototyping/qtquick-live-preview-android.qdoc new file mode 100644 index 00000000000..11980d1128c --- /dev/null +++ b/doc/qtdesignstudio/src/prototyping/qtquick-live-preview-android.qdoc @@ -0,0 +1,200 @@ +/**************************************************************************** +** +** Copyright (C) 2021 The Qt Company Ltd. +** Contact: https://www.qt.io/licensing/ +** +** This file is part of the Qt Design Studio documentation. +** +** Commercial License Usage +** Licensees holding valid commercial Qt licenses may use this file in +** accordance with the commercial license agreement provided with the +** Software or, alternatively, in accordance with the terms contained in +** a written agreement between you and The Qt Company. For licensing terms +** and conditions see https://www.qt.io/terms-conditions. For further +** information use the contact form at https://www.qt.io/contact-us. +** +** GNU Free Documentation License Usage +** Alternatively, this file may be used under the terms of the GNU Free +** Documentation License version 1.3 as published by the Free Software +** Foundation and appearing in the file included in the packaging of +** this file. Please review the following information to ensure +** the GNU Free Documentation License version 1.3 requirements +** will be met: https://www.gnu.org/licenses/fdl-1.3.html. +** +****************************************************************************/ + +/*! + \previouspage creator-live-preview-devices.html + \page creator-live-preview-android.html + \nextpage qt-design-viewer.html + + \title Previewing Android Applications + + In \QDS, you can preview Android applications live using an Android emulator. + + \section1 Prerequisites + + \section2 Install OpenJDK 11 + + You need to install OpenJDK 11 as described in \l{Getting Started with Qt for Android}, + to do this: + + \list + \li On Linux: + \list 1 + \li In the command line, run: + \code + sudo apt-get install openjdk-11-jdk + \endcode + \endlist + \li On macOS: + \list 1 + \li Download OpenJDK 11 from \l{Download OpenJDK}. + \li In the command line, run: + \code + cd ~/Downloads + tar xf microsoft-jdk-11.0.13.8.1-macos-x64.tar.gz + \endcode + \li Copy the unzipped folder to a location where macOS searches for Java by default: + \code + sudo cp -Rv jdk-11.0.13+8 /Library/Java/JavaVirtualMachines/ + \endcode + \li Check if Java was correctly installed: + \code + java -version + \endcode + The Java installation is correct if the command returns something like: + \code + openjdk version "11.0.13" 2021-10-19 LTS + OpenJDK Runtime Environment Microsoft-27990 (build 11.0.13+8-LTS) + OpenJDK 64-Bit Server VM Microsoft-27990 (build 11.0.13+8-LTS, mixed mode) + \endcode + \endlist + \li On Windows: + \list + \li OpenJDK 11 is automatically installed with Android Studio. + \endlist + \endlist + + \section2 Install Android Studio and SDK Tools + + You need to install Android Studio: + + \list 1 + \li Download Android Studio from \l{Download Android Studio}. + \li Install Android Studio according to the + \l{Android Studio Installation Guide}. + \endlist + + Next, you need to install Android SDK command-line tools: + + \list 1 + \li Run Android Studio and on the welcome page, select \uicontrol{More Actions} > + \uicontrol{SDK Manager}. + \image android-studio-sdk-manager.png + \li Select \uicontrol{Android SDK Build-Tools 32-rc1}, \uicontrol{NDK (Side by side)}, and + \uicontrol{Android SDK Command-line Tools (latest)}. + \image android-studio-sdk-tools.png + \li Select \uicontrol{Apply} and follow the instructions in the wizard to finalize the + installation. + \endlist + + \section2 Install Android SDK Packages in \QDS + + You need to install Android SDK packages in \QDS: + \list 1 + \li Run \QDS. + \li Go to \uicontrol Tools > \uicontrol Options > \uicontrol{Devices}. + \li Select \uicontrol Yes on the \uicontrol{Missing Android SDK Packages} dialog. + \image qtds-options-dialog-missing-packages.png + \li Select \uicontrol OK on the \uicontrol{Android SDK Changes} dialog. + \image qtds-android-sdk-changes-dialog.png + \li Select \uicontrol Yes on the \uicontrol{Android SDK Licenses} dialog. + \image qtds-android-sdk-licenses-dialog.png + \endlist + + \note The installation can take a while. If the installation process seems to + have stopped working, try to restart \QDS and run the installation again. + + After completing these steps, you should no longer have any errors on the + \uicontrol Tools > \uicontrol Options > \uicontrol Devices page. + \image qtds-options-accept-licenses.png + + \section2 Create Android Virtual Devices + + Next, you need to create an Android Virtual Device (AVD): + + \note You might need to download a system image depending on your setup. + + \list 1 + \li Run Android Studio and on the welcome page, select \uicontrol{More Actions} > + \uicontrol{AVD Manager}. + \image android-studio-avd-manager.png + \li Select \uicontrol{Create Virtual Device} and follow the instructions in the wizard to + finalize the creation. + \endlist + + \QDS has a AVD manager where you can create AVDs as well but it is recommended to use Android + Studio because then you can directly install the needed system package for the selected device + configuration. + + To create an AVD in \QDS: + \list 1 + \li Go to \uicontrol Tools > \uicontrol Options. + \li On the \uicontrol Devices tab, select \uicontrol Add and follow the wizard to finalize + the creation. If there is no entry for \e{Android Device} in the + \uicontrol{Available device types} list, try restarting \QDS. + \endlist + + \note Many device images require Intel HAXM to work on Windows 10 and later, you can + download and install the drivers from + \l{https://github.com/intel/haxm/wiki/Installation-Instructions-on-Windows}{here}. + + \image qtds-options-devices.png + + \section2 Set the AVD as the Device in the Android Kit + + Next, you need to set the AVD as the Android device kit. You do this under the the + \uicontrol Kits tab. If the \uicontrol Kits list is empty, restart \QDS. + + \image qtds-options-kits.png + + \section1 Create a Project and Run the Emulator + + Now, you are set up and can create a project in \QDS. In the project, configure it to run on the + Android device: + \list 1 + \li Select the \uicontrol Projects mode tab. + \li Under \uicontrol{Build & Run}, select the Android device. + \endlist + + \image qtds-run-settings.png + + Next, to run the emulator, do one of the following: + \list + \li Select \uicontrol{Show Live Preview} in the \uicontrol{Form Editor} toolbar. + \image toolbar-show-live-preview.png + \li Select \uicontrol Build > \uicontrol{QML Preview}. + \note The \uicontrol Build menu option is not visible by default. To show + it, go to \uicontrol Tools > \uicontrol Options > \uicontrol Environment + > \uicontrol {Qt Design Studio Configuration}. + \image menu-build-qml-preview.png + \endlist + + Now the emulator runs, the qtdesignviewer APK delivered with the \QDS installation + is uploaded, and the project is uploaded and shown in the emulator. + \image qtds-running-emulator.png + + Note the following: + \list + \li The qtdesignviewer for Android currently has no live preview. You have to restart + the preview to see updates. + \li Android typically has very high DPI and it is good to familiarize yourself with how + \l{https://doc-snapshots.qt.io/qt6-dev/highdpi.html}{high DPI works in Qt 6}. You can, + for example, use QT_SCALE_FACTOR or QT_USE_PHYSICAL_DPI. You can define those in the + \e .qmlproject file. + \li The qtdesignviewer for Android is currently built with Qt 6.2 and comes with all + QML modules shipped with \QDS 2.3. + \endlist + +*/ diff --git a/doc/qtdesignstudio/src/qtbridge/qtbridge-figma-using.qdoc b/doc/qtdesignstudio/src/qtbridge/qtbridge-figma-using.qdoc index 30f172b9f7f..1d38ca9b5ee 100644 --- a/doc/qtdesignstudio/src/qtbridge/qtbridge-figma-using.qdoc +++ b/doc/qtdesignstudio/src/qtbridge/qtbridge-figma-using.qdoc @@ -97,6 +97,25 @@ handle, such as gradient fill colors or a mixed radius, the frames are exported as images. + + \section2 Using Variants + Figma variants are exported as a component with states. All variants + inside a \e component-set are merged together and the differences across + the variants are translated into states. + + For an optimal output, follow these guidelines: + \list + \li \QBF panel is disabled for variants. Before adding + a variant to a component, the \QBF settings for the component + should be complete. + \li Do not change the layer names across the variants. The \l ID of + a layer is derived from the layer name which in turn is used + to identify the property differences for the state generation, so + it is essential to keep the layer names same across variants. + \li Adding and removing layers across the variants is fine and + encouraged to create the variant differences. + \endlist + \section1 Exporting Designs \image qt-figma-bridge.png "Qt Bridge for Figma" diff --git a/doc/qtdesignstudio/src/qtdesignstudio-packaging.qdoc b/doc/qtdesignstudio/src/qtdesignstudio-packaging.qdoc index d908bd0dba1..cbb654a9eca 100644 --- a/doc/qtdesignstudio/src/qtdesignstudio-packaging.qdoc +++ b/doc/qtdesignstudio/src/qtdesignstudio-packaging.qdoc @@ -67,7 +67,7 @@ \section1 Embedding Resources into Applications Alternatively, you can embedd the resources into your application by - selecting \uicontrol Build > \uicontrol {Generate RCC Resource File}. + selecting \uicontrol Build > \uicontrol {Generate Deployable Package}. Select the location for the .qmlrc file, and then select the files to embedd in the \uicontrol {Add Resources} dialog. diff --git a/doc/qtdesignstudio/src/qtdesignstudio-toc.qdoc b/doc/qtdesignstudio/src/qtdesignstudio-toc.qdoc index ed3d3c48dad..f3a7a0d4f7d 100644 --- a/doc/qtdesignstudio/src/qtdesignstudio-toc.qdoc +++ b/doc/qtdesignstudio/src/qtdesignstudio-toc.qdoc @@ -151,6 +151,7 @@ \list \li \l{Previewing on Desktop} \li \l{Previewing on Devices} + \li \l{Previewing Android Applications} \li \l{Previewing in Browsers} \endlist \li \l {Asset Creation with Other Tools} diff --git a/doc/qtdesignstudio/src/qtquick3d-editor/qtdesignstudio-3d-particles.qdoc b/doc/qtdesignstudio/src/qtquick3d-editor/qtdesignstudio-3d-particles.qdoc index 12638642ffe..6f1a2c58463 100644 --- a/doc/qtdesignstudio/src/qtquick3d-editor/qtdesignstudio-3d-particles.qdoc +++ b/doc/qtdesignstudio/src/qtquick3d-editor/qtdesignstudio-3d-particles.qdoc @@ -31,7 +31,7 @@ \nextpage studio-3d-particle-system.html \title Particles - A \e {particle system} enables you to use sprites, 3D models, or images to + With a \e {particle system} you can use sprites, 3D models, or images to create effects that are hard to reproduce with conventional rendering techniques. This includes chaotic systems, natural phenomena, or processes caused by chemical reactions. For example, you can simulate fire, smoke, @@ -47,15 +47,16 @@ \li \l {Particle Directions} \endlist - \section1 Adding a Particle System - - Preset particle components are available in - \uicontrol Components > \uicontrol {Qt Quick 3D Particles 3D} + Preset particle \l{Particle Components}{components}, + \l{Particle Templates}{templates}, and \l{Particle Effects}{effects} are + available in \uicontrol Components > \uicontrol {QtQuick3D Particles3D} after you add the \uicontrol {QtQuick3D.Particles3D} module to your project, as instructed in \l{Adding and Removing Modules}. \image studio-3d-particles.png "3D Particles" + \section1 Particle Components + When you add an instance of the \uicontrol {Particle System} component to a scene, \QDS automatically adds instances of the \uicontrol {Sprite Particle}, \uicontrol Emitter, and \uicontrol {Vector Direction} components for you. @@ -82,53 +83,6 @@ to simulate flying objects that follow wavy curves, or an instance of the \uicontrol {Point Rotator} to simulate windy weather. - To add a particle system that emits sprite particles: - - \list 1 - \li Select \uicontrol Assets > \inlineimage icons/plus.png - to add your sprites, 3D models, textures, and other graphical - \l{Assets}{assets} to the project. - \li Drag-and-drop an instance of the \uicontrol {Particle System} - component from \uicontrol Components to a scene component instance - in \l Navigator. - \li Drag-and-drop the sprite image from \uicontrol Assets to the sprite - particle instance in \uicontrol Navigator. - \endlist - - Add instances of other components according to your use case. - - \section1 Performance Considerations - - The particles are designed to be usable on a variety of hardware on - desktops, as well as mobile and embedded devices. However, in addition - to rendering the maximum amount of particle elements on the screen, - extensibility to different use-cases, rendering quality, integration - with the other UI elements, are also important. - - Currently, the rendering runs on GPU, while the particle system logic - runs on CPU. However, the \e {stateless particle system} enables you - to move the system logic onto GPU if that seems beneficial. The initial - measurements indicate that the system is quite well balanced between - CPU and GPU. The stateless system also enables animating particles by - using a \l{Timeline}{timeline}. The model particles use instanced rendering - to boost the performance. Therefore, OpenGL ES 2.0 isn't sufficient to make - rendering performant, and at least OpenGL ES 3.0, Vulkan, or some other - modern backend is required. - - To get a more concrete view on the actual performance, the video below shows - a particles Testbed application running on four different Android devices. - These devices and their chipsets and GPUs could be considered to be - lower-end to mid-range, confirming that the particles can perform well also - on affordable hardware. - - \youtube 9MqUCP6JLCQ - - \section1 Summary of 3D Particles - - \note The \uicontrol {Particles 3D} components are released as a tech - preview feature in \QDS 2.2, and their functionality will be improved - in future releases. - The following table lists preset particle components. \table @@ -207,6 +161,190 @@ \li Applies random wave curves to particles. \endtable + \section1 Particle Templates + + A particle template is a preset of particle components that you can use to + create specific particle effects in a convenient way. + + The following table lists particle templates and their components. + + \table + \header + \li Template + \li Components + \row + \li Animated Sprite + \li + Particle System + \list + \li Particle Emitter + \list + \li Sprite Particle + \li Sprite Sequence + \li Texture + \endlist + \li Vector Direction + \endlist + \row + \li Attractor + \li + Particle System + \list + \li Particle Emitter + \list + \li Sprite Particle + \li Vector Direction + \endlist + \li Particle Attractor + \endlist + \row + \li Burst + \li + Particle System + \list + \li Particle Emitter + \list + \li Sprite Particle + \li Vector Direction + \li Emit Burst + \endlist + \endlist + \row + \li Model Blend + \li + Particle System + \list + \li Particle Emitter + \list + \li Node + \li Model Blend Particle + \li Particle Emitter + \list + \li Vector Direction + \endlist + \endlist + \endlist + \row + \li Model Shape + \li + Particle System + \list + \li Particle Emitter + \list + \li Sprite Particle + \list + \li Vector Direction + \endlist + \endlist + \li Particle Model Shape + \endlist + \row + \li Particle Trail + \li + Particle System + \list + \li Trail Emitter + \list + \li Vector Direction + \li Sprite Particle + \endlist + \li Particle Emitter + \list + \li Vector Direction + \li Sprite Particle + \endlist + \endlist + \row + \li Sprite + \li + Particle System + \list + \li Sprite Emitter + \list + \li Sprite Particle + \li Vector Direction + \endlist + \endlist + \row + \li Wander + \li + Particle System + \list + \li Sprite Emitter + \list + \li Sprite Particle + \list + \li Texture + \endlist + \li Wander + \li Node + \endlist + \endlist + \endtable + + \section1 Particle Effects + + A particle effect is a ready-made effect that you can use to create, for + example, fire, rain, or mist in a convenient way. + + The following particle effects are available: + + \list + \li Clouds + \li Dust + \li Exhaust + \li Fire + \li Heavy Rain + \li Heavy Tire Spray + \li Light Rain + \li Light Tire Spray + \li Rain Mist + \li Snow + \li Steam + \endlist + + \section1 Adding a Particle System + + The recommended way to add a particle system is to use one of the + \l{Particle Templates}{particle templates} and then add or remove + particle components according to your use case. + + For example, to add a particle system that emits sprite particles: + + \list + \li From \uicontrol {Qt Quick 3D Particles System Templates} in + \uicontrol {Components}, drag \uicontrol Sprite to a scene component in + \uicontrol Navigator. You can also drag it to \uicontrol {3D Editor}. + \endlist + + \image studio-3d-particles-sprite-template.png + + \section1 Performance Considerations + + The particles are designed to be usable on a variety of hardware on + desktops, as well as mobile and embedded devices. However, in addition + to rendering the maximum amount of particle elements on the screen, + extensibility to different use-cases, rendering quality, integration + with the other UI elements, are also important. + + Currently, the rendering runs on GPU, while the particle system logic + runs on CPU. However, the \e {stateless particle system} enables you + to move the system logic onto GPU if that seems beneficial. The initial + measurements indicate that the system is quite well balanced between + CPU and GPU. The stateless system also enables animating particles by + using a \l{Timeline}{timeline}. The model particles use instanced rendering + to boost the performance. Therefore, OpenGL ES 2.0 isn't sufficient to make + rendering performant, and at least OpenGL ES 3.0, Vulkan, or some other + modern backend is required. + + To get a more concrete view on the actual performance, the video below shows + a particles Testbed application running on four different Android devices. + These devices and their chipsets and GPUs could be considered to be + lower-end to mid-range, confirming that the particles can perform well also + on affordable hardware. + + \youtube 9MqUCP6JLCQ + \section1 Particle System Tutorials \list diff --git a/scripts/deployqtHelper_mac.sh b/scripts/deployqtHelper_mac.sh index e8f46032a4c..e85c48ef203 100755 --- a/scripts/deployqtHelper_mac.sh +++ b/scripts/deployqtHelper_mac.sh @@ -67,41 +67,6 @@ if [ -d "$assetimporterSrcDir" ]; then fi fi -# collect tls plugins to have ssl download feature available -tlsDestDir="$app_path/Contents/PlugIns/tls" -tlssrcDir="$plugin_src/tls" -if [ -d "$tlssrcDir" ]; then - if [ ! -d "$tlsDestDir" ]; then - echo "- Copying tls plugins to have ssl download feature available" - mkdir -p "$tlsDestDir" - find "$tlssrcDir" -iname "*.dylib" -maxdepth 1 -exec cp {} "$tlsDestDir"/ \; - fi -fi - -# workaround for Qt 6.2: -# - QTBUG-94796 macdeployqt does not deploy /Contents/PlugIns/sqldrivers/libqsqlite.dylib anymore -sqldriversDestDir="$app_path/Contents/PlugIns/sqldrivers" -sqldriversSrcDir="$plugin_src/sqldrivers" -if [ -d "$sqldriversSrcDir" ]; then - if [ ! -d "$sqldriversDestDir" ]; then - echo "- Copying sqlitedriver plugin" - mkdir -p "$sqldriversDestDir" - cp "$sqldriversSrcDir/libqsqlite.dylib" "$sqldriversDestDir/libqsqlite.dylib" - fi -fi - -# workaround for Qt 6.2: -# - QTBUG-94796 macdeployqt does not deploy /Contents/PlugIns/imageformats/libqsvg.dylib anymore -imageformatsDestDir="$app_path/Contents/PlugIns/imageformats" -imageformatsSrcDir="$plugin_src/imageformats" -if [ -d "$imageformatsSrcDir" ]; then - if [ ! -d "$imageformatsDestDir" ]; then - echo "- Copying sqlitedriver plugin" - mkdir -p "$imageformatsDestDir" - cp "$imageformatsSrcDir/libqsvg.dylib" "$imageformatsDestDir/libqsvg.dylib" - fi -fi - # copy Qt Quick 2 imports imports2Dir="$app_path/Contents/Imports/qtquick2" if [ -d "$quick2_src" ]; then @@ -209,3 +174,19 @@ if [ ! -d "$app_path/Contents/Frameworks/QtCore.framework" ]; then "$clangbackendArgument" || exit 1 fi + +# clean up after macdeployqt +# it deploys some plugins (and libs for these) that interfere with what we want +echo "Cleaning up after macdeployqt..." +toRemove=(\ + "Contents/PlugIns/tls/libqopensslbackend.dylib" \ + "Contents/PlugIns/sqldrivers/libqsqlpsql.dylib" \ + "Contents/PlugIns/sqldrivers/libqsqlodbc.dylib" \ + "Contents/Frameworks/libpq.*dylib" \ + "Contents/Frameworks/libssl.*dylib" \ + "Contents/Frameworks/libcrypto.*dylib" \ +) +for f in "${toRemove[@]}"; do + echo "- removing \"$app_path/$f\"" + rm "$app_path"/$f 2> /dev/null; done +exit 0 diff --git a/share/qtcreator/qml/qmlpuppet/commands/createscenecommand.h b/share/qtcreator/qml/qmlpuppet/commands/createscenecommand.h index 5ebe7638f74..1eb6ba5018d 100644 --- a/share/qtcreator/qml/qmlpuppet/commands/createscenecommand.h +++ b/share/qtcreator/qml/qmlpuppet/commands/createscenecommand.h @@ -25,9 +25,10 @@ #pragma once -#include +#include #include #include +#include #include "instancecontainer.h" #include "reparentcontainer.h" @@ -55,6 +56,8 @@ public: const QUrl &resourceUrl, const QHash &edit3dToolStates, const QString &language, + QSize captureImageMinimumSize, + QSize captureImageMaximumSize, qint32 stateInstanceId) : instances(instanceContainer) , reparentInstances(reparentContainer) @@ -68,6 +71,8 @@ public: , resourceUrl(resourceUrl) , edit3dToolStates(edit3dToolStates) , language(language) + , captureImageMinimumSize(captureImageMinimumSize) + , captureImageMaximumSize(captureImageMaximumSize) , stateInstanceId{stateInstanceId} {} @@ -86,6 +91,8 @@ public: out << command.edit3dToolStates; out << command.language; out << command.stateInstanceId; + out << command.captureImageMinimumSize; + out << command.captureImageMaximumSize; return out; } @@ -105,6 +112,8 @@ public: in >> command.edit3dToolStates; in >> command.language; in >> command.stateInstanceId; + in >> command.captureImageMinimumSize; + in >> command.captureImageMaximumSize; return in; } @@ -122,6 +131,8 @@ public: QUrl resourceUrl; QHash edit3dToolStates; QString language; + QSize captureImageMinimumSize; + QSize captureImageMaximumSize; qint32 stateInstanceId = 0; }; diff --git a/share/qtcreator/qml/qmlpuppet/qml2puppet/instances/qt5captureimagenodeinstanceserver.cpp b/share/qtcreator/qml/qmlpuppet/qml2puppet/instances/qt5captureimagenodeinstanceserver.cpp index cff435bdd49..dccfb19d573 100644 --- a/share/qtcreator/qml/qmlpuppet/qml2puppet/instances/qt5captureimagenodeinstanceserver.cpp +++ b/share/qtcreator/qml/qmlpuppet/qml2puppet/instances/qt5captureimagenodeinstanceserver.cpp @@ -38,16 +38,22 @@ namespace QmlDesigner { namespace { -QImage renderImage(ServerNodeInstance rootNodeInstance) +QImage renderImage(ServerNodeInstance rootNodeInstance, QSize minimumSize, QSize maximumSize) { rootNodeInstance.updateDirtyNodeRecursive(); QSize previewImageSize = rootNodeInstance.boundingRect().size().toSize(); - if (previewImageSize.isEmpty()) - previewImageSize = {150, 150}; + if (previewImageSize.isEmpty()) { + previewImageSize = minimumSize; + } else if (previewImageSize.width() < minimumSize.width() + || previewImageSize.height() < minimumSize.height()) { + previewImageSize.scale(minimumSize, Qt::KeepAspectRatio); + } - if (previewImageSize.width() > 150 || previewImageSize.height() > 150) - previewImageSize.scale({150, 150}, Qt::KeepAspectRatio); + if (previewImageSize.width() > maximumSize.width() + || previewImageSize.height() > maximumSize.height()) { + previewImageSize.scale(maximumSize, Qt::KeepAspectRatio); + } QImage previewImage = rootNodeInstance.renderPreviewImage(previewImageSize); @@ -73,7 +79,7 @@ void Qt5CaptureImageNodeInstanceServer::collectItemChangesAndSendChangeCommands( DesignerSupport::polishItems(quickWindow()); - QImage image = renderImage(rooNodeInstance); + QImage image = renderImage(rooNodeInstance, m_minimumSize, m_maximumSize); nodeInstanceClient()->capturedData(CapturedDataCommand{std::move(image)}); @@ -82,4 +88,12 @@ void Qt5CaptureImageNodeInstanceServer::collectItemChangesAndSendChangeCommands( } } +void QmlDesigner::Qt5CaptureImageNodeInstanceServer::createScene(const CreateSceneCommand &command) +{ + m_minimumSize = command.captureImageMinimumSize; + m_maximumSize = command.captureImageMaximumSize; + + Qt5PreviewNodeInstanceServer::createScene(command); +} + } // namespace diff --git a/share/qtcreator/qml/qmlpuppet/qml2puppet/instances/qt5captureimagenodeinstanceserver.h b/share/qtcreator/qml/qmlpuppet/qml2puppet/instances/qt5captureimagenodeinstanceserver.h index 7c26e47a879..2642294849c 100644 --- a/share/qtcreator/qml/qmlpuppet/qml2puppet/instances/qt5captureimagenodeinstanceserver.h +++ b/share/qtcreator/qml/qmlpuppet/qml2puppet/instances/qt5captureimagenodeinstanceserver.h @@ -36,10 +36,14 @@ public: : Qt5PreviewNodeInstanceServer(nodeInstanceClient) {} + void createScene(const CreateSceneCommand &command) override; + protected: void collectItemChangesAndSendChangeCommands() override; private: + QSize m_minimumSize; + QSize m_maximumSize; }; } // namespace QmlDesigner diff --git a/share/qtcreator/qmldesigner/statesEditorQmlSources/StatesDelegate.qml b/share/qtcreator/qmldesigner/statesEditorQmlSources/StatesDelegate.qml index 7d0aa14cfd6..005ec1f400c 100644 --- a/share/qtcreator/qmldesigner/statesEditorQmlSources/StatesDelegate.qml +++ b/share/qtcreator/qmldesigner/statesEditorQmlSources/StatesDelegate.qml @@ -285,6 +285,7 @@ Rectangle { anchors.fill: parent source: delegateStateImageSource fillMode: Image.PreserveAspectFit + mipmap: true } } } diff --git a/share/qtcreator/qmldesigner/studio_templates/projects/common/app.qmlproject.tpl b/share/qtcreator/qmldesigner/studio_templates/projects/common/app.qmlproject.tpl index 47f83a1b428..dd494846d7a 100644 --- a/share/qtcreator/qmldesigner/studio_templates/projects/common/app.qmlproject.tpl +++ b/share/qtcreator/qmldesigner/studio_templates/projects/common/app.qmlproject.tpl @@ -95,6 +95,15 @@ Project { @if %{IsQt6Project} /* If any modules the project imports require widgets (e.g. QtCharts), widgetApp must be true */ widgetApp: true + + /* args: Specifies command line arguments for qsb tool to generate shaders. + files: Specifies target files for qsb tool. If path is included, it must be relative to this file. + Wildcard '*' can be used in the file name part of the path. + e.g. files: [ "content/shaders/*.vert", "*.frag" ] */ + ShaderTool { + args: "-s --glsl \\\"100 es,120,150\\\" --hlsl 50 --msl 12" + files: [ "content/shaders/*" ] + } @endif multilanguageSupport: true diff --git a/src/libs/cplusplus/NamePrettyPrinter.cpp b/src/libs/cplusplus/NamePrettyPrinter.cpp index 89d427fafa5..67d2a002c93 100644 --- a/src/libs/cplusplus/NamePrettyPrinter.cpp +++ b/src/libs/cplusplus/NamePrettyPrinter.cpp @@ -84,10 +84,13 @@ void NamePrettyPrinter::visit(const TemplateNameId *name) TemplateArgument templArg = name->templateArgumentAt(index); QString arg; - if (templArg.type().isValid()) - arg = overview()->prettyType(templArg.type()); - else if (const NumericLiteral *num = templArg.numericLiteral()) + if (templArg.type().isValid()) { + Overview o = *_overview; + o.showReturnTypes = true; + arg = o.prettyType(templArg.type()); + } else if (const NumericLiteral *num = templArg.numericLiteral()) { arg = QString::fromLatin1(num->chars(), num->size()); + } if (arg.isEmpty()) _name += QString::fromLatin1("_Tp%1").arg(index + 1); diff --git a/src/plugins/android/androidrunnerworker.cpp b/src/plugins/android/androidrunnerworker.cpp index 43a03472840..944129aee09 100644 --- a/src/plugins/android/androidrunnerworker.cpp +++ b/src/plugins/android/androidrunnerworker.cpp @@ -290,8 +290,8 @@ AndroidRunnerWorker::AndroidRunnerWorker(RunWorker *runner, const QString &packa for (const QString &shellCmd : commands) m_beforeStartAdbCommands.append(QString("shell %1").arg(shellCmd)); } - const auto data = runner->recordedData(Constants::ANDROID_PRESTARTSHELLCMDLIST).toStringList(); - for (const QString &shellCmd : data) + const auto preStartCmdList = runner->recordedData(Constants::ANDROID_PRESTARTSHELLCMDLIST); + for (const QString &shellCmd : preStartCmdList.toStringList()) m_beforeStartAdbCommands.append(QString("shell %1").arg(shellCmd)); if (auto aspect = runControl->aspect(Constants::ANDROID_POSTFINISHSHELLCMDLIST)) { @@ -300,8 +300,8 @@ AndroidRunnerWorker::AndroidRunnerWorker(RunWorker *runner, const QString &packa for (const QString &shellCmd : commands) m_afterFinishAdbCommands.append(QString("shell %1").arg(shellCmd)); } - const auto data2 = runner->recordedData(Constants::ANDROID_POSTFINISHSHELLCMDLIST).toStringList(); - for (const QString &shellCmd : data) + const auto postFinishCmdList = runner->recordedData(Constants::ANDROID_POSTFINISHSHELLCMDLIST); + for (const QString &shellCmd : postFinishCmdList.toStringList()) m_afterFinishAdbCommands.append(QString("shell %1").arg(shellCmd)); m_debugServerPath = debugServer(m_useLldb, target).toString(); diff --git a/src/plugins/clangcodemodel/clangdclient.cpp b/src/plugins/clangcodemodel/clangdclient.cpp index b3e61789bf5..8bc48d66a88 100644 --- a/src/plugins/clangcodemodel/clangdclient.cpp +++ b/src/plugins/clangcodemodel/clangdclient.cpp @@ -677,6 +677,7 @@ public: void update(); void finalize(); + void resetData(bool resetFollowSymbolData); private: IAssistProposal *perform(const AssistInterface *) override @@ -689,8 +690,6 @@ private: return createProposal(false); } - void resetData(); - IAssistProposal *immediateProposalImpl() const; IAssistProposal *createProposal(bool final) const; CppEditor::VirtualFunctionProposalItem *createEntry(const QString &name, @@ -726,7 +725,7 @@ public: { closeTempDocuments(); if (virtualFuncAssistProcessor) - virtualFuncAssistProcessor->cancel(); + virtualFuncAssistProcessor->resetData(false); for (const MessageId &id : qAsConst(pendingSymbolInfoRequests)) q->cancelRequest(id); for (const MessageId &id : qAsConst(pendingGotoImplRequests)) @@ -2715,6 +2714,7 @@ private: const AstNode &m_ast; const QTextDocument * const m_doc; const QString &m_docContent; + AstNode::FileStatus m_currentFileStatus = AstNode::FileStatus::Unknown; }; // clangd reports also the #ifs, #elses and #endifs around the disabled code as disabled, @@ -2839,11 +2839,16 @@ static void semanticHighlighter(QFutureInterface &future, return true; if (it->kind() == "Call") { - // In class templates, member calls can result in "Call" nodes rather than - // "CXXMemberCall". We try to detect this by checking for a certain kind of - // child node. + // The first child is e.g. a called lambda or an object on which + // the call happens, and should not be highlighted as an output argument. + // If the call is not fully resolved (as in templates), we don't + // know whether the argument is passed as const or not. + if (it->arcanaContains("dependent type")) + return false; const QList children = it->children().value_or(QList()); - return children.isEmpty() || children.first().kind() != "CXXDependentScopeMember"; + return children.isEmpty() + || (children.first().range() != (it - 1)->range() + && children.first().kind() != "UnresolvedLookup"); } // The token should get marked for e.g. lambdas, but not for assignment operators, @@ -2863,7 +2868,7 @@ static void semanticHighlighter(QFutureInterface &future, // The callable is never displayed as an output parameter. // TODO: A good argument can be made to display objects on which a non-const // operator or function is called as output parameters. - if (children.at(1).range() == range) + if (children.at(1).range().contains(range)) return false; QList firstChildTree{children.first()}; @@ -2883,6 +2888,8 @@ static void semanticHighlighter(QFutureInterface &future, if (it->kind() == "Lambda") return false; + if (it->kind() == "BinaryOperator") + return false; if (it->hasConstType()) return false; @@ -3110,7 +3117,7 @@ void ClangdClient::Private::handleSemanticTokens(TextDocument *doc, void ClangdClient::VirtualFunctionAssistProcessor::cancel() { - resetData(); + resetData(true); } void ClangdClient::VirtualFunctionAssistProcessor::update() @@ -3132,15 +3139,16 @@ void ClangdClient::VirtualFunctionAssistProcessor::finalize() } else { setAsyncProposalAvailable(proposal); } - resetData(); + resetData(true); } -void ClangdClient::VirtualFunctionAssistProcessor::resetData() +void ClangdClient::VirtualFunctionAssistProcessor::resetData(bool resetFollowSymbolData) { if (!m_data) return; m_data->followSymbolData->virtualFuncAssistProcessor = nullptr; - m_data->followSymbolData.reset(); + if (resetFollowSymbolData) + m_data->followSymbolData.reset(); m_data = nullptr; } @@ -3503,6 +3511,8 @@ QIcon ClangdCompletionItem::icon() const case SpecialQtType::None: break; } + if (item().kind().value_or(CompletionItemKind::Text) == CompletionItemKind::Property) + return Utils::CodeModelIcon::iconForType(Utils::CodeModelIcon::VarPublicStatic); return LanguageClientCompletionItem::icon(); } @@ -4080,7 +4090,13 @@ void ExtraHighlightingResultsCollector::visitNode(const AstNode &node) { if (m_future.isCanceled()) return; - switch (node.fileStatus(m_filePath)) { + const AstNode::FileStatus prevFileStatus = m_currentFileStatus; + m_currentFileStatus = node.fileStatus(m_filePath); + if (m_currentFileStatus == AstNode::FileStatus::Unknown + && prevFileStatus != AstNode::FileStatus::Ours) { + m_currentFileStatus = prevFileStatus; + } + switch (m_currentFileStatus) { case AstNode::FileStatus::Ours: case AstNode::FileStatus::Unknown: collectFromNode(node); @@ -4095,6 +4111,7 @@ void ExtraHighlightingResultsCollector::visitNode(const AstNode &node) break; } } + m_currentFileStatus = prevFileStatus; } bool ClangdClient::FollowSymbolData::defLinkIsAmbiguous() const diff --git a/src/plugins/clangcodemodel/test/clangautomationutils.h b/src/plugins/clangcodemodel/test/clangautomationutils.h index dcb62eda768..7b9a5bb262e 100644 --- a/src/plugins/clangcodemodel/test/clangautomationutils.h +++ b/src/plugins/clangcodemodel/test/clangautomationutils.h @@ -27,8 +27,9 @@ #include -#include +#include #include +#include namespace TextEditor { class BaseTextEditor; } diff --git a/src/plugins/clangcodemodel/test/clangdtests.cpp b/src/plugins/clangcodemodel/test/clangdtests.cpp index 67339c77293..c0b0805ca32 100644 --- a/src/plugins/clangcodemodel/test/clangdtests.cpp +++ b/src/plugins/clangcodemodel/test/clangdtests.cpp @@ -1321,6 +1321,14 @@ void ClangdTestHighlighting::test_data() << QList{C_FIELD} << 0; QTest::newRow("member call on dependent (3)") << 999 << 9 << 999 << 12 << QList{C_LOCAL} << 0; + QTest::newRow("member access via operator->") << 1009 << 7 << 1009 << 21 + << QList{C_FIELD} << 0; + QTest::newRow("lambda call in member") << 1023 << 9 << 1023 << 15 + << QList{C_LOCAL} << 0; + QTest::newRow("call on inherited member") << 1024 << 9 << 1024 << 12 + << QList{C_FIELD} << 0; + QTest::newRow("pass inherited member by value") << 1038 << 21 << 1038 << 26 + << QList{C_FIELD} << 0; } void ClangdTestHighlighting::test() @@ -1423,12 +1431,12 @@ void ClangdTestHighlighting::test() void ClangdTestHighlighting::testIfdefedOutBlocks() { QCOMPARE(m_ifdefedOutBlocks.size(), 3); - QCOMPARE(m_ifdefedOutBlocks.at(0).first(), 12033); - QCOMPARE(m_ifdefedOutBlocks.at(0).last(), 12050); - QCOMPARE(m_ifdefedOutBlocks.at(1).first(), 13351); - QCOMPARE(m_ifdefedOutBlocks.at(1).last(), 13364); - QCOMPARE(m_ifdefedOutBlocks.at(2).first(), 13390); - QCOMPARE(m_ifdefedOutBlocks.at(2).last(), 13402); + QCOMPARE(m_ifdefedOutBlocks.at(0).first(), 12056); + QCOMPARE(m_ifdefedOutBlocks.at(0).last(), 12073); + QCOMPARE(m_ifdefedOutBlocks.at(1).first(), 13374); + QCOMPARE(m_ifdefedOutBlocks.at(1).last(), 13387); + QCOMPARE(m_ifdefedOutBlocks.at(2).first(), 13413); + QCOMPARE(m_ifdefedOutBlocks.at(2).last(), 13425); } diff --git a/src/plugins/clangcodemodel/test/data/highlighting/highlighting.cpp b/src/plugins/clangcodemodel/test/data/highlighting/highlighting.cpp index 1d4bcce7f8e..cd4ecb46cec 100644 --- a/src/plugins/clangcodemodel/test/data/highlighting/highlighting.cpp +++ b/src/plugins/clangcodemodel/test/data/highlighting/highlighting.cpp @@ -5,7 +5,7 @@ auto *rawVariable = R"(Vari auto Character = 'c'; namespace std { -template class vector {}; +template class vector { public: void clear(); }; template class pair {}; } @@ -999,3 +999,44 @@ public: ptr->bar(); } }; + +namespace std { template struct optional { T* operator->(); }; } +struct structWithData { int value; }; +struct structWithOptional { std::optional opt_my_struct1; }; + +void foo(structWithOptional & s) +{ + s.opt_my_struct1->value = 5; +} + +class BaseWithMember +{ +protected: + std::vector vec; +}; + +template class Derived : public BaseWithMember +{ + void foo() + { + auto lambda = [&] {}; + lambda(); + vec.clear(); + } +}; + +static bool testVal(int val); +class BaseWithMember2 +{ +protected: + int value; +}; +template class Derived2 : public BaseWithMember2 +{ + bool foo() + { + if (testVal(value)) + return true; + return false; + } +}; diff --git a/src/plugins/cmakeprojectmanager/cmakebuildconfiguration.cpp b/src/plugins/cmakeprojectmanager/cmakebuildconfiguration.cpp index f48628b81ac..476513456de 100644 --- a/src/plugins/cmakeprojectmanager/cmakebuildconfiguration.cpp +++ b/src/plugins/cmakeprojectmanager/cmakebuildconfiguration.cpp @@ -259,7 +259,7 @@ CMakeBuildSettingsWidget::CMakeBuildSettingsWidget(CMakeBuildConfiguration *bc) m_configView->setUniformRowHeights(true); m_configView->setSortingEnabled(true); m_configView->sortByColumn(0, Qt::AscendingOrder); - auto stretcher = new HeaderViewStretcher(m_configView->header(), 0); + (void) new HeaderViewStretcher(m_configView->header(), 0); m_configView->setSelectionMode(QAbstractItemView::ExtendedSelection); m_configView->setSelectionBehavior(QAbstractItemView::SelectItems); m_configView->setAlternatingRowColors(true); @@ -373,18 +373,15 @@ CMakeBuildSettingsWidget::CMakeBuildSettingsWidget(CMakeBuildConfiguration *bc) m_configModel->setConfiguration(m_buildConfiguration->configurationFromCMake()); m_configModel->setInitialParametersConfiguration( m_buildConfiguration->initialCMakeConfiguration()); - m_configView->expandAll(); } - connect(bc->buildSystem(), &BuildSystem::parsingFinished, this, [this, stretcher] { + connect(bc->buildSystem(), &BuildSystem::parsingFinished, this, [this] { m_configModel->setConfiguration(m_buildConfiguration->configurationFromCMake()); m_configModel->setInitialParametersConfiguration( m_buildConfiguration->initialCMakeConfiguration()); m_buildConfiguration->filterConfigArgumentsFromAdditionalCMakeArguments(); updateFromKit(); - m_configView->expandAll(); m_configView->setEnabled(true); - stretcher->stretch(); updateButtonState(); m_showProgressTimer.stop(); m_progressIndicator->hide(); @@ -402,10 +399,6 @@ CMakeBuildSettingsWidget::CMakeBuildSettingsWidget(CMakeBuildConfiguration *bc) m_progressIndicator->hide(); updateConfigurationStateSelection(); }); - connect(m_configTextFilterModel, &QAbstractItemModel::modelReset, this, [this, stretcher]() { - m_configView->expandAll(); - stretcher->stretch(); - }); connect(m_configModel, &QAbstractItemModel::dataChanged, this, &CMakeBuildSettingsWidget::updateButtonState); diff --git a/src/plugins/coreplugin/find/searchresulttreeitemdelegate.cpp b/src/plugins/coreplugin/find/searchresulttreeitemdelegate.cpp index 9351387c5b8..7bd37a555bc 100644 --- a/src/plugins/coreplugin/find/searchresulttreeitemdelegate.cpp +++ b/src/plugins/coreplugin/find/searchresulttreeitemdelegate.cpp @@ -216,8 +216,8 @@ void SearchResultTreeItemDelegate::drawText(QPainter *painter, const QString textBefore = text.left(searchTermStart).replace(QLatin1Char('\t'), m_tabString); const QString textHighlight = text.mid(searchTermStart, searchTermLength).replace(QLatin1Char('\t'), m_tabString); const QString textAfter = text.mid(searchTermStart + searchTermLength).replace(QLatin1Char('\t'), m_tabString); - int searchTermStartPixels = painter->fontMetrics().horizontalAdvance(textBefore); - int searchTermLengthPixels = painter->fontMetrics().horizontalAdvance(textHighlight); + int searchTermStartPixels = option.fontMetrics.horizontalAdvance(textBefore); + int searchTermLengthPixels = option.fontMetrics.horizontalAdvance(textHighlight); // rects QRect beforeHighlightRect(rect); diff --git a/src/plugins/cppeditor/cppquickfix_test.cpp b/src/plugins/cppeditor/cppquickfix_test.cpp index a2ed383c12f..ce17fbdf9b9 100644 --- a/src/plugins/cppeditor/cppquickfix_test.cpp +++ b/src/plugins/cppeditor/cppquickfix_test.cpp @@ -3273,6 +3273,58 @@ void QuickfixTest::testGenerateGetterSetterOnlySetter() QuickFixOperationTest(testDocuments, &factory, ProjectExplorer::HeaderPaths(), 0); } +void QuickfixTest::testGenerateGetterSetterAnonymousClass() +{ + QList testDocuments; + QByteArray original; + QByteArray expected; + QuickFixSettings s; + s->setterInCppFileFrom = 1; + s->setterParameterNameTemplate = "value"; + + // Header File + original = R"( + class { + int @m_foo; + } bar; +)"; + expected = R"( + class { + int m_foo; + + public: + int foo() const + { + return m_foo; + } + void setFoo(int value) + { + if (m_foo == value) + return; + m_foo = value; + emit fooChanged(); + } + void resetFoo() + { + setFoo({}); // TODO: Adapt to use your actual default defaultValue + } + + signals: + void fooChanged(); + + private: + Q_PROPERTY(int foo READ foo WRITE setFoo RESET resetFoo NOTIFY fooChanged) + } bar; +)"; + testDocuments << CppTestDocument::create("file.h", original, expected); + + // Source File + testDocuments << CppTestDocument::create("file.cpp", {}, {}); + + GenerateGetterSetter factory; + QuickFixOperationTest(testDocuments, &factory, ProjectExplorer::HeaderPaths(), 4); +} + void QuickfixTest::testGenerateGetterSetterInlineInHeaderFile() { QList testDocuments; @@ -3362,6 +3414,43 @@ void QuickfixTest::testGenerateGetterSetterOnlySetterHeaderFileWithIncludeGuard( QuickFixOperationTest(testDocuments, &factory, ProjectExplorer::HeaderPaths(), 0); } +void QuickfixTest::testGenerateGetterFunctionAsTemplateArg() +{ + QList testDocuments; + const QByteArray original = R"( +template class TS {}; +template class TS {}; + +class S2 { + TS @member; +}; +)"; + const QByteArray expected = R"( +template class TS {}; +template class TS {}; + +class S2 { + TS member; + +public: + const TS &getMember() const + { + return member; + } +}; +)"; + + testDocuments << CppTestDocument::create("file.h", original, expected); + + QuickFixSettings s; + s->getterOutsideClassFrom = 0; + s->getterInCppFileFrom = 0; + s->getterNameTemplate = "get"; + + GenerateGetterSetter factory; + QuickFixOperationTest(testDocuments, &factory, ProjectExplorer::HeaderPaths(), 1); +} + class CppCodeStyleSettingsChanger { public: CppCodeStyleSettingsChanger(const CppCodeStyleSettings &settings); diff --git a/src/plugins/cppeditor/cppquickfix_test.h b/src/plugins/cppeditor/cppquickfix_test.h index 3995234374b..a4d256ba684 100644 --- a/src/plugins/cppeditor/cppquickfix_test.h +++ b/src/plugins/cppeditor/cppquickfix_test.h @@ -113,8 +113,10 @@ private slots: void testGenerateGetterSetterGeneralTests(); void testGenerateGetterSetterOnlyGetter(); void testGenerateGetterSetterOnlySetter(); + void testGenerateGetterSetterAnonymousClass(); void testGenerateGetterSetterInlineInHeaderFile(); void testGenerateGetterSetterOnlySetterHeaderFileWithIncludeGuard(); + void testGenerateGetterFunctionAsTemplateArg(); void testGenerateGettersSetters_data(); void testGenerateGettersSetters(); diff --git a/src/plugins/cppeditor/cppquickfixes.cpp b/src/plugins/cppeditor/cppquickfixes.cpp index 6ed9736f3e1..6c98b2dd10a 100644 --- a/src/plugins/cppeditor/cppquickfixes.cpp +++ b/src/plugins/cppeditor/cppquickfixes.cpp @@ -3907,7 +3907,12 @@ void GetterSetterRefactoringHelper::performGeneration(ExistingGetterSetterData d else getterInClassDeclaration += QLatin1String(" const"); getterInClassDeclaration.prepend(m_settings->getterAttributes + QLatin1Char(' ')); + auto getterLocation = m_settings->determineGetterLocation(1); + // if we have an anonymous class we must add code inside the class + if (data.clazz->name()->isAnonymousNameId()) + getterLocation = CppQuickFixSettings::FunctionLocation::InsideClass; + if (getterLocation == CppQuickFixSettings::FunctionLocation::InsideClass) { getterInClassDeclaration += QLatin1String("\n{\nreturn ") + returnExpression + QLatin1String(";\n}\n"); @@ -4026,6 +4031,10 @@ void GetterSetterRefactoringHelper::performGeneration(ExistingGetterSetterData d body += "}"; auto setterLocation = m_settings->determineSetterLocation(body.count('\n') - 2); + // if we have an anonymous class we must add code inside the class + if (data.clazz->name()->isAnonymousNameId()) + setterLocation = CppQuickFixSettings::FunctionLocation::InsideClass; + if (setterLocation == CppQuickFixSettings::FunctionLocation::CppFile && !hasSourceFile()) setterLocation = CppQuickFixSettings::FunctionLocation::OutsideClass; @@ -4100,6 +4109,10 @@ void GetterSetterRefactoringHelper::performGeneration(ExistingGetterSetterData d body.replace(QRegularExpression("\\b" + parameterName + "\\b"), "defaultValue"); // body.count('\n') - 2 : do not count the 2 at start auto resetLocation = m_settings->determineSetterLocation(body.count('\n') - 2); + // if we have an anonymous class we must add code inside the class + if (data.clazz->name()->isAnonymousNameId()) + resetLocation = CppQuickFixSettings::FunctionLocation::InsideClass; + if (resetLocation == CppQuickFixSettings::FunctionLocation::CppFile && !hasSourceFile()) resetLocation = CppQuickFixSettings::FunctionLocation::OutsideClass; diff --git a/src/plugins/debugger/debuggeritem.cpp b/src/plugins/debugger/debuggeritem.cpp index bdc46cb71e1..973a436cc6c 100644 --- a/src/plugins/debugger/debuggeritem.cpp +++ b/src/plugins/debugger/debuggeritem.cpp @@ -290,6 +290,13 @@ bool DebuggerItem::addAndroidLldbPythonEnv(const Utils::FilePath &lldbCmd, Utils if (pythonBinDir.exists()) { env.set("PYTHONHOME", pythonDir.toUserOutput()); env.prependOrSetPath(pythonBinDir); + + if (HostOsInfo::isAnyUnixHost()) { + const FilePath pythonLibDir = pythonDir.pathAppended("lib"); + if (pythonLibDir.exists()) + env.prependOrSet("LD_LIBRARY_PATH", pythonLibDir.toString()); + } + return true; } } diff --git a/src/plugins/genericprojectmanager/genericproject.cpp b/src/plugins/genericprojectmanager/genericproject.cpp index f9f5a7cd949..c6c4d0411b2 100644 --- a/src/plugins/genericprojectmanager/genericproject.cpp +++ b/src/plugins/genericprojectmanager/genericproject.cpp @@ -435,17 +435,22 @@ void GenericBuildSystem::parse(RefreshOptions options) if (options & Configuration) { m_rawProjectIncludePaths = readLines(m_includesFileName); - Utils::FilePaths normalPaths; - Utils::FilePaths frameworkPaths; + QStringList normalPaths; + QStringList frameworkPaths; const auto baseDir = Utils::FilePath::fromString(m_includesFileName).parentDir(); for (const QString &rawPath : qAsConst(m_rawProjectIncludePaths)) { if (rawPath.startsWith("-F")) - frameworkPaths << baseDir.resolvePath(rawPath.mid(2)); + frameworkPaths << rawPath.mid(2); else - normalPaths << baseDir.resolvePath(rawPath); + normalPaths << rawPath; } - m_projectIncludePaths = toUserHeaderPaths(normalPaths); - m_projectIncludePaths << toFrameworkHeaderPaths(frameworkPaths); + const auto expandedPaths = [this](const QStringList &paths) { + return Utils::transform(processEntries(paths), [](const auto &pair) { + return pair.first; + }); + }; + m_projectIncludePaths = toUserHeaderPaths(expandedPaths(normalPaths)); + m_projectIncludePaths << toFrameworkHeaderPaths(expandedPaths(frameworkPaths)); m_cxxflags = readFlags(m_cxxflagsFileName); m_cflags = readFlags(m_cflagsFileName); } diff --git a/src/plugins/qmldesigner/components/assetslibrary/assetslibraryview.cpp b/src/plugins/qmldesigner/components/assetslibrary/assetslibraryview.cpp index 3bb1f3cb21a..d222f2cacc8 100644 --- a/src/plugins/qmldesigner/components/assetslibrary/assetslibraryview.cpp +++ b/src/plugins/qmldesigner/components/assetslibrary/assetslibraryview.cpp @@ -50,31 +50,17 @@ namespace QmlDesigner { -namespace { -ProjectExplorer::Target *activeTarget(ProjectExplorer::Project *project) -{ - if (project) - return project->activeTarget(); - - return {}; -} -} // namespace - -class ImageCacheData +class AssetsLibraryView::ImageCacheData { public: Sqlite::Database database{Utils::PathString{ - Core::ICore::cacheResourcePath("imagecache-v2.db").toString()}, + Core::ICore::cacheResourcePath("fontimagecache.db").toString()}, Sqlite::JournalMode::Wal, Sqlite::LockingMode::Normal}; ImageCacheStorage storage{database}; - ImageCacheConnectionManager connectionManager; - ImageCacheCollector collector{connectionManager}; ImageCacheFontCollector fontCollector; - ImageCacheGenerator generator{collector, storage}; ImageCacheGenerator fontGenerator{fontCollector, storage}; TimeStampProvider timeStampProvider; - AsynchronousImageCache cache{storage, generator, timeStampProvider}; AsynchronousImageCache asynchronousFontImageCache{storage, fontGenerator, timeStampProvider}; SynchronousImageCache synchronousFontImageCache{storage, timeStampProvider, fontCollector}; }; @@ -94,9 +80,8 @@ bool AssetsLibraryView::hasWidget() const WidgetInfo AssetsLibraryView::widgetInfo() { if (m_widget.isNull()) { - m_widget = new AssetsLibraryWidget{imageCacheData()->cache, - imageCacheData()->asynchronousFontImageCache, - imageCacheData()->synchronousFontImageCache}; + m_widget = new AssetsLibraryWidget{imageCacheData()->asynchronousFontImageCache, + imageCacheData()->synchronousFontImageCache}; } return createWidgetInfo(m_widget.data(), "Assets", WidgetInfo::LeftPane, 0, tr("Assets")); @@ -128,49 +113,18 @@ void AssetsLibraryView::setResourcePath(const QString &resourcePath) m_lastResourcePath = resourcePath; if (m_widget.isNull()) { - m_widget = new AssetsLibraryWidget{m_imageCacheData->cache, - m_imageCacheData->asynchronousFontImageCache, - m_imageCacheData->synchronousFontImageCache}; + m_widget = new AssetsLibraryWidget{imageCacheData()->asynchronousFontImageCache, + imageCacheData()->synchronousFontImageCache}; } m_widget->setResourcePath(resourcePath); } -ImageCacheData *AssetsLibraryView::imageCacheData() +AssetsLibraryView::ImageCacheData *AssetsLibraryView::imageCacheData() { - std::call_once(imageCacheFlag, [this]() { - m_imageCacheData = std::make_unique(); - auto setTargetInImageCache = - [imageCacheData = m_imageCacheData.get()](ProjectExplorer::Target *target) { - if (target == imageCacheData->collector.target()) - return; - - if (target) - imageCacheData->cache.clean(); - - imageCacheData->collector.setTarget(target); - }; - - if (auto project = ProjectExplorer::SessionManager::startupProject(); project) { - m_imageCacheData->collector.setTarget(project->activeTarget()); - connect(project, - &ProjectExplorer::Project::activeTargetChanged, - this, - setTargetInImageCache); - } - connect(ProjectExplorer::SessionManager::instance(), - &ProjectExplorer::SessionManager::startupProjectChanged, - this, - [=](ProjectExplorer::Project *project) { - setTargetInImageCache(activeTarget(project)); - }); - }); + std::call_once(imageCacheFlag, + [this]() { m_imageCacheData = std::make_unique(); }); return m_imageCacheData.get(); } -AsynchronousImageCache &AssetsLibraryView::imageCache() -{ - return imageCacheData()->cache; -} - } // namespace QmlDesigner diff --git a/src/plugins/qmldesigner/components/assetslibrary/assetslibraryview.h b/src/plugins/qmldesigner/components/assetslibrary/assetslibraryview.h index ae623a183b3..743d0bb30e3 100644 --- a/src/plugins/qmldesigner/components/assetslibrary/assetslibraryview.h +++ b/src/plugins/qmldesigner/components/assetslibrary/assetslibraryview.h @@ -34,7 +34,6 @@ namespace QmlDesigner { class AssetsLibraryWidget; -class ImageCacheData; class AsynchronousImageCache; class AssetsLibraryView : public AbstractView @@ -54,9 +53,8 @@ public: void setResourcePath(const QString &resourcePath); - AsynchronousImageCache &imageCache(); - private: + class ImageCacheData; ImageCacheData *imageCacheData(); std::once_flag imageCacheFlag; diff --git a/src/plugins/qmldesigner/components/assetslibrary/assetslibrarywidget.cpp b/src/plugins/qmldesigner/components/assetslibrary/assetslibrarywidget.cpp index 1b6c4f64fb9..162fadcf78c 100644 --- a/src/plugins/qmldesigner/components/assetslibrary/assetslibrarywidget.cpp +++ b/src/plugins/qmldesigner/components/assetslibrary/assetslibrarywidget.cpp @@ -110,16 +110,14 @@ bool AssetsLibraryWidget::eventFilter(QObject *obj, QEvent *event) return QObject::eventFilter(obj, event); } -AssetsLibraryWidget::AssetsLibraryWidget(AsynchronousImageCache &imageCache, - AsynchronousImageCache &asynchronousFontImageCache, - SynchronousImageCache &synchronousFontImageCache) +AssetsLibraryWidget::AssetsLibraryWidget(AsynchronousImageCache &asynchronousFontImageCache, + SynchronousImageCache &synchronousFontImageCache) : m_itemIconSize(24, 24) , m_fontImageCache(synchronousFontImageCache) , m_assetsIconProvider(new AssetsLibraryIconProvider(synchronousFontImageCache)) , m_fileSystemWatcher(new Utils::FileSystemWatcher(this)) , m_assetsModel(new AssetsLibraryModel(m_fileSystemWatcher, this)) , m_assetsWidget(new QQuickWidget(this)) - , m_imageCache{imageCache} { m_assetCompressionTimer.setInterval(200); m_assetCompressionTimer.setSingleShot(true); diff --git a/src/plugins/qmldesigner/components/assetslibrary/assetslibrarywidget.h b/src/plugins/qmldesigner/components/assetslibrary/assetslibrarywidget.h index abf91c3a8ce..3128b823b3c 100644 --- a/src/plugins/qmldesigner/components/assetslibrary/assetslibrarywidget.h +++ b/src/plugins/qmldesigner/components/assetslibrary/assetslibrarywidget.h @@ -60,8 +60,7 @@ class AssetsLibraryWidget : public QFrame Q_OBJECT public: - AssetsLibraryWidget(AsynchronousImageCache &imageCache, - AsynchronousImageCache &asynchronousFontImageCache, + AssetsLibraryWidget(AsynchronousImageCache &asynchronousFontImageCache, SynchronousImageCache &synchronousFontImageCache); ~AssetsLibraryWidget(); @@ -110,7 +109,6 @@ private: std::unique_ptr m_fontPreviewTooltipBackend; QShortcut *m_qmlSourceUpdateShortcut = nullptr; - AsynchronousImageCache &m_imageCache; QPointer m_model; QStringList m_assetsToDrag; bool m_updateRetry = false; diff --git a/src/plugins/qmldesigner/components/componentcore/hdrimage.cpp b/src/plugins/qmldesigner/components/componentcore/hdrimage.cpp index ed2eb7af20d..1dd0ceaa1c4 100644 --- a/src/plugins/qmldesigner/components/componentcore/hdrimage.cpp +++ b/src/plugins/qmldesigner/components/componentcore/hdrimage.cpp @@ -41,29 +41,6 @@ typedef unsigned char RGBE[4]; #define B 2 #define E 3 -struct M8E8 -{ - quint8 m; - quint8 e; - M8E8() : m(0), e(0){ - } - M8E8(const float val) { - float l2 = 1.f + std::floor(log2f(val)); - float mm = val / powf(2.f, l2); - m = quint8(mm * 255.f); - e = quint8(l2 + 128); - } - M8E8(const float val, quint8 exp) { - if (val <= 0) { - m = e = 0; - return; - } - float mm = val / powf(2.f, exp - 128); - m = quint8(mm * 255.f); - e = exp; - } -}; - QByteArray fileToByteArray(QString const &filename) { QFile file(filename); @@ -147,17 +124,18 @@ void decodeScanlineToImageData(RGBE *scanline, int width, void *outBuf, quint32 rgbaF32[R] = convertComponent(scanline[i][E], scanline[i][R]); rgbaF32[G] = convertComponent(scanline[i][E], scanline[i][G]); rgbaF32[B] = convertComponent(scanline[i][E], scanline[i][B]); - rgbaF32[3] = 1.0f; + rgbaF32[E] = 1.0f; - float max = qMax(rgbaF32[R], qMax(rgbaF32[G], rgbaF32[B])); - M8E8 ex(max); - M8E8 a(rgbaF32[R], ex.e); - M8E8 b(rgbaF32[G], ex.e); - M8E8 c(rgbaF32[B], ex.e); quint8 *dst = target + i * 4; - dst[0] = c.m; - dst[1] = b.m; - dst[2] = a.m; + + auto getColor = [](float src) -> quint8 { + const float srcColor = (src > 1.0f) ? 1.0f : src; + return quint8(srcColor * 255.0f); + }; + + dst[0] = getColor(rgbaF32[B]); + dst[1] = getColor(rgbaF32[G]); + dst[2] = getColor(rgbaF32[R]); dst[3] = 255; } } diff --git a/src/plugins/qmldesigner/components/componentcore/modelnodecontextmenu_helper.cpp b/src/plugins/qmldesigner/components/componentcore/modelnodecontextmenu_helper.cpp index b7a68890b82..975a59d478d 100644 --- a/src/plugins/qmldesigner/components/componentcore/modelnodecontextmenu_helper.cpp +++ b/src/plugins/qmldesigner/components/componentcore/modelnodecontextmenu_helper.cpp @@ -33,6 +33,8 @@ #include #include +#include + namespace QmlDesigner { static inline bool itemsHaveSameParent(const QList &siblingList) @@ -94,10 +96,24 @@ bool selectionHasSameParent(const SelectionContext &selectionState) return !selectionState.selectedModelNodes().isEmpty() && itemsHaveSameParent(selectionState.selectedModelNodes()); } +bool fileComponentExists(const ModelNode &modelNode) +{ + if (!modelNode.metaInfo().isFileComponent()) + return true; + + const QString fileName = modelNode.metaInfo().componentFileName(); + + if (fileName.contains("qml/QtQuick")) + return false; + + return QFile::exists(fileName); +} + bool selectionIsComponent(const SelectionContext &selectionState) { return selectionState.currentSingleSelectedNode().isValid() - && selectionState.currentSingleSelectedNode().isComponent(); + && selectionState.currentSingleSelectedNode().isComponent() + && fileComponentExists(selectionState.currentSingleSelectedNode()); } bool selectionIsImported3DAsset(const SelectionContext &selectionState) diff --git a/src/plugins/qmldesigner/components/itemlibrary/itemlibraryassetimportdialog.cpp b/src/plugins/qmldesigner/components/itemlibrary/itemlibraryassetimportdialog.cpp index 6c5005546e8..0fe286a9982 100644 --- a/src/plugins/qmldesigner/components/itemlibrary/itemlibraryassetimportdialog.cpp +++ b/src/plugins/qmldesigner/components/itemlibrary/itemlibraryassetimportdialog.cpp @@ -55,6 +55,7 @@ #include #include #include +#include namespace QmlDesigner { @@ -73,7 +74,11 @@ static void addFormattedMessage(Utils::OutputFormatter *formatter, const QString formatter->plainTextEdit()->verticalScrollBar()->maximum()); } -static const int rowHeight = 26; +static const int rowHeight = 28; +static const int checkBoxColWidth = 18; +static const int labelMinWidth = 130; +static const int controlMinWidth = 65; +static const int columnSpacing = 16; } @@ -120,6 +125,12 @@ ItemLibraryAssetImportDialog::ItemLibraryAssetImportDialog( ui->buttonBox->button(QDialogButtonBox::Close)->setDefault(true); + ui->advancedSettingsButton->setStyleSheet( + "QPushButton#advancedSettingsButton {background-color: transparent}"); + ui->advancedSettingsButton->setStyleSheet( + QString("QPushButton { border: none; color :%1 }").arg( + Utils::creatorTheme()->color(Utils::Theme::QmlDesigner_HighlightColor).name())); + QStringList importPaths; auto doc = QmlDesignerPlugin::instance()->currentDesignDocument(); if (doc) { @@ -196,6 +207,13 @@ ItemLibraryAssetImportDialog::ItemLibraryAssetImportDialog( ++optIndex; } + // Resize lists in loop for Qt5 compatibility + for (int i = 0; i < optIndex; ++i) { + m_simpleData.contentWidgets.append({}); + m_advancedData.contentWidgets.append({}); + m_labelToControlWidgetMaps.append(QHash()); + } + // Create tab for each supported extension group that also has files included in the import QMap tabMap; // QMap used for alphabetical order for (const auto &file : qAsConst(m_quick3DFiles)) { @@ -214,22 +232,21 @@ ItemLibraryAssetImportDialog::ItemLibraryAssetImportDialog( auto tabIt = tabMap.constBegin(); while (tabIt != tabMap.constEnd()) { createTab(tabIt.key(), tabIt.value(), groups[tabIt.value()]); - ++tabIt; - } - // Pad all tabs to same height - for (int i = 0; i < ui->tabWidget->count(); ++i) { - auto optionsArea = qobject_cast(ui->tabWidget->widget(i)); - if (optionsArea && optionsArea->widget()) { - auto grid = qobject_cast(optionsArea->widget()->layout()); + auto padGrid = [](QWidget *widget, int optionRows) { + auto grid = qobject_cast(widget->layout()); if (grid) { int rows = grid->rowCount(); - for (int j = rows; j < m_optionsRows; ++j) { - grid->addWidget(new QWidget(optionsArea->widget()), j, 0); - grid->setRowMinimumHeight(j, rowHeight); + for (int i = rows; i addWidget(new QWidget(widget), i, 0); + grid->setRowMinimumHeight(i, rowHeight); } } - } + }; + padGrid(m_simpleData.contentWidgets[tabIt.value()], m_simpleData.optionsRows); + padGrid(m_advancedData.contentWidgets[tabIt.value()], m_advancedData.optionsRows); + + ++tabIt; } ui->tabWidget->setCurrentIndex(0); @@ -257,8 +274,10 @@ ItemLibraryAssetImportDialog::ItemLibraryAssetImportDialog( for (const auto &file : qAsConst(m_quick3DFiles)) addInfo(file); - QTimer::singleShot(0, [this]() { - ui->tabWidget->setMaximumHeight(m_optionsHeight + ui->tabWidget->tabBar()->height() + 10); + connect(ui->advancedSettingsButton, &QPushButton::clicked, + this, &ItemLibraryAssetImportDialog::toggleAdvanced); + + QTimer::singleShot(0, this, [this]() { updateUi(); }); } @@ -390,28 +409,45 @@ void ItemLibraryAssetImportDialog::updateImport(const ModelNode &updateNode, void ItemLibraryAssetImportDialog::createTab(const QString &tabLabel, int optionsIndex, const QJsonObject &groups) { - const int checkBoxColWidth = 18; - const int labelMinWidth = 130; - const int controlMinWidth = 65; - const int columnSpacing = 16; - int rowIndex[2] = {0, 0}; - - QJsonObject &options = m_importOptions[optionsIndex]; - - // First index has ungrouped widgets, rest are groups - // First item in each real group is group label - QVector>> widgets; - QHash groupIndexMap; - QHash> optionToWidgetsMap; - QHash conditionMap; - QHash conditionalWidgetMap; - QHash optionToGroupMap; - auto optionsArea = new QScrollArea(ui->tabWidget); optionsArea->setHorizontalScrollBarPolicy(Qt::ScrollBarAlwaysOff); auto optionsAreaContents = new QWidget(optionsArea); + m_simpleData.contentWidgets[optionsIndex] = new QWidget(optionsAreaContents); + m_advancedData.contentWidgets[optionsIndex] = new QWidget(optionsAreaContents); - auto layout = new QGridLayout(optionsAreaContents); + // Advanced widgets need to be set up first, as simple widgets will connect to those + QGridLayout *advancedLayout = createOptionsGrid(m_advancedData.contentWidgets[optionsIndex], true, + optionsIndex, groups); + QGridLayout *simpleLayout = createOptionsGrid(m_simpleData.contentWidgets[optionsIndex], false, + optionsIndex, groups); + + m_advancedData.contentWidgets[optionsIndex]->setLayout(advancedLayout); + m_simpleData.contentWidgets[optionsIndex]->setLayout(simpleLayout); + + m_advancedData.contentWidgets[optionsIndex]->setVisible(false); + + auto layout = new QVBoxLayout(optionsAreaContents); + layout->addWidget(m_simpleData.contentWidgets[optionsIndex]); + layout->addWidget(m_advancedData.contentWidgets[optionsIndex]); + + optionsAreaContents->setContentsMargins(0, 0, 0, 0); + optionsAreaContents->setLayout(layout); + optionsAreaContents->setMinimumWidth( + (checkBoxColWidth + labelMinWidth + controlMinWidth) * 2 + columnSpacing); + optionsAreaContents->setObjectName("optionsAreaContents"); // For stylesheet + + optionsArea->setWidget(optionsAreaContents); + optionsArea->setStyleSheet("QScrollArea {background-color: transparent}"); + optionsAreaContents->setStyleSheet( + "QWidget#optionsAreaContents {background-color: transparent}"); + + ui->tabWidget->addTab(optionsArea, tr("%1 options").arg(tabLabel)); +} + +QGridLayout *ItemLibraryAssetImportDialog::createOptionsGrid( + QWidget *contentWidget, bool advanced, int optionsIndex, const QJsonObject &groups) +{ + auto layout = new QGridLayout(); layout->setColumnMinimumWidth(0, checkBoxColWidth); layout->setColumnMinimumWidth(1, labelMinWidth); layout->setColumnMinimumWidth(2, controlMinWidth); @@ -427,14 +463,29 @@ void ItemLibraryAssetImportDialog::createTab(const QString &tabLabel, int option layout->setColumnStretch(5, 4); layout->setColumnStretch(6, 2); + // First index has ungrouped widgets, rest are groups + // First item in each real group is group label + QVector>> widgets; + QHash groupIndexMap; + QHash> optionToWidgetsMap; + QHash conditionMap; + QHash conditionalWidgetMap; + QHash optionToGroupMap; + + int rowIndex[2] = {0, 0}; + widgets.append(QVector>()); - for (const auto &group : groups) { + const QStringList &groupIds = groups.keys(); + for (const QString &groupId : groupIds) { + if (!advanced && !isSimpleGroup(groupId)) + continue; + const auto &group = groups.value(groupId); const QString name = group.toObject().value("name").toString(); const QJsonArray items = group.toObject().value("items").toArray(); for (const auto &item : items) optionToGroupMap.insert(item.toString(), name); - auto groupLabel = new QLabel(name, optionsAreaContents); + auto groupLabel = new QLabel(name, contentWidget); QFont labelFont = groupLabel->font(); labelFont.setBold(true); groupLabel->setFont(labelFont); @@ -442,8 +493,11 @@ void ItemLibraryAssetImportDialog::createTab(const QString &tabLabel, int option groupIndexMap.insert(name, widgets.size() - 1); } + QJsonObject &options = m_importOptions[optionsIndex]; const auto optKeys = options.keys(); for (const auto &optKey : optKeys) { + if (!advanced && !isSimpleOption(optKey)) + continue; QJsonObject optObj = options.value(optKey).toObject(); const QString optName = optObj.value("name").toString(); const QString optDesc = optObj.value("description").toString(); @@ -452,24 +506,41 @@ void ItemLibraryAssetImportDialog::createTab(const QString &tabLabel, int option QJsonValue optValue = optObj.value("value"); QJsonArray conditions = optObj.value("conditions").toArray(); - auto *optLabel = new QLabel(optionsAreaContents); + auto *optLabel = new QLabel(contentWidget); optLabel->setText(optName); optLabel->setToolTip(optDesc); QWidget *optControl = nullptr; if (optType == "Boolean") { - auto *optCheck = new QCheckBox(optionsAreaContents); + auto *optCheck = new QCheckBox(contentWidget); optCheck->setChecked(optValue.toBool()); optControl = optCheck; - QObject::connect(optCheck, &QCheckBox::toggled, - [this, optCheck, optKey, optionsIndex]() { - QJsonObject optObj = m_importOptions[optionsIndex].value(optKey).toObject(); - QJsonValue value(optCheck->isChecked()); - optObj.insert("value", value); - m_importOptions[optionsIndex].insert(optKey, optObj); - }); + if (advanced) { + QObject::connect(optCheck, &QCheckBox::toggled, this, + [this, optCheck, optKey, optionsIndex]() { + QJsonObject optObj = m_importOptions[optionsIndex].value(optKey).toObject(); + QJsonValue value(optCheck->isChecked()); + optObj.insert("value", value); + m_importOptions[optionsIndex].insert(optKey, optObj); + }); + } else { + // Simple options also exist in advanced, so don't connect simple controls directly + // to import options. Connect them instead to corresponding advanced controls. + auto *advCheck = qobject_cast( + m_labelToControlWidgetMaps[optionsIndex].value(optKey)); + if (advCheck) { + QObject::connect(optCheck, &QCheckBox::toggled, this, [optCheck, advCheck]() { + if (advCheck->isChecked() != optCheck->isChecked()) + advCheck->setChecked(optCheck->isChecked()); + }); + QObject::connect(advCheck, &QCheckBox::toggled, this, [optCheck, advCheck]() { + if (advCheck->isChecked() != optCheck->isChecked()) + optCheck->setChecked(advCheck->isChecked()); + }); + } + } } else if (optType == "Real") { - auto *optSpin = new QDoubleSpinBox(optionsAreaContents); + auto *optSpin = new QDoubleSpinBox(contentWidget); double min = -999999999.; double max = 999999999.; double step = 1.; @@ -493,13 +564,31 @@ void ItemLibraryAssetImportDialog::createTab(const QString &tabLabel, int option optSpin->setSingleStep(step); optSpin->setMinimumWidth(controlMinWidth); optControl = optSpin; - QObject::connect(optSpin, QOverload::of(&QDoubleSpinBox::valueChanged), - [this, optSpin, optKey, optionsIndex]() { - QJsonObject optObj = m_importOptions[optionsIndex].value(optKey).toObject(); - QJsonValue value(optSpin->value()); - optObj.insert("value", value); - m_importOptions[optionsIndex].insert(optKey, optObj); - }); + if (advanced) { + QObject::connect(optSpin, QOverload::of(&QDoubleSpinBox::valueChanged), this, + [this, optSpin, optKey, optionsIndex]() { + QJsonObject optObj = m_importOptions[optionsIndex].value(optKey).toObject(); + QJsonValue value(optSpin->value()); + optObj.insert("value", value); + m_importOptions[optionsIndex].insert(optKey, optObj); + }); + } else { + auto *advSpin = qobject_cast( + m_labelToControlWidgetMaps[optionsIndex].value(optKey)); + if (advSpin) { + // Connect corresponding advanced control + QObject::connect(optSpin, QOverload::of(&QDoubleSpinBox::valueChanged), + this, [optSpin, advSpin]() { + if (advSpin->value() != optSpin->value()) + advSpin->setValue(optSpin->value()); + }); + QObject::connect(advSpin, QOverload::of(&QDoubleSpinBox::valueChanged), + this, [optSpin, advSpin]() { + if (advSpin->value() != optSpin->value()) + optSpin->setValue(advSpin->value()); + }); + } + } } else { qWarning() << __FUNCTION__ << "Unsupported option type:" << optType; continue; @@ -515,6 +604,8 @@ void ItemLibraryAssetImportDialog::createTab(const QString &tabLabel, int option else widgets[0].append({optLabel, optControl}); optionToWidgetsMap.insert(optKey, {optLabel, optControl}); + if (advanced) + m_labelToControlWidgetMaps[optionsIndex].insert(optKey, optControl); } // Handle conditions @@ -562,7 +653,7 @@ void ItemLibraryAssetImportDialog::createTab(const QString &tabLabel, int option else conditionalWidgetMap.insert(optCb, conControl); QObject::connect( - optCb, &QCheckBox::toggled, + optCb, &QCheckBox::toggled, optCb, [optCb, conLabel, conControl, mode, enableConditionally]() { enableConditionally(optCb, conLabel, conControl, mode); }); @@ -586,7 +677,7 @@ void ItemLibraryAssetImportDialog::createTab(const QString &tabLabel, int option enableConditionally(optSpin, conLabel, conControl, mode); QObject::connect( optSpin, QOverload::of(&QDoubleSpinBox::valueChanged), - [optSpin, conLabel, conControl, mode, enableConditionally]() { + optSpin, [optSpin, conLabel, conControl, mode, enableConditionally]() { enableConditionally(optSpin, conLabel, conControl, mode); }); } @@ -646,8 +737,13 @@ void ItemLibraryAssetImportDialog::createTab(const QString &tabLabel, int option }; if (widgets.size() == 1 && widgets[0].isEmpty()) { - layout->addWidget(new QLabel(tr("No options available for this type."), - optionsAreaContents), 0, 0, 2, 7, Qt::AlignCenter); + if (advanced) { + layout->addWidget(new QLabel(tr("No options available for this type."), + contentWidget), 0, 0, 2, 7, Qt::AlignCenter); + } else { + layout->addWidget(new QLabel(tr("No simple options available for this type."), + contentWidget), 0, 0, 2, 7, Qt::AlignCenter); + } incrementColIndex(0); incrementColIndex(0); } @@ -663,7 +759,7 @@ void ItemLibraryAssetImportDialog::createTab(const QString &tabLabel, int option for (int j = 1; j < groupWidgets.size(); ++j) insertOptionToLayout(col, groupWidgets[j]); // Add a separator line after each group - auto *separator = new QFrame(optionsAreaContents); + auto *separator = new QFrame(contentWidget); separator->setMaximumHeight(1); separator->setFrameShape(QFrame::HLine); separator->setFrameShadow(QFrame::Sunken); @@ -681,38 +777,56 @@ void ItemLibraryAssetImportDialog::createTab(const QString &tabLabel, int option } int optionRows = qMax(rowIndex[0], rowIndex[1]); - m_optionsRows = qMax(m_optionsRows, optionRows); - m_optionsHeight = qMax(rowHeight * optionRows + 16, m_optionsHeight); - layout->setContentsMargins(8, 8, 8, 8); - optionsAreaContents->setContentsMargins(0, 0, 0, 0); - optionsAreaContents->setLayout(layout); - optionsAreaContents->setMinimumWidth( - (checkBoxColWidth + labelMinWidth + controlMinWidth) * 2 + columnSpacing); - optionsAreaContents->setObjectName("optionsAreaContents"); // For stylesheet + int &globalOptionRows = advanced ? m_advancedData.optionsRows : m_simpleData.optionsRows; + int &globalOptionsHeight = advanced ? m_advancedData.optionsHeight : m_simpleData.optionsHeight; + globalOptionRows = qMax(globalOptionRows, optionRows); + globalOptionsHeight = qMax(rowHeight * optionRows + 20, globalOptionsHeight); + layout->setContentsMargins(8, 8, 8, 0); - optionsArea->setWidget(optionsAreaContents); - optionsArea->setStyleSheet("QScrollArea {background-color: transparent}"); - optionsAreaContents->setStyleSheet( - "QWidget#optionsAreaContents {background-color: transparent}"); - - ui->tabWidget->addTab(optionsArea, tr("%1 options").arg(tabLabel)); + return layout; } void ItemLibraryAssetImportDialog::updateUi() { auto optionsArea = qobject_cast(ui->tabWidget->currentWidget()); if (optionsArea) { + int optionsHeight = m_advancedMode ? m_advancedData.optionsHeight + : m_simpleData.optionsHeight; + + ui->tabWidget->setMaximumHeight(optionsHeight + ui->tabWidget->tabBar()->height() + 10); auto optionsAreaContents = optionsArea->widget(); int scrollBarWidth = optionsArea->verticalScrollBar()->isVisible() ? optionsArea->verticalScrollBar()->width() : 0; - optionsAreaContents->resize(optionsArea->contentsRect().width() - - scrollBarWidth - 8, m_optionsHeight); + + optionsAreaContents->resize(optionsArea->contentsRect().width() - scrollBarWidth - 8, + optionsHeight); + + resize(width(), m_dialogHeight); } } +bool ItemLibraryAssetImportDialog::isSimpleGroup(const QString &id) +{ + static QStringList simpleGroups { + "globalScale" + }; + + return simpleGroups.contains(id); +} + +bool ItemLibraryAssetImportDialog::isSimpleOption(const QString &id) +{ + static QStringList simpleOptions { + "globalScale", + "globalScaleValue" + }; + + return simpleOptions.contains(id); +} + void ItemLibraryAssetImportDialog::resizeEvent(QResizeEvent *event) { - Q_UNUSED(event) + m_dialogHeight = event->size().height(); updateUi(); } @@ -801,4 +915,27 @@ void ItemLibraryAssetImportDialog::onClose() } } +void ItemLibraryAssetImportDialog::toggleAdvanced() +{ + m_advancedMode = !m_advancedMode; + for (const auto &widget : qAsConst(m_simpleData.contentWidgets)) { + if (widget) + widget->setVisible(!m_advancedMode); + } + for (const auto &widget : qAsConst(m_advancedData.contentWidgets)) { + if (widget) + widget->setVisible(m_advancedMode); + } + + if (m_advancedMode) + ui->advancedSettingsButton->setText(tr("Hide Advanced Options")); + else + ui->advancedSettingsButton->setText(tr("Show All Options")); + + int diff = qMin(300, m_advancedData.optionsHeight - m_simpleData.optionsHeight); + m_dialogHeight = qMax(350, m_dialogHeight + (m_advancedMode ? diff : -diff)); + + updateUi(); +} + } diff --git a/src/plugins/qmldesigner/components/itemlibrary/itemlibraryassetimportdialog.h b/src/plugins/qmldesigner/components/itemlibrary/itemlibraryassetimportdialog.h index 1b2c4c4ebda..1e3f7daad99 100644 --- a/src/plugins/qmldesigner/components/itemlibrary/itemlibraryassetimportdialog.h +++ b/src/plugins/qmldesigner/components/itemlibrary/itemlibraryassetimportdialog.h @@ -31,6 +31,10 @@ #include #include +QT_BEGIN_NAMESPACE +class QGridLayout; +QT_END_NAMESPACE + namespace Utils { class OutputFormatter; } @@ -76,21 +80,37 @@ private: void onImportNearlyFinished(); void onImportFinished(); void onClose(); + void toggleAdvanced(); void createTab(const QString &tabLabel, int optionsIndex, const QJsonObject &groups); + QGridLayout *createOptionsGrid(QWidget *contentWidget, bool advanced, int optionsIndex, + const QJsonObject &groups); void updateUi(); + bool isSimpleGroup(const QString &id); + bool isSimpleOption(const QString &id); + Ui::ItemLibraryAssetImportDialog *ui = nullptr; Utils::OutputFormatter *m_outputFormatter = nullptr; + struct OptionsData + { + int optionsRows = 0; + int optionsHeight = 0; + QList contentWidgets; // Tab content widgets + }; + QStringList m_quick3DFiles; QString m_quick3DImportPath; ItemLibraryAssetImporter m_importer; QVector m_importOptions; QHash m_extToImportOptionsMap; - int m_optionsHeight = 0; - int m_optionsRows = 0; QSet m_preselectedFilesForOverwrite; bool m_closeOnFinish = true; + QList> m_labelToControlWidgetMaps; + OptionsData m_simpleData; + OptionsData m_advancedData; + bool m_advancedMode = false; + int m_dialogHeight = 350; }; } diff --git a/src/plugins/qmldesigner/components/itemlibrary/itemlibraryassetimportdialog.ui b/src/plugins/qmldesigner/components/itemlibrary/itemlibraryassetimportdialog.ui index e6b02863574..34a6ef66ccb 100644 --- a/src/plugins/qmldesigner/components/itemlibrary/itemlibraryassetimportdialog.ui +++ b/src/plugins/qmldesigner/components/itemlibrary/itemlibraryassetimportdialog.ui @@ -6,68 +6,118 @@ 0 0 - 631 - 750 + 630 + 350 Asset Import - - - - - - 0 - 2 - - - - 0 - - - false - - - - Import Options - - - - - - - - - 0 - 1 - - - - true - - - - - - - - - - - - - - 0 - - - - - - - QDialogButtonBox::Close|QDialogButtonBox::Ok - - + + + + + + + + 0 + 2 + + + + 0 + + + false + + + + Import Options + + + + + + + + + + Qt::Horizontal + + + + 80 + 20 + + + + + + + + Show All Settings + + + + + + + Qt::Horizontal + + + QSizePolicy::Fixed + + + + 8 + 20 + + + + + + + + + + + 0 + 1 + + + + true + + + + + + + + 0 + 0 + + + + + + + + + + + 0 + + + + + + + QDialogButtonBox::Close|QDialogButtonBox::Ok + + + + diff --git a/src/plugins/qmldesigner/components/itemlibrary/itemlibraryview.cpp b/src/plugins/qmldesigner/components/itemlibrary/itemlibraryview.cpp index 321607fc7bf..8af21584e3b 100644 --- a/src/plugins/qmldesigner/components/itemlibrary/itemlibraryview.cpp +++ b/src/plugins/qmldesigner/components/itemlibrary/itemlibraryview.cpp @@ -62,7 +62,7 @@ ProjectExplorer::Target *activeTarget(ProjectExplorer::Project *project) } } // namespace -class ImageCacheData +class ItemLibraryView::ImageCacheData { public: Sqlite::Database database{Utils::PathString{ @@ -71,7 +71,7 @@ public: Sqlite::LockingMode::Normal}; ImageCacheStorage storage{database}; ImageCacheConnectionManager connectionManager; - ImageCacheCollector collector{connectionManager}; + ImageCacheCollector collector{connectionManager, QSize{300, 300}, QSize{600, 600}}; ImageCacheFontCollector fontCollector; ImageCacheGenerator generator{collector, storage}; ImageCacheGenerator fontGenerator{fontCollector, storage}; @@ -177,7 +177,7 @@ void ItemLibraryView::usedImportsChanged(const QList &usedImports) m_widget->updateUsedImports(usedImports); } -ImageCacheData *ItemLibraryView::imageCacheData() +ItemLibraryView::ImageCacheData *ItemLibraryView::imageCacheData() { std::call_once(imageCacheFlag, [this]() { m_imageCacheData = std::make_unique(); diff --git a/src/plugins/qmldesigner/components/itemlibrary/itemlibraryview.h b/src/plugins/qmldesigner/components/itemlibrary/itemlibraryview.h index 8d85383d5dc..b7b91eaf3f8 100644 --- a/src/plugins/qmldesigner/components/itemlibrary/itemlibraryview.h +++ b/src/plugins/qmldesigner/components/itemlibrary/itemlibraryview.h @@ -34,7 +34,6 @@ namespace QmlDesigner { class ItemLibraryWidget; -class ImageCacheData; class AsynchronousImageCache; class ItemLibraryView : public AbstractView @@ -65,6 +64,7 @@ protected: void updateImports(); private: + class ImageCacheData; ImageCacheData *imageCacheData(); std::once_flag imageCacheFlag; diff --git a/src/plugins/qmldesigner/components/itemlibrary/itemlibrarywidget.cpp b/src/plugins/qmldesigner/components/itemlibrary/itemlibrarywidget.cpp index 516dfa233b1..5f18557d88b 100644 --- a/src/plugins/qmldesigner/components/itemlibrary/itemlibrarywidget.cpp +++ b/src/plugins/qmldesigner/components/itemlibrary/itemlibrarywidget.cpp @@ -273,8 +273,10 @@ void ItemLibraryWidget::handleAddImport(int index) Import import = m_addModuleModel->getImportAt(index); if (import.isLibraryImport() && (import.url().startsWith("QtQuick") || import.url().startsWith("SimulinkConnector"))) { + QString importStr = import.toImportString(); + importStr.replace(' ', '-'); QmlDesignerPlugin::emitUsageStatistics(Constants::EVENT_IMPORT_ADDED - + import.toImportString()); + + importStr); } QList imports; diff --git a/src/plugins/qmldesigner/components/navigator/navigatorsearchwidget.cpp b/src/plugins/qmldesigner/components/navigator/navigatorsearchwidget.cpp index 77199017c14..2a4454b4882 100644 --- a/src/plugins/qmldesigner/components/navigator/navigatorsearchwidget.cpp +++ b/src/plugins/qmldesigner/components/navigator/navigatorsearchwidget.cpp @@ -28,30 +28,87 @@ #include #include +#include #include #include -#include +#include +#include namespace QmlDesigner { +LineEdit::LineEdit(QWidget *parent) + : QLineEdit(parent) +{ + clearButton = new QToolButton(this); + + const QString fontName = "qtds_propertyIconFont.ttf"; + const int searchIconSize = 16; + const int clearIconSize = 12; + const QColor iconColor(QmlDesigner::Theme::getColor(QmlDesigner::Theme::DSiconColor)); + + const QIcon searchIcon + = Utils::StyleHelper::getIconFromIconFont(fontName, + QmlDesigner::Theme::getIconUnicode( + QmlDesigner::Theme::Icon::search), + searchIconSize, + searchIconSize, + iconColor); + + const QIcon clearIcon + = Utils::StyleHelper::getIconFromIconFont(fontName, + QmlDesigner::Theme::getIconUnicode( + QmlDesigner::Theme::Icon::closeCross), + clearIconSize, + clearIconSize, + iconColor); + + addAction(searchIcon, QLineEdit::LeadingPosition); + + clearButton->setIcon(clearIcon); + clearButton->setIconSize(QSize(clearIconSize, clearIconSize)); + clearButton->setCursor(Qt::ArrowCursor); + clearButton->hide(); + clearButton->setStyleSheet(Theme::replaceCssColors( + QString("QToolButton { border: none; padding: 0px; }" + "QToolButton:hover { background: creatorTheme.DScontrolBackgroundHover; }"))); + + setClearButtonEnabled(false); + + connect(clearButton, &QToolButton::clicked, this, &QLineEdit::clear); + connect(this, &QLineEdit::textChanged, this, &LineEdit::updateClearButton); + + int frameWidth = style()->pixelMetric(QStyle::PM_DefaultFrameWidth); + setStyleSheet(QString("QLineEdit { padding-right: %1px; } ") + .arg(clearButton->sizeHint().width() + frameWidth + 8)); + + setFixedHeight(29); +} + +void LineEdit::resizeEvent(QResizeEvent *) +{ + QSize hint = clearButton->sizeHint(); + int frameWidth = style()->pixelMetric(QStyle::PM_DefaultFrameWidth); + + clearButton->move(rect().right() - frameWidth - hint.width() - 3, + (rect().bottom() + 1 - hint.height()) / 2); +} + +void LineEdit::updateClearButton(const QString& text) +{ + clearButton->setVisible(!text.isEmpty()); +} + NavigatorSearchWidget::NavigatorSearchWidget(QWidget *parent) : QWidget(parent) { auto layout = new QBoxLayout(QBoxLayout::LeftToRight); + layout->setSpacing(0); + layout->setContentsMargins(5, 5, 5, 3); setLayout(layout); - const QString fontName = "qtds_propertyIconFont.ttf"; - const int iconSize = 15; - const QColor iconColor(QmlDesigner::Theme::getColor(QmlDesigner::Theme::IconsBaseColor)); - const QIcon searchIcon = Utils::StyleHelper::getIconFromIconFont( - fontName, QmlDesigner::Theme::getIconUnicode(QmlDesigner::Theme::Icon::search), - iconSize, iconSize, iconColor); - - m_textField = new QLineEdit; - m_textField->setPlaceholderText(tr("Filter")); + m_textField = new LineEdit; + m_textField->setPlaceholderText(tr("Search")); m_textField->setFrame(false); - m_textField->setClearButtonEnabled(true); - m_textField->addAction(searchIcon, QLineEdit::LeadingPosition); connect(m_textField, &QLineEdit::textChanged, this, &NavigatorSearchWidget::textChanged); diff --git a/src/plugins/qmldesigner/components/navigator/navigatorsearchwidget.h b/src/plugins/qmldesigner/components/navigator/navigatorsearchwidget.h index d1c4e0269b6..f96c3202ace 100644 --- a/src/plugins/qmldesigner/components/navigator/navigatorsearchwidget.h +++ b/src/plugins/qmldesigner/components/navigator/navigatorsearchwidget.h @@ -27,8 +27,27 @@ #include +class QToolButton; + namespace QmlDesigner { +class LineEdit : public QLineEdit +{ + Q_OBJECT + +public: + LineEdit(QWidget *parent = nullptr); + +protected: + void resizeEvent(QResizeEvent *); + +private slots: + void updateClearButton(const QString &text); + +private: + QToolButton *clearButton; +}; + class NavigatorSearchWidget : public QWidget { Q_OBJECT @@ -42,8 +61,7 @@ signals: void textChanged(const QString &text); private: - - QLineEdit *m_textField; + LineEdit *m_textField; }; } //QmlDesigner diff --git a/src/plugins/qmldesigner/components/navigator/navigatorwidget.cpp b/src/plugins/qmldesigner/components/navigator/navigatorwidget.cpp index 4929c75bd91..5899ec9dd7b 100644 --- a/src/plugins/qmldesigner/components/navigator/navigatorwidget.cpp +++ b/src/plugins/qmldesigner/components/navigator/navigatorwidget.cpp @@ -69,6 +69,10 @@ NavigatorWidget::NavigatorWidget(NavigatorView *view) toolBar->setParent(this); layout->addWidget(toolBar); + m_searchWidget = new NavigatorSearchWidget(); + connect(m_searchWidget, &NavigatorSearchWidget::textChanged, this, &NavigatorWidget::textFilterChanged); + layout->addWidget(m_searchWidget); + layout->addWidget(m_treeView); setLayout(layout); @@ -161,10 +165,6 @@ QToolBar *NavigatorWidget::createToolBar() for (auto toolButton : buttons) toolBar->addWidget(toolButton); - m_searchWidget = new NavigatorSearchWidget(); - connect(m_searchWidget, &NavigatorSearchWidget::textChanged, this, &NavigatorWidget::textFilterChanged); - toolBar->addWidget(m_searchWidget); - return toolBar; } diff --git a/src/plugins/qmldesigner/components/previewtooltip/previewimagetooltip.cpp b/src/plugins/qmldesigner/components/previewtooltip/previewimagetooltip.cpp index 3b70d79fd11..1e418642f2f 100644 --- a/src/plugins/qmldesigner/components/previewtooltip/previewimagetooltip.cpp +++ b/src/plugins/qmldesigner/components/previewtooltip/previewimagetooltip.cpp @@ -68,7 +68,8 @@ void PreviewImageTooltip::setImage(const QImage &image, bool scale) if (scale) { m_ui->imageLabel->setPixmap(pm.scaled(m_ui->imageLabel->width(), m_ui->imageLabel->height(), - Qt::KeepAspectRatio)); + Qt::KeepAspectRatio, + Qt::SmoothTransformation)); } else { m_ui->imageLabel->setPixmap(pm); } diff --git a/src/plugins/qmldesigner/designercore/imagecache/imagecachecollector.cpp b/src/plugins/qmldesigner/designercore/imagecache/imagecachecollector.cpp index f5164a97213..530724315a0 100644 --- a/src/plugins/qmldesigner/designercore/imagecache/imagecachecollector.cpp +++ b/src/plugins/qmldesigner/designercore/imagecache/imagecachecollector.cpp @@ -61,8 +61,12 @@ QString fileToString(const QString &filename) } // namespace ImageCacheCollector::ImageCacheCollector(ImageCacheConnectionManager &connectionManager, + QSize captureImageMinimumSize, + QSize captureImageMaximumSize, ImageCacheCollectorNullImageHandling nullImageHandling) : m_connectionManager{connectionManager} + , captureImageMinimumSize{captureImageMinimumSize} + , captureImageMaximumSize{captureImageMaximumSize} , nullImageHandling{nullImageHandling} {} @@ -76,6 +80,8 @@ void ImageCacheCollector::start(Utils::SmallStringView name, { RewriterView rewriterView{RewriterView::Amend, nullptr}; NodeInstanceView nodeInstanceView{m_connectionManager}; + nodeInstanceView.setCaptureImageMinimumAndMaximumSize(captureImageMinimumSize, + captureImageMaximumSize); const QString filePath{name}; std::unique_ptr model{QmlDesigner::Model::create("QtQuick/Item", 2, 1)}; @@ -107,7 +113,10 @@ void ImageCacheCollector::start(Utils::SmallStringView name, || !image.isNull()) { QSize smallImageSize = image.size().scaled(QSize{96, 96}.boundedTo(image.size()), Qt::KeepAspectRatio); - QImage smallImage = image.isNull() ? QImage{} : image.scaled(smallImageSize); + QImage smallImage = image.isNull() ? QImage{} + : image.scaled(smallImageSize, + Qt::IgnoreAspectRatio, + Qt::SmoothTransformation); captureCallback(image, smallImage); } }; diff --git a/src/plugins/qmldesigner/designercore/imagecache/imagecachecollector.h b/src/plugins/qmldesigner/designercore/imagecache/imagecachecollector.h index 2e2803114ac..465e2d4d3f1 100644 --- a/src/plugins/qmldesigner/designercore/imagecache/imagecachecollector.h +++ b/src/plugins/qmldesigner/designercore/imagecache/imagecachecollector.h @@ -51,6 +51,8 @@ class ImageCacheCollector final : public ImageCacheCollectorInterface { public: ImageCacheCollector(ImageCacheConnectionManager &connectionManager, + QSize captureImageMinimumSize, + QSize captureImageMaximumSize, ImageCacheCollectorNullImageHandling nullImageHandling = {}); ~ImageCacheCollector(); @@ -75,6 +77,8 @@ public: private: ImageCacheConnectionManager &m_connectionManager; QPointer m_target; + QSize captureImageMinimumSize; + QSize captureImageMaximumSize; ImageCacheCollectorNullImageHandling nullImageHandling{}; }; diff --git a/src/plugins/qmldesigner/designercore/include/nodeinstanceview.h b/src/plugins/qmldesigner/designercore/include/nodeinstanceview.h index d4ff9358f52..62efb225d44 100644 --- a/src/plugins/qmldesigner/designercore/include/nodeinstanceview.h +++ b/src/plugins/qmldesigner/designercore/include/nodeinstanceview.h @@ -161,6 +161,13 @@ public: m_crashCallback = std::move(crashCallback); } + void setCaptureImageMinimumAndMaximumSize(QSize captureImageMinimumSize, + QSize captureImageMaximumSize) + { + m_captureImageMinimumSize = captureImageMinimumSize; + m_captureImageMaximumSize = captureImageMaximumSize; + } + void startNanotrace(); void endNanotrace(); @@ -237,6 +244,7 @@ private: // functions void updateWatcher(const QString &path); void handleShaderChanges(); void handleQsbProcessExit(Utils::QtcProcess *qsbProcess, const QString &shader); + void updateQsbPathToFilterMap(); void updateRotationBlocks(); void maybeResetOnPropertyChange(const PropertyName &name, const ModelNode &node, PropertyChangeFlags flags); @@ -288,9 +296,12 @@ private: QTimer m_generateQsbFilesTimer; Utils::FilePath m_qsbPath; QSet m_pendingUpdateDirs; - QSet m_pendingQsbTargets; - int m_remainingQsbTargets; + QHash m_qsbTargets; // Value indicates if target is pending qsb generation + QHash m_qsbPathToFilterMap; + int m_remainingQsbTargets = 0; QTimer m_rotBlockTimer; + QSize m_captureImageMinimumSize{150, 150}; + QSize m_captureImageMaximumSize{1000, 1000}; }; } // namespace ProxyNodeInstanceView diff --git a/src/plugins/qmldesigner/designercore/instances/nodeinstanceview.cpp b/src/plugins/qmldesigner/designercore/instances/nodeinstanceview.cpp index 818b6093b3b..8dbe236ca0a 100644 --- a/src/plugins/qmldesigner/designercore/instances/nodeinstanceview.cpp +++ b/src/plugins/qmldesigner/designercore/instances/nodeinstanceview.cpp @@ -98,6 +98,7 @@ #include #include +#include #include #include @@ -113,6 +114,8 @@ #include #include #include +#include +#include enum { debug = false @@ -174,9 +177,6 @@ NodeInstanceView::NodeInstanceView(ConnectionManagerInterface &connectionManager m_generateQsbFilesTimer.setInterval(100); QObject::connect(&m_generateQsbFilesTimer, &QTimer::timeout, [this] { handleShaderChanges(); - - if (m_qsbPath.isEmpty() || m_remainingQsbTargets <= 0) - m_resetTimer.start(); }); connect(m_fileSystemWatcher, &QFileSystemWatcher::directoryChanged, @@ -196,8 +196,12 @@ NodeInstanceView::NodeInstanceView(ConnectionManagerInterface &connectionManager }); connect(m_fileSystemWatcher, &QFileSystemWatcher::fileChanged, [this](const QString &path) { - m_pendingQsbTargets.insert(path); - m_generateQsbFilesTimer.start(); + if (m_qsbTargets.contains(path)) { + m_qsbTargets.insert(path, true); + m_generateQsbFilesTimer.start(); + } else if (m_remainingQsbTargets <= 0) { + m_resetTimer.start(); + } }); m_rotBlockTimer.setSingleShot(true); @@ -277,7 +281,15 @@ void NodeInstanceView::modelAttached(Model *model) activateState(newStateInstance); } - updateWatcher({}); + // If model gets attached on non-main thread of the application, do not attempt to monitor + // file changes. Such models are typically short lived for specific purpose, and timers + // will not work at all, if the thread is not based on QThread. + if (QThread::currentThread() == qApp->thread()) { + m_generateQsbFilesTimer.stop(); + m_qsbTargets.clear(); + updateQsbPathToFilterMap(); + updateWatcher({}); + } } void NodeInstanceView::modelAboutToBeDetached(Model * model) @@ -303,6 +315,9 @@ void NodeInstanceView::modelAboutToBeDetached(Model * model) m_pendingUpdateDirs.clear(); m_fileSystemWatcher->removePaths(m_fileSystemWatcher->directories()); m_fileSystemWatcher->removePaths(m_fileSystemWatcher->files()); + + m_generateQsbFilesTimer.stop(); + m_qsbTargets.clear(); } void NodeInstanceView::handleCrash() @@ -1123,24 +1138,27 @@ CreateSceneCommand NodeInstanceView::createCreateSceneCommand() if (stateNode.isValid() && stateNode.metaInfo().isSubclassOf("QtQuick.State", 1, 0)) stateInstanceId = stateNode.internalId(); - return CreateSceneCommand(instanceContainerList, - reparentContainerList, - idContainerList, - valueContainerList, - bindingContainerList, - auxiliaryContainerVector, - importVector, - mockupTypesVector, - model()->fileUrl(), + return CreateSceneCommand( + instanceContainerList, + reparentContainerList, + idContainerList, + valueContainerList, + bindingContainerList, + auxiliaryContainerVector, + importVector, + mockupTypesVector, + model()->fileUrl(), #ifndef QMLDESIGNER_TEST - QUrl::fromLocalFile(QmlDesigner::DocumentManager::currentResourcePath() - .toFileInfo().absoluteFilePath()), + QUrl::fromLocalFile( + QmlDesigner::DocumentManager::currentResourcePath().toFileInfo().absoluteFilePath()), #else - QUrl::fromLocalFile(QFileInfo(model()->fileUrl().toLocalFile()).absolutePath()), + QUrl::fromLocalFile(QFileInfo(model()->fileUrl().toLocalFile()).absolutePath()), #endif - m_edit3DToolStates[model()->fileUrl()], - lastUsedLanguage, - stateInstanceId); + m_edit3DToolStates[model()->fileUrl()], + lastUsedLanguage, + m_captureImageMinimumSize, + m_captureImageMaximumSize, + stateInstanceId); } ClearSceneCommand NodeInstanceView::createClearSceneCommand() const @@ -1488,9 +1506,6 @@ void NodeInstanceView::setTarget(ProjectExplorer::Target *newTarget) } } - m_generateQsbFilesTimer.stop(); - m_pendingQsbTargets.clear(); - m_remainingQsbTargets = 0; restartProcess(); } } @@ -1885,12 +1900,18 @@ void NodeInstanceView::updateWatcher(const QString &path) QStringList oldDirs; QStringList newFiles; QStringList newDirs; + QStringList qsbFiles; +#ifndef QMLDESIGNER_TEST + const QString projPath = QmlDesignerPlugin::instance()->documentManager().currentProjectDirPath().toString(); +#else + const QString projPath = QFileInfo(model()->fileUrl().toLocalFile()).absolutePath(); +#endif const QStringList files = m_fileSystemWatcher->files(); const QStringList directories = m_fileSystemWatcher->directories(); if (path.isEmpty()) { // Do full update - rootPath = QFileInfo(model()->fileUrl().toLocalFile()).absolutePath(); + rootPath = projPath; if (!directories.isEmpty()) m_fileSystemWatcher->removePaths(directories); if (!files.isEmpty()) @@ -1916,12 +1937,47 @@ void NodeInstanceView::updateWatcher(const QString &path) // Common shader suffixes static const QStringList filterList {"*.frag", "*.vert", "*.glsl", "*.glslv", "*.glslf", - "*.vsh","*.fsh"}; + "*.vsh", "*.fsh"}; QDirIterator fileIterator(rootPath, filterList, QDir::Files, QDirIterator::Subdirectories); while (fileIterator.hasNext()) newFiles.append(fileIterator.next()); + // Find out which shader files need qsb files generated for them. + // Go through all configured paths and find files that match the specified filter in that path. + bool generateQsb = false; + QHash::const_iterator it = m_qsbPathToFilterMap.constBegin(); + while (it != m_qsbPathToFilterMap.constEnd()) { + if (!it.key().isEmpty() && !it.key().startsWith(rootPath)) { + ++it; + continue; + } + + QDirIterator qsbIterator(it.key().isEmpty() ? rootPath : it.key(), + it.value(), QDir::Files, + it.key().isEmpty() ? QDirIterator::Subdirectories + : QDirIterator::NoIteratorFlags); + + while (qsbIterator.hasNext()) { + QString qsbFile = qsbIterator.next(); + + if (qsbFile.endsWith(".qsb")) + continue; // Skip any generated files that are caught by wildcards + + // Filters may specify shader files with non-default suffixes, so add them to newFiles + if (!newFiles.contains(qsbFile)) + newFiles.append(qsbFile); + + // Only generate qsb files for newly detected files. This avoids immediately regenerating + // qsb file if it's manually deleted, as directory change triggers calling this method. + if (!oldFiles.contains(qsbFile)) { + m_qsbTargets.insert(qsbFile, true); + generateQsb = true; + } + } + ++it; + } + if (oldDirs != newDirs) { if (!oldDirs.isEmpty()) m_fileSystemWatcher->removePaths(oldDirs); @@ -1934,15 +1990,10 @@ void NodeInstanceView::updateWatcher(const QString &path) m_fileSystemWatcher->removePaths(oldFiles); if (!newFiles.isEmpty()) m_fileSystemWatcher->addPaths(newFiles); - - for (const auto &newFile : qAsConst(newFiles)) { - if (!oldFiles.contains(newFile)) - m_pendingQsbTargets.insert(newFile); - } - - if (!m_pendingQsbTargets.isEmpty()) - m_generateQsbFilesTimer.start(); } + + if (generateQsb) + m_generateQsbFilesTimer.start(); } void NodeInstanceView::handleQsbProcessExit(Utils::QtcProcess *qsbProcess, const QString &shader) @@ -1969,51 +2020,102 @@ void NodeInstanceView::handleQsbProcessExit(Utils::QtcProcess *qsbProcess, const qsbProcess->deleteLater(); } -void NodeInstanceView::handleShaderChanges() +void NodeInstanceView::updateQsbPathToFilterMap() { - m_remainingQsbTargets += m_pendingQsbTargets.size(); + m_qsbPathToFilterMap.clear(); + if (m_currentTarget && !m_qsbPath.isEmpty()) { + const auto bs = qobject_cast(m_currentTarget->buildSystem()); + const QStringList shaderToolFiles = bs->shaderToolFiles(); - for (const auto &shader : qAsConst(m_pendingQsbTargets)) { - // Run qsb for changed shader file - if (!m_qsbPath.isEmpty() && !shader.isEmpty()) { - const Utils::FilePath sourceFile = Utils::FilePath::fromString(shader); - const Utils::FilePath srcPath = sourceFile.absolutePath(); - const Utils::FilePath outPath = Utils::FilePath::fromString(shader + ".qsb"); - - if (!sourceFile.exists() || (outPath.exists() && outPath.lastModified() > sourceFile.lastModified())) { - --m_remainingQsbTargets; - continue; - } - - // Run QSB with same parameters as Qt build does - // TODO: Parameters should be configurable (QDS-6590) - const QStringList args = {"-s", "--glsl", "100 es,120,150", "--hlsl", "50", "--msl", "12", - "-o", outPath.toString(), shader}; - auto qsbProcess = new Utils::QtcProcess; - qsbProcess->setWorkingDirectory(srcPath); - qsbProcess->setCommand({m_qsbPath, args}); - qsbProcess->start(); - - if (!qsbProcess->waitForStarted()) { - handleQsbProcessExit(qsbProcess, shader); - continue; - } - - if (qsbProcess->state() == QProcess::Running) { - connect(qsbProcess, &Utils::QtcProcess::finished, - [thisView = QPointer(this), qsbProcess, shader]() { - if (thisView) - thisView->handleQsbProcessExit(qsbProcess, shader); - else - qsbProcess->deleteLater(); - }); +#ifndef QMLDESIGNER_TEST + const QString projPath = QmlDesignerPlugin::instance()->documentManager().currentProjectDirPath().toString(); +#else + const QString projPath = QFileInfo(model()->fileUrl().toLocalFile()).absolutePath(); +#endif + // Parse ShaderTool files from project configuration. + // Separate files to path and file name (called filter here as it can contain wildcards) + // and group filters by paths. Blank path indicates project-wide file wildcard. + for (const auto &file : shaderToolFiles) { + int idx = file.lastIndexOf('/'); + QString key; + QString filter; + if (idx >= 0) { + key = projPath + "/" + file.left(idx); + filter = file.mid(idx + 1); } else { - handleQsbProcessExit(qsbProcess, shader); + filter = file; } + m_qsbPathToFilterMap[key].append(filter); } } +} - m_pendingQsbTargets.clear(); +void NodeInstanceView::handleShaderChanges() +{ + if (!m_currentTarget) + return; + + const auto bs = qobject_cast(m_currentTarget->buildSystem()); + QStringList baseArgs = bs->shaderToolArgs(); + if (baseArgs.isEmpty()) + return; + + QStringList newShaders; + QHash::iterator it = m_qsbTargets.begin(); + while (it != m_qsbTargets.end()) { + if (it.value()) { + newShaders.append(it.key()); + it.value() = false; + } + ++it; + } + + if (newShaders.isEmpty()) + return; + + m_remainingQsbTargets += newShaders.size(); + + for (const auto &shader : qAsConst(newShaders)) { + const Utils::FilePath srcFile = Utils::FilePath::fromString(shader); + const Utils::FilePath srcPath = srcFile.absolutePath(); + const Utils::FilePath outPath = Utils::FilePath::fromString(shader + ".qsb"); + + if (!srcFile.exists()) { + m_qsbTargets.remove(shader); + --m_remainingQsbTargets; + continue; + } + + if ((outPath.exists() && outPath.lastModified() > srcFile.lastModified())) { + --m_remainingQsbTargets; + continue; + } + + QStringList args = baseArgs; + args.append(outPath.toString()); + args.append(shader); + auto qsbProcess = new Utils::QtcProcess; + qsbProcess->setWorkingDirectory(srcPath); + qsbProcess->setCommand({m_qsbPath, args}); + qsbProcess->start(); + + if (!qsbProcess->waitForStarted()) { + handleQsbProcessExit(qsbProcess, shader); + continue; + } + + if (qsbProcess->state() == QProcess::Running) { + connect(qsbProcess, &Utils::QtcProcess::finished, + [thisView = QPointer(this), qsbProcess, shader]() { + if (thisView) + thisView->handleQsbProcessExit(qsbProcess, shader); + else + qsbProcess->deleteLater(); + }); + } else { + handleQsbProcessExit(qsbProcess, shader); + } + } } void NodeInstanceView::updateRotationBlocks() diff --git a/src/plugins/qmldesigner/generateresource.cpp b/src/plugins/qmldesigner/generateresource.cpp index 7876639c9b2..7210a144717 100644 --- a/src/plugins/qmldesigner/generateresource.cpp +++ b/src/plugins/qmldesigner/generateresource.cpp @@ -353,7 +353,7 @@ void GenerateResource::generateMenuEntry() // ToDo: move this to QtCreator and add tr to the string then auto rccAction = new QAction(QCoreApplication::translate("QmlDesigner::GenerateResource", - "Generate RCC Resource File")); + "Generate Deployable Package")); rccAction->setEnabled(ProjectExplorer::SessionManager::startupProject() != nullptr); QObject::connect(ProjectExplorer::SessionManager::instance(), &ProjectExplorer::SessionManager::startupProjectChanged, [rccAction]() { diff --git a/src/plugins/qmldesigner/qmldesignerconstants.h b/src/plugins/qmldesigner/qmldesignerconstants.h index fc394ae089c..81b9d8a4a7a 100644 --- a/src/plugins/qmldesigner/qmldesignerconstants.h +++ b/src/plugins/qmldesigner/qmldesignerconstants.h @@ -90,23 +90,23 @@ const char M_VIEW_WORKSPACES[] = "QmlDesigner.Menu.View.Workspaces"; const int MODELNODE_PREVIEW_IMAGE_DIMENSIONS = 150; -const char EVENT_TIMELINE_ADDED[] = "Timeline Added"; -const char EVENT_TRANSITION_ADDED[] = "Transition Added"; -const char EVENT_STATE_ADDED[] = "State Added"; -const char EVENT_CONNECTION_ADDED[] = "Connection Added"; -const char EVENT_PROPERTY_ADDED[] = "Property Added"; -const char EVENT_ANNOTATION_ADDED[] = "Annotation Added"; -const char EVENT_RESOURCE_IMPORTED[] = "Resource Imported "; -const char EVENT_ACTION_EXECUTED[] = "Action Executed "; -const char EVENT_HELP_REQUESTED[] = "Help Requested "; -const char EVENT_IMPORT_ADDED[] = "Import Added "; -const char EVENT_BINDINGEDITOR_OPENED[] = "Binding Editor Opened"; -const char EVENT_RICHTEXT_OPENED[] = "Richtext Editor Opened"; -const char EVENT_FORMEDITOR_TIME[] = "Form Editor"; -const char EVENT_3DEDITOR_TIME[] = "3D Editor"; -const char EVENT_TIMELINE_TIME[] = "Timeline"; -const char EVENT_TRANSITIONEDITOR_TIME[] = "Transition Editor"; -const char EVENT_CURVEDITOR_TIME[] = "Curve Editor"; +const char EVENT_TIMELINE_ADDED[] = "timelineAdded"; +const char EVENT_TRANSITION_ADDED[] = "transitionAdded"; +const char EVENT_STATE_ADDED[] = "stateAdded"; +const char EVENT_CONNECTION_ADDED[] = "connectionAdded"; +const char EVENT_PROPERTY_ADDED[] = "propertyAdded"; +const char EVENT_ANNOTATION_ADDED[] = "annotationAdded"; +const char EVENT_RESOURCE_IMPORTED[] = "resourceImported"; +const char EVENT_ACTION_EXECUTED[] = "actionExecuted"; +const char EVENT_HELP_REQUESTED[] = "helpRequested"; +const char EVENT_IMPORT_ADDED[] = "importAdded:"; +const char EVENT_BINDINGEDITOR_OPENED[] = "bindingEditorOpened"; +const char EVENT_RICHTEXT_OPENED[] = "richtextEditorOpened"; +const char EVENT_FORMEDITOR_TIME[] = "formEditor"; +const char EVENT_3DEDITOR_TIME[] = "3DEditor"; +const char EVENT_TIMELINE_TIME[] = "timeline"; +const char EVENT_TRANSITIONEDITOR_TIME[] = "transitionEditor"; +const char EVENT_CURVEDITOR_TIME[] = "curveEditor"; const char PROPERTY_EDITOR_CLASSNAME_PROPERTY[] = "__classNamePrivateInternal"; diff --git a/src/plugins/qmldesigner/qmldesignerplugin.cpp b/src/plugins/qmldesigner/qmldesignerplugin.cpp index d23575a8395..ee1d1041a59 100644 --- a/src/plugins/qmldesigner/qmldesignerplugin.cpp +++ b/src/plugins/qmldesigner/qmldesignerplugin.cpp @@ -100,6 +100,16 @@ namespace QmlDesigner { namespace Internal { +QString normalizeIdentifier(const QString &string) +{ + if (string.isEmpty()) + return {}; + QString ret = string; + ret.remove(' '); + ret[0] = ret.at(0).toLower(); + return ret; +} + class QtQuickDesignerFactory : public QmlJSEditor::QmlJSEditorFactory { public: @@ -318,7 +328,7 @@ bool QmlDesignerPlugin::delayedInitialize() emitUsageStatistics("StandaloneMode"); if (QmlProjectManager::QmlProject::isQtDesignStudioStartedFromQtC()) emitUsageStatistics("QDSlaunchedFromQtC"); - emitUsageStatistics("QDSstartupCount"); + emitUsageStatistics("qdsStartupCount"); FoundLicense license = checkLicense(); if (license == FoundLicense::enterprise) @@ -353,7 +363,7 @@ void QmlDesignerPlugin::extensionsInitialized() ExtensionSystem::IPlugin::ShutdownFlag QmlDesignerPlugin::aboutToShutdown() { if (QmlProjectManager::QmlProject::isQtDesignStudio()) - emitUsageStatistics("QDSstartupCount"); + emitUsageStatistics("qdsShutdownCount"); return SynchronousShutdown; } @@ -642,7 +652,8 @@ double QmlDesignerPlugin::formEditorDevicePixelRatio() void QmlDesignerPlugin::emitUsageStatistics(const QString &identifier) { QTC_ASSERT(instance(), return); - emit instance()->usageStatisticsNotifier(identifier); + emit instance()->usageStatisticsNotifier(normalizeIdentifier(identifier)); + qDebug() << normalizeIdentifier(identifier); } void QmlDesignerPlugin::emitUsageStatisticsContextAction(const QString &identifier) @@ -667,7 +678,9 @@ void QmlDesignerPlugin::registerPreviewImageProvider(QQmlEngine *engine) void QmlDesignerPlugin::emitUsageStatisticsTime(const QString &identifier, int elapsed) { - emit instance()->usageStatisticsUsageTimer(identifier, elapsed); + QTC_ASSERT(instance(), return); + emit instance()->usageStatisticsUsageTimer(normalizeIdentifier(identifier), elapsed); + qDebug() << normalizeIdentifier(identifier); } QmlDesignerPlugin *QmlDesignerPlugin::instance() diff --git a/src/plugins/qmldesigner/qmldesignerprojectmanager.cpp b/src/plugins/qmldesigner/qmldesignerprojectmanager.cpp index e9de2cb251b..538c3939f2f 100644 --- a/src/plugins/qmldesigner/qmldesignerprojectmanager.cpp +++ b/src/plugins/qmldesigner/qmldesignerprojectmanager.cpp @@ -108,6 +108,8 @@ public: {} ImageCacheConnectionManager connectionManager; ImageCacheCollector collector{connectionManager, + QSize{300, 300}, + QSize{1000, 1000}, ImageCacheCollectorNullImageHandling::DontCaptureNullImage}; TimeStampProvider timeStampProvider; AsynchronousImageFactory factory; diff --git a/src/plugins/qmlprojectmanager/fileformat/qmlprojectfileformat.cpp b/src/plugins/qmlprojectmanager/fileformat/qmlprojectfileformat.cpp index 710f34b445b..ce54df3d8d5 100644 --- a/src/plugins/qmlprojectmanager/fileformat/qmlprojectfileformat.cpp +++ b/src/plugins/qmlprojectmanager/fileformat/qmlprojectfileformat.cpp @@ -161,6 +161,26 @@ QmlProjectItem *QmlProjectFileFormat::parseProjectFile(const Utils::FilePath &fi projectItem->addToEnviroment(i.key(), i.value().value.toString()); ++i; } + } else if (childNode->name() == "ShaderTool") { + QmlJS::SimpleReaderNode::Property commandLine = childNode->property("args"); + if (commandLine.isValid()) { + const QStringList quotedArgs = commandLine.value.toString().split('\"'); + QStringList args; + for (int i = 0; i < quotedArgs.size(); ++i) { + // Each odd arg in this list is a single quoted argument, which we should + // not be split further + if (i % 2 == 0) + args.append(quotedArgs[i].trimmed().split(' ')); + else + args.append(quotedArgs[i]); + } + args.removeAll({}); + args.append("-o"); // Prepare for adding output file as next arg + projectItem->setShaderToolArgs(args); + } + QmlJS::SimpleReaderNode::Property files = childNode->property("files"); + if (files.isValid()) + projectItem->setShaderToolFiles(files.value.toStringList()); } else { qWarning() << "Unknown type:" << childNode->name(); } diff --git a/src/plugins/qmlprojectmanager/fileformat/qmlprojectitem.h b/src/plugins/qmlprojectmanager/fileformat/qmlprojectitem.h index 01d3b8572e0..02916555a7c 100644 --- a/src/plugins/qmlprojectmanager/fileformat/qmlprojectitem.h +++ b/src/plugins/qmlprojectmanager/fileformat/qmlprojectitem.h @@ -84,6 +84,12 @@ public: bool widgetApp() const { return m_widgetApp; } void setWidgetApp(bool widgetApp) { m_widgetApp = widgetApp; } + QStringList shaderToolArgs() const { return m_shaderToolArgs; } + void setShaderToolArgs(const QStringList &args) {m_shaderToolArgs = args; } + + QStringList shaderToolFiles() const { return m_shaderToolFiles; } + void setShaderToolFiles(const QStringList &files) {m_shaderToolFiles = files; } + void appendContent(QmlProjectContentItem *item) { m_content.append(item); } Utils::EnvironmentItems environment() const; @@ -107,6 +113,8 @@ protected: bool m_qtForMCUs = false; bool m_qt6Project = false; bool m_widgetApp = false; + QStringList m_shaderToolArgs; + QStringList m_shaderToolFiles; }; } // namespace QmlProjectManager diff --git a/src/plugins/qmlprojectmanager/qmlproject.cpp b/src/plugins/qmlprojectmanager/qmlproject.cpp index 32bcad2d1d5..67a9ab3dc03 100644 --- a/src/plugins/qmlprojectmanager/qmlproject.cpp +++ b/src/plugins/qmlprojectmanager/qmlproject.cpp @@ -626,6 +626,20 @@ bool QmlBuildSystem::widgetApp() const return false; } +QStringList QmlBuildSystem::shaderToolArgs() const +{ + if (m_projectItem) + return m_projectItem->shaderToolArgs(); + return {}; +} + +QStringList QmlBuildSystem::shaderToolFiles() const +{ + if (m_projectItem) + return m_projectItem->shaderToolFiles(); + return {}; +} + bool QmlBuildSystem::addFiles(Node *context, const FilePaths &filePaths, FilePaths *) { if (!dynamic_cast(context)) diff --git a/src/plugins/qmlprojectmanager/qmlproject.h b/src/plugins/qmlprojectmanager/qmlproject.h index fed2002912a..78a30187f6e 100644 --- a/src/plugins/qmlprojectmanager/qmlproject.h +++ b/src/plugins/qmlprojectmanager/qmlproject.h @@ -95,6 +95,8 @@ public: void setPrimaryLanguage(QString language); bool forceFreeType() const; bool widgetApp() const; + QStringList shaderToolArgs() const; + QStringList shaderToolFiles() const; bool addFiles(const QStringList &filePaths); diff --git a/src/plugins/qtsupport/exampleslistmodel.cpp b/src/plugins/qtsupport/exampleslistmodel.cpp index ebe547176e2..841ecd318ff 100644 --- a/src/plugins/qtsupport/exampleslistmodel.cpp +++ b/src/plugins/qtsupport/exampleslistmodel.cpp @@ -42,6 +42,7 @@ #include #include +#include #include #include #include @@ -50,6 +51,8 @@ #include #include +using namespace Utils; + namespace QtSupport { namespace Internal { @@ -101,12 +104,21 @@ ExampleSetModel::ExampleSetModel() qWarning() << "Manifest path " << set.manifestPath << "is not a readable directory, ignoring"; continue; } - m_extraExampleSets.append(set); if (debugExamples()) { qWarning() << "Adding examples set displayName=" << set.displayName << ", manifestPath=" << set.manifestPath << ", examplesPath=" << set.examplesPath; } + if (!Utils::anyOf(m_extraExampleSets, [&set](const ExtraExampleSet &s) { + return FilePath::fromString(s.examplesPath).cleanPath() + == FilePath::fromString(set.examplesPath).cleanPath() + && FilePath::fromString(s.manifestPath).cleanPath() + == FilePath::fromString(set.manifestPath).cleanPath(); + })) { + m_extraExampleSets.append(set); + } else if (debugExamples()) { + qWarning() << "Not adding, because example set with same directories exists"; + } } m_extraExampleSets += pluginRegisteredExampleSets(); diff --git a/src/plugins/qtsupport/qtcreator_tutorials.xml b/src/plugins/qtsupport/qtcreator_tutorials.xml index 71227a53380..4d898483609 100644 --- a/src/plugins/qtsupport/qtcreator_tutorials.xml +++ b/src/plugins/qtsupport/qtcreator_tutorials.xml @@ -91,10 +91,6 @@ qtformcus,mcus,qt,video,2021 - - - qt creator,talk,2020 - qt creator,wizard,talk,2015 diff --git a/src/plugins/studiowelcome/examplecheckout.cpp b/src/plugins/studiowelcome/examplecheckout.cpp index d0f1d1ce996..86d0bc41fef 100644 --- a/src/plugins/studiowelcome/examplecheckout.cpp +++ b/src/plugins/studiowelcome/examplecheckout.cpp @@ -41,6 +41,8 @@ #include +#include + #include #include #include @@ -83,6 +85,7 @@ FileDownloader::~FileDownloader() void FileDownloader::start() { + QmlDesigner::QmlDesignerPlugin::emitUsageStatistics("exampleDownload:" + name()); m_tempFile.setFileName(QDir::tempPath() + "/" + name() + ".XXXXXX" + ".zip"); m_tempFile.open(QIODevice::WriteOnly); diff --git a/src/plugins/studiowelcome/qml/splashscreen/CustomButton.ui.qml b/src/plugins/studiowelcome/qml/splashscreen/CustomButton.ui.qml new file mode 100644 index 00000000000..4cce33d42b2 --- /dev/null +++ b/src/plugins/studiowelcome/qml/splashscreen/CustomButton.ui.qml @@ -0,0 +1,108 @@ +/**************************************************************************** +** +** Copyright (C) 2022 The Qt Company Ltd. +** Contact: https://www.qt.io/licensing/ +** +** This file is part of Qt Creator. +** +** Commercial License Usage +** Licensees holding valid commercial Qt licenses may use this file in +** accordance with the commercial license agreement provided with the +** Software or, alternatively, in accordance with the terms contained in +** a written agreement between you and The Qt Company. For licensing terms +** and conditions see https://www.qt.io/terms-conditions. For further +** information use the contact form at https://www.qt.io/contact-us. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU +** General Public License version 3 as published by the Free Software +** Foundation with exceptions as appearing in the file LICENSE.GPL3-EXCEPT +** included in the packaging of this file. Please review the following +** information to ensure the GNU General Public License requirements will +** be met: https://www.gnu.org/licenses/gpl-3.0.html. +** +****************************************************************************/ + +/* +This is a UI file (.ui.qml) that is intended to be edited in Qt Design Studio only. +It is supposed to be strictly declarative and only uses a subset of QML. If you edit +this file manually, you might introduce QML code that is not supported by Qt Design Studio. +Check out https://doc.qt.io/qtcreator/creator-quick-ui-forms.html for details on .ui.qml files. +*/ +import QtQuick 2.15 +import QtQuick.Templates 2.15 +import StudioFonts 1.0 + +Button { + id: control + + implicitWidth: Math.max( + buttonBackground ? buttonBackground.implicitWidth : 0, + textItem.implicitWidth + leftPadding + rightPadding) + implicitHeight: Math.max( + buttonBackground ? buttonBackground.implicitHeight : 0, + textItem.implicitHeight + topPadding + bottomPadding) + leftPadding: 16 + rightPadding: 16 + + text: "My Button" + + font.family: StudioFonts.titilliumWeb_light + + //property color accentColor: "#047eff" + property color accentColor: "#126491" + + background: buttonBackground + Rectangle { + id: buttonBackground + color: "#00000000" + implicitWidth: 100 + implicitHeight: 40 + opacity: enabled ? 1 : 0.3 + radius: 2 + border.color: control.accentColor + } + + contentItem: textItem + Text { + id: textItem + text: control.text + + opacity: enabled ? 1.0 : 0.3 + color: "#ffffff" + horizontalAlignment: Text.AlignHCenter + verticalAlignment: Text.AlignVCenter + } + + states: [ + State { + name: "normal" + when: !control.down + + PropertyChanges { + target: buttonBackground + color: "#00000000" + border.color: control.accentColor + } + + PropertyChanges { + target: textItem + color: "#ffffff" + } + }, + State { + name: "down" + when: control.down + PropertyChanges { + target: textItem + color: "#ffffff" + } + + PropertyChanges { + target: buttonBackground + color: control.accentColor + border.color: "#00000000" + } + } + ] +} diff --git a/src/plugins/studiowelcome/qml/splashscreen/Splash_Image25d.qml b/src/plugins/studiowelcome/qml/splashscreen/Splash_Image25d.qml index 3d54304195b..f0ae6c2d8b0 100644 --- a/src/plugins/studiowelcome/qml/splashscreen/Splash_Image25d.qml +++ b/src/plugins/studiowelcome/qml/splashscreen/Splash_Image25d.qml @@ -29,7 +29,7 @@ Rectangle { id: splashBackground width: 460 height: 480 - color: "#11102d" + color: "transparent" layer.enabled: true layer.textureSize: Qt.size(width * 2, height * 2) @@ -37,6 +37,7 @@ Rectangle { Item { id: composition + anchors.centerIn: parent width: 460 height: 480 @@ -56,25 +57,4 @@ Rectangle { } } } - - Image { - id: highlight - x: -56 - y: -19 - width: 520 - height: 506 - fillMode: Image.PreserveAspectFit - source: "welcome_windows/highlight.png" - } - - Image { - id: hand - x: 245 - y: 227 - width: 224 - height: 264 - visible: true - fillMode: Image.PreserveAspectFit - source: "welcome_windows/hand.png" - } } diff --git a/src/plugins/studiowelcome/qml/splashscreen/Welcome_splash.qml b/src/plugins/studiowelcome/qml/splashscreen/Welcome_splash.qml index 5cff58fad40..24fba429eaa 100644 --- a/src/plugins/studiowelcome/qml/splashscreen/Welcome_splash.qml +++ b/src/plugins/studiowelcome/qml/splashscreen/Welcome_splash.qml @@ -32,8 +32,7 @@ import usagestatistics 1.0 Rectangle { id: welcome_splash - width: 800 - height: 480 + anchors.fill: parent gradient: Gradient { orientation: Gradient.Horizontal @@ -46,43 +45,27 @@ Rectangle { signal closeClicked signal configureClicked - property alias doNotShowAgain: doNotShowCheckBox.checked + property bool doNotShowAgain: true property bool loadingPlugins: true - - // called from C++ - function onPluginInitialized(crashReportingEnabled: bool, crashReportingOn: bool) - { - loadingPlugins = false - - if (crashReportingEnabled) { - var configureButton = "" - + qsTr("[Configure]") + ""; - var settingPath = Qt.platform.os === "osx" - ? qsTr("Qt Creator > Preferences > Environment > System") - : qsTr("Tools > Options > Environment > System") - var strConfigure = qsTr("Qt Design Studio collects usage statistics and crash reports for the sole purpose of fixing bugs and improving the tool. " - + "You can configure the crash reporter under %1. %2").arg(settingPath).arg(configureButton) - - crash_reporting_text.text = strConfigure - crashReportCheckBox.visible = true - } - } + color: "#1d212a" Image { id: logo - x: 15 - y: 11 - width: 66 - height: 50 + anchors.top: parent.top + anchors.left: parent.left + anchors.margins: 10 + width: 66 * 2 + height: 50 * 2 + smooth: true source: "welcome_windows/logo.png" } + Text { - id: qt_design_studio - x: 13 - y: 81 - width: 336 - height: 46 + id: qt_design_studio_text + anchors.top: logo.top + anchors.left: logo.right + anchors.leftMargin: 10 color: "#25709a" text: qsTr("Qt Design Studio") font.pixelSize: 36 @@ -90,156 +73,89 @@ Rectangle { } Text { - id: software_for_ui - x: 15 - y: 126 - width: 300 - height: 30 - color: "#ffffff" - text: qsTr("Software for UI and UX Designers") - renderType: Text.QtRendering - font.pixelSize: 15 + id: qt_design_studio_version_text + anchors.left: qt_design_studio_text.right + anchors.baseline: qt_design_studio_text.baseline + anchors.leftMargin: 10 + color: "#25709a" + text: usageStatisticModel.version + font.family: StudioFonts.titilliumWeb_light + font.pixelSize: 36 } Text { - id: copyright - x: 15 - y: 155 - width: 270 - height: 24 + id: license_variant_text + anchors.left: qt_design_studio_text.left + anchors.top: qt_design_studio_text.bottom + anchors.leftMargin: 5 color: "#ffffff" - text: qsTr("Copyright 2008 - 2022 The Qt Company") - font.pixelSize: 14 - font.family: StudioFonts.titilliumWeb_light - } - Text { - id: all_rights_reserved - x: 15 - y: 174 - width: 250 - height: 24 - color: "#ffffff" - text: qsTr("All Rights Reserved") - font.pixelSize: 14 font.family: StudioFonts.titilliumWeb_light - } + font.pixelSize: 20 - Text { - id: marketing_1 - x: 15 - y: 206 - width: 406 - height: 31 - color: "#ffffff" - text: qsTr("Multi-paradigm language for creating highly dynamic applications.") - wrapMode: Text.WordWrap - font.family: StudioFonts.titilliumWeb_light - font.pixelSize: 12 - font.wordSpacing: 0 - } + text: { + if (projectModel.communityVersion) + return qsTr("Community Edition") + if (projectModel.enterpriseVersion) + return qsTr("Enterprise Edition") + return qsTr("Professional Edition") + } - Text { - id: marketing_2 - x: 15 - y: 229 - width: 341 - height: 31 - color: "#ffffff" - text: qsTr("Run your concepts and prototypes on your final hardware.") - wrapMode: Text.WordWrap - font.family: StudioFonts.titilliumWeb_light - font.pixelSize: 12 - font.wordSpacing: 0 - } + ProjectModel { + id: projectModel + } - Text { - id: marketing_3 - x: 15 - y: 252 - width: 336 - height: 31 - color: "#ffffff" - text: qsTr("Seamless integration between designer and developer.") - wrapMode: Text.WordWrap - font.family: StudioFonts.titilliumWeb_light - font.pixelSize: 12 - font.wordSpacing: 0 - } - - Text { - id: crash_reporting_text - color: "#ffffff" - anchors.bottom: columnLayout.top - textFormat: Text.RichText - x: 15 - y: 280 - width: 311 - wrapMode: Text.WordWrap - anchors.bottomMargin: 8 - font.family: StudioFonts.titilliumWeb_light - font.pixelSize: 12 - font.wordSpacing: 0 - onLinkActivated: welcome_splash.configureClicked() - - MouseArea { // show hand cursor on link hover - anchors.fill: parent - acceptedButtons: Qt.NoButton // don't eat clicks on the Text - cursorShape: parent.hoveredLink ? Qt.PointingHandCursor : Qt.ArrowCursor + UsageStatisticModel { + id: usageStatisticModel } } Dof_Effect { - id: dof_Effect - x: 358 + id: dof_effect + anchors.top: qt_design_studio_text.bottom + anchors.horizontalCenter: welcome_splash.horizontalCenter width: 442 height: 480 - visible: true maskBlurSamples: 64 maskBlurRadius: 32 Splash_Image25d { id: animated_artwork - x: 358 - y: 0 - width: 442 - height: 480 + width: dof_effect.width + height: dof_effect.height clip: true } } - Image { - id: close_window - anchors.top: parent.top + Text { + id: help_us_text + anchors.left: welcome_splash.left anchors.right: parent.right - anchors.margins: 8 - width: 13 - height: 13 - fillMode: Image.PreserveAspectFit - source: "welcome_windows/close.png" - opacity: area.containsMouse ? 1 : 0.8 + anchors.leftMargin: 10 + anchors.top: dof_effect.bottom + anchors.topMargin: 10 + color: "#FFFFFF" + text: qsTr("Before we let you move on to your wonderful designs, help us make Qt Design Studio even better by letting us know how you're using it.") - MouseArea { - id: area - hoverEnabled: true - anchors.fill: parent - anchors.margins: -10 - onClicked: welcome_splash.closeClicked() - } + font.family: StudioFonts.titilliumWeb_light + font.pixelSize: 18 + wrapMode: Text.WordWrap + anchors.rightMargin: 10 } ColumnLayout { id: columnLayout anchors.left: parent.left - anchors.bottom: parent.bottom - anchors.leftMargin: 16 - anchors.bottomMargin: 10 + anchors.top: help_us_text.bottom + anchors.leftMargin: 10 + anchors.topMargin: 20 spacing: 3 CheckBox { + visible: false id: usageStatisticCheckBox - text: qsTr("Enable Usage Statistics") + text: qsTr("Send Usage Statistics") checked: usageStatisticModel.usageStatisticEnabled padding: 0 spacing: 12 @@ -255,11 +171,11 @@ Rectangle { } CheckBox { + visible: false id: crashReportCheckBox - text: qsTr("Enable Crash Reports") + text: qsTr("Send Crash Reports") spacing: 12 checked: usageStatisticModel.crashReporterEnabled - visible: false onCheckedChanged: { usageStatisticModel.setCrashReporterEnabled(crashReportCheckBox.checked) @@ -274,90 +190,41 @@ Rectangle { } padding: 0 } - - CheckBox { - id: doNotShowCheckBox - text: qsTr("Do not show this again") - padding: 0 - spacing: 12 - - contentItem: Text { - text: doNotShowCheckBox.text - color: "#ffffff" - leftPadding: doNotShowCheckBox.indicator.width + doNotShowCheckBox.spacing - font.pixelSize: 12 - } - } } RowLayout { - x: 16 - y: 277 - visible: welcome_splash.loadingPlugins + anchors.right: parent.right + anchors.bottom: welcome_splash.bottom + anchors.rightMargin: 10 + anchors.bottomMargin: 10 + spacing: 20 - Text { - id: text1 - color: "#ffffff" - text: qsTr("%") - font.pixelSize: 12 - - RotationAnimator { - target: text1 - from: 0 - to: 360 - duration: 1800 - running: true - loops: -1 + CustomButton { + text: qsTr("Don't send") + onClicked: { + usageStatisticModel.setTelemetryEnabled(false) + usageStatisticModel.setCrashReporterEnabled(false) + welcome_splash.closeClicked() } } - Text { - id: loading_progress - color: "#ffffff" - text: qsTr("Loading Plugins") - font.family: StudioFonts.titilliumWeb_light - font.pixelSize: 16 - } - - Text { - id: text2 - color: "#ffffff" - text: qsTr("%") - font.pixelSize: 12 - - RotationAnimator { - target: text2 - from: 0 - to: 360 - duration: 2000 - running: true - loops: -1 + CustomButton { + text: qsTr("Send analytics data") + onClicked: { + usageStatisticModel.setTelemetryEnabled(true) + usageStatisticModel.setCrashReporterEnabled(true) + welcome_splash.closeClicked() } } } - Text { - id: all_rights_reserved1 - x: 15 - y: 65 - color: "#ffffff" - - font.pixelSize: 13 - font.family: StudioFonts.titilliumWeb_light - text: { - if (projectModel.communityVersion) - return qsTr("Community Edition") - if (projectModel.enterpriseVersion) - return qsTr("Enterprise Edition") - return qsTr("Professional Edition") - } - - ProjectModel { - id: projectModel - } - - UsageStatisticModel { - id: usageStatisticModel - } + CustomButton { + y: 430 + text: qsTr("Learn More") + anchors.left: parent.left + anchors.bottom: parent.bottom + anchors.bottomMargin: 10 + anchors.leftMargin: 10 + onClicked: Qt.openUrlExternally("https://www.qt.io/terms-conditions/telemetry-privacy") } } diff --git a/src/plugins/studiowelcome/qml/splashscreen/main.qml b/src/plugins/studiowelcome/qml/splashscreen/main.qml index 674bb47c9fa..9ada7e7504f 100644 --- a/src/plugins/studiowelcome/qml/splashscreen/main.qml +++ b/src/plugins/studiowelcome/qml/splashscreen/main.qml @@ -27,8 +27,8 @@ import QtQuick 2.0 Item { id: root - width: 800 - height: 480 + width: 720 + height: 720 signal closeClicked signal checkBoxToggled diff --git a/src/plugins/studiowelcome/qml/welcomepage/HoverOverDesaturate.qml b/src/plugins/studiowelcome/qml/welcomepage/HoverOverDesaturate.qml index 18e645c3240..189694d330b 100644 --- a/src/plugins/studiowelcome/qml/welcomepage/HoverOverDesaturate.qml +++ b/src/plugins/studiowelcome/qml/welcomepage/HoverOverDesaturate.qml @@ -116,6 +116,7 @@ Item { id: image width: 240 height: 125 + mipmap: true fillMode: Image.PreserveAspectFit } } diff --git a/src/plugins/studiowelcome/qml/welcomepage/mockData/usagestatistics/UsageStatisticModel.qml b/src/plugins/studiowelcome/qml/welcomepage/mockData/usagestatistics/UsageStatisticModel.qml index c19250f2149..28f245910a2 100644 --- a/src/plugins/studiowelcome/qml/welcomepage/mockData/usagestatistics/UsageStatisticModel.qml +++ b/src/plugins/studiowelcome/qml/welcomepage/mockData/usagestatistics/UsageStatisticModel.qml @@ -27,4 +27,5 @@ import QtQuick 2.0 QtObject { property bool usageStatisticEnabled: false + property string version: "3.3.0" } diff --git a/src/plugins/studiowelcome/studiowelcomeplugin.cpp b/src/plugins/studiowelcome/studiowelcomeplugin.cpp index 15f21400a4f..fbd1bd52e0e 100644 --- a/src/plugins/studiowelcome/studiowelcomeplugin.cpp +++ b/src/plugins/studiowelcome/studiowelcomeplugin.cpp @@ -133,11 +133,13 @@ class UsageStatisticPluginModel : public QObject Q_PROPERTY(bool usageStatisticEnabled MEMBER m_usageStatisticEnabled NOTIFY usageStatisticChanged) Q_PROPERTY(bool crashReporterEnabled MEMBER m_crashReporterEnabled NOTIFY crashReporterEnabledChanged) + Q_PROPERTY(QString version MEMBER m_versionString CONSTANT) public: explicit UsageStatisticPluginModel(QObject *parent = nullptr) : QObject(parent) { + m_versionString = Core::Constants::IDE_VERSION_DISPLAY; setupModel(); } @@ -160,13 +162,10 @@ public: Core::ICore::settings()->setValue(CRASH_REPORTER_SETTING, b); - s_pluginInstance->pauseRemoveSplashTimer(); - const QString restartText = tr("The change will take effect after restart."); Core::RestartDialog restartDialog(Core::ICore::dialogParent(), restartText); restartDialog.exec(); - s_pluginInstance->resumeRemoveSplashTimer(); setupModel(); } @@ -179,14 +178,10 @@ public: settings->setValue(STATISTICS_COLLECTION_MODE, b ? DETAILED_USAGE_STATISTICS : NO_TELEMETRY); - // pause remove splash timer while dialog is open otherwise splash crashes upon removal - s_pluginInstance->pauseRemoveSplashTimer(); - const QString restartText = tr("The change will take effect after restart."); Core::RestartDialog restartDialog(Core::ICore::dialogParent(), restartText); restartDialog.exec(); - s_pluginInstance->resumeRemoveSplashTimer(); setupModel(); } @@ -197,6 +192,7 @@ signals: private: bool m_usageStatisticEnabled = false; bool m_crashReporterEnabled = false; + QString m_versionString; }; class ProjectModel : public QAbstractListModel @@ -249,6 +245,9 @@ public: const QString &formFile, const QString &explicitQmlproject) { + QmlDesigner::QmlDesignerPlugin::emitUsageStatistics("exampleOpened:" + + exampleName); + const QString exampleFolder = examplePath + "/" + exampleName + "/"; QString projectFile = exampleFolder + exampleName + ".qmlproject"; @@ -517,10 +516,7 @@ void StudioWelcomePlugin::showSystemSettings() Core::ICore::infoBar()->removeInfo("WarnCrashReporting"); Core::ICore::infoBar()->globallySuppressInfo("WarnCrashReporting"); - // pause remove splash timer while settings dialog is open otherwise splash crashes upon removal - pauseRemoveSplashTimer(); Core::ICore::showOptionsDialog(Core::Constants::SETTINGS_ID_SYSTEM); - resumeRemoveSplashTimer(); } StudioWelcomePlugin::StudioWelcomePlugin() @@ -543,11 +539,6 @@ bool StudioWelcomePlugin::initialize(const QStringList &arguments, QString *erro m_welcomeMode = new WelcomeMode; - m_removeSplashTimer.setSingleShot(true); - const QString splashScreenTimeoutEntry = "QML/Designer/splashScreenTimeout"; - m_removeSplashTimer.setInterval( - Core::ICore::settings()->value(splashScreenTimeoutEntry, 15000).toInt()); - connect(&m_removeSplashTimer, &QTimer::timeout, this, [this] { closeSplashScreen(); }); return true; } @@ -620,8 +611,6 @@ void StudioWelcomePlugin::extensionsInitialized() s_view->show(); s_view->raise(); - - m_removeSplashTimer.start(); }); } } @@ -633,34 +622,9 @@ bool StudioWelcomePlugin::delayedInitialize() QTC_ASSERT(s_view->rootObject(), return true); -#ifdef ENABLE_CRASHPAD - const bool crashReportingEnabled = true; - const bool crashReportingOn = Core::ICore::settings()->value(CRASH_REPORTER_SETTING, false).toBool(); -#else - const bool crashReportingEnabled = false; - const bool crashReportingOn = false; -#endif - - QMetaObject::invokeMethod(s_view->rootObject(), "onPluginInitialized", - Q_ARG(bool, crashReportingEnabled), Q_ARG(bool, crashReportingOn)); - return false; } -void StudioWelcomePlugin::pauseRemoveSplashTimer() -{ - if (m_removeSplashTimer.isActive()) { - m_removeSplashRemainingTime = m_removeSplashTimer.remainingTime(); // milliseconds - m_removeSplashTimer.stop(); - } -} - -void StudioWelcomePlugin::resumeRemoveSplashTimer() -{ - if (!m_removeSplashTimer.isActive()) - m_removeSplashTimer.start(m_removeSplashRemainingTime); -} - Utils::FilePath StudioWelcomePlugin::defaultExamplesPath() { QStandardPaths::StandardLocation location = Utils::HostOsInfo::isMacHost() diff --git a/src/plugins/studiowelcome/studiowelcomeplugin.h b/src/plugins/studiowelcome/studiowelcomeplugin.h index 1fdc811d37e..2968f3694a9 100644 --- a/src/plugins/studiowelcome/studiowelcomeplugin.h +++ b/src/plugins/studiowelcome/studiowelcomeplugin.h @@ -77,9 +77,6 @@ public: void extensionsInitialized() override; bool delayedInitialize() override; - void pauseRemoveSplashTimer(); - void resumeRemoveSplashTimer(); - static Utils::FilePath defaultExamplesPath(); static QString examplesPathSetting(); @@ -88,9 +85,7 @@ signals: private: class WelcomeMode *m_welcomeMode = nullptr; - QTimer m_removeSplashTimer; StudioWelcomeSettingsPage m_settingsPage; - int m_removeSplashRemainingTime = 0; }; } // namespace Internal diff --git a/src/plugins/texteditor/quickfix.h b/src/plugins/texteditor/quickfix.h index 2cc573b53cf..61a37d5bfae 100644 --- a/src/plugins/texteditor/quickfix.h +++ b/src/plugins/texteditor/quickfix.h @@ -27,6 +27,7 @@ #include "texteditor_global.h" +#include #include #include #include diff --git a/src/plugins/texteditor/textdocument.cpp b/src/plugins/texteditor/textdocument.cpp index e31f9044fbc..2c4a95d99eb 100644 --- a/src/plugins/texteditor/textdocument.cpp +++ b/src/plugins/texteditor/textdocument.cpp @@ -164,11 +164,10 @@ MultiTextCursor TextDocumentPrivate::indentOrUnindent(const MultiTextCursor &cur } // make sure that selection that begins in first column stays at first column // even if we insert text at first column + cursor = textCursor; if (cursorAtBlockStart) { - cursor = textCursor; cursor.setPosition(startBlock.position(), QTextCursor::KeepAnchor); } else if (anchorAtBlockStart) { - cursor = textCursor; cursor.setPosition(startBlock.position(), QTextCursor::MoveAnchor); cursor.setPosition(textCursor.position(), QTextCursor::KeepAnchor); } diff --git a/src/plugins/webassembly/webassemblyrunconfiguration.cpp b/src/plugins/webassembly/webassemblyrunconfiguration.cpp index 735739f7945..6bb00bc5536 100644 --- a/src/plugins/webassembly/webassemblyrunconfiguration.cpp +++ b/src/plugins/webassembly/webassemblyrunconfiguration.cpp @@ -128,6 +128,7 @@ public: runControl->buildKey(), browserId, QString::number(portsGatherer->findEndPoint().port())); + r.environment = runControl->buildEnvironment(); SimpleTargetRunner::doStart(r); }); } diff --git a/src/shared/qbs b/src/shared/qbs index 66c67898456..0ccbc9f30d3 160000 --- a/src/shared/qbs +++ b/src/shared/qbs @@ -1 +1 @@ -Subproject commit 66c67898456c4f599e48d5466022d49b044f679d +Subproject commit 0ccbc9f30d3fc6994d6ec3a7db0ed60e2c9dc500 diff --git a/tests/system/shared/utils.py b/tests/system/shared/utils.py index 180b06c365c..79e4dffe1cd 100644 --- a/tests/system/shared/utils.py +++ b/tests/system/shared/utils.py @@ -226,11 +226,11 @@ def logApplicationOutput(): # get the output from a given cmdline call def getOutputFromCmdline(cmdline, environment=None, acceptedError=0): try: - return subprocess.check_output(cmdline, env=environment) + return stringify(subprocess.check_output(cmdline, env=environment)) except subprocess.CalledProcessError as e: if e.returncode != acceptedError: test.warning("Command '%s' returned %d" % (e.cmd, e.returncode)) - return e.output + return stringify(e.output) def selectFromFileDialog(fileName, waitForFile=False, ignoreFinalSnooze=False): def __closePopupIfNecessary__(): @@ -238,41 +238,29 @@ def selectFromFileDialog(fileName, waitForFile=False, ignoreFinalSnooze=False): test.log("Closing active popup widget") QApplication.activePopupWidget().close() - if platform.system() == "Darwin": + fName = os.path.basename(os.path.abspath(fileName)) + pName = os.path.dirname(os.path.abspath(fileName)) + os.sep + try: + waitForObject("{name='QFileDialog' type='QFileDialog' visible='1'}", 5000) + pathLine = waitForObject("{name='fileNameEdit' type='QLineEdit' visible='1'}") + replaceEditorContent(pathLine, pName) snooze(1) - nativeType("") + clickButton(waitForObject("{text='Open' type='QPushButton'}")) + waitFor("str(pathLine.text)==''") + replaceEditorContent(pathLine, fName) snooze(1) - nativeType(fileName) - snooze(2) - nativeType("") - snooze(3) + __closePopupIfNecessary__() + clickButton(waitForObject("{text='Open' type='QPushButton'}")) + except: + nativeType("") + nativeType("") + nativeType(pName + fName) + seconds = len(pName + fName) / 20 + test.log("Using snooze(%d) [problems with event processing of nativeType()]" % seconds) + snooze(seconds) nativeType("") if not ignoreFinalSnooze: - snooze(1) - else: - fName = os.path.basename(os.path.abspath(fileName)) - pName = os.path.dirname(os.path.abspath(fileName)) + os.sep - try: - waitForObject("{name='QFileDialog' type='QFileDialog' visible='1'}", 5000) - pathLine = waitForObject("{name='fileNameEdit' type='QLineEdit' visible='1'}") - replaceEditorContent(pathLine, pName) - snooze(1) - clickButton(waitForObject("{text='Open' type='QPushButton'}")) - waitFor("str(pathLine.text)==''") - replaceEditorContent(pathLine, fName) - snooze(1) - __closePopupIfNecessary__() - clickButton(waitForObject("{text='Open' type='QPushButton'}")) - except: - nativeType("") - nativeType("") - nativeType(pName + fName) - seconds = len(pName + fName) / 20 - test.log("Using snooze(%d) [problems with event processing of nativeType()]" % seconds) - snooze(seconds) - nativeType("") - if not ignoreFinalSnooze: - snooze(3) + snooze(3) if waitForFile: fileCombo = waitForObject(":Qt Creator_FilenameQComboBox") if not waitFor("str(fileCombo.currentText) in fileName", 5000): @@ -447,6 +435,7 @@ def iterateQtVersions(keepOptionsOpen=False, alreadyOnOptionsDialog=False, rootChildText = str(rootIndex.data()).replace(".", "\\.").replace("_", "\\_") for subIndex in dumpIndices(model, rootIndex): subChildText = str(subIndex.data()).replace(".", "\\.").replace("_", "\\_") + treeView.scrollTo(subIndex) mouseClick(waitForObjectItem(treeView, ".".join([rootChildText,subChildText]))) currentText = str(waitForObject(":QtSupport__Internal__QtVersionManager.QLabel").text) matches = pattern.match(currentText) @@ -684,3 +673,12 @@ def isString(sth): return isinstance(sth, str) else: return isinstance(sth, (str, unicode)) + +# helper function to ensure we get str, converts bytes if necessary +def stringify(obj): + stringTypes = (str, unicode) if sys.version_info.major == 2 else (str) + if isinstance(obj, stringTypes): + return obj + if isinstance(obj, bytes): + tmp = obj.decode('cp1252') if platform.system() in ('Microsoft','Windows') else obj.decode() + return tmp diff --git a/tests/system/suite_general/tst_cmake_speedcrunch/test.py b/tests/system/suite_general/tst_cmake_speedcrunch/test.py index 9a9e88d3c95..0c89714062a 100644 --- a/tests/system/suite_general/tst_cmake_speedcrunch/test.py +++ b/tests/system/suite_general/tst_cmake_speedcrunch/test.py @@ -32,8 +32,9 @@ def cmakeSupported(): versionLines = filter(lambda line: "cmake version " in line, getOutputFromCmdline(["cmake", "--version"]).splitlines()) try: - test.log("Using " + versionLines[0]) - matcher = re.match("cmake version (\d+)\.(\d+)\.\d+", versionLines[0]) + versionLine = list(versionLines)[0] + test.log("Using " + versionLine) + matcher = re.match("cmake version (\d+)\.(\d+)\.\d+", versionLine) major = __builtin__.int(matcher.group(1)) minor = __builtin__.int(matcher.group(2)) except: diff --git a/tests/system/suite_general/tst_create_proj_wizard/test.py b/tests/system/suite_general/tst_create_proj_wizard/test.py index 8d33ba62c48..a8ef4782fc5 100644 --- a/tests/system/suite_general/tst_create_proj_wizard/test.py +++ b/tests/system/suite_general/tst_create_proj_wizard/test.py @@ -1,6 +1,6 @@ ############################################################################ # -# Copyright (C) 2016 The Qt Company Ltd. +# Copyright (C) 2022 The Qt Company Ltd. # Contact: https://www.qt.io/licensing/ # # This file is part of Qt Creator. @@ -66,8 +66,8 @@ def main(): availableProjectTypes.append({category:template}) safeClickButton("Cancel") for current in availableProjectTypes: - category = current.keys()[0] - template = current.values()[0] + category = list(current.keys())[0] + template = list(current.values())[0] with TestSection("Testing project template %s -> %s" % (category, template)): displayedPlatforms = __createProject__(category, template) if template == "Qt Quick Application":