Merge "Merge remote-tracking branch 'origin/6.0'"

This commit is contained in:
The Qt Project
2022-01-14 11:47:06 +00:00
39 changed files with 707 additions and 384 deletions

82
dist/changes-6.0.2.md vendored Normal file
View File

@@ -0,0 +1,82 @@
Qt Creator 6.0.2
================
Qt Creator version 6.0.2 contains bug fixes.
The most important changes are listed in this document. For a complete list of
changes, see the Git log for the Qt Creator sources that you can check out from
the public Git repository. For example:
git clone git://code.qt.io/qt-creator/qt-creator.git
git log --cherry-pick --pretty=oneline origin/v6.0.1..v6.0.2
General
-------
* Fixed crash in process launcher (QTCREATORBUG-26726)
Editing
-------
* Fixed that `Select All` scrolled to bottom (QTCREATORBUG-26736)
* Fixed copying with block selection (QTCREATORBUG-26761)
### C++
* ClangCodeModel
* Fixed performance regression of code completion on Windows and macOS
(QTCREATORBUG-26754)
### Python
* Fixed working directory for `REPL`
### Modeling
* Fixed missing options in property editor (QTCREATORBUG-26760)
Projects
--------
* Fixed that closing application in `Application Output` pane killed process
even if `Keep Running` was selected
* Fixed filtering in target setup page (QTCREATORBUG-26779)
### CMake
* Fixed that GUI project wizards did not create GUI applications on Windows and
app bundles on macOS
Platforms
---------
### Linux
* Fixed that commercial plugins linked to libGLX and libOpenGL
(QTCREATORBUG-26744)
### macOS
* Fixed crash when switching screen configuration (QTCREATORBUG-26019)
Credits for these changes go to:
--------------------------------
Allan Sandfeld Jensen
André Pönitz
Antti Määttä
Christiaan Janssen
Christian Kandeler
Christian Stenger
Cristian Adam
David Schulz
Eike Ziller
Henning Gruendl
Jaroslaw Kobus
Knud Dollereder
Leena Miettinen
Marco Bubke
Mats Honkamaa
Samuel Ghinet
Tapani Mattila
Thomas Hartmann
Tuomo Pelkonen

Binary file not shown.

Before

Width:  |  Height:  |  Size: 15 KiB

View File

@@ -1,106 +0,0 @@
/****************************************************************************
**
** Copyright (C) 2017 The Qt Company Ltd.
** Contact: https://www.qt.io/licensing/
**
** This file is part of the Qt Creator 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.
**
****************************************************************************/
// **********************************************************************
// NOTE: the sections are not ordered by their logical order to avoid
// reshuffling the file each time the index order changes (i.e., often).
// Run the fixnavi.pl script to adjust the links to the index order.
// **********************************************************************
/*!
//! [cmake deploying embedded]
\section1 Deploying CMake Projects to Generic Remote Linux Devices
\QC cannot directly extract files to be installed from a CMake project.
Therefore, a special deploy step is created that installs the project into
a local directory. The files in that directory are then deployed to the
remote device.
Alternatively, you can provide a \c {QtCreatorDeployment.txt} file in which
you must specify all files to be deployed which are not executables or
libraries. You place this file in either the root directory of the CMake
project or the build directory of the active build configuration.
Currently, \QC first checks the root directory and only if no
\c {QtCreatorDeployment.txt} exists it checks the active build directory.
Use the following syntax in the file:
\code
<deployment/prefix>
<relative/source/file1>:<relative/destination/dir1>
...
<relative/source/filen>:<relative/destination/dirn>
\endcode
Where:
\list
\li \c {<deployment/prefix>} is the (absolute) path prefix to where
files are copied on the remote machine.
\li \c {<relative/source/file>} is the file path relative to the CMake
project root. No directories or wildcards are allowed in this
value.
\li \c {<relative/destination/dir>} is the destination directory path
relative to \c {deployment/prefix}.
\endlist
To automate the creation of \c {QtCreatorDeployment.txt} file:
\list 1
\li Define the following macros in the top level \c {CMakeLists.txt}
file:
\code
file(WRITE "${CMAKE_SOURCE_DIR}/QtCreatorDeployment.txt" "<deployment/prefix>\n")
macro(add_deployment_file SRC DEST)
file(RELATIVE_PATH path ${CMAKE_SOURCE_DIR} ${CMAKE_CURRENT_SOURCE_DIR})
file(APPEND "${CMAKE_SOURCE_DIR}/QtCreatorDeployment.txt" "${path}/${SRC}:${DEST}\n")
endmacro()
macro(add_deployment_directory SRC DEST)
file(GLOB_RECURSE files RELATIVE "${CMAKE_CURRENT_SOURCE_DIR}" "${SRC}/*")
foreach(filename ${files})
get_filename_component(path ${filename} PATH)
add_deployment_file("${filename}" "${DEST}/${path}")
endforeach(filename)
endmacro()
\endcode
\li Use \c {add_deployment_file(<file/name>)} to add files and
\c {add_deployment_directory(<folder/name>)} to add directories
(including subdirectories) to the \c QtCreatorDeployment.txt file.
\li Re-run \c cmake after you add or remove files using the macros.
\endlist
//! [cmake deploying embedded]
*/

View File

@@ -1,6 +1,6 @@
/****************************************************************************
**
** Copyright (C) 2021 The Qt Company Ltd.
** Copyright (C) 2022 The Qt Company Ltd.
** Contact: https://www.qt.io/licensing/
**
** This file is part of the Qt Creator documentation.
@@ -42,8 +42,9 @@
native build configurations and workspaces that you can use in the compiler
environment of your choice.
You can use CMake from \QC to build applications for the desktop and
Android devices. You can also build single files to test your changes.
You can use CMake from \QC to build applications for the desktop, as well
as mobile and embedded devices. You can also build single files to test
your changes.
\QC automatically detects the CMake executable specified in the \c PATH.
You can add paths to other CMake executables and use them in different
@@ -168,6 +169,6 @@
\li \l {Opening Projects}
\li \l {CMake Build Configuration}
\li \l {Specifying Run Settings}
\li \l {Deploying CMake Projects to Generic Remote Linux Devices}
\li \l {Deploying Applications to Generic Remote Linux Devices}
\endlist
*/

View File

@@ -1,6 +1,6 @@
/****************************************************************************
**
** Copyright (C) 2021 The Qt Company Ltd.
** Copyright (C) 2022 The Qt Company Ltd.
** Contact: https://www.qt.io/licensing/
**
** This file is part of the Qt Creator documentation.
@@ -30,13 +30,18 @@
\title Deploying Applications to Boot2Qt Devices
You can specify the generic deployment steps for remote Linux devices also
for \l{Boot2Qt} devices.
You can specify settings for deploying applications to \l{Boot2Qt} devices
in the project configuration file and in \uicontrol Projects >
\uicontrol {Run Settings} > \uicontrol Deployment.
\image qtcreator-boot2qt-deployment-steps.png "Boot2Qt deployment steps"
For more information, see \l{Generic Deployment Steps}.
The deployment process is described in more detail in
\l{Deploying Applications to Generic Remote Linux Devices}.
\section1 Launching Applications on Boot
In addition, to have your application launch on boot, select
\uicontrol {Add Deploy Step} > \uicontrol {Change Default Application}.
\uicontrol {Add Deploy Step} > \uicontrol {Change default application}
> \uicontrol {Set this application to start by default}.
*/

View File

@@ -1,6 +1,6 @@
/****************************************************************************
**
** Copyright (C) 2020 The Qt Company Ltd.
** Copyright (C) 2022 The Qt Company Ltd.
** Contact: https://www.qt.io/licensing/
**
** This file is part of the Qt Creator documentation.
@@ -41,58 +41,70 @@
\title Deploying Applications to Generic Remote Linux Devices
You can specify settings for deploying applications to generic remote
Linux devices in the project .pro file. You can view the settings in
the \uicontrol Projects mode, in \uicontrol {Run Settings}.
Linux devices in the project configuration file and in the
\uicontrol Projects mode, in \uicontrol {Run Settings}.
\image qtcreator-embedded-linux-deployment-overview.png "Deploy to device"
\image qtcreator-embedded-linux-deployment-details.png "Deploy to embedded Linux"
The files to be installed are listed in the \uicontrol {Deployment} step,
the \uicontrol {Files to deploy} field. The \uicontrol {Local File Path}
field displays the location of the file on the development PC. The
\uicontrol {Remote Directory} field displays the folder where the file is
\uicontrol {Remote Directory} field displays the directory where the file is
installed on the device. Text in red color indicates that the information is
missing. Edit the qmake \l{Variables#installs} {INSTALLS variable} in the
project \c .pro file to add the missing files.
missing.
\section1 Adding Missing Files
The process to add files to deploy depends on the build system you use.
\section2 CMake
When using CMake as the build system, use the \l{CMake: install command}
{install} command in the CMakeLists.txt file to add the missing files.
For example, add the following lines to the CMakeLists.txt file to install
the binary of your project to the \c /opt directory on the remote device:
\badcode
set(INSTALL_DESTDIR "/opt")
install(TARGETS <target>
RUNTIME DESTINATION "${INSTALL_DESTDIR}"
BUNDLE DESTINATION "${INSTALL_DESTDIR}"
LIBRARY DESTINATION "${INSTALL_DESTDIR}"
)
\endcode
\section2 qmake
When using qmake, edit the \l{Variables#installs}{INSTALLS variable} in
the project \c .pro file.
When you run the application, \QC copies the necessary files to the device
and starts the application on it.
For example, adding
For example, add the following lines to the \c .pro file to copy the binary
of your project to the \c /opt directory on the remote device:
\code
target.path = /root
target.path = /opt
INSTALLS += target
\endcode
to the project .pro file will copy the binary of your project to \c /root
on the remote device. Additional files can be deployed by adding them to
further targets and adding those to \c INSTALLS as well.
To deploy additional files, add them to further targets that you also add
to \c INSTALLS.
\section1 Generic Deployment Steps
\section1 Deploy Steps
\image qtcreator-embedded-linux-deployment-details.png "Deploy to embedded Linux"
When you run the application on the device, \QC first uploads the
necessary files to it, as specified by the deploy steps.
When you run the application on the device, \QC
deploys the application as specified by the deploy steps. By default, \QC
copies the application files to the device by using the SSH file transfer
protocol (SFTP), as specified by the \uicontrol {Upload files via SFTP}
step.
\section2 Finding Configured Devices
If you have a lot of data to copy, select \uicontrol Details in the
\uicontrol {Upload Files via SFTP} step, and then select the
\uicontrol {Incremental deployment} check box. \QC takes note of the
deployment time and only copies files that have changed since the last
deployment. However, when you make major changes on the device, such as
removing files from the device manually or flashing a new disk image, or
when you use another device with the same IP address, deselect the check box
once, to have \QC deploy all files again.
The \uicontrol {Check for a configured device} step looks for a device that
is ready for deployment.
To only create a tarball and not copy the files to the device, select
\uicontrol {Add Deploy Step} > \uicontrol {Create tarball}. Then remove all
other deploy steps.
The \uicontrol {Deploy tarball via SFTP upload} step specifies that \QC
uploads the tarball to the device and extracts it.
\section2 Checking for Free Disk Space
The \uicontrol {Check for free disk space} step is by default the first
deploy step. Use it to find out whether the remote file system has enough
@@ -104,7 +116,27 @@
support will crash when an SFTP upload is being attempted. This is not a bug
in \QC.
\if defined(qtcreator)
\include creator-projects-cmake-deploying.qdocinc cmake deploying embedded
\endif
\section2 Uploading Files
By default, \QC copies the application files to the device by
using the SSH file transfer protocol (SFTP), as specified by
the \uicontrol {Upload files via SFTP} step.
If you have a lot of data to copy, select \uicontrol Details in the
\uicontrol {Upload Files via SFTP} step, and then select the
\uicontrol {Incremental deployment} check box. \QC takes note of the
deployment time and only copies files that have changed since the last
deployment. However, when you make major changes on the device, such as
removing files from the device manually or flashing a new disk image, or
when you use another device with the same IP address, deselect the check box
once, to have \QC deploy all files again.
\section2 Creating a Tarball
To only create a tarball and not copy the files to the device, select
\uicontrol {Add Deploy Step} > \uicontrol {Create tarball}. Then remove all
other deploy steps.
The \uicontrol {Deploy tarball via SFTP upload} step specifies that \QC
uploads the tarball to the device and extracts it.
*/

View File

@@ -1,6 +1,6 @@
/****************************************************************************
**
** Copyright (C) 2019 The Qt Company Ltd.
** Copyright (C) 2022 The Qt Company Ltd.
** Contact: https://www.qt.io/licensing/
**
** This file is part of the Qt Creator documentation.
@@ -144,8 +144,8 @@
If you want to run your application on a generic remote Linux device,
you first need to deploy your executable and possibly other files.
\QC does that for you automatically if you provide the necessary
information. This works the same way as explained for CMake
\l {Deploying CMake Projects to Generic Remote Linux Devices}{here},
information. This works the same way as explained for CMake in
\l {Deploying Applications to Generic Remote Linux Devices},
except that you also need to include your application binary in the list.
\section1 Creating a Run Configuration

View File

@@ -1,13 +1,13 @@
/****************************************************************************
**
** This file is part of Qt Creator
**
** Copyright (C) 2018 Blackberry
**
** Contact: Blackberry (qt@blackberry.com)
** Contact: KDAB (info@kdab.com)
**
** This file is part of the documentation of the Qt Toolkit.
** Copyright (C) 2022 The Qt Company Ltd.
** Contact: https://www.qt.io/licensing/
**
** This file is part of the Qt Creator documentation.
**
** Commercial License Usage
** Licensees holding valid commercial Qt licenses may use this file in
@@ -40,19 +40,12 @@
\title Deploying Applications to QNX Neutrino Devices
You can deploy applications to QNX Neutrino devices in the way that is
described in \l{Deploying Applications to Generic Remote Linux Devices}.
You can specify settings for deploying applications to QNX Neutrino
devices in the project configuration file and in \uicontrol Projects
> \uicontrol {Run Settings} > \uicontrol Deployment.
\image qtcreator-qnx-deployment.png "Deploy to device"
The files to be installed are listed in the \uicontrol {Deployment} step,
the \uicontrol {Files to deploy} field. The
\uicontrol {Local File Path} field displays the location of the file on the
development PC. The \uicontrol {Remote Directory} field displays the folder
where the file is installed on the device. Text in red color indicates that
the information is missing. Edit the qmake \l{Variables#installs}
{INSTALLS variable} in the project \c .pro file to add the missing files.
When you run the application, \QC copies the necessary files to the device
and starts the application on it.
The deployment process is described in more detail in
\l{Deploying Applications to Generic Remote Linux Devices}.
*/

Binary file not shown.

After

Width:  |  Height:  |  Size: 25 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 9.8 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 22 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 5.5 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 18 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 35 KiB

View File

@@ -0,0 +1,198 @@
/****************************************************************************
**
** 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.
**
****************************************************************************/
/*!
\page rain-snow-particle-effect.html
\ingroup gstutorials
\title Rain and Snow Effect
\brief Illustrates how to create a rain and snow effect with the \QDS
particle system.
\image snow-particles.png
The \e{Rain and Snow Effect} tutorial illustrates how you can add a rain and
a snow effect to your
scene using the \QDS particle system.
You need to download the starting project for this tutorial from
\l{https://git.qt.io/public-demos/qtdesign-studio/-/tree/master/
tutorial%20projects/rain-snow-particles/Start}{here} before you start.
Download the project and open the \e faceparticles.qmlproject file in \QDS
to get started.
\image rain-snow-tutorial-start.png
\section1 Creating a Rain Effect
\section2 Adding a Particle System to Your Scene
To add a particle system, you first need to import the QtQuick3D.Particles3D
module to your project:
\list 1
\li In the \uicontrol Library view, select
\inlineimage icons/plus.png
next to \uicontrol Components.
\li Find QtQuick3D.Particles3D and select it to add it to your project.
\li From \uicontrol Library > \uicontrol Components, drag a
\uicontrol{Particle System} to \uicontrol scene in \uicontrol Navigator.
\endlist
Now you have added a particle system to your scene.
\image rain-snow-tutorial-particle-system
\section2 Adjusting the Behavior and Apperance of the Particle System
Next, you adjust the position, behavior, and apperance of the particle
system to create a simple rain effect:
\list 1
\li Adjust the position of the particle system to align with the sphere.
In \uicontrol Navigator, select \e particleSystem and in
\uicontrol Properties, set \uicontrol Translation > \uicontrol Y to 193.
\li Set the \e rain-drop-white-square.png as texture for the particles.
From \uicontrol Library > \uicontrol Components, drag a \uicontrol Texture
to \e spriteParticle.
\li In \uicontrol Navigator, select \uicontrol texture1 and in \uicontrol
Properties, set \uicontrol Source to \e rain-drop-white-square.png.
\li In \uicontrol Navigator, select \uicontrol spriteParticle and in the
\uicontrol Properties, set \uicontrol Sprite to texture.
\li Adjust the apperance and behavior of the sprite further. In \uicontrol
Properties, set:
\list
\li \uicontrol{Particle Scale} to 10.
\li \uicontrol{Max Amount} to 1000.
\li \uicontrol Color to #91ffffff.
\li \uicontrol{Fade In Effect} to FadeNone.
\li \uicontrol{Fade Out Effect} to FadeNone.
\endlist
\li Now you have set the apperance of the particles. Next, adjust
the particle emitter. In \uicontrol Navigator, select \uicontrol
particleEmitter, and in \uicontrol Properties set:
\list
\li \uicontrol System to particleSystem.
\li \uicontrol{Emit Rate} to 1500.
\li \uicontrol{Life Span} to 100.
\li \uicontrol{Life Span Variation} to 0.
\li \uicontrol{Particle End Scale} to 1.
\li \uicontrol{Particle Scale Variation} to 0,5.
\li \uicontrol{Particle End Scale Variation} to 0,5.
\li \uicontrol{Particle Rotation} > \uicontrol Variation >
\uicontrol X, \uicontrol Y,
and \uicontrol Z to 0.
\li \uicontrol{Particle Rotation} > \uicontrol{Velocity Variation} >
\uicontrol X,
\uicontrol Y, and \uicontrol Z to 0.
\li \uicontrol Transform > \uicontrol Translation \uicontrol Y to -69.
\endlist
\li Finally, you set the direction of the particles. In \uicontrol
Navigator, select \uicontrol dir3d and in \uicontrol
Properties set:
\list
\li \uicontrol Direction > \uicontrol Y to -500.
\li \uicontrol Direction > \uicontrol Z to 0.
\li \uicontrol{Direction Variation} > \uicontrol X, \uicontrol Y, and
\uicontrol Z to 0.
\endlist
\endlist
\section2 Adjusting the Size of the Emitting Area
By default, the \uicontrol {Particle Emitter} emits particles from one
point in the scene. In this scene you want to emit particles from a bigger
area matching the size of the sphere. To do this, you need to add
a \uicontrol{Particle Shape} component:
\list 1
\li From \uicontrol Components, drag a \uicontrol{Particle Shape}
component to \uicontrol{particleSystem} in \uicontrol Navigator.
\li In \uicontrol Navigator, select \uicontrol particleShape, and in
\uicontrol Properties set:
\list
\li \uicontrol Type to \uicontrol Sphere.
\li \uicontrol Extends \uicontrol X to 85.
\li \uicontrol Extends \uicontrol Y to 85.
\li \uicontrol Extends \uicontrol Z to 85.
\endlist
\li In \uicontrol Navigator, select \uicontrol particleEmitter, and in
\uicontrol Particle set
\uicontrol Shape to \uicontrol particleShape.
\endlist
\image rain-snow-tutorial-navigator.png
Now, the rain effect is ready. Press \key Alt+P to see it in the live
preview.
\section1 Creating a Snow Effect
To make it easy, you can duplicate the particle system you created for the
rain effect and adjust the properties to create a snow effect. To do this,
first create a new state for the snow effect:
\list
\li In \uicontrol{States}, select \uicontrol{Create New State}.
\endlist
\image rain-snow-tutorial-states.png
\section2 Turning the Rain into Snow
\list 1
\li With the new state that you just created selected in
\uicontrol{States}, in \uicontrol{Navigator}, select \uicontrol
spriteParticle and set \uicontrol Color to #ffffff.
\li In \uicontrol{Navigator}, select \uicontrol texture1 and set
\uicontrol Source to \e{snowflake.png}.
\li In \uicontrol{Navigator}, select \uicontrol particleEmitter and set:
\list
\li \uicontrol{Emit Rate} to 250.
\li \uicontrol{Life Span} to 450.
\li \uicontrol{Particle Rotation} > \uicontrol Variation >
\uicontrol{X}, \uicontrol{Y}, and \uicontrol Z to 180.
\li \uicontrol{Particle Rotation} > \uicontrol{Velocity Variation} >
\uicontrol{X}, \uicontrol{Y}, and \uicontrol Z to 200.
\endlist
\li In \uicontrol{Navigator}, select \uicontrol particleEmitter
> \uicontrol dir3d and set:
\list
\li \uicontrol Direction > \uicontrol Y to -100.
\li \uicontrol{Direction Variation} \uicontrol{X}, \uicontrol{Y},
and \uicontrol Z
to 10.
\endlist
\endlist
Now you can run the snow effect in the live preview:
\list 1
\li In \uicontrol{States} next to \uicontrol State1 select
\inlineimage icons/action-icon.png
and select \uicontrol{Set as Default}.
\li Press \key{Alt+P}.
\endlist
\image rain-snow-tutorial-default-state.png
*/

Binary file not shown.

Before

Width:  |  Height:  |  Size: 9.6 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 9.2 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 14 KiB

After

Width:  |  Height:  |  Size: 109 KiB

View File

@@ -48,95 +48,83 @@
prompt you to enter the settings needed for a particular type of project
and create the necessary files for you.
\QDS projects are useful for creating UIs. You cannot use them for
application development, because they do not contain:
\list
\li C++ code
\li Resource files (.qrc)
\li Code needed for deploying applications to devices.
\endlist
Because the projects do not contain any C++ code, you do not need
to build them. To test how well your designs work, you can preview the
UIs on the desktop or embedded Linux devices. For more
To test how well your designs work, you can preview the
UIs on the desktop, embedded Linux devices, or Android devices. For more
information, see \l{Validating with Target Hardware}.
\image studio-project-wizards.png "A list of project wizards"
You can export designs from other design tools and import them to projects
or create them from scratch using the following wizard templates:
or create them from scratch using the following wizard presets:
\table
\header
\li Category
\li Wizard Template
\li Wizard Preset
\li Purpose
\row
\li {1,2} General
\li Qt Quick Application - Empty
\li Creates a project that uses default components and preset UI
controls and can be run on all target platforms.
\li Empty
\li Creates a project that uses default components such as rectangles,
images, and text. You can run the application on all target
platforms.
\row
\li Qt Quick 3D Application
\li Creates a project that uses default components, UI controls, and
3D components.
\li 3D
\li Creates a project that uses default and 3D components such as
cameras, lights, 3D models, and materials.
\row
\li Qt for MCUs
\li Qt for MCUs Application
\li Creates an application that uses a subset of preset components
\li MCU
\li Creates an application that uses a subset of default components
(as supported by Qt for MCUs) that you can deploy, run, and debug
on MCU boards.
\row
\li {1,2} Mobile
\li Qt Quick Application - Scroll
\li Creates an application that uses UI controls to implement a
\li {1,3} Mobile
\li Scroll
\li Creates an application that uses Qt Quick controls to implement a
scrollable list.
\row
\li Qt Quick Application - Stack
\li Creates an application that uses UI controls to implement a
\li Stack
\li Creates an application that uses Qt Quick controls to implement a
set of pages with a stack-based navigation model.
\row
\li Swipe
\li Creates an application that uses Qt Quick controls to implement a
swipable screen.
\row
\li Desktop
\li Qt Quick Application - Launcher
\li Creates a project that uses default components and UI controls and
defines a launcher application.
\li Launcher
\li Creates a project that uses default components such as rectangles,
images, and text, and defines a launcher application.
\endtable
For an example of creating a \uicontrol {Qt Quick 3D Application} project,
watch the following video:
\youtube 9ihYeC0YJ0M
\section1 Using Project Wizards
To create a new project:
\list 1
\li Select \uicontrol File > \uicontrol {New Project}.
\li Select a wizard template, and then select \uicontrol Choose.
\li In the \uicontrol Name field, enter a name for the project.
Keep in mind that projects cannot be easily renamed later.
\image studio-project-location.png "Project Location dialog"
\li In the \uicontrol {Create in} field, enter the path for the project
files. You can move project folders later without problems.
\li Select \uicontrol Next (or \uicontrol Continue on \macos).
\li In the \uicontrol {Screen resolution} field, select the screen
resolution for previewing the UI on the desktop or on a device.
This determines the screen size.
\image studio-project-custom-screen-size.png "Define Project Details dialog"
\li To use a custom screen size, specify the width and height of the
screen in the \uicontrol {Custom screen width} and
\uicontrol {Custom screen height} fields.
You can easily change the screen size later in \l Properties.
\li In the \uicontrol {Qt Quick Controls Style} field, select one of
\li In the \uicontrol Presets tab, select a wizard preset.
\li In the \uicontrol Details tab:
\list
\li Enter a name for the project. Keep in mind that projects
cannot be easily renamed later.
\li Select the path for the project files. You can move project
folders later.
\li Set the screen resolution for previewing the UI on the
desktop or on a device. This determines the screen size. You can
change the screen size later in \l Properties.
\li Select \uicontrol {Use Qt Virtual Keyboard} to
enable users to enter text using a virtual keyboard.
\li In \uicontrol {Target Qt Version}, select the Qt
version to use for developing the application. While you can
change the Qt version later in the \uicontrol {Run Settings}
of the project, keep in mind that the two versions are not fully
compatible.
\endlist
\li In the \uicontrol {Style} tab, select one of
the predefined \l{Styling Qt Quick Controls}{UI styles} to use.
\li Select the \uicontrol {Use Qt Virtual Keyboard} check box to enable
users to enter text using a virtual keyboard.
\li In the \uicontrol {Target Qt Version} field, select the Qt version
to use for developing the application. While you can change the
Qt version later in the \uicontrol {Run Settings} of the project,
keep in mind that the two versions are not fully compatible.
\li Select \uicontrol Finish (or \uicontrol Done on \macos) to create
the project.
\li Select \uicontrol Create to create the project.
\endlist
\QDS creates the following files and folders:
@@ -155,6 +143,9 @@
Specifically, if you export and import designs using \QB, your main
file is most likely called something else. For more information,
see \l {Exporting from Design Tools}.
\li \e CMakeLists.txt project configuration file allowing you to
share your project as a fully working C++ application with
developers.
\li qtquickcontrols2.conf file specifies the preferred style and some
style-specific arguments.
\li \e fonts folder contains font files that you have added in

View File

@@ -237,7 +237,7 @@
"enabled": "%{IsTopLevelProject}",
"data": {
"projectFilePath": "%{ProjectFilePath}",
"requiredFeatures": [ "%{JS: (value('TestFrameWork') === 'QtQuickTest' ? 'QtSupport.Wizards.FeatureQt.5' : ((value('BuildSystem') === 'qmake' || value('TestFrameWork') === 'QtTest') ? 'QtSupport.Wizards.FeatureQt' : 'DeviceType.Desktop' )) }" ]
"requiredFeatures": [ "%{JS: (value('TestFrameWork') === 'QtQuickTest' ? 'QtSupport.Wizards.FeatureQtQuick.2' : ((value('BuildSystem') === 'qmake' || value('TestFrameWork') === 'QtTest') ? 'QtSupport.Wizards.FeatureQt' : 'DeviceType.Desktop' )) }" ]
}
},
{

View File

@@ -25,6 +25,7 @@
#pragma once
#include <utils/optional.h>
#include <utils/smallstringview.h>
#include <type_traits>
@@ -62,7 +63,7 @@ void insertUpdateDelete(SqliteRange &&sqliteRange,
auto endSqliteIterator = sqliteRange.end();
auto currentValueIterator = values.begin();
auto endValueIterator = values.end();
std::optional<std::decay_t<decltype(*currentValueIterator)>> lastValue;
Utils::optional<std::decay_t<decltype(*currentValueIterator)>> lastValue;
while (true) {
bool hasMoreValues = currentValueIterator != endValueIterator;

View File

@@ -41,6 +41,17 @@ public:
}
friend bool operator!=(TimeStamp first, TimeStamp second) { return !(first == second); }
friend bool operator<(TimeStamp first, TimeStamp second) { return first.value < second.value; }
friend TimeStamp operator+(TimeStamp first, TimeStamp second)
{
return first.value + second.value;
}
friend TimeStamp operator-(TimeStamp first, TimeStamp second)
{
return first.value - second.value;
}
bool isValid() const { return value >= 0; }

View File

@@ -408,7 +408,10 @@ QFuture<ResultType> runAsync_internal(QThreadPool *pool,
QFuture<ResultType> future = job->future();
if (pool) {
job->setThreadPool(pool);
pool->start(job);
if (QThread::currentThread() == pool->thread())
pool->start(job);
else
QMetaObject::invokeMethod(pool, [pool, job]() { pool->start(job); }, Qt::QueuedConnection);
} else {
auto thread = new Internal::RunnableThread(job);
if (stackSize)

View File

@@ -138,11 +138,10 @@ void DPasteDotComProtocol::paste(
});
}
bool DPasteDotComProtocol::checkConfiguration(QString *errorMessage)
bool DPasteDotComProtocol::checkConfiguration(QString * /*errorMessage*/)
{
if (!m_hostKnownOk)
m_hostKnownOk = httpStatus(baseUrl(), errorMessage);
return m_hostKnownOk;
// we need a 1s gap between requests, so skip status check to avoid failing
return true;
}
void DPasteDotComProtocol::reportError(const QString &message)

View File

@@ -50,8 +50,6 @@ private:
bool checkConfiguration(QString *errorMessage) override;
static void reportError(const QString &message);
bool m_hostKnownOk = false;
};
} // namespace CodePaster

View File

@@ -1572,7 +1572,9 @@ static const MsvcToolChain *selectMsvcToolChain(const QString &displayedVarsBat,
QTC_CHECK(displayedVarsBat.isEmpty());
const QVersionNumber version = clangClVersion(clangClPath);
if (version.majorVersion() >= 6) {
toolChain = findMsvcToolChain(wordWidth, Abi::WindowsMsvc2019Flavor);
toolChain = findMsvcToolChain(wordWidth, Abi::WindowsMsvc2022Flavor);
if (!toolChain)
toolChain = findMsvcToolChain(wordWidth, Abi::WindowsMsvc2019Flavor);
if (!toolChain)
toolChain = findMsvcToolChain(wordWidth, Abi::WindowsMsvc2017Flavor);
}

View File

@@ -185,7 +185,7 @@ void CMakeGeneratorDialogTreeModel::createNodes(const FilePaths &candidates, QSt
const CheckableFileTreeItem* CMakeGeneratorDialogTreeModel::constNodeForIndex(const QModelIndex &index) const
{
const QStandardItem *parent = static_cast<const QStandardItem*>(index.constInternalPointer());
const QStandardItem *parent = static_cast<const QStandardItem*>(index.internalPointer());
const QStandardItem *item = parent->child(index.row(), index.column());
return static_cast<const CheckableFileTreeItem*>(item);
}

View File

@@ -1050,15 +1050,16 @@ static QString getAssetDefaultDirectory(const QString &assetDir, const QString &
{
QString adjustedDefaultDirectory = defaultDirectory;
Utils::FilePath assetPath = projectFilePath();
if (assetPath.pathAppended("content").exists())
assetPath= assetPath.pathAppended("content");
Utils::FilePath contentPath = projectFilePath();
assetPath = assetPath.pathAppended(assetDir);
if (contentPath.pathAppended("content").exists())
contentPath = contentPath.pathAppended("content");
Utils::FilePath assetPath = contentPath.pathAppended(assetDir);
if (!assetPath.exists()) {
// Create the default asset type directory if it doesn't exist
QDir dir(projectFilePath().toString());
QDir dir(contentPath.toString());
dir.mkpath(assetDir);
}

View File

@@ -25,18 +25,19 @@
#include "asynchronousimagefactory.h"
#include "imagecachecollector.h"
#include "imagecachegenerator.h"
#include "imagecachestorage.h"
#include "timestampprovider.h"
#include "timestampproviderinterface.h"
namespace QmlDesigner {
AsynchronousImageFactory::AsynchronousImageFactory(ImageCacheStorageInterface &storage,
ImageCacheGeneratorInterface &generator,
TimeStampProviderInterface &timeStampProvider)
TimeStampProviderInterface &timeStampProvider,
ImageCacheCollectorInterface &collector)
: m_storage(storage)
, m_generator(generator)
, m_timeStampProvider(timeStampProvider)
, m_collector(collector)
{
m_backgroundThread = std::thread{[this] {
while (isRunning()) {
@@ -45,8 +46,8 @@ AsynchronousImageFactory::AsynchronousImageFactory(ImageCacheStorageInterface &s
entry->extraId,
std::move(entry->auxiliaryData),
m_storage,
m_generator,
m_timeStampProvider);
m_timeStampProvider,
m_collector);
}
waitForEntries();
@@ -107,30 +108,33 @@ void AsynchronousImageFactory::request(Utils::SmallStringView name,
Utils::SmallStringView extraId,
ImageCache::AuxiliaryData auxiliaryData,
ImageCacheStorageInterface &storage,
ImageCacheGeneratorInterface &generator,
TimeStampProviderInterface &timeStampProvider)
TimeStampProviderInterface &timeStampProvider,
ImageCacheCollectorInterface &collector)
{
const auto id = extraId.empty() ? Utils::PathString{name}
: Utils::PathString::join({name, "+", extraId});
const auto currentModifiedTime = timeStampProvider.timeStamp(name);
const auto storageModifiedTime = storage.fetchModifiedImageTime(id);
const auto pause = timeStampProvider.pause();
if (currentModifiedTime == storageModifiedTime && storage.fetchHasImage(id))
if (currentModifiedTime < (storageModifiedTime + pause))
return;
generator.generateImage(name,
extraId,
currentModifiedTime,
ImageCache::CaptureImageWithSmallImageCallback{},
ImageCache::AbortCallback{},
std::move(auxiliaryData));
auto capture = [=](const QImage &image, const QImage &smallImage) {
m_storage.storeImage(id, currentModifiedTime, image, smallImage);
};
collector.start(name,
extraId,
std::move(auxiliaryData),
std::move(capture),
ImageCache::AbortCallback{});
}
void AsynchronousImageFactory::clean()
{
clearEntries();
m_generator.clean();
}
void AsynchronousImageFactory::wait()

View File

@@ -39,15 +39,14 @@ namespace QmlDesigner {
class TimeStampProviderInterface;
class ImageCacheStorageInterface;
class ImageCacheGeneratorInterface;
class ImageCacheCollectorInterface;
class AsynchronousImageFactory
{
public:
AsynchronousImageFactory(ImageCacheStorageInterface &storage,
ImageCacheGeneratorInterface &generator,
TimeStampProviderInterface &timeStampProvider);
TimeStampProviderInterface &timeStampProvider,
ImageCacheCollectorInterface &collector);
~AsynchronousImageFactory();
@@ -83,8 +82,8 @@ private:
Utils::SmallStringView extraId,
ImageCache::AuxiliaryData auxiliaryData,
ImageCacheStorageInterface &storage,
ImageCacheGeneratorInterface &generator,
TimeStampProviderInterface &timeStampProvider);
TimeStampProviderInterface &timeStampProvider,
ImageCacheCollectorInterface &collector);
void wait();
void clearEntries();
void stopThread();
@@ -95,8 +94,8 @@ private:
std::condition_variable m_condition;
std::thread m_backgroundThread;
ImageCacheStorageInterface &m_storage;
ImageCacheGeneratorInterface &m_generator;
TimeStampProviderInterface &m_timeStampProvider;
ImageCacheCollectorInterface &m_collector;
bool m_finishing{false};
};

View File

@@ -60,8 +60,10 @@ QString fileToString(const QString &filename)
} // namespace
ImageCacheCollector::ImageCacheCollector(ImageCacheConnectionManager &connectionManager)
ImageCacheCollector::ImageCacheCollector(ImageCacheConnectionManager &connectionManager,
ImageCacheCollectorNullImageHandling nullImageHandling)
: m_connectionManager{connectionManager}
, nullImageHandling{nullImageHandling}
{}
ImageCacheCollector::~ImageCacheCollector() = default;
@@ -89,7 +91,8 @@ void ImageCacheCollector::start(Utils::SmallStringView name,
model->setRewriterView(&rewriterView);
if (rewriterView.inErrorState() || !rewriterView.rootModelNode().metaInfo().isGraphicalItem()) {
abortCallback(ImageCache::AbortReason::Failed);
if (abortCallback)
abortCallback(ImageCache::AbortReason::Failed);
return;
}
@@ -98,12 +101,14 @@ void ImageCacheCollector::start(Utils::SmallStringView name,
if (stateNode.isValid())
rewriterView.setCurrentStateNode(stateNode);
auto callback = [captureCallback = std::move(captureCallback)](const QImage &image) {
QSize smallImageSize = image.size().scaled(QSize{96, 96}.boundedTo(image.size()),
Qt::KeepAspectRatio);
QImage smallImage = image.isNull() ? QImage{} : image.scaled(smallImageSize);
captureCallback(image, smallImage);
auto callback = [=, captureCallback = std::move(captureCallback)](const QImage &image) {
if (nullImageHandling == ImageCacheCollectorNullImageHandling::CaptureNullImage
|| !image.isNull()) {
QSize smallImageSize = image.size().scaled(QSize{96, 96}.boundedTo(image.size()),
Qt::KeepAspectRatio);
QImage smallImage = image.isNull() ? QImage{} : image.scaled(smallImageSize);
captureCallback(image, smallImage);
}
};
if (!m_target)
@@ -122,29 +127,21 @@ void ImageCacheCollector::start(Utils::SmallStringView name,
model->setNodeInstanceView({});
model->setRewriterView({});
if (!capturedDataArrived)
if (!capturedDataArrived && abortCallback)
abortCallback(ImageCache::AbortReason::Failed);
}
std::pair<QImage, QImage> ImageCacheCollector::createImage(Utils::SmallStringView filePath,
Utils::SmallStringView state,
const ImageCache::AuxiliaryData &auxiliaryData)
std::pair<QImage, QImage> ImageCacheCollector::createImage(Utils::SmallStringView,
Utils::SmallStringView,
const ImageCache::AuxiliaryData &)
{
Q_UNUSED(filePath)
Q_UNUSED(state)
Q_UNUSED(auxiliaryData)
return {};
}
QIcon ImageCacheCollector::createIcon(Utils::SmallStringView filePath,
Utils::SmallStringView state,
const ImageCache::AuxiliaryData &auxiliaryData)
QIcon ImageCacheCollector::createIcon(Utils::SmallStringView,
Utils::SmallStringView,
const ImageCache::AuxiliaryData &)
{
Q_UNUSED(filePath)
Q_UNUSED(state)
Q_UNUSED(auxiliaryData)
return {};
}

View File

@@ -45,10 +45,13 @@ class ImageCacheConnectionManager;
class RewriterView;
class NodeInstanceView;
enum class ImageCacheCollectorNullImageHandling { CaptureNullImage, DontCaptureNullImage };
class ImageCacheCollector final : public ImageCacheCollectorInterface
{
public:
ImageCacheCollector(ImageCacheConnectionManager &connectionManager);
ImageCacheCollector(ImageCacheConnectionManager &connectionManager,
ImageCacheCollectorNullImageHandling nullImageHandling = {});
~ImageCacheCollector();
@@ -72,6 +75,7 @@ public:
private:
ImageCacheConnectionManager &m_connectionManager;
QPointer<ProjectExplorer::Target> m_target;
ImageCacheCollectorNullImageHandling nullImageHandling{};
};
} // namespace QmlDesigner

View File

@@ -33,6 +33,7 @@ class TimeStampProvider : public TimeStampProviderInterface
{
public:
Sqlite::TimeStamp timeStamp(Utils::SmallStringView name) const override;
Sqlite::TimeStamp pause() const override { return 0; }
};
} // namespace QmlDesigner

View File

@@ -36,6 +36,7 @@ class TimeStampProviderInterface
{
public:
virtual Sqlite::TimeStamp timeStamp(Utils::SmallStringView name) const = 0;
virtual Sqlite::TimeStamp pause() const = 0;
protected:
~TimeStampProviderInterface() = default;

View File

@@ -137,7 +137,8 @@ void BaseConnectionManager::callCrashCallback()
{
std::lock_guard<std::mutex> lock{m_callbackMutex};
m_crashCallback();
if (m_crashCallback)
m_crashCallback();
}
} // namespace QmlDesigner

View File

@@ -50,7 +50,7 @@
#include <imagecache/imagecacheconnectionmanager.h>
#include <imagecache/imagecachegenerator.h>
#include <imagecache/imagecachestorage.h>
#include <imagecache/timestampprovider.h>
#include <imagecache/timestampproviderinterface.h>
#include <coreplugin/icore.h>
@@ -70,6 +70,23 @@ QString defaultImagePath()
return qobject_cast<::QmlProjectManager::QmlBuildSystem *>(target->buildSystem());
}
class TimeStampProvider : public TimeStampProviderInterface
{
public:
Sqlite::TimeStamp timeStamp(Utils::SmallStringView) const override
{
auto now = std::chrono::steady_clock::now();
return std::chrono::duration_cast<std::chrono::seconds>(now.time_since_epoch()).count();
}
Sqlite::TimeStamp pause() const override
{
using namespace std::chrono_literals;
return std::chrono::duration_cast<std::chrono::seconds>(1h).count();
}
};
} // namespace
class PreviewImageCacheData
@@ -81,11 +98,11 @@ public:
Sqlite::LockingMode::Normal};
ImageCacheStorage<Sqlite::Database> storage{database};
ImageCacheConnectionManager connectionManager;
ImageCacheCollector collector{connectionManager};
ImageCacheGenerator generator{collector, storage};
ImageCacheCollector collector{connectionManager,
ImageCacheCollectorNullImageHandling::DontCaptureNullImage};
TimeStampProvider timeStampProvider;
AsynchronousExplicitImageCache cache{storage};
AsynchronousImageFactory factory{storage, generator, timeStampProvider};
AsynchronousImageFactory factory{storage, timeStampProvider, collector};
};
class QmlDesignerProjectManagerProjectData
@@ -155,8 +172,10 @@ void QmlDesignerProjectManager::projectAdded(::ProjectExplorer::Project *project
void QmlDesignerProjectManager::aboutToRemoveProject(::ProjectExplorer::Project *)
{
m_imageCacheData->collector.setTarget(m_projectData->activeTarget);
m_projectData.reset();
if (m_projectData) {
m_imageCacheData->collector.setTarget(m_projectData->activeTarget);
m_projectData.reset();
}
}
void QmlDesignerProjectManager::projectRemoved(::ProjectExplorer::Project *) {}

View File

@@ -28,6 +28,8 @@
#include "qdsnewdialog.h"
#include <app/app_version.h>
#include <coreplugin/coreconstants.h>
#include <coreplugin/dialogs/restartdialog.h>
#include <coreplugin/editormanager/editormanager.h>
@@ -268,6 +270,24 @@ int ProjectModel::rowCount(const QModelIndex &) const
return ProjectExplorer::ProjectExplorerPlugin::recentProjects().count();
}
QString getQDSVersion(const QString &projectFilePath)
{
const QString defaultReturn = "";
Utils::FileReader reader;
if (!reader.fetch(Utils::FilePath::fromString(projectFilePath)))
return defaultReturn;
const QByteArray data = reader.data();
QRegularExpression regexp(R"x(qdsVersion: "(.*)")x");
QRegularExpressionMatch match = regexp.match(QString::fromUtf8(data));
if (!match.hasMatch())
return defaultReturn;
return ProjectModel::tr("Created with Qt Design Studio version: %1").arg(match.captured(1));
}
QString getMainQmlFile(const QString &projectFilePath)
{
const QString defaultReturn = "content/App.qml";
@@ -293,8 +313,8 @@ QString appQmlFile(const QString &projectFilePath)
static QString fromCamelCase(const QString &s) {
static QRegularExpression regExp1 {"(.)([A-Z][a-z]+)"};
static QRegularExpression regExp2 {"([a-z0-9])([A-Z])"};
const QRegularExpression regExp1 {"(.)([A-Z][a-z]+)"};
const QRegularExpression regExp2 {"([a-z0-9])([A-Z])"};
QString result = s;
result.replace(regExp1, "\\1 \\2");
result.replace(regExp2, "\\1 \\2");
@@ -302,15 +322,49 @@ static QString fromCamelCase(const QString &s) {
return result;
}
static QString resolutionFromConstants(const QString &projectFilePath)
{
const QFileInfo fileInfo(projectFilePath);
const QString fileName = fileInfo.dir().absolutePath()
+ "/" + "imports" + "/" + fileInfo.baseName() + "/Constants.qml";
Utils::FileReader reader;
if (!reader.fetch(Utils::FilePath::fromString(fileName)))
return {};
const QByteArray data = reader.data();
const QRegularExpression regexpWidth(R"x(readonly\s+property\s+int\s+width:\s+(\d*))x");
const QRegularExpression regexpHeight(R"x(readonly\s+property\s+int\s+height:\s+(\d*))x");
int width = -1;
int height = -1;
QRegularExpressionMatch match = regexpHeight.match(QString::fromUtf8(data));
if (match.hasMatch())
height = match.captured(1).toInt();
match = regexpWidth.match(QString::fromUtf8(data));
if (match.hasMatch())
width = match.captured(1).toInt();
if (width > 0 && height > 0)
return ProjectModel::tr("Resolution: %1x%2").arg(width).arg(height);
return {};
}
static QString description(const QString &projectFilePath)
{
const QString created = "Created: " +
QFileInfo(projectFilePath).fileTime(QFileDevice::FileBirthTime).toString();
const QString lastEdited = "Last Edited: " +
QFileInfo(projectFilePath).fileTime(QFileDevice::FileModificationTime).toString();
const QString created = ProjectModel::tr("Created: %1").arg(
QFileInfo(projectFilePath).fileTime(QFileDevice::FileBirthTime).toString());
const QString lastEdited = ProjectModel::tr("Last Edited: %1").arg(
QFileInfo(projectFilePath).fileTime(QFileDevice::FileModificationTime).toString());
return fromCamelCase(QFileInfo(projectFilePath).baseName()) + "\n" + created + "\n" + lastEdited;
return fromCamelCase(QFileInfo(projectFilePath).baseName()) + "\n\n" + created + "\n" + lastEdited
+ "\n" + resolutionFromConstants(projectFilePath)
+ "\n" + getQDSVersion(projectFilePath);
}
static QString tags(const QString &projectFilePath)
@@ -438,6 +492,26 @@ bool StudioWelcomePlugin::initialize(const QStringList &arguments, QString *erro
return true;
}
static bool showSplashScreen()
{
const QString lastQDSVersionEntry = "QML/Designer/lastQDSVersion";
QSettings *settings = Core::ICore::settings();
const QString lastQDSVersion = settings->value(lastQDSVersionEntry).toString();
const QString currentVersion = Core::Constants::IDE_VERSION_DISPLAY;
if (currentVersion != lastQDSVersion) {
settings->setValue(lastQDSVersionEntry, currentVersion);
return true;
}
return Utils::CheckableMessageBox::shouldAskAgain(Core::ICore::settings(),
DO_NOT_SHOW_SPLASHSCREEN_AGAIN_KEY);
}
void StudioWelcomePlugin::extensionsInitialized()
{
Core::ModeManager::activateMode(m_welcomeMode->id());
@@ -445,8 +519,7 @@ void StudioWelcomePlugin::extensionsInitialized()
// Enable QDS new project dialog
Core::ICore::setNewDialogFactory([](QWidget *parent) { return new QdsNewDialog(parent); });
if (Utils::CheckableMessageBox::shouldAskAgain(Core::ICore::settings(),
DO_NOT_SHOW_SPLASHSCREEN_AGAIN_KEY)) {
if (showSplashScreen()) {
connect(Core::ICore::instance(), &Core::ICore::coreOpened, this, [this] {
s_view = new QQuickWidget(Core::ICore::dialogParent());
s_view->setResizeMode(QQuickWidget::SizeRootObjectToView);
@@ -532,6 +605,8 @@ WelcomeMode::WelcomeMode()
setContextHelp("Qt Design Studio Manual");
setContext(Core::Context(Core::Constants::C_WELCOME_MODE));
QFontDatabase::addApplicationFont(":/studiofonts/TitilliumWeb-Regular.ttf");
m_modeWidget = new QQuickWidget;
m_modeWidget->setMinimumSize(1024, 768);
m_modeWidget->setResizeMode(QQuickWidget::SizeRootObjectToView);

View File

@@ -25,6 +25,7 @@
#include "googletest.h"
#include "imagecachecollectormock.h"
#include "mockimagecachegenerator.h"
#include "mockimagecachestorage.h"
#include "mocktimestampprovider.h"
@@ -41,67 +42,64 @@ class AsynchronousImageFactory : public testing::Test
protected:
AsynchronousImageFactory()
{
ON_CALL(mockTimeStampProvider, timeStamp(Eq("/path/to/Component.qml")))
ON_CALL(timeStampProviderMock, timeStamp(Eq("/path/to/Component.qml")))
.WillByDefault(Return(Sqlite::TimeStamp{123}));
}
protected:
Notification notification;
Notification waitInThread;
NiceMock<MockImageCacheStorage> mockStorage;
NiceMock<MockImageCacheGenerator> mockGenerator;
NiceMock<MockTimeStampProvider> mockTimeStampProvider;
QmlDesigner::AsynchronousImageFactory factory{mockStorage, mockGenerator, mockTimeStampProvider};
NiceMock<MockImageCacheStorage> storageMock;
NiceMock<ImageCacheCollectorMock> collectorMock;
NiceMock<MockTimeStampProvider> timeStampProviderMock;
QmlDesigner::AsynchronousImageFactory factory{storageMock, timeStampProviderMock, collectorMock};
QImage image1{10, 10, QImage::Format_ARGB32};
QImage smallImage1{1, 1, QImage::Format_ARGB32};
};
TEST_F(AsynchronousImageFactory, RequestImageRequestImageFromGenerator)
TEST_F(AsynchronousImageFactory, RequestImageRequestImageFromCollector)
{
EXPECT_CALL(mockGenerator,
generateImage(Eq("/path/to/Component.qml"),
IsEmpty(),
Eq(Sqlite::TimeStamp{123}),
_,
_,
VariantWith<Utils::monostate>(Utils::monostate{})))
.WillRepeatedly([&](auto, auto, auto, auto, auto, auto) { notification.notify(); });
EXPECT_CALL(collectorMock,
start(Eq("/path/to/Component.qml"),
IsEmpty(),
VariantWith<Utils::monostate>(Utils::monostate{}),
_,
_))
.WillRepeatedly([&](auto, auto, auto, auto, auto) { notification.notify(); });
factory.generate("/path/to/Component.qml");
notification.wait();
}
TEST_F(AsynchronousImageFactory, RequestImageWithExtraIdRequestImageFromGenerator)
TEST_F(AsynchronousImageFactory, RequestImageWithExtraIdRequestImageFromCollector)
{
EXPECT_CALL(mockGenerator,
generateImage(Eq("/path/to/Component.qml"),
Eq("foo"),
Eq(Sqlite::TimeStamp{123}),
_,
_,
VariantWith<Utils::monostate>(Utils::monostate{})))
.WillRepeatedly([&](auto, auto, auto, auto, auto, auto) { notification.notify(); });
EXPECT_CALL(collectorMock,
start(Eq("/path/to/Component.qml"),
Eq("foo"),
VariantWith<Utils::monostate>(Utils::monostate{}),
_,
_))
.WillRepeatedly([&](auto, auto, auto, auto, auto) { notification.notify(); });
factory.generate("/path/to/Component.qml", "foo");
notification.wait();
}
TEST_F(AsynchronousImageFactory, RequestImageWithAuxiliaryDataRequestImageFromGenerator)
TEST_F(AsynchronousImageFactory, RequestImageWithAuxiliaryDataRequestImageFromCollector)
{
std::vector<QSize> sizes{{20, 11}};
EXPECT_CALL(mockGenerator,
generateImage(Eq("/path/to/Component.qml"),
Eq("foo"),
Eq(Sqlite::TimeStamp{123}),
_,
_,
VariantWith<FontCollectorSizesAuxiliaryData>(AllOf(
Field(&FontCollectorSizesAuxiliaryData::sizes,
ElementsAre(QSize{20, 11})),
Field(&FontCollectorSizesAuxiliaryData::colorName, Eq(u"color")),
Field(&FontCollectorSizesAuxiliaryData::text, Eq(u"some text"))))))
.WillRepeatedly([&](auto, auto, auto, auto, auto, auto) { notification.notify(); });
EXPECT_CALL(collectorMock,
start(Eq("/path/to/Component.qml"),
Eq("foo"),
VariantWith<FontCollectorSizesAuxiliaryData>(
AllOf(Field(&FontCollectorSizesAuxiliaryData::sizes,
ElementsAre(QSize{20, 11})),
Field(&FontCollectorSizesAuxiliaryData::colorName, Eq(u"color")),
Field(&FontCollectorSizesAuxiliaryData::text, Eq(u"some text")))),
_,
_))
.WillRepeatedly([&](auto, auto, auto, auto, auto) { notification.notify(); });
factory.generate("/path/to/Component.qml",
"foo",
@@ -111,40 +109,34 @@ TEST_F(AsynchronousImageFactory, RequestImageWithAuxiliaryDataRequestImageFromGe
notification.wait();
}
TEST_F(AsynchronousImageFactory, DontRequestImageRequestImageFromGeneratorIfFileWasNotUpdated)
TEST_F(AsynchronousImageFactory, DontRequestImageRequestImageFromCollectorIfFileWasUpdatedRecently)
{
ON_CALL(mockStorage, fetchHasImage(Eq("/path/to/Component.qml"))).WillByDefault([&](auto) {
ON_CALL(storageMock, fetchModifiedImageTime(Eq("/path/to/Component.qml"))).WillByDefault([&](auto) {
notification.notify();
return true;
return Sqlite::TimeStamp{124};
});
ON_CALL(mockStorage, fetchModifiedImageTime(Eq("/path/to/Component.qml")))
.WillByDefault(Return(Sqlite::TimeStamp{124}));
ON_CALL(mockTimeStampProvider, timeStamp(Eq("/path/to/Component.qml")))
.WillByDefault(Return(Sqlite::TimeStamp{124}));
ON_CALL(timeStampProviderMock, timeStamp(Eq("/path/to/Component.qml")))
.WillByDefault(Return(Sqlite::TimeStamp{125}));
ON_CALL(timeStampProviderMock, timeStamp(Eq("/path/to/Component.qml")))
.WillByDefault(Return(Sqlite::TimeStamp{1}));
EXPECT_CALL(mockGenerator, generateImage(_, _, _, _, _, _)).Times(0);
EXPECT_CALL(collectorMock, start(_, _, _, _, _)).Times(0);
factory.generate("/path/to/Component.qml");
notification.wait();
}
TEST_F(AsynchronousImageFactory,
RequestImageRequestImageFromGeneratorIfFileWasNotUpdatedButTheImageIsNull)
TEST_F(AsynchronousImageFactory, RequestImageRequestImageFromCollectorIfFileWasNotUpdatedRecently)
{
ON_CALL(mockStorage, fetchHasImage(Eq("/path/to/Component.qml"))).WillByDefault(Return(false));
ON_CALL(mockStorage, fetchModifiedImageTime(Eq("/path/to/Component.qml")))
.WillByDefault(Return(Sqlite::TimeStamp{124}));
ON_CALL(mockTimeStampProvider, timeStamp(Eq("/path/to/Component.qml")))
.WillByDefault(Return(Sqlite::TimeStamp{124}));
ON_CALL(storageMock, fetchModifiedImageTime(Eq("/path/to/Component.qml")))
.WillByDefault(Return(Sqlite::TimeStamp{123}));
ON_CALL(timeStampProviderMock, timeStamp(Eq("/path/to/Component.qml")))
.WillByDefault(Return(Sqlite::TimeStamp{125}));
ON_CALL(timeStampProviderMock, pause()).WillByDefault(Return(Sqlite::TimeStamp{1}));
EXPECT_CALL(mockGenerator,
generateImage(Eq("/path/to/Component.qml"),
IsEmpty(),
Eq(Sqlite::TimeStamp{124}),
_,
_,
VariantWith<Utils::monostate>(Utils::monostate{})))
.WillRepeatedly([&](auto, auto, auto, auto, auto, auto) { notification.notify(); });
EXPECT_CALL(collectorMock, start(_, _, _, _, _)).WillOnce([&](auto, auto, auto, auto, auto) {
notification.notify();
});
factory.generate("/path/to/Component.qml");
notification.wait();
@@ -152,39 +144,57 @@ TEST_F(AsynchronousImageFactory,
TEST_F(AsynchronousImageFactory, CleanRemovesEntries)
{
EXPECT_CALL(mockGenerator, generateImage(Eq("/path/to/Component1.qml"), _, _, _, _, _))
.WillRepeatedly([&](auto, auto, auto, auto, auto, auto) { waitInThread.wait(); });
EXPECT_CALL(collectorMock, start(Eq("/path/to/Component1.qml"), _, _, _, _))
.WillRepeatedly([&](auto, auto, auto, auto, auto) { waitInThread.wait(); });
factory.generate("/path/to/Component1.qml");
EXPECT_CALL(mockGenerator, generateImage(Eq("/path/to/Component3.qml"), _, _, _, _, _)).Times(0);
EXPECT_CALL(collectorMock, start(Eq("/path/to/Component3.qml"), _, _, _, _)).Times(0);
factory.generate("/path/to/Component3.qml");
factory.clean();
waitInThread.notify();
}
TEST_F(AsynchronousImageFactory, CleanCallsGeneratorClean)
{
EXPECT_CALL(mockGenerator, clean()).Times(AtLeast(1));
factory.clean();
}
TEST_F(AsynchronousImageFactory, AfterCleanNewJobsWorks)
{
factory.clean();
EXPECT_CALL(mockGenerator,
generateImage(Eq("/path/to/Component.qml"),
IsEmpty(),
Eq(Sqlite::TimeStamp{123}),
_,
_,
VariantWith<Utils::monostate>(Utils::monostate{})))
.WillRepeatedly([&](auto, auto, auto, auto, auto, auto) { notification.notify(); });
EXPECT_CALL(collectorMock,
start(Eq("/path/to/Component.qml"),
IsEmpty(),
VariantWith<Utils::monostate>(Utils::monostate{}),
_,
_))
.WillRepeatedly([&](auto, auto, auto, auto, auto) { notification.notify(); });
factory.generate("/path/to/Component.qml");
notification.wait();
}
TEST_F(AsynchronousImageFactory, CaptureImageCallbackStoresImage)
{
ON_CALL(storageMock, fetchModifiedImageTime(Eq("/path/to/Component.qml")))
.WillByDefault(Return(Sqlite::TimeStamp{123}));
ON_CALL(timeStampProviderMock, timeStamp(Eq("/path/to/Component.qml")))
.WillByDefault(Return(Sqlite::TimeStamp{125}));
ON_CALL(timeStampProviderMock, pause()).WillByDefault(Return(Sqlite::TimeStamp{1}));
ON_CALL(collectorMock,
start(Eq("/path/to/Component.qml"),
Eq("id"),
VariantWith<Utils::monostate>(Utils::monostate{}),
_,
_))
.WillByDefault([&](auto, auto, auto, auto capture, auto) { capture(image1, smallImage1); });
EXPECT_CALL(storageMock,
storeImage(Eq("/path/to/Component.qml+id"),
Sqlite::TimeStamp{125},
Eq(image1),
Eq(smallImage1)))
.WillOnce([&](auto, auto, auto, auto) { notification.notify(); });
factory.generate("/path/to/Component.qml", "id");
notification.wait();
}
} // namespace

View File

@@ -33,4 +33,5 @@ class MockTimeStampProvider : public QmlDesigner::TimeStampProviderInterface
{
public:
MOCK_METHOD(Sqlite::TimeStamp, timeStamp, (Utils::SmallStringView name), (const, override));
MOCK_METHOD(Sqlite::TimeStamp, pause, (), (const, override));
};