Merge "Merge remote-tracking branch 'origin/6.0'"
82
dist/changes-6.0.2.md
vendored
Normal 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
|
Before Width: | Height: | Size: 15 KiB |
@@ -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]
|
||||
*/
|
@@ -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
|
||||
*/
|
||||
|
@@ -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}.
|
||||
*/
|
||||
|
@@ -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.
|
||||
*/
|
||||
|
@@ -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
|
||||
|
@@ -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}.
|
||||
*/
|
||||
|
After Width: | Height: | Size: 25 KiB |
After Width: | Height: | Size: 9.8 KiB |
After Width: | Height: | Size: 22 KiB |
After Width: | Height: | Size: 5.5 KiB |
After Width: | Height: | Size: 18 KiB |
BIN
doc/qtdesignstudio/examples/doc/images/snow-particles.png
Normal file
After Width: | Height: | Size: 35 KiB |
198
doc/qtdesignstudio/examples/doc/rainSnowParticles.qdoc
Normal 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
|
||||
*/
|
Before Width: | Height: | Size: 9.6 KiB |
Before Width: | Height: | Size: 9.2 KiB |
Before Width: | Height: | Size: 14 KiB After Width: | Height: | Size: 109 KiB |
@@ -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
|
||||
|
@@ -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' )) }" ]
|
||||
}
|
||||
},
|
||||
{
|
||||
|
@@ -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;
|
||||
|
@@ -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; }
|
||||
|
||||
|
@@ -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)
|
||||
|
@@ -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)
|
||||
|
@@ -50,8 +50,6 @@ private:
|
||||
bool checkConfiguration(QString *errorMessage) override;
|
||||
|
||||
static void reportError(const QString &message);
|
||||
|
||||
bool m_hostKnownOk = false;
|
||||
};
|
||||
|
||||
} // namespace CodePaster
|
||||
|
@@ -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);
|
||||
}
|
||||
|
@@ -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);
|
||||
}
|
||||
|
@@ -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);
|
||||
}
|
||||
|
||||
|
@@ -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()
|
||||
|
@@ -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};
|
||||
};
|
||||
|
||||
|
@@ -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 {};
|
||||
}
|
||||
|
||||
|
@@ -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
|
||||
|
@@ -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
|
||||
|
@@ -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;
|
||||
|
@@ -137,7 +137,8 @@ void BaseConnectionManager::callCrashCallback()
|
||||
{
|
||||
std::lock_guard<std::mutex> lock{m_callbackMutex};
|
||||
|
||||
m_crashCallback();
|
||||
if (m_crashCallback)
|
||||
m_crashCallback();
|
||||
}
|
||||
} // namespace QmlDesigner
|
||||
|
||||
|
@@ -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 *) {}
|
||||
|
@@ -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);
|
||||
|
@@ -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
|
||||
|
@@ -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));
|
||||
};
|
||||
|