Merge remote-tracking branch 'origin/7.0'
Conflicts: src/plugins/webassembly/webassemblyrunconfiguration.cpp src/tools/processlauncher/launchersockethandler.cpp Change-Id: Iab052af98013aa59282c16f22ae6e9ecb32f50c4
@@ -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."
|
||||
|
@@ -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
|
||||
|
@@ -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."
|
||||
|
@@ -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
|
||||
|
@@ -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
|
||||
*/
|
||||
|
@@ -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.
|
||||
|
@@ -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
|
||||
|
@@ -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.
|
||||
|
@@ -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
|
||||
*/
|
||||
|
@@ -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.
|
||||
|
@@ -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}
|
||||
|
@@ -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
|
||||
|
||||
|
@@ -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}.
|
||||
*/
|
||||
|
@@ -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}
|
||||
|
BIN
doc/qtdesignstudio/images/android-studio-avd-manager.png
Normal file
After Width: | Height: | Size: 32 KiB |
BIN
doc/qtdesignstudio/images/android-studio-sdk-manager.png
Normal file
After Width: | Height: | Size: 32 KiB |
BIN
doc/qtdesignstudio/images/android-studio-sdk-tools.png
Normal file
After Width: | Height: | Size: 85 KiB |
BIN
doc/qtdesignstudio/images/menu-build-qml-preview.png
Normal file
After Width: | Height: | Size: 67 KiB |
BIN
doc/qtdesignstudio/images/qtds-android-sdk-changes-dialog.png
Normal file
After Width: | Height: | Size: 19 KiB |
BIN
doc/qtdesignstudio/images/qtds-android-sdk-licenses-dialog.png
Normal file
After Width: | Height: | Size: 16 KiB |
BIN
doc/qtdesignstudio/images/qtds-options-accept-licenses.png
Normal file
After Width: | Height: | Size: 124 KiB |
BIN
doc/qtdesignstudio/images/qtds-options-devices.png
Normal file
After Width: | Height: | Size: 66 KiB |
After Width: | Height: | Size: 120 KiB |
BIN
doc/qtdesignstudio/images/qtds-options-kits.png
Normal file
After Width: | Height: | Size: 78 KiB |
BIN
doc/qtdesignstudio/images/qtds-run-settings.png
Normal file
After Width: | Height: | Size: 182 KiB |
BIN
doc/qtdesignstudio/images/qtds-running-emulator.png
Normal file
After Width: | Height: | Size: 225 KiB |
After Width: | Height: | Size: 12 KiB |
Before Width: | Height: | Size: 12 KiB After Width: | Height: | Size: 27 KiB |
BIN
doc/qtdesignstudio/images/toolbar-show-live-preview.png
Normal file
After Width: | Height: | Size: 8.2 KiB |
@@ -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
|
||||
|
||||
*/
|
@@ -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"
|
||||
|
@@ -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.
|
||||
|
||||
|
@@ -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}
|
||||
|
@@ -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
|
||||
|
@@ -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
|
||||
|
@@ -25,9 +25,10 @@
|
||||
|
||||
#pragma once
|
||||
|
||||
#include <qmetatype.h>
|
||||
#include <QSize>
|
||||
#include <QUrl>
|
||||
#include <QVector>
|
||||
#include <qmetatype.h>
|
||||
|
||||
#include "instancecontainer.h"
|
||||
#include "reparentcontainer.h"
|
||||
@@ -55,6 +56,8 @@ public:
|
||||
const QUrl &resourceUrl,
|
||||
const QHash<QString, QVariantMap> &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<QString, QVariantMap> edit3dToolStates;
|
||||
QString language;
|
||||
QSize captureImageMinimumSize;
|
||||
QSize captureImageMaximumSize;
|
||||
qint32 stateInstanceId = 0;
|
||||
};
|
||||
|
||||
|
@@ -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
|
||||
|
@@ -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
|
||||
|
@@ -285,6 +285,7 @@ Rectangle {
|
||||
anchors.fill: parent
|
||||
source: delegateStateImageSource
|
||||
fillMode: Image.PreserveAspectFit
|
||||
mipmap: true
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@@ -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
|
||||
|
@@ -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);
|
||||
|
@@ -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();
|
||||
|
@@ -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<HighlightingResult> &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<AstNode> children = it->children().value_or(QList<AstNode>());
|
||||
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<HighlightingResult> &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<AstNode> firstChildTree{children.first()};
|
||||
@@ -2883,6 +2888,8 @@ static void semanticHighlighter(QFutureInterface<HighlightingResult> &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
|
||||
|
@@ -27,8 +27,9 @@
|
||||
|
||||
#include <texteditor/codeassist/iassistproposalmodel.h>
|
||||
|
||||
#include <QString>
|
||||
#include <QList>
|
||||
#include <QSharedPointer>
|
||||
#include <QString>
|
||||
|
||||
namespace TextEditor { class BaseTextEditor; }
|
||||
|
||||
|
@@ -1321,6 +1321,14 @@ void ClangdTestHighlighting::test_data()
|
||||
<< QList<int>{C_FIELD} << 0;
|
||||
QTest::newRow("member call on dependent (3)") << 999 << 9 << 999 << 12
|
||||
<< QList<int>{C_LOCAL} << 0;
|
||||
QTest::newRow("member access via operator->") << 1009 << 7 << 1009 << 21
|
||||
<< QList<int>{C_FIELD} << 0;
|
||||
QTest::newRow("lambda call in member") << 1023 << 9 << 1023 << 15
|
||||
<< QList<int>{C_LOCAL} << 0;
|
||||
QTest::newRow("call on inherited member") << 1024 << 9 << 1024 << 12
|
||||
<< QList<int>{C_FIELD} << 0;
|
||||
QTest::newRow("pass inherited member by value") << 1038 << 21 << 1038 << 26
|
||||
<< QList<int>{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);
|
||||
}
|
||||
|
||||
|
||||
|
@@ -5,7 +5,7 @@ auto *rawVariable = R"(Vari
|
||||
auto Character = 'c';
|
||||
|
||||
namespace std {
|
||||
template<typename T> class vector {};
|
||||
template<typename T> class vector { public: void clear(); };
|
||||
template<typename T, typename U> class pair {};
|
||||
}
|
||||
|
||||
@@ -999,3 +999,44 @@ public:
|
||||
ptr->bar();
|
||||
}
|
||||
};
|
||||
|
||||
namespace std { template<typename T> struct optional { T* operator->(); }; }
|
||||
struct structWithData { int value; };
|
||||
struct structWithOptional { std::optional<structWithData> opt_my_struct1; };
|
||||
|
||||
void foo(structWithOptional & s)
|
||||
{
|
||||
s.opt_my_struct1->value = 5;
|
||||
}
|
||||
|
||||
class BaseWithMember
|
||||
{
|
||||
protected:
|
||||
std::vector<unsigned char> vec;
|
||||
};
|
||||
|
||||
template<typename T> class Derived : public BaseWithMember
|
||||
{
|
||||
void foo()
|
||||
{
|
||||
auto lambda = [&] {};
|
||||
lambda();
|
||||
vec.clear();
|
||||
}
|
||||
};
|
||||
|
||||
static bool testVal(int val);
|
||||
class BaseWithMember2
|
||||
{
|
||||
protected:
|
||||
int value;
|
||||
};
|
||||
template<typename T> class Derived2 : public BaseWithMember2
|
||||
{
|
||||
bool foo()
|
||||
{
|
||||
if (testVal(value))
|
||||
return true;
|
||||
return false;
|
||||
}
|
||||
};
|
||||
|
@@ -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);
|
||||
|
@@ -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);
|
||||
|
@@ -3273,6 +3273,58 @@ void QuickfixTest::testGenerateGetterSetterOnlySetter()
|
||||
QuickFixOperationTest(testDocuments, &factory, ProjectExplorer::HeaderPaths(), 0);
|
||||
}
|
||||
|
||||
void QuickfixTest::testGenerateGetterSetterAnonymousClass()
|
||||
{
|
||||
QList<TestDocumentPtr> 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<TestDocumentPtr> testDocuments;
|
||||
@@ -3362,6 +3414,43 @@ void QuickfixTest::testGenerateGetterSetterOnlySetterHeaderFileWithIncludeGuard(
|
||||
QuickFixOperationTest(testDocuments, &factory, ProjectExplorer::HeaderPaths(), 0);
|
||||
}
|
||||
|
||||
void QuickfixTest::testGenerateGetterFunctionAsTemplateArg()
|
||||
{
|
||||
QList<TestDocumentPtr> testDocuments;
|
||||
const QByteArray original = R"(
|
||||
template<typename T> class TS {};
|
||||
template<typename T, typename U> class TS<T(U)> {};
|
||||
|
||||
class S2 {
|
||||
TS<int(int)> @member;
|
||||
};
|
||||
)";
|
||||
const QByteArray expected = R"(
|
||||
template<typename T> class TS {};
|
||||
template<typename T, typename U> class TS<T(U)> {};
|
||||
|
||||
class S2 {
|
||||
TS<int(int)> member;
|
||||
|
||||
public:
|
||||
const TS<int (int)> &getMember() const
|
||||
{
|
||||
return member;
|
||||
}
|
||||
};
|
||||
)";
|
||||
|
||||
testDocuments << CppTestDocument::create("file.h", original, expected);
|
||||
|
||||
QuickFixSettings s;
|
||||
s->getterOutsideClassFrom = 0;
|
||||
s->getterInCppFileFrom = 0;
|
||||
s->getterNameTemplate = "get<Name>";
|
||||
|
||||
GenerateGetterSetter factory;
|
||||
QuickFixOperationTest(testDocuments, &factory, ProjectExplorer::HeaderPaths(), 1);
|
||||
}
|
||||
|
||||
class CppCodeStyleSettingsChanger {
|
||||
public:
|
||||
CppCodeStyleSettingsChanger(const CppCodeStyleSettings &settings);
|
||||
|
@@ -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();
|
||||
|
||||
|
@@ -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;
|
||||
|
||||
|
@@ -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;
|
||||
}
|
||||
}
|
||||
|
@@ -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);
|
||||
}
|
||||
|
@@ -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<Sqlite::Database> 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<ImageCacheData>();
|
||||
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<ImageCacheData>(); });
|
||||
return m_imageCacheData.get();
|
||||
}
|
||||
|
||||
AsynchronousImageCache &AssetsLibraryView::imageCache()
|
||||
{
|
||||
return imageCacheData()->cache;
|
||||
}
|
||||
|
||||
} // namespace QmlDesigner
|
||||
|
@@ -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;
|
||||
|
@@ -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);
|
||||
|
@@ -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<PreviewTooltipBackend> m_fontPreviewTooltipBackend;
|
||||
|
||||
QShortcut *m_qmlSourceUpdateShortcut = nullptr;
|
||||
AsynchronousImageCache &m_imageCache;
|
||||
QPointer<Model> m_model;
|
||||
QStringList m_assetsToDrag;
|
||||
bool m_updateRetry = false;
|
||||
|
@@ -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;
|
||||
}
|
||||
}
|
||||
|
@@ -33,6 +33,8 @@
|
||||
#include <qmldesignerplugin.h>
|
||||
#include <qmldesignerconstants.h>
|
||||
|
||||
#include <QFile>
|
||||
|
||||
namespace QmlDesigner {
|
||||
|
||||
static inline bool itemsHaveSameParent(const QList<ModelNode> &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)
|
||||
|
@@ -55,6 +55,7 @@
|
||||
#include <QScrollArea>
|
||||
#include <QMessageBox>
|
||||
#include <QFileDialog>
|
||||
#include <QVBoxLayout>
|
||||
|
||||
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<QString, QWidget *>());
|
||||
}
|
||||
|
||||
// Create tab for each supported extension group that also has files included in the import
|
||||
QMap<QString, int> 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<QScrollArea *>(ui->tabWidget->widget(i));
|
||||
if (optionsArea && optionsArea->widget()) {
|
||||
auto grid = qobject_cast<QGridLayout *>(optionsArea->widget()->layout());
|
||||
auto padGrid = [](QWidget *widget, int optionRows) {
|
||||
auto grid = qobject_cast<QGridLayout *>(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 <optionRows; ++i) {
|
||||
grid->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<QVector<QPair<QWidget *, QWidget *>>> widgets;
|
||||
QHash<QString, int> groupIndexMap;
|
||||
QHash<QString, QPair<QWidget *, QWidget *>> optionToWidgetsMap;
|
||||
QHash<QString, QJsonArray> conditionMap;
|
||||
QHash<QWidget *, QWidget *> conditionalWidgetMap;
|
||||
QHash<QString, QString> 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<QVector<QPair<QWidget *, QWidget *>>> widgets;
|
||||
QHash<QString, int> groupIndexMap;
|
||||
QHash<QString, QPair<QWidget *, QWidget *>> optionToWidgetsMap;
|
||||
QHash<QString, QJsonArray> conditionMap;
|
||||
QHash<QWidget *, QWidget *> conditionalWidgetMap;
|
||||
QHash<QString, QString> optionToGroupMap;
|
||||
|
||||
int rowIndex[2] = {0, 0};
|
||||
|
||||
widgets.append(QVector<QPair<QWidget *, QWidget *>>());
|
||||
|
||||
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<QCheckBox *>(
|
||||
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<double>::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<double>::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<QDoubleSpinBox *>(
|
||||
m_labelToControlWidgetMaps[optionsIndex].value(optKey));
|
||||
if (advSpin) {
|
||||
// Connect corresponding advanced control
|
||||
QObject::connect(optSpin, QOverload<double>::of(&QDoubleSpinBox::valueChanged),
|
||||
this, [optSpin, advSpin]() {
|
||||
if (advSpin->value() != optSpin->value())
|
||||
advSpin->setValue(optSpin->value());
|
||||
});
|
||||
QObject::connect(advSpin, QOverload<double>::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<double>::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<QScrollArea *>(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();
|
||||
}
|
||||
|
||||
}
|
||||
|
@@ -31,6 +31,10 @@
|
||||
#include <QJsonObject>
|
||||
#include <QSet>
|
||||
|
||||
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<QWidget *> contentWidgets; // Tab content widgets
|
||||
};
|
||||
|
||||
QStringList m_quick3DFiles;
|
||||
QString m_quick3DImportPath;
|
||||
ItemLibraryAssetImporter m_importer;
|
||||
QVector<QJsonObject> m_importOptions;
|
||||
QHash<QString, int> m_extToImportOptionsMap;
|
||||
int m_optionsHeight = 0;
|
||||
int m_optionsRows = 0;
|
||||
QSet<QString> m_preselectedFilesForOverwrite;
|
||||
bool m_closeOnFinish = true;
|
||||
QList<QHash<QString, QWidget *>> m_labelToControlWidgetMaps;
|
||||
OptionsData m_simpleData;
|
||||
OptionsData m_advancedData;
|
||||
bool m_advancedMode = false;
|
||||
int m_dialogHeight = 350;
|
||||
};
|
||||
}
|
||||
|
@@ -6,68 +6,118 @@
|
||||
<rect>
|
||||
<x>0</x>
|
||||
<y>0</y>
|
||||
<width>631</width>
|
||||
<height>750</height>
|
||||
<width>630</width>
|
||||
<height>350</height>
|
||||
</rect>
|
||||
</property>
|
||||
<property name="windowTitle">
|
||||
<string>Asset Import</string>
|
||||
</property>
|
||||
<layout class="QVBoxLayout" name="verticalLayout">
|
||||
<item>
|
||||
<widget class="QTabWidget" name="tabWidget">
|
||||
<property name="sizePolicy">
|
||||
<sizepolicy hsizetype="Expanding" vsizetype="Expanding">
|
||||
<horstretch>0</horstretch>
|
||||
<verstretch>2</verstretch>
|
||||
</sizepolicy>
|
||||
</property>
|
||||
<property name="currentIndex">
|
||||
<number>0</number>
|
||||
</property>
|
||||
<property name="tabBarAutoHide">
|
||||
<bool>false</bool>
|
||||
</property>
|
||||
<widget class="QWidget" name="modelOptionsTab">
|
||||
<attribute name="title">
|
||||
<string>Import Options</string>
|
||||
</attribute>
|
||||
</widget>
|
||||
</widget>
|
||||
</item>
|
||||
<item>
|
||||
<widget class="QPlainTextEdit" name="plainTextEdit">
|
||||
<property name="sizePolicy">
|
||||
<sizepolicy hsizetype="Expanding" vsizetype="Expanding">
|
||||
<horstretch>0</horstretch>
|
||||
<verstretch>1</verstretch>
|
||||
</sizepolicy>
|
||||
</property>
|
||||
<property name="readOnly">
|
||||
<bool>true</bool>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item>
|
||||
<widget class="QLabel" name="progressLabel">
|
||||
<property name="text">
|
||||
<string/>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item>
|
||||
<widget class="QProgressBar" name="progressBar">
|
||||
<property name="value">
|
||||
<number>0</number>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item>
|
||||
<widget class="QDialogButtonBox" name="buttonBox">
|
||||
<property name="standardButtons">
|
||||
<set>QDialogButtonBox::Close|QDialogButtonBox::Ok</set>
|
||||
</property>
|
||||
</widget>
|
||||
<layout class="QFormLayout" name="formLayout">
|
||||
<item row="0" column="0" colspan="2">
|
||||
<layout class="QVBoxLayout" name="verticalLayout">
|
||||
<item>
|
||||
<widget class="QTabWidget" name="tabWidget">
|
||||
<property name="sizePolicy">
|
||||
<sizepolicy hsizetype="Expanding" vsizetype="Expanding">
|
||||
<horstretch>0</horstretch>
|
||||
<verstretch>2</verstretch>
|
||||
</sizepolicy>
|
||||
</property>
|
||||
<property name="currentIndex">
|
||||
<number>0</number>
|
||||
</property>
|
||||
<property name="tabBarAutoHide">
|
||||
<bool>false</bool>
|
||||
</property>
|
||||
<widget class="QWidget" name="modelOptionsTab">
|
||||
<attribute name="title">
|
||||
<string>Import Options</string>
|
||||
</attribute>
|
||||
</widget>
|
||||
</widget>
|
||||
</item>
|
||||
<item>
|
||||
<layout class="QHBoxLayout" name="horizontalLayout">
|
||||
<item>
|
||||
<spacer name="horizontalSpacer">
|
||||
<property name="orientation">
|
||||
<enum>Qt::Horizontal</enum>
|
||||
</property>
|
||||
<property name="sizeHint" stdset="0">
|
||||
<size>
|
||||
<width>80</width>
|
||||
<height>20</height>
|
||||
</size>
|
||||
</property>
|
||||
</spacer>
|
||||
</item>
|
||||
<item>
|
||||
<widget class="QPushButton" name="advancedSettingsButton">
|
||||
<property name="text">
|
||||
<string>Show All Settings</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item>
|
||||
<spacer name="horizontalSpacer_2">
|
||||
<property name="orientation">
|
||||
<enum>Qt::Horizontal</enum>
|
||||
</property>
|
||||
<property name="sizeType">
|
||||
<enum>QSizePolicy::Fixed</enum>
|
||||
</property>
|
||||
<property name="sizeHint" stdset="0">
|
||||
<size>
|
||||
<width>8</width>
|
||||
<height>20</height>
|
||||
</size>
|
||||
</property>
|
||||
</spacer>
|
||||
</item>
|
||||
</layout>
|
||||
</item>
|
||||
<item>
|
||||
<widget class="QPlainTextEdit" name="plainTextEdit">
|
||||
<property name="sizePolicy">
|
||||
<sizepolicy hsizetype="Expanding" vsizetype="Expanding">
|
||||
<horstretch>0</horstretch>
|
||||
<verstretch>1</verstretch>
|
||||
</sizepolicy>
|
||||
</property>
|
||||
<property name="readOnly">
|
||||
<bool>true</bool>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item>
|
||||
<widget class="QLabel" name="progressLabel">
|
||||
<property name="sizePolicy">
|
||||
<sizepolicy hsizetype="Preferred" vsizetype="Fixed">
|
||||
<horstretch>0</horstretch>
|
||||
<verstretch>0</verstretch>
|
||||
</sizepolicy>
|
||||
</property>
|
||||
<property name="text">
|
||||
<string/>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item>
|
||||
<widget class="QProgressBar" name="progressBar">
|
||||
<property name="value">
|
||||
<number>0</number>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item>
|
||||
<widget class="QDialogButtonBox" name="buttonBox">
|
||||
<property name="standardButtons">
|
||||
<set>QDialogButtonBox::Close|QDialogButtonBox::Ok</set>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
</layout>
|
||||
</item>
|
||||
</layout>
|
||||
</widget>
|
||||
|
@@ -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<Sqlite::Database> 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<Import> &usedImports)
|
||||
m_widget->updateUsedImports(usedImports);
|
||||
}
|
||||
|
||||
ImageCacheData *ItemLibraryView::imageCacheData()
|
||||
ItemLibraryView::ImageCacheData *ItemLibraryView::imageCacheData()
|
||||
{
|
||||
std::call_once(imageCacheFlag, [this]() {
|
||||
m_imageCacheData = std::make_unique<ImageCacheData>();
|
||||
|
@@ -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;
|
||||
|
@@ -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<Import> imports;
|
||||
|
@@ -28,30 +28,87 @@
|
||||
#include <utils/stylehelper.h>
|
||||
#include <theme.h>
|
||||
|
||||
#include <QAction>
|
||||
#include <QBoxLayout>
|
||||
#include <QLabel>
|
||||
#include <QPushButton>
|
||||
#include <QStyle>
|
||||
#include <QToolButton>
|
||||
|
||||
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);
|
||||
|
||||
|
@@ -27,8 +27,27 @@
|
||||
|
||||
#include <QLineEdit>
|
||||
|
||||
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
|
||||
|
@@ -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;
|
||||
}
|
||||
|
||||
|
@@ -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);
|
||||
}
|
||||
|
@@ -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> 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);
|
||||
}
|
||||
};
|
||||
|
@@ -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<ProjectExplorer::Target> m_target;
|
||||
QSize captureImageMinimumSize;
|
||||
QSize captureImageMaximumSize;
|
||||
ImageCacheCollectorNullImageHandling nullImageHandling{};
|
||||
};
|
||||
|
||||
|
@@ -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<QString> m_pendingUpdateDirs;
|
||||
QSet<QString> m_pendingQsbTargets;
|
||||
int m_remainingQsbTargets;
|
||||
QHash<QString, bool> m_qsbTargets; // Value indicates if target is pending qsb generation
|
||||
QHash<QString, QStringList> m_qsbPathToFilterMap;
|
||||
int m_remainingQsbTargets = 0;
|
||||
QTimer m_rotBlockTimer;
|
||||
QSize m_captureImageMinimumSize{150, 150};
|
||||
QSize m_captureImageMaximumSize{1000, 1000};
|
||||
};
|
||||
|
||||
} // namespace ProxyNodeInstanceView
|
||||
|
@@ -98,6 +98,7 @@
|
||||
#include <projectexplorer/target.h>
|
||||
|
||||
#include <qmlprojectmanager/qmlmultilanguageaspect.h>
|
||||
#include <qmlprojectmanager/qmlproject.h>
|
||||
|
||||
#include <utils/algorithm.h>
|
||||
#include <utils/qtcassert.h>
|
||||
@@ -113,6 +114,8 @@
|
||||
#include <QDirIterator>
|
||||
#include <QFileSystemWatcher>
|
||||
#include <QScopedPointer>
|
||||
#include <QThread>
|
||||
#include <QApplication>
|
||||
|
||||
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<QString, QStringList>::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<QmlProjectManager::QmlBuildSystem *>(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<NodeInstanceView>(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<QmlProjectManager::QmlBuildSystem *>(m_currentTarget->buildSystem());
|
||||
QStringList baseArgs = bs->shaderToolArgs();
|
||||
if (baseArgs.isEmpty())
|
||||
return;
|
||||
|
||||
QStringList newShaders;
|
||||
QHash<QString, bool>::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<NodeInstanceView>(this), qsbProcess, shader]() {
|
||||
if (thisView)
|
||||
thisView->handleQsbProcessExit(qsbProcess, shader);
|
||||
else
|
||||
qsbProcess->deleteLater();
|
||||
});
|
||||
} else {
|
||||
handleQsbProcessExit(qsbProcess, shader);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void NodeInstanceView::updateRotationBlocks()
|
||||
|
@@ -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]() {
|
||||
|
@@ -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";
|
||||
|
||||
|
@@ -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()
|
||||
|
@@ -108,6 +108,8 @@ public:
|
||||
{}
|
||||
ImageCacheConnectionManager connectionManager;
|
||||
ImageCacheCollector collector{connectionManager,
|
||||
QSize{300, 300},
|
||||
QSize{1000, 1000},
|
||||
ImageCacheCollectorNullImageHandling::DontCaptureNullImage};
|
||||
TimeStampProvider timeStampProvider;
|
||||
AsynchronousImageFactory factory;
|
||||
|
@@ -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();
|
||||
}
|
||||
|
@@ -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
|
||||
|
@@ -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<QmlProjectNode *>(context))
|
||||
|
@@ -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);
|
||||
|
||||
|
@@ -42,6 +42,7 @@
|
||||
#include <qtsupport/qtversionmanager.h>
|
||||
|
||||
#include <utils/algorithm.h>
|
||||
#include <utils/filepath.h>
|
||||
#include <utils/fileutils.h>
|
||||
#include <utils/qtcassert.h>
|
||||
#include <utils/stringutils.h>
|
||||
@@ -50,6 +51,8 @@
|
||||
#include <algorithm>
|
||||
#include <memory>
|
||||
|
||||
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();
|
||||
|
||||
|
@@ -91,10 +91,6 @@
|
||||
<tags>qtformcus,mcus,qt,video,2021</tags>
|
||||
</tutorial>
|
||||
|
||||
<tutorial imageUrl=":qtsupport/images/icons/qteventicon.png" difficulty="" projectPath="" name="Talk: Introduction to Qt Creator IDE" isVideo="true" videoUrl="https://www.youtube.com/watch?v=nGFmjOiT22Y" videoLength="1:06:32">
|
||||
<description><![CDATA[Getting started with using Qt Creator for cross-platform development.]]></description>
|
||||
<tags>qt creator,talk,2020</tags>
|
||||
</tutorial>
|
||||
<tutorial imageUrl=":qtsupport/images/icons/qteventicon.png" difficulty="" projectPath="" name="Talk: Custom Qt Creator Wizards" isVideo="true" videoUrl="https://www.youtube.com/watch?v=Ko3DuCgFamo" videoLength="27:21">
|
||||
<description><![CDATA[Adding custom file and project creation wizards to Qt Creator.]]></description>
|
||||
<tags>qt creator,wizard,talk,2015</tags>
|
||||
|
@@ -41,6 +41,8 @@
|
||||
|
||||
#include <projectexplorer/projectexplorer.h>
|
||||
|
||||
#include <qmldesigner/qmldesignerplugin.h>
|
||||
|
||||
#include <QDialog>
|
||||
#include <QFileDialog>
|
||||
#include <QFileInfo>
|
||||
@@ -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);
|
||||
|
||||
|
108
src/plugins/studiowelcome/qml/splashscreen/CustomButton.ui.qml
Normal file
@@ -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"
|
||||
}
|
||||
}
|
||||
]
|
||||
}
|
@@ -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"
|
||||
}
|
||||
}
|
||||
|
@@ -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 = "<a href='#' style='text-decoration:none;color:#ffff00'>"
|
||||
+ qsTr("[Configure]") + "</a>";
|
||||
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")
|
||||
}
|
||||
}
|
||||
|
@@ -27,8 +27,8 @@ import QtQuick 2.0
|
||||
|
||||
Item {
|
||||
id: root
|
||||
width: 800
|
||||
height: 480
|
||||
width: 720
|
||||
height: 720
|
||||
|
||||
signal closeClicked
|
||||
signal checkBoxToggled
|
||||
|
@@ -116,6 +116,7 @@ Item {
|
||||
id: image
|
||||
width: 240
|
||||
height: 125
|
||||
mipmap: true
|
||||
fillMode: Image.PreserveAspectFit
|
||||
}
|
||||
}
|
||||
|
@@ -27,4 +27,5 @@ import QtQuick 2.0
|
||||
|
||||
QtObject {
|
||||
property bool usageStatisticEnabled: false
|
||||
property string version: "3.3.0"
|
||||
}
|
||||
|
@@ -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()
|
||||
|
@@ -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
|
||||
|
@@ -27,6 +27,7 @@
|
||||
|
||||
#include "texteditor_global.h"
|
||||
|
||||
#include <QList>
|
||||
#include <QString>
|
||||
#include <QMetaType>
|
||||
#include <QSharedPointer>
|
||||
|
@@ -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);
|
||||
}
|
||||
|
@@ -128,6 +128,7 @@ public:
|
||||
runControl->buildKey(),
|
||||
browserId,
|
||||
QString::number(portsGatherer->findEndPoint().port()));
|
||||
r.environment = runControl->buildEnvironment();
|
||||
SimpleTargetRunner::doStart(r);
|
||||
});
|
||||
}
|
||||
|
@@ -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("<Command+Shift+g>")
|
||||
clickButton(waitForObject("{text='Open' type='QPushButton'}"))
|
||||
waitFor("str(pathLine.text)==''")
|
||||
replaceEditorContent(pathLine, fName)
|
||||
snooze(1)
|
||||
nativeType(fileName)
|
||||
snooze(2)
|
||||
nativeType("<Return>")
|
||||
snooze(3)
|
||||
__closePopupIfNecessary__()
|
||||
clickButton(waitForObject("{text='Open' type='QPushButton'}"))
|
||||
except:
|
||||
nativeType("<Ctrl+a>")
|
||||
nativeType("<Delete>")
|
||||
nativeType(pName + fName)
|
||||
seconds = len(pName + fName) / 20
|
||||
test.log("Using snooze(%d) [problems with event processing of nativeType()]" % seconds)
|
||||
snooze(seconds)
|
||||
nativeType("<Return>")
|
||||
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("<Ctrl+a>")
|
||||
nativeType("<Delete>")
|
||||
nativeType(pName + fName)
|
||||
seconds = len(pName + fName) / 20
|
||||
test.log("Using snooze(%d) [problems with event processing of nativeType()]" % seconds)
|
||||
snooze(seconds)
|
||||
nativeType("<Return>")
|
||||
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
|
||||
|
@@ -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:
|
||||
|
@@ -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":
|
||||
|