Merge remote-tracking branch 'origin/4.14'

Conflicts:
	src/plugins/projectexplorer/gcctoolchain.cpp

Change-Id: I2136ba89d3aa3c4c2a0e7a4f9d8ba9cec32924ce
This commit is contained in:
Eike Ziller
2020-11-30 16:14:32 +01:00
92 changed files with 1268 additions and 655 deletions

View File

@@ -48,3 +48,17 @@ macro.beginfloatright.HTML = "<div style=\"float: right; margin-left: 2em\">"
macro.endfloat.HTML = "</div>" macro.endfloat.HTML = "</div>"
macro.clearfloat.HTML = "<br style=\"clear: both\" />" macro.clearfloat.HTML = "<br style=\"clear: both\" />"
macro.emptyspan.HTML = "<span></span>" macro.emptyspan.HTML = "<span></span>"
# Embed YouTube content by video ID - Example: \youtube dQw4w9WgXcQ
# Also requires a <ID>.jpg thumbnail for offline docs. In .qdocconf, add:
#
# HTML.extraimages += images/dQw4w9WgXcQ.jpg
# qhp.ProjectName.extraFiles += images/dQw4w9WgXcQ.jpg
#
macro.youtube.HTML = "<div class=\"video\">\n<span class=\"vspan\"></span>\n" \
"<iframe src=\"https://www.youtube.com/embed/\1\"" \
"frameborder=\"0\" allowfullscreen>\n" \
"<a href=\"https://www.youtube.com/watch/?v=\1\">\n"\
"<img src=\"images/\1.jpg\"" \
"title=\"Click to play in a browser\" /></a>\n" \
"</iframe></div>\n"

View File

@@ -43,7 +43,7 @@
\if defined(qtdesignstudio) \if defined(qtdesignstudio)
For guidelines on how to achieve best results when importing assets, see For guidelines on how to achieve best results when importing assets, see
\l {Exporting Artwork from Design Tools}. \l {Exporting from Design Tools}.
\endif \endif
\section1 Naming Conventions \section1 Naming Conventions

View File

@@ -60,7 +60,9 @@
selected item. The item ID is displayed in the \uicontrol Item selected item. The item ID is displayed in the \uicontrol Item
column. column.
\li Double-click the value in the \uicontrol Property column to give a \li Double-click the value in the \uicontrol Property column to give a
name to the property. name to the property. Property names must begin with a lower case
letter and can only contain letters, numbers, and underscores.
JavaScript \e {reserved words} are not valid property names.
\li Double-click the value in the \uicontrol {Property Type} column to \li Double-click the value in the \uicontrol {Property Type} column to
specify the \l{Supported Property Types}{type of the property}. specify the \l{Supported Property Types}{type of the property}.
\li Double-click the value in the \uicontrol {Property Value} column \li Double-click the value in the \uicontrol {Property Value} column

View File

@@ -42,19 +42,20 @@
for you. for you.
\endif \endif
Qt Quick enables you to build UIs around the behavior of Qt Quick enables you to build UIs around the behavior of \e components and
\e components and how they connect with one another. You how they connect with one another. You create components using Qt Quick and
create components using Qt Quick and QML types that are available in QML types that are available in the \uicontrol Library view in the Design
the Design mode. You can specify values for the \e properties of a mode. You can specify values for the \e properties of a
component to change its appearance and behavior. All QML types have a component to change its appearance and behavior. All QML types have a
set of predefined properties, some of which control things that are set of predefined properties, some of which control things that are
visible to users, while others are used behind the scene. visible to users, while others are used behind the scene.
While it is useful to learn the basics of Qt Quick, you can also rely on While it is useful to learn the basics of Qt Quick, you can also rely on
\QMLD to write the code for you when you drag-and-drop the ready-made \QMLD to write the code for you when you drag-and-drop the ready-made
components to the \uicontrol {Form Editor} view and change them to your components from the \uicontrol Library view to the \uicontrol {Form Editor}
liking by modifying their properties in the \uicontrol Properties view in or \uicontrol Navigator view and change them to your liking by modifying
the Design mode. You can always check up details in the extensive Qt Quick their properties in the \uicontrol Properties view.
You can always check up details in the extensive Qt Quick
documentation by pressing \key F1. documentation by pressing \key F1.
\list \list
@@ -62,9 +63,8 @@
\if defined(qtdesignstudio) \if defined(qtdesignstudio)
\li \l {Designing Application Flows} \li \l {Designing Application Flows}
After you export and import your artwork, you can design the You can design an application in the form of a \e {schematic diagram}
application flow in the form of a \e {schematic diagram} that that shows all significant components of an application UI and their
shows all significant components of an application UI and their
interconnections by means of symbols. This results in an interconnections by means of symbols. This results in an
interactive prototype that can be clicked through to simulate interactive prototype that can be clicked through to simulate
the user experience of the application. the user experience of the application.
@@ -72,16 +72,15 @@
\li \l {Creating Components} \li \l {Creating Components}
In addition to your imported artwork, you can use the Design You can enhance imported designs by customizing ready-made
mode to customize ready-made components or design any custom form components or design custom forms and shapes directly as
and shape directly as QML types. You can import visual assets in QML types. You can import visual assets in various formats,
various formats, such as PNG, JPG, and SVG for use in the such as PNG, JPG, and SVG for use in the components.
components.
\li \l {Managing Item Hierarchy} \li \l {Managing Item Hierarchy}
You can manage the items in the current QML file and their You can manage the items in the current QML file and their
relationships in the \uicontrol Navigator. relationships in the \uicontrol Navigator view.
\li \l {Specifying Item Properties} \li \l {Specifying Item Properties}
@@ -92,6 +91,13 @@
type. You can specify properties for your components in the type. You can specify properties for your components in the
\uicontrol Properties view. \uicontrol Properties view.
\li \l {Positioning Items}
The position of an item in a UI can be either absolute or relative
to other items. While manual positioning is efficient for a static
UI, consider the other available method, such as anchors, layouts,
positioners, and property bindings, for dynamic UIs.
\li \l {Using Custom Fonts} \li \l {Using Custom Fonts}
You can load custom fonts to \QMLD and use them in your designs. You can load custom fonts to \QMLD and use them in your designs.

View File

@@ -418,6 +418,52 @@
optipng -o 7 -strip all doc/images/<screenshot_name> optipng -o 7 -strip all doc/images/<screenshot_name>
\endcode \endcode
\section2 Linking to Youtube Videos
You can use the \c {\youtube} macro to link to a video on Youtube. The HTML
docs show a thumbnail of the video with a play button.
The support for the macro is defined in the
\c {qtcreator\doc\config\macros.qdocconf} file. To use the
macro, you need to save a thumbnail of the video in
\c {qtcreator\doc\qtcreator\images\videoicons} or
\c {qtcreator\doc\qtdesignstudio\images\videoicons}.
You can use the following URL to open the thumbnail image in a browser:
\c {https://img.youtube.com/vi/<ID>/0.jpg}. The \e {<ID>} is the ID of
the video on Youtube. For example, if the URL to the video is
\c {https://www.youtube.com/watch?v=9ihYeC0YJ0M&feature=youtu.be},
the ID is \c 9ihYeC0YJ0M. Save the image file as \c {9ihYeC0YJ0M.jpg}.
You must add the filename of the thumbnail file to
\c {\qtcreator\doc\qtcreator\config\qtcreator-project.qdocconf} and
\c {\qtcreator\doc\qtdesignstudio\config\qtdesignstudio.qdocconf}
to the value of the \c {HTML.extraimages,qhp.qtcreator.extraFiles}
or \c {HTML.extraimages,qhp.qtdesignstudio.extraFiles} option.
If you'll only link to the video from the \QC Manual or the \QDS Manual,
you'll only need to add the thumbnail filename to the \c .qdocconf file
for that project.
For example, to enable linking to a video with the thumbnail filename
\c 9ihYeC0YJ0M.jpg in the \QDS Manual, the \c {qtdesignstudio.qdocconf}
file should contain the following entry:
\code
{HTML.extraimages,qhp.qtdesignstudio.extraFiles} += ../../config/images/commercial.png \
../images/videoicons/9ihYeC0YJ0M.jpg \
../images/videoicons/aV6kFxH3Xws.jpg \
../images/videoicons/ZzbucmQPU44.jpg
\endcode
To add a link to the video in text, you would write:
\code
\youtube 9ihYeC0YJ0M
\endcode
\note Leave out the filename extension when referring to the thumbnail.
\section1 Building Documentation \section1 Building Documentation
You use QDoc to build the documentation. Build the documentation before You use QDoc to build the documentation. Build the documentation before

View File

@@ -69,8 +69,12 @@ exampledirs = ../examples/ \
../../qtcreator/examples ../../qtcreator/examples
examples.fileextensions += *.qml *.svg *.ts *.qm examples.fileextensions += *.qml *.svg *.ts *.qm
HTML.extraimages = ../../config/images/commercial.png {HTML.extraimages,qhp.qtdesignstudio.extraFiles} += ../../config/images/commercial.png \
qhp.QtCreator.extraFiles = ../../config/images/commercial.png ../images/videoicons/SsFWyUeAA_4.jpg \
../images/videoicons/9ihYeC0YJ0M.jpg \
../images/videoicons/aV6kFxH3Xws.jpg \
../images/videoicons/ZzbucmQPU44.jpg
depends += qtwidgets \ depends += qtwidgets \
qtcore \ qtcore \

Binary file not shown.

Before

Width:  |  Height:  |  Size: 48 KiB

After

Width:  |  Height:  |  Size: 41 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 228 KiB

After

Width:  |  Height:  |  Size: 206 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 8.1 KiB

After

Width:  |  Height:  |  Size: 12 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 18 KiB

After

Width:  |  Height:  |  Size: 14 KiB

View File

@@ -42,12 +42,12 @@
\section1 Exporting from Adobe Photoshop \section1 Exporting from Adobe Photoshop
We use Adobe Photoshop to design our application and \QB to export our We use Adobe Photoshop to design our application and \QB to export our
artwork to \QDS as PNG images and custom QML types. design to \QDS as PNG images and custom QML types.
Before we can begin, we must set up \QB as instructed in Before we can begin, we must set up \QB as instructed in
\l{Exporting Designs from Adobe Photoshop}. \l{Exporting Designs from Adobe Photoshop}.
We organize our artwork in Photoshop using artboards as instructed in We organize our design in Photoshop using artboards as instructed in
\l{Organizing Assets}. \l{Organizing Assets}.
\QB automatically proposes identifiers for all groups and layers. The ids \QB automatically proposes identifiers for all groups and layers. The ids
@@ -116,10 +116,10 @@
To be able to use the type, we added the statement that imports the To be able to use the type, we added the statement that imports the
Qt Quick Studio Effects module: \c {QtQuick.Studio.Effects 1.0}. Qt Quick Studio Effects module: \c {QtQuick.Studio.Effects 1.0}.
We specify that the artwork to which we want to apply the effect is a We specify that the component to which we want to apply the effect is a
child of the effect. We then specify the radius property for the effect, child of the effect. We then specify the radius property for the effect,
in the \uicontrol {QML Properties} field. We can modify the property in in the \uicontrol {QML Properties} field. We can modify the property in
\QDS. the \uicontrol Radius field in the \uicontrol Properties view in \QDS.
\image webinardemo-blureffect.png "FastBlurItem QML item in Design mode" \image webinardemo-blureffect.png "FastBlurItem QML item in Design mode"
@@ -142,18 +142,18 @@
We want to animate the contents of the \e largePopup artboard in \QDS, so We want to animate the contents of the \e largePopup artboard in \QDS, so
we export each group and layer as a child. we export each group and layer as a child.
\section2 Exporting Artwork \section2 Exporting Our Design
When we have specified settings for all the artboards and the groups and When we have specified settings for all the artboards and the groups and
layers in them, we select \uicontrol Export to copy the assets and metadata layers in them, we select \uicontrol Export to copy the assets and metadata
to the export path we specified. to the export path we specified.
\section1 Importing Artwork \section1 Importing Our Design
After using \QB in Adobe Photoshop to export our artwork, we import it into After using \QB in Adobe Photoshop to export our design, we import it into
a project that we create in \QDS, as instructed in \l{Importing Designs}. a project that we create in \QDS, as instructed in \l{Importing Designs}.
If we need to make changes in Photoshop later and export our artwork again, If we need to make changes in Photoshop later and export our design again,
\QDS will try to merge our changes during the import, so that none of the \QDS will try to merge our changes during the import, so that none of the
changes we mage in \QDS are lost. changes we mage in \QDS are lost.
@@ -185,7 +185,7 @@
\image webinardemo-states.png "Popup states in the States view" \image webinardemo-states.png "Popup states in the States view"
For more information about using states, see \l {Creating Animations}. For more information about using states, see \l {Creating States}.
We then use the \uicontrol Timeline view to add animations that are run We then use the \uicontrol Timeline view to add animations that are run
when moving from one state to another. when moving from one state to another.

Binary file not shown.

Before

Width:  |  Height:  |  Size: 25 KiB

After

Width:  |  Height:  |  Size: 17 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 7.6 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 20 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 2.3 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 2.8 KiB

View File

@@ -31,7 +31,7 @@
\title Exporting Designs from Adobe Illustrator \title Exporting Designs from Adobe Illustrator
Even though \QDS does not provide a specific export bridge for Adobe Even though \QDS does not provide a specific export bridge for Adobe
Illustrator, you can create artwork in it and export it to \QDS in Illustrator, you can desing UIs in it and export your designs to \QDS in
the following ways: the following ways:
\list \list

View File

@@ -28,7 +28,7 @@
\page qtbridge-overview.html \page qtbridge-overview.html
\nextpage qtbridge-ai.html \nextpage qtbridge-ai.html
\title Exporting Artwork from Design Tools \title Exporting from Design Tools
You need to use \QB to first export 2D assets from design tools and then to You need to use \QB to first export 2D assets from design tools and then to
\l{Importing Designs}{import} them into \QDS. \l{Importing Designs}{import} them into \QDS.
@@ -56,12 +56,12 @@
\li \l{Exporting Designs from Adobe Photoshop} \li \l{Exporting Designs from Adobe Photoshop}
You can use the \QBPS export tool in Adobe Photoshop to convert You can use the \QBPS export tool in Adobe Photoshop to convert
artwork into \e {.metadata} format that you can import into designs into \e {.metadata} format that you can import into
projects in \QDS. projects in \QDS.
\li \l{Exporting Designs from Sketch} \li \l{Exporting Designs from Sketch}
You can use the \QBSK export tool in Sketch to convert artwork into You can use the \QBSK export tool in Sketch to convert designs into
metadata that you can import into projects in \QDS. metadata that you can import into projects in \QDS.
\li \l{Exporting 3D Assets} \li \l{Exporting 3D Assets}

View File

@@ -44,7 +44,7 @@
\li \l{Setting Up Qt Bridge for Adobe Photoshop} \li \l{Setting Up Qt Bridge for Adobe Photoshop}
You must install and set up the \QBPS export tool before you can use You must install and set up the \QBPS export tool before you can use
it to export artwork. it to export designs.
\li \l{Using Qt Bridge for Adobe Photoshop} \li \l{Using Qt Bridge for Adobe Photoshop}
@@ -52,4 +52,6 @@
Photoshop, you should follow the guidelines for working with Photoshop, you should follow the guidelines for working with
Photoshop and organizing your assets. Photoshop and organizing your assets.
\endlist \endlist
\include qtbridge-tutorial-links.qdocinc qtpsbridge videos
*/ */

View File

@@ -60,7 +60,7 @@
will be imported as a single QML file that can contain other assets. A child will be imported as a single QML file that can contain other assets. A child
will be imported as a single image file that you can use within QML files. will be imported as a single image file that you can use within QML files.
If you plan to use pieces of your artwork as separate images in the UI, If you plan to use pieces of your design as separate images in the UI,
group them on an artboard as separate layers. You can then export the group group them on an artboard as separate layers. You can then export the group
as a component and each layer within it as a child. The children are as a component and each layer within it as a child. The children are
imported to \QDS as separate PNG files that you can use as image sources. imported to \QDS as separate PNG files that you can use as image sources.
@@ -249,15 +249,6 @@
In the \QBPS \uicontrol Settings dialog, select \uicontrol {Override JSX Script} to set the In the \QBPS \uicontrol Settings dialog, select \uicontrol {Override JSX Script} to set the
override JSX script. override JSX script.
For more information, watch a video tutorial and webinar about using \QBPS:
\list
\li \l{https://resources.qt.io/development-topic-ui-design/qtdesignstudio-clustertutorial-partone}
{Building an Instrument Cluster for Your Car HMI, Part 1}
\li \l{https://www.youtube.com/watch?v=ZzbucmQPU44}
{From Photoshop to Prototype with Qt Design Studio}
\endlist
\section1 Importing Metadata & Assets \section1 Importing Metadata & Assets
\QBPS can import metadata generated from other tools and generate a Photoshop document. A \QBPS can import metadata generated from other tools and generate a Photoshop document. A

View File

@@ -44,7 +44,7 @@
\li \l{Setting Up Qt Bridge for Sketch} \li \l{Setting Up Qt Bridge for Sketch}
You must install Sketch and the \QBSK export tool before you can use You must install Sketch and the \QBSK export tool before you can use
the tool to export artwork. the tool to export designs.
\li \l{Using Qt Bridge for Sketch} \li \l{Using Qt Bridge for Sketch}
@@ -52,4 +52,6 @@
Sketch, you should follow the guidelines for working with Sketch and Sketch, you should follow the guidelines for working with Sketch and
organizing your assets. organizing your assets.
\endlist \endlist
\include qtbridge-tutorial-links.qdocinc qtsketchbridge tutorials
*/ */

View File

@@ -0,0 +1,64 @@
/****************************************************************************
**
** Copyright (C) 2020 The Qt Company Ltd.
** Contact: https://www.qt.io/licensing/
**
** This file is part of the Qt Bridge 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.
**
****************************************************************************/
//! [qtpsbridge videos]
\section1 \QBPS Videos
For more information, watch a video tutorial and webinar about using \QBPS
that are also accessible from the \uicontrol Tutorials tab of the Welcome
mode:
\list
\li Building an Instrument Cluster for Your Car HMI, Part 1
\youtube aV6kFxH3Xws
You can access the Cluster tutorial source files in the
\uicontrol Examples tab.
\li From Photoshop to Prototype with Qt Design Studio
\youtube ZzbucmQPU44
\endlist
//! [qtpsbridge videos]
//! [qtsketchbridge tutorials]
\section1 \QBSK Tutorials
For more information, read the tutorials about using \QBSK that are also
accessible from the \uicontrol Tutorials tab of the Welcome mode:
\list
\li \l{https://www.qt.io/blog/qt-design-studio-sketch-bridge-tutorial-part-1}
{Sketch Bridge Tutorial Part 1}
\li \l{https://www.qt.io/blog/qt-design-studio-sketch-bridge-tutorial-part-2}
{Sketch Bridge Tutorial Part 2}
\endlist
//! [qtsketchbridge tutorials]

View File

@@ -30,10 +30,8 @@
\title Designing Application Flows \title Designing Application Flows
After you \l {Exporting Artwork from Design Tools}{export} your artwork from You can design the application flow in the form of a \e {schematic diagram}
your favorite design tool and \l{Importing Designs}{import} it to \QDS, you that shows all significant components of an application UI and their
can design the application flow in the form of a \e {schematic diagram} that
shows all significant components of an application UI and their
interconnections by means of symbols. This results in an interactive interconnections by means of symbols. This results in an interactive
prototype that can be clicked through to simulate the user experience of prototype that can be clicked through to simulate the user experience of
the application. The QML code is created in the background and can be used the application. The QML code is created in the background and can be used

View File

@@ -38,8 +38,8 @@
The \uicontrol Tutorials tab contains links to video tutorials that provide The \uicontrol Tutorials tab contains links to video tutorials that provide
more information about \QDS. more information about \QDS.
You can access the Cluster tutorial source files in the \uicontrol Examples \include qtbridge-tutorial-links.qdocinc qtpsbridge videos
tab. \include qtbridge-tutorial-links.qdocinc qtsketchbridge tutorials
\section1 Examples \section1 Examples

View File

@@ -30,9 +30,9 @@
\title Getting Started \title Getting Started
Typically, you as a designer would create artwork in imaging and design Typically, you as a designer would design a UI using imaging and design
tools, such as Adobe Photoshop, Sketch, Blender, or Maya, and then send it tools, such as Adobe Photoshop, Sketch, Blender, or Maya, and then send your
to a developer for adding it to the application. With the \QB export tool, design to a developer for implementation. With the \QB export tool,
you can convert 2D assets into \l {Qt Quick} files. You can use the export you can convert 2D assets into \l {Qt Quick} files. You can use the export
functionality of 3D graphics tools to save your 3D assets in a format functionality of 3D graphics tools to save your 3D assets in a format
supported by \QDS. You can import the 2D and 3D assets into \QDS for supported by \QDS. You can import the 2D and 3D assets into \QDS for
@@ -46,8 +46,8 @@
The workflow consists of the following steps: The workflow consists of the following steps:
\list 1 \list 1
\li Export your artwork from a design tool. \li Export your design from a design tool.
\li Create a project in \QDS and import your artwork to it. \li Create a project in \QDS and import your design to it.
\li Create reusable components in the Design mode. \li Create reusable components in the Design mode.
\li Animate your design with the timeline and easing curve editor. \li Animate your design with the timeline and easing curve editor.
\li Create interactions using states and connections. \li Create interactions using states and connections.
@@ -59,16 +59,16 @@
way around \QDS: way around \QDS:
\list \list
\li \l {Exporting Artwork from Design Tools} \li \l {Exporting from Design Tools}
Describes how to export 2D and 3D assets into files that Describes how to export designs containing 2D and 3D assets into
you can import to projects in \QDS. files that you can import to projects in \QDS.
\li \l {User Interface} \li \l {User Interface}
Describes the parts and basic features of \QDS. Describes the parts and basic features of \QDS.
\li \l{Editing QML Files in Design Mode} \li \l{Editing QML Files in Design Mode}
Describes the parts and basic features of the Design mode. Describes the views and basic features of the Design mode.
This is where you'll do most of your work. This is where you'll do most of your work.
\li \l {Tutorials} \li \l {Tutorials}

View File

@@ -30,13 +30,13 @@
\title Importing 2D Assets \title Importing 2D Assets
\image studio-imported-assets.png "Artwork imported into Qt Design Studio" \image studio-imported-assets.png "UI imported into Qt Design Studio"
\QB enables you to export assets and then import them to a \QDS project \QB enables you to export assets and then import them to a \QDS project
as image and QML files for editing in the \uicontrol {Form Editor}. If you as image and QML files for editing in the \uicontrol {Form Editor}. If you
make changes to your design in the design tool, you can merge the changes make changes to your design in the design tool, you can merge the changes
into existing QML files without overwriting the changes you have made in into existing QML files without overwriting the changes you have made in
\QDS. For more information, see \l {Exporting Artwork from Design Tools}. \QDS. For more information, see \l {Exporting from Design Tools}.
\note Attempting to import assets exported on another system might fail. \note Attempting to import assets exported on another system might fail.
@@ -48,8 +48,9 @@
\list 1 \list 1
\li Select \uicontrol File > \uicontrol {New File or Project} > \li Select \uicontrol File > \uicontrol {New File or Project} >
\uicontrol General > \uicontrol Choose, and follow the \uicontrol General > \uicontrol {Qt Quick Application - Empty} >
instructions of the wizard to create an empty project. \uicontrol Choose, and follow the instructions of the wizard to
create an empty project.
\li In \uicontrol Projects, double-click \e Screen01.ui.qml to move to \li In \uicontrol Projects, double-click \e Screen01.ui.qml to move to
the Design mode. the Design mode.
\li Select \uicontrol Library > \uicontrol Assets > \li Select \uicontrol Library > \uicontrol Assets >
@@ -70,6 +71,9 @@
QML files to. QML files to.
\li In the \uicontrol Assets field, you can change the folder to copy \li In the \uicontrol Assets field, you can change the folder to copy
the image files to. the image files to.
\li Select the \uicontrol {Create sub directory for each metadata}
check box to copy the directory structure from the metadata file
to \QDS.
\li Deselect the \uicontrol {Import assets} check box if you only want \li Deselect the \uicontrol {Import assets} check box if you only want
to create QML files. to create QML files.
\li Deselect the \uicontrol {Generate QML} check box if you only \li Deselect the \uicontrol {Generate QML} check box if you only
@@ -100,19 +104,6 @@
\uicontrol {Asset Import} dialog while importing, fix the issues in \uicontrol {Asset Import} dialog while importing, fix the issues in
design tool and export the assets again. design tool and export the assets again.
\section1 \QB Videos \include qtbridge-tutorial-links.qdocinc qtpsbridge videos
\include qtbridge-tutorial-links.qdocinc qtsketchbridge tutorials
For more information, see the \QB tutorials that are also accessible from
the \uicontrol Tutorials tab of the Welcome mode:
\list
\li \l{https://resources.qt.io/development-topic-ui-design/qtdesignstudio-clustertutorial-partone}
{Building an Instrument Cluster for Your Car HMI, Part 1} (\QBPS)
\li \l{https://www.youtube.com/watch?v=ZzbucmQPU44}
{From Photoshop to Prototype with Qt Design Studio}
\li \l{https://www.qt.io/blog/qt-design-studio-sketch-bridge-tutorial-part-1}
{Sketch Bridge Tutorial Part 1}
\li \l{https://www.qt.io/blog/qt-design-studio-sketch-bridge-tutorial-part-2}
{Sketch Bridge Tutorial Part 2}
\endlist
*/ */

View File

@@ -81,6 +81,11 @@
application. application.
\endlist \endlist
For an example of creating a \uicontrol {Qt Quick 3D Application} project,
watch the following video:
\youtube 9ihYeC0YJ0M
\section1 Using Project Wizards \section1 Using Project Wizards
\list 1 \list 1

View File

@@ -31,7 +31,7 @@
\list \list
\li \l{Getting Started} \li \l{Getting Started}
\list \list
\li \l{Exporting Artwork from Design Tools} \li \l{Exporting from Design Tools}
\list \list
\li \l{Exporting Designs from Adobe Illustrator} \li \l{Exporting Designs from Adobe Illustrator}
\li \l{Exporting Designs from Adobe Photoshop} \li \l{Exporting Designs from Adobe Photoshop}

View File

@@ -45,7 +45,7 @@
\row \row
\li \b {\l{Getting Started}} \li \b {\l{Getting Started}}
\list \list
\li \l{Exporting Artwork from Design Tools} \li \l{Exporting from Design Tools}
\li \l{User Interface} \li \l{User Interface}
\li \l{Editing QML Files in Design Mode} \li \l{Editing QML Files in Design Mode}
\li \l{Tutorials} \li \l{Tutorials}

View File

@@ -66,6 +66,11 @@
\image studio-3d-editor.png "3D Editor" \image studio-3d-editor.png "3D Editor"
The following video illustrates navigating in \uicontrol {3D Editor} and
using the toolbar:
\youtube SsFWyUeAA_4
\section1 Controlling the 3D Editor Camera \section1 Controlling the 3D Editor Camera
To switch to perspective camera mode, select To switch to perspective camera mode, select

View File

@@ -555,7 +555,8 @@ class DumperBase():
return 0, size return 0, size
return size, limit return size, limit
def vectorDataHelper(self, vector_data_ptr): def vectorData(self, value):
vector_data_ptr = self.extractPointer(value)
# vector_data_ptr is what is e.g. stored in a QVector's d_ptr. # vector_data_ptr is what is e.g. stored in a QVector's d_ptr.
if self.qtVersion() >= 0x050000: if self.qtVersion() >= 0x050000:
if self.ptrSize() == 4: if self.ptrSize() == 4:
@@ -570,6 +571,16 @@ class DumperBase():
self.check(0 <= size and size <= alloc and alloc <= 1000 * 1000 * 1000) self.check(0 <= size and size <= alloc and alloc <= 1000 * 1000 * 1000)
return data, size, alloc return data, size, alloc
def qArrayData(self, value):
if self.qtVersion() >= 0x60000:
dd, data, size = self.split('ppi', value)
if dd:
alloc, i, i = self.split('Pii', dd)
else: # fromRawData
alloc = size
return data, size, alloc
return self.qArrayDataHelper(self.extractPointer(value))
def qArrayDataHelper(self, array_data_ptr): def qArrayDataHelper(self, array_data_ptr):
# array_data_ptr is what is e.g. stored in a QByteArray's d_ptr. # array_data_ptr is what is e.g. stored in a QByteArray's d_ptr.
if self.qtVersion() >= 0x050000: if self.qtVersion() >= 0x050000:
@@ -614,15 +625,14 @@ class DumperBase():
# of inferior calls # of inferior calls
if addr == 0: if addr == 0:
return 0, '' return 0, ''
data, size, alloc = self.qArrayDataHelper(addr) data, size, alloc = self.qArrayData(value)
if alloc != 0: if alloc != 0:
self.check(0 <= size and size <= alloc and alloc <= 100 * 1000 * 1000) self.check(0 <= size and size <= alloc and alloc <= 100 * 1000 * 1000)
elided, shown = self.computeLimit(size, limit) elided, shown = self.computeLimit(size, limit)
return elided, self.readMemory(data, 2 * shown) return elided, self.readMemory(data, 2 * shown)
def encodeByteArrayHelper(self, value, limit): def encodeByteArrayHelper(self, value, limit):
addr = self.extractPointer(value) data, size, alloc = self.qArrayData(value)
data, size, alloc = self.qArrayDataHelper(addr)
if alloc != 0: if alloc != 0:
self.check(0 <= size and size <= alloc and alloc <= 100 * 1000 * 1000) self.check(0 <= size and size <= alloc and alloc <= 100 * 1000 * 1000)
elided, shown = self.computeLimit(size, limit) elided, shown = self.computeLimit(size, limit)
@@ -675,9 +685,6 @@ class DumperBase():
elided, data = self.encodeByteArrayHelper(value, limit) elided, data = self.encodeByteArrayHelper(value, limit)
return data return data
def qArrayData(self, value):
return self.qArrayDataHelper(self.extractPointer(value))
def putByteArrayValue(self, value): def putByteArrayValue(self, value):
elided, data = self.encodeByteArrayHelper(value, self.displayStringLimit) elided, data = self.encodeByteArrayHelper(value, self.displayStringLimit)
self.putValue(data, 'latin1', elided=elided) self.putValue(data, 'latin1', elided=elided)
@@ -701,14 +708,6 @@ class DumperBase():
return self.encodedUtf16ToUtf8(self.encodeString(value, limit)) return self.encodedUtf16ToUtf8(self.encodeString(value, limit))
def stringData(self, value): # -> (data, size, alloc) def stringData(self, value): # -> (data, size, alloc)
if self.qtVersion() >= 0x60000:
dd, data, size = value.split('ppi')
if dd:
alloc, i, i = self.split('Pii', dd)
else: # fromRawData
alloc = size
return data, size, alloc
else:
return self.qArrayData(value) return self.qArrayData(value)
def extractTemplateArgument(self, typename, position): def extractTemplateArgument(self, typename, position):
@@ -1442,22 +1441,27 @@ class DumperBase():
intSize = 4 intSize = 4
ptrSize = self.ptrSize() ptrSize = self.ptrSize()
if self.qtVersion() < 0x050000: if self.qtVersion() >= 0x060000:
# Size of QObjectData: 5 pointer + 2 int # Size of QObjectData: 7 pointer + 2 int
# - vtable # - vtable
# - QObject *q_ptr; # - QObject *q_ptr;
# - QObject *parent; # - QObject *parent;
# - QObjectList children; # - QObjectList children;
# - uint isWidget : 1; etc.. # - uint isWidget : 1; etc...
# - int postedEvents; # - int postedEvents;
# - QMetaObject *metaObject; # - QDynamicMetaObjectData *metaObject;
extra = self.extractPointer(dd + 7 * ptrSize + 2 * intSize)
if extra == 0:
return False
# Offset of objectName in QObjectPrivate: 5 pointer + 2 int # Offset of objectName in ExtraData: 12 pointer
# - [QObjectData base] # - QList<QByteArray> propertyNames;
# - QList<QVariant> propertyValues;
# - QVector<int> runningTimers;
# - QList<QPointer<QObject> > eventFilters;
# - QString objectName # - QString objectName
objectName = self.extractPointer(dd + 5 * ptrSize + 2 * intSize) objectNameAddress = extra + 12 * ptrSize
elif self.qtVersion() >= 0x050000:
else:
# Size of QObjectData: 5 pointer + 2 int # Size of QObjectData: 5 pointer + 2 int
# - vtable # - vtable
# - QObject *q_ptr; # - QObject *q_ptr;
@@ -1477,9 +1481,24 @@ class DumperBase():
# - QVector<int> runningTimers; # - QVector<int> runningTimers;
# - QList<QPointer<QObject> > eventFilters; # - QList<QPointer<QObject> > eventFilters;
# - QString objectName # - QString objectName
objectName = self.extractPointer(extra + 5 * ptrSize) objectNameAddress = extra + 5 * ptrSize
else:
# Size of QObjectData: 5 pointer + 2 int
# - vtable
# - QObject *q_ptr;
# - QObject *parent;
# - QObjectList children;
# - uint isWidget : 1; etc..
# - int postedEvents;
# - QMetaObject *metaObject;
data, size, alloc = self.qArrayDataHelper(objectName) # Offset of objectName in QObjectPrivate: 5 pointer + 2 int
# - [QObjectData base]
# - QString objectName
objectNameAddress = dd + 5 * ptrSize + 2 * intSize
data, size, alloc = self.qArrayData(objectNameAddress)
# Object names are short, and GDB can crash on to big chunks. # Object names are short, and GDB can crash on to big chunks.
# Since this here is a convenience feature only, limit it. # Since this here is a convenience feature only, limit it.
@@ -1734,9 +1753,8 @@ class DumperBase():
yield self.createValue(data + i * stepSize, innerType) yield self.createValue(data + i * stepSize, innerType)
#yield self.createValue(data + i * stepSize, 'void*') #yield self.createValue(data + i * stepSize, 'void*')
def vectorChildrenGenerator(self, addr, innerType): def vectorChildrenGenerator(self, value, innerType):
base = self.extractPointer(addr) data, size, _ = self.vectorData(value)
data, size, alloc = self.vectorDataHelper(base)
for i in range(size): for i in range(size):
yield self.createValue(data + i * innerType.size(), innerType) yield self.createValue(data + i * innerType.size(), innerType)
@@ -1766,16 +1784,24 @@ class DumperBase():
def metaString(self, metaObjectPtr, index, revision): def metaString(self, metaObjectPtr, index, revision):
ptrSize = self.ptrSize() ptrSize = self.ptrSize()
stringdata = self.extractPointer(toInteger(metaObjectPtr) + ptrSize) stringdata = self.extractPointer(toInteger(metaObjectPtr) + ptrSize)
if revision >= 7: # Qt 5.
byteArrayDataSize = 24 if ptrSize == 8 else 16 def unpackString(base, size):
literal = stringdata + toInteger(index) * byteArrayDataSize
ldata, lsize, lalloc = self.qArrayDataHelper(literal)
try: try:
s = struct.unpack_from('%ds' % lsize, self.readRawMemory(ldata, lsize))[0] s = struct.unpack_from('%ds' % size, self.readRawMemory(base, size))[0]
return s if sys.version_info[0] == 2 else s.decode('utf8') return s if sys.version_info[0] == 2 else s.decode('utf8')
except: except:
return '<not available>' return '<not available>'
else: # Qt 4.
if revision >= 9: # Qt 6.
pos, size = self.split('II', stringdata + 8 * index)
return unpackString(stringdata + pos, size)
if revision >= 7: # Qt 5.
byteArrayDataSize = 24 if ptrSize == 8 else 16
literal = stringdata + toInteger(index) * byteArrayDataSize
base, size, _ = self.qArrayDataHelper(literal)
return unpackString(base, size)
ldata = stringdata + index ldata = stringdata + index
return self.extractCString(ldata).decode('utf8') return self.extractCString(ldata).decode('utf8')
@@ -1784,11 +1810,24 @@ class DumperBase():
self.putField('sortgroup', sortorder) self.putField('sortgroup', sortorder)
def putQMetaStuff(self, value, origType): def putQMetaStuff(self, value, origType):
(metaObjectPtr, handle) = value.split('pI') if self.qtVersion() >= 0x060000:
metaObjectPtr, handle = value.split('pp')
else:
metaObjectPtr, handle = value.split('pI')
if metaObjectPtr != 0: if metaObjectPtr != 0:
if self.qtVersion() >= 0x060000:
revision = 9
name, alias, flags, keyCount, data = self.split('IIIII', handle)
index = name
elif self.qtVersion() >= 0x050000:
revision = 7
dataPtr = self.extractPointer(metaObjectPtr + 2 * self.ptrSize()) dataPtr = self.extractPointer(metaObjectPtr + 2 * self.ptrSize())
index = self.extractInt(dataPtr + 4 * handle) index = self.extractInt(dataPtr + 4 * handle)
revision = 7 if self.qtVersion() >= 0x050000 else 6 else:
revision = 6
dataPtr = self.extractPointer(metaObjectPtr + 2 * self.ptrSize())
index = self.extractInt(dataPtr + 4 * handle)
#self.putValue("index: %s rev: %s" % (index, revision))
name = self.metaString(metaObjectPtr, index, revision) name = self.metaString(metaObjectPtr, index, revision)
self.putValue(name) self.putValue(name)
self.putExpandable() self.putExpandable()
@@ -2142,8 +2181,7 @@ class DumperBase():
with Children(self): with Children(self):
innerType = connections.type[0] innerType = connections.type[0]
# Should check: innerType == ns::QObjectPrivate::ConnectionList # Should check: innerType == ns::QObjectPrivate::ConnectionList
base = self.extractPointer(connections) data, size, _ = self.vectorData(connections)
data, size, alloc = self.vectorDataHelper(base)
connectionType = self.createType('@QObjectPrivate::Connection') connectionType = self.createType('@QObjectPrivate::Connection')
for i in range(size): for i in range(size):
first = self.extractPointer(data + i * 2 * ptrSize) first = self.extractPointer(data + i * 2 * ptrSize)

View File

@@ -1047,9 +1047,9 @@ class Dumper(DumperBase):
def handleNewObjectFile(self, objfile): def handleNewObjectFile(self, objfile):
name = objfile.filename name = objfile.filename
if self.isWindowsTarget(): if self.isWindowsTarget():
qtCoreMatch = re.match(r'.*Qt5?Core[^/.]*d?\.dll', name) qtCoreMatch = re.match(r'.*Qt[56]?Core[^/.]*d?\.dll', name)
else: else:
qtCoreMatch = re.match(r'.*/libQt5?Core[^/.]*\.so', name) qtCoreMatch = re.match(r'.*/libQt[56]?Core[^/.]*\.so', name)
if qtCoreMatch is not None: if qtCoreMatch is not None:
self.addDebugLibs(objfile) self.addDebugLibs(objfile)

View File

@@ -1620,13 +1620,13 @@ def qdump__QStack(d, value):
def qdump__QPolygonF(d, value): def qdump__QPolygonF(d, value):
data, size, alloc = d.vectorDataHelper(d.extractPointer(value)) data, size, _ = d.vectorData(value)
d.putItemCount(size) d.putItemCount(size)
d.putPlotData(data, size, d.createType('QPointF')) d.putPlotData(data, size, d.createType('QPointF'))
def qdump__QPolygon(d, value): def qdump__QPolygon(d, value):
data, size, alloc = d.vectorDataHelper(d.extractPointer(value)) data, size, _ = d.vectorData(value)
d.putItemCount(size) d.putItemCount(size)
d.putPlotData(data, size, d.createType('QPoint')) d.putPlotData(data, size, d.createType('QPoint'))
@@ -1640,7 +1640,7 @@ def qdump__QGraphicsPolygonItem(d, value):
offset = 328 if d.isMsvcTarget() else 320 offset = 328 if d.isMsvcTarget() else 320
else: else:
offset = 308 offset = 308
data, size, alloc = d.vectorDataHelper(d.extractPointer(dptr + offset)) data, size, alloc = d.vectorData(dptr + offset)
d.putItemCount(size) d.putItemCount(size)
d.putPlotData(data, size, d.createType('QPointF')) d.putPlotData(data, size, d.createType('QPointF'))
@@ -2101,7 +2101,7 @@ def qdump__QVariant(d, value):
def qedit__QVector(d, value, data): def qedit__QVector(d, value, data):
values = data.split(',') values = data.split(',')
d.call('void', value, 'resize', str(len(values))) d.call('void', value, 'resize', str(len(values)))
base, vsize, valloc = d.vectorDataHelper(d.extractPointer(value)) base, vsize, valloc = d.vectorData(value)
d.setValues(base, value.type[0].name, values) d.setValues(base, value.type[0].name, values)
@@ -2119,8 +2119,7 @@ def qdump__QVector(d, value):
if value.type.name == d.qtNamespace() + "QVector": if value.type.name == d.qtNamespace() + "QVector":
d.putBetterType(value.type.name + '<' + value.type.ltarget[0].name + '>') d.putBetterType(value.type.name + '<' + value.type.ltarget[0].name + '>')
else: else:
dd = d.extractPointer(value) data, size, alloc = d.vectorData(value)
data, size, alloc = d.vectorDataHelper(dd)
d.check(0 <= size and size <= alloc and alloc <= 1000 * 1000 * 1000) d.check(0 <= size and size <= alloc and alloc <= 1000 * 1000 * 1000)
d.putItemCount(size) d.putItemCount(size)
d.putPlotData(data, size, value.type[0]) d.putPlotData(data, size, value.type[0])
@@ -2128,8 +2127,7 @@ def qdump__QVector(d, value):
if False: if False:
def qdump__QObjectConnectionList(d, value): def qdump__QObjectConnectionList(d, value):
dd = d.extractPointer(value) data, size, alloc = d.vectorData(value)
data, size, alloc = d.vectorDataHelper(dd)
d.check(0 <= size and size <= alloc and alloc <= 1000 * 1000 * 1000) d.check(0 <= size and size <= alloc and alloc <= 1000 * 1000 * 1000)
d.putItemCount(size) d.putItemCount(size)
d.putPlotData(data, size, d.createType('@QObjectPrivate::ConnectionList')) d.putPlotData(data, size, d.createType('@QObjectPrivate::ConnectionList'))
@@ -3168,14 +3166,14 @@ def qdump__qfloat16(d, value):
def qdumpHelper_QCbor_string(d, container_ptr, element_index, is_bytes): def qdumpHelper_QCbor_string(d, container_ptr, element_index, is_bytes):
# d.split('i@{QByteArray::size_type}pp', container_ptr) doesn't work with CDB, so be explicit: # d.split('i@{QByteArray::size_type}pp', container_ptr) doesn't work with CDB,
offset = 2 * d.ptrSize() if d.qtVersion() >= 0x060000 else 8 # so be explicit:
data_d_ptr, elements_d_ptr = d.split('pp', container_ptr + offset) pos = container_ptr + (2 * d.ptrSize() if d.qtVersion() >= 0x060000 else 8)
elements_data_ptr, elements_size, _ = d.vectorDataHelper(elements_d_ptr) elements_data_ptr, elements_size, _ = d.vectorData(pos + d.ptrSize())
element_at_n_addr = elements_data_ptr + element_index * 16 # sizeof(QtCbor::Element) == 15 element_at_n_addr = elements_data_ptr + element_index * 16 # sizeof(QtCbor::Element) == 15
element_value, _, element_flags = d.split('qII', element_at_n_addr) element_value, _, element_flags = d.split('qII', element_at_n_addr)
enc = 'latin1' if is_bytes or (element_flags & 8) else 'utf16' enc = 'latin1' if is_bytes or (element_flags & 8) else 'utf16'
bytedata, _, _ = d.qArrayDataHelper(data_d_ptr) bytedata, _, _ = d.qArrayData(pos)
bytedata += element_value bytedata += element_value
if d.qtVersion() >= 0x060000: if d.qtVersion() >= 0x060000:
bytedata_len = d.extractInt64(bytedata) bytedata_len = d.extractInt64(bytedata)
@@ -3204,13 +3202,13 @@ def qdumpHelper_QCbor_array(d, container_ptr, is_cbor):
if not container_ptr: if not container_ptr:
d.putItemCount(0) d.putItemCount(0)
return return
# d.split('i@{QByteArray::size_type}pp', container_ptr) doesn't work with CDB, so be explicit: # d.split('i@{QByteArray::size_type}pp', container_ptr) doesn't work with CDB,
offset = 2 * d.ptrSize() if d.qtVersion() >= 0x060000 else 8 # so be explicit:
data_d_ptr, elements_d_ptr = d.split('pp', container_ptr + offset) pos = container_ptr + (2 * d.ptrSize() if d.qtVersion() >= 0x060000 else 8)
elements_data_ptr, elements_size, _ = d.vectorDataHelper(elements_d_ptr) elements_data_ptr, elements_size, _ = d.vectorData(pos + d.ptrSize())
d.putItemCount(elements_size) d.putItemCount(elements_size)
if d.isExpanded(): if d.isExpanded():
bytedata, _, _ = d.qArrayDataHelper(data_d_ptr) bytedata, _, _ = d.qArrayData(pos)
with Children(d, maxNumChild=1000): with Children(d, maxNumChild=1000):
for i in range(elements_size): for i in range(elements_size):
d.putSubItem(i, qdumpHelper_QCborArray_valueAt(d, container_ptr, elements_data_ptr, i, bytedata, is_cbor)) d.putSubItem(i, qdumpHelper_QCborArray_valueAt(d, container_ptr, elements_data_ptr, i, bytedata, is_cbor))
@@ -3225,14 +3223,14 @@ def qdumpHelper_QCbor_map(d, container_ptr, is_cbor):
if not container_ptr: if not container_ptr:
d.putItemCount(0) d.putItemCount(0)
return return
# d.split('i@{QByteArray::size_type}pp', container_ptr) doesn't work with CDB, so be explicit: # d.split('i@{QByteArray::size_type}pp', container_ptr) doesn't work with CDB,
offset = 2 * d.ptrSize() if d.qtVersion() >= 0x060000 else 8 # so be explicit:
data_d_ptr, elements_d_ptr = d.split('pp', container_ptr + offset) pos = container_ptr + (2 * d.ptrSize() if d.qtVersion() >= 0x060000 else 8)
elements_data_ptr, elements_size, _ = d.vectorDataHelper(elements_d_ptr) elements_data_ptr, elements_size, _ = d.vectorData(pos + d.ptrSize())
elements_size = int(elements_size / 2) elements_size = int(elements_size / 2)
d.putItemCount(elements_size) d.putItemCount(elements_size)
if d.isExpanded(): if d.isExpanded():
bytedata, _, _ = d.qArrayDataHelper(data_d_ptr) bytedata, _, _ = d.qArrayDataHelper(pos)
with Children(d, maxNumChild=1000): with Children(d, maxNumChild=1000):
for i in range(elements_size): for i in range(elements_size):
key = qdumpHelper_QCborArray_valueAt(d, container_ptr, elements_data_ptr, 2 * i, bytedata, is_cbor) key = qdumpHelper_QCborArray_valueAt(d, container_ptr, elements_data_ptr, 2 * i, bytedata, is_cbor)

View File

@@ -57,6 +57,10 @@ Item {
property var selectionBoxes: [] property var selectionBoxes: []
property rect viewPortRect: Qt.rect(0, 0, 1000, 1000) property rect viewPortRect: Qt.rect(0, 0, 1000, 1000)
property bool shuttingDown: false
property real fps: 0
signal selectionChanged(var selectedNodes) signal selectionChanged(var selectedNodes)
signal commitObjectProperty(var object, var propName) signal commitObjectProperty(var object, var propName)
signal changeObjectProperty(var object, var propName) signal changeObjectProperty(var object, var propName)
@@ -71,6 +75,11 @@ Item {
onActiveSceneChanged: updateActiveScene() onActiveSceneChanged: updateActiveScene()
function aboutToShutDown()
{
shuttingDown = true;
}
function createEditView() function createEditView()
{ {
var component = Qt.createComponent("SceneView3D.qml"); var component = Qt.createComponent("SceneView3D.qml");
@@ -125,9 +134,13 @@ Item {
} else { } else {
// When active scene is deleted, this function gets called by object deletion // When active scene is deleted, this function gets called by object deletion
// handlers without going through setActiveScene, so make sure sceneId is cleared. // handlers without going through setActiveScene, so make sure sceneId is cleared.
// This is skipped during application shutdown, as calling QQuickText::setText()
// during application shutdown can crash the application.
if (!shuttingDown) {
sceneId = ""; sceneId = "";
storeCurrentToolStates(); storeCurrentToolStates();
} }
}
notifyActiveSceneChange(); notifyActiveSceneChange();
} }
@@ -704,6 +717,10 @@ Item {
Text { Text {
id: gizmoLabelText id: gizmoLabelText
text: { text: {
// This is skipped during application shutdown, as calling QQuickText::setText()
// during application shutdown can crash the application.
if (shuttingDown)
return text;
var l = Qt.locale(); var l = Qt.locale();
var targetProperty; var targetProperty;
if (viewRoot.selectedNode) { if (viewRoot.selectedNode) {
@@ -738,6 +755,10 @@ Item {
Text { Text {
id: rotateGizmoLabelText id: rotateGizmoLabelText
text: { text: {
// This is skipped during application shutdown, as calling QQuickText::setText()
// during application shutdown can crash the application.
if (shuttingDown)
return text;
var l = Qt.locale(); var l = Qt.locale();
if (rotateGizmo.targetNode) { if (rotateGizmo.targetNode) {
var degrees = rotateGizmo.currentAngle * (180 / Math.PI); var degrees = rotateGizmo.currentAngle * (180 / Math.PI);
@@ -796,5 +817,16 @@ Item {
font.pixelSize: 14 font.pixelSize: 14
color: "white" color: "white"
} }
Text {
id: fpsLabel
text: viewRoot.fps
anchors.bottom: parent.bottom
anchors.left: parent.left
anchors.margins: 4
font.pixelSize: 12
color: "white"
visible: viewRoot.fps > 0
}
} }
} }

View File

@@ -50,11 +50,8 @@ Item {
view.destroy(); view.destroy();
} }
function createViewForObject(obj, w, h) function createViewForObject(obj)
{ {
width = w;
height = h;
if (obj instanceof Material) if (obj instanceof Material)
createViewForMaterial(obj); createViewForMaterial(obj);
else if (obj instanceof Model) else if (obj instanceof Model)

View File

@@ -45,6 +45,12 @@
#include <QtQuick3D/private/qquick3dviewport_p.h> #include <QtQuick3D/private/qquick3dviewport_p.h>
#endif #endif
#if QT_VERSION >= QT_VERSION_CHECK(6, 0, 0)
#include <QtGui/private/qrhi_p.h>
#include <QtQuick/private/qquickrendercontrol_p.h>
#include <QtQuick/private/qquickrendertarget_p.h>
#endif
#include <private/qquickdesignersupportitems_p.h> #include <private/qquickdesignersupportitems_p.h>
IconRenderer::IconRenderer(int size, const QString &filePath, const QString &source) IconRenderer::IconRenderer(int size, const QString &filePath, const QString &source)
@@ -62,23 +68,26 @@ void IconRenderer::setupRender()
DesignerSupport::activateDesignerWindowManager(); DesignerSupport::activateDesignerWindowManager();
#endif #endif
m_quickView = new QQuickView; QQmlEngine *engine = nullptr;
#if QT_VERSION < QT_VERSION_CHECK(6, 0, 0) #if QT_VERSION < QT_VERSION_CHECK(6, 0, 0)
QSurfaceFormat surfaceFormat = m_quickView->requestedFormat(); auto view = new QQuickView;
engine = view->engine();
m_window = view;
QSurfaceFormat surfaceFormat = view->requestedFormat();
surfaceFormat.setVersion(4, 1); surfaceFormat.setVersion(4, 1);
surfaceFormat.setProfile(QSurfaceFormat::CoreProfile); surfaceFormat.setProfile(QSurfaceFormat::CoreProfile);
m_quickView->setFormat(surfaceFormat); view->setFormat(surfaceFormat);
DesignerSupport::createOpenGLContext(view);
DesignerSupport::createOpenGLContext(m_quickView);
#else #else
m_quickView->setDefaultAlphaBuffer(true); engine = new QQmlEngine;
m_quickView->setColor(Qt::transparent); m_renderControl = new QQuickRenderControl;
m_ratio = m_quickView->devicePixelRatio(); m_window = new QQuickWindow(m_renderControl);
m_quickView->installEventFilter(this); m_window->setDefaultAlphaBuffer(true);
m_window->setColor(Qt::transparent);
m_renderControl->initialize();
#endif #endif
QQmlComponent component(m_quickView->engine()); QQmlComponent component(engine);
component.loadUrl(QUrl::fromLocalFile(m_source)); component.loadUrl(QUrl::fromLocalFile(m_source));
QObject *iconItem = component.create(); QObject *iconItem = component.create();
@@ -86,13 +95,19 @@ void IconRenderer::setupRender()
#ifdef QUICK3D_MODULE #ifdef QUICK3D_MODULE
if (auto scene = qobject_cast<QQuick3DNode *>(iconItem)) { if (auto scene = qobject_cast<QQuick3DNode *>(iconItem)) {
qmlRegisterType<QmlDesigner::Internal::SelectionBoxGeometry>("SelectionBoxGeometry", 1, 0, "SelectionBoxGeometry"); qmlRegisterType<QmlDesigner::Internal::SelectionBoxGeometry>("SelectionBoxGeometry", 1, 0, "SelectionBoxGeometry");
QQmlComponent component(m_quickView->engine()); QQmlComponent component(engine);
component.loadUrl(QUrl("qrc:/qtquickplugin/mockfiles/IconRenderer3D.qml")); component.loadUrl(QUrl("qrc:/qtquickplugin/mockfiles/IconRenderer3D.qml"));
m_containerItem = qobject_cast<QQuickItem *>(component.create()); m_containerItem = qobject_cast<QQuickItem *>(component.create());
DesignerSupport::setRootItem(m_quickView, m_containerItem); #if QT_VERSION < QT_VERSION_CHECK(6, 0, 0)
DesignerSupport::setRootItem(view, m_containerItem);
#else
m_window->contentItem()->setSize(m_containerItem->size());
m_window->setGeometry(0, 0, m_containerItem->width(), m_containerItem->height());
m_containerItem->setParentItem(m_window->contentItem());
#endif
auto helper = new QmlDesigner::Internal::GeneralHelper(); auto helper = new QmlDesigner::Internal::GeneralHelper();
m_quickView->engine()->rootContext()->setContextProperty("_generalHelper", helper); engine->rootContext()->setContextProperty("_generalHelper", helper);
m_contentItem = QQmlProperty::read(m_containerItem, "view3D").value<QQuickItem *>(); m_contentItem = QQmlProperty::read(m_containerItem, "view3D").value<QQuickItem *>();
auto view3D = qobject_cast<QQuick3DViewport *>(m_contentItem); auto view3D = qobject_cast<QQuick3DViewport *>(m_contentItem);
@@ -104,21 +119,21 @@ void IconRenderer::setupRender()
m_contentItem = scene; m_contentItem = scene;
m_containerItem = new QQuickItem(); m_containerItem = new QQuickItem();
m_containerItem->setSize(QSizeF(1024, 1024)); m_containerItem->setSize(QSizeF(1024, 1024));
DesignerSupport::setRootItem(m_quickView, m_containerItem); #if QT_VERSION < QT_VERSION_CHECK(6, 0, 0)
DesignerSupport::setRootItem(view, m_containerItem);
#else
m_window->contentItem()->setSize(m_containerItem->size());
m_window->setGeometry(0, 0, m_containerItem->width(), m_containerItem->height());
m_containerItem->setParentItem(m_window->contentItem());
#endif
m_contentItem->setParentItem(m_containerItem); m_contentItem->setParentItem(m_containerItem);
} }
if (m_containerItem && m_contentItem) { if (m_containerItem && m_contentItem) {
resizeContent(m_size); resizeContent(m_size);
#if QT_VERSION < QT_VERSION_CHECK(6, 0, 0) if (!initRhi())
QTimer::singleShot(0, qGuiApp, &QGuiApplication::quit);
QTimer::singleShot(0, this, &IconRenderer::createIcon); QTimer::singleShot(0, this, &IconRenderer::createIcon);
#else
m_quickView->show();
m_quickView->lower();
// Failsafe to exit eventually if window fails to expose
QTimer::singleShot(10000, qGuiApp, &QGuiApplication::quit);
#endif
} else { } else {
QTimer::singleShot(0, qGuiApp, &QGuiApplication::quit); QTimer::singleShot(0, qGuiApp, &QGuiApplication::quit);
} }
@@ -127,25 +142,12 @@ void IconRenderer::setupRender()
} }
} }
bool IconRenderer::eventFilter(QObject *watched, QEvent *event)
{
#if QT_VERSION >= QT_VERSION_CHECK(6, 0, 0)
if (watched == m_quickView && event->type() == QEvent::Expose)
QTimer::singleShot(0, this, &IconRenderer::createIcon);
#else
Q_UNUSED(watched)
Q_UNUSED(event)
#endif
return false;
}
void IconRenderer::createIcon() void IconRenderer::createIcon()
{ {
#if QT_VERSION < QT_VERSION_CHECK(6, 0, 0) #if QT_VERSION < QT_VERSION_CHECK(6, 0, 0)
m_designerSupport.refFromEffectItem(m_quickView->rootObject(), false); m_designerSupport.refFromEffectItem(m_containerItem, false);
#endif #endif
QQuickDesignerSupportItems::disableNativeTextRendering(m_quickView->rootObject()); QQuickDesignerSupportItems::disableNativeTextRendering(m_containerItem);
#ifdef QUICK3D_MODULE #ifdef QUICK3D_MODULE
if (m_is3D) { if (m_is3D) {
// Render once to make sure scene is up to date before we set up the selection box // Render once to make sure scene is up to date before we set up the selection box
@@ -166,6 +168,8 @@ void IconRenderer::createIcon()
// Render @2x image // Render @2x image
resizeContent(m_size * 2); resizeContent(m_size * 2);
if (!initRhi())
QTimer::singleShot(1000, qGuiApp, &QGuiApplication::quit);
QString saveFile; QString saveFile;
saveFile = fi.absolutePath() + '/' + fi.completeBaseName() + "@2x"; saveFile = fi.absolutePath() + '/' + fi.completeBaseName() + "@2x";
@@ -194,23 +198,39 @@ void IconRenderer::render(const QString &fileName)
item->update(); item->update();
#endif #endif
}; };
updateNodesRecursive(m_quickView->rootObject()); updateNodesRecursive(m_containerItem);
QRect rect(QPoint(), m_contentItem->size().toSize()); QRect rect(QPoint(), m_contentItem->size().toSize());
QImage renderImage;
#if QT_VERSION < QT_VERSION_CHECK(6, 0, 0) #if QT_VERSION < QT_VERSION_CHECK(6, 0, 0)
QImage renderImage = m_designerSupport.renderImageForItem(m_quickView->rootObject(), renderImage = m_designerSupport.renderImageForItem(m_containerItem, rect, rect.size());
rect, rect.size());
#else #else
QImage renderImage = m_quickView->grabWindow(); m_renderControl->polishItems();
m_renderControl->beginFrame();
m_renderControl->sync();
m_renderControl->render();
bool readCompleted = false;
QRhiReadbackResult readResult;
readResult.completed = [&] {
readCompleted = true;
QImage wrapperImage(reinterpret_cast<const uchar *>(readResult.data.constData()),
readResult.pixelSize.width(), readResult.pixelSize.height(),
QImage::Format_RGBA8888_Premultiplied);
if (m_rhi->isYUpInFramebuffer())
renderImage = wrapperImage.mirrored().copy(0, 0, rect.width(), rect.height());
else
renderImage = wrapperImage.copy(0, 0, rect.width(), rect.height());
};
QRhiResourceUpdateBatch *readbackBatch = m_rhi->nextResourceUpdateBatch();
readbackBatch->readBackTexture(m_texture, &readResult);
QQuickRenderControlPrivate *rd = QQuickRenderControlPrivate::get(m_renderControl);
rd->cb->resourceUpdate(readbackBatch);
m_renderControl->endFrame();
#endif #endif
if (!fileName.isEmpty()) { if (!fileName.isEmpty()) {
#if QT_VERSION >= QT_VERSION_CHECK(6, 0, 0)
if (m_ratio != 1.) {
rect.setWidth(qRound(rect.size().width() * m_ratio));
rect.setHeight(qRound(rect.size().height() * m_ratio));
}
renderImage = renderImage.copy(rect);
#endif
QFileInfo fi(fileName); QFileInfo fi(fileName);
if (fi.suffix().isEmpty()) if (fi.suffix().isEmpty())
renderImage.save(fileName, "PNG"); renderImage.save(fileName, "PNG");
@@ -219,16 +239,60 @@ void IconRenderer::render(const QString &fileName)
} }
} }
void IconRenderer::resizeContent(int size) void IconRenderer::resizeContent(int dimensions)
{ {
int theSize = size; QSizeF size(dimensions, dimensions);
#if QT_VERSION >= QT_VERSION_CHECK(6, 0, 0) m_contentItem->setSize(size);
if (m_ratio != 1.)
theSize = qRound(qreal(size) / m_quickView->devicePixelRatio());
#endif
m_contentItem->setSize(QSizeF(theSize, theSize));
if (m_contentItem->width() > m_containerItem->width()) if (m_contentItem->width() > m_containerItem->width())
m_containerItem->setWidth(m_contentItem->width()); m_containerItem->setWidth(m_contentItem->width());
if (m_contentItem->height() > m_containerItem->height()) if (m_contentItem->height() > m_containerItem->height())
m_containerItem->setHeight(m_contentItem->height()); m_containerItem->setHeight(m_contentItem->height());
} }
bool IconRenderer::initRhi()
{
#if QT_VERSION >= QT_VERSION_CHECK(6, 0, 0)
if (!m_rhi) {
QQuickRenderControlPrivate *rd = QQuickRenderControlPrivate::get(m_renderControl);
m_rhi = rd->rhi;
if (!m_rhi) {
qWarning() << __FUNCTION__ << "Rhi is null";
return false;
}
}
// Don't bother deleting old ones as iconrender is a single shot executable
m_texTarget = nullptr;
m_rpDesc = nullptr;
m_buffer = nullptr;
m_texture = nullptr;
const QSize size = m_containerItem->size().toSize();
m_texture = m_rhi->newTexture(QRhiTexture::RGBA8, size, 1,
QRhiTexture::RenderTarget | QRhiTexture::UsedAsTransferSource);
if (!m_texture->create()) {
qWarning() << __FUNCTION__ << "QRhiTexture creation failed";
return false;
}
m_buffer = m_rhi->newRenderBuffer(QRhiRenderBuffer::DepthStencil, size, 1);
if (!m_buffer->create()) {
qWarning() << __FUNCTION__ << "Depth/stencil buffer creation failed";
return false;
}
QRhiTextureRenderTargetDescription rtDesc {QRhiColorAttachment(m_texture)};
rtDesc.setDepthStencilBuffer(m_buffer);
m_texTarget = m_rhi->newTextureRenderTarget(rtDesc);
m_rpDesc = m_texTarget->newCompatibleRenderPassDescriptor();
m_texTarget->setRenderPassDescriptor(m_rpDesc);
if (!m_texTarget->create()) {
qWarning() << __FUNCTION__ << "Texture render target creation failed";
return false;
}
// redirect Qt Quick rendering into our texture
m_window->setRenderTarget(QQuickRenderTarget::fromRhiRenderTarget(m_texTarget));
#endif
return true;
}

View File

@@ -31,8 +31,16 @@
#include <designersupportdelegate.h> #include <designersupportdelegate.h>
QT_BEGIN_NAMESPACE QT_BEGIN_NAMESPACE
class QQuickView; class QQuickWindow;
class QQuickItem; class QQuickItem;
#if QT_VERSION >= QT_VERSION_CHECK(6, 0, 0)
class QQuickRenderControl;
class QRhi;
class QRhiTexture;
class QRhiRenderBuffer;
class QRhiTextureRenderTarget;
class QRhiRenderPassDescriptor;
#endif
QT_END_NAMESPACE QT_END_NAMESPACE
class IconRenderer : public QObject class IconRenderer : public QObject
@@ -44,21 +52,26 @@ public:
void setupRender(); void setupRender();
protected:
bool eventFilter(QObject *watched, QEvent *event) override;
private: private:
void createIcon(); void createIcon();
void render(const QString &fileName); void render(const QString &fileName);
void resizeContent(int size); void resizeContent(int dimensions);
bool initRhi();
int m_size = 16; int m_size = 16;
double m_ratio = 1.;
QString m_filePath; QString m_filePath;
QString m_source; QString m_source;
QQuickView *m_quickView = nullptr; QQuickWindow *m_window = nullptr;
QQuickItem *m_contentItem = nullptr; QQuickItem *m_contentItem = nullptr;
QQuickItem *m_containerItem = nullptr; QQuickItem *m_containerItem = nullptr;
DesignerSupport m_designerSupport; DesignerSupport m_designerSupport;
bool m_is3D = false; bool m_is3D = false;
#if QT_VERSION >= QT_VERSION_CHECK(6, 0, 0)
QQuickRenderControl *m_renderControl = nullptr;
QRhi *m_rhi = nullptr;
QRhiTexture *m_texture = nullptr;
QRhiRenderBuffer *m_buffer = nullptr;
QRhiTextureRenderTarget *m_texTarget = nullptr;
QRhiRenderPassDescriptor *m_rpDesc = nullptr;
#endif
}; };

View File

@@ -189,9 +189,14 @@ NodeInstanceServer::NodeInstanceServer(NodeInstanceClientInterface *nodeInstance
Internal::QmlPrivateGate::registerFixResourcePathsForObjectCallBack(); Internal::QmlPrivateGate::registerFixResourcePathsForObjectCallBack();
} }
NodeInstanceServer::~NodeInstanceServer()
{
m_objectInstanceHash.clear();
}
QList<ServerNodeInstance> NodeInstanceServer::createInstances(const QVector<InstanceContainer> &containerVector) QList<ServerNodeInstance> NodeInstanceServer::createInstances(const QVector<InstanceContainer> &containerVector)
{ {
Q_ASSERT(declarativeView() || quickView()); Q_ASSERT(declarativeView() || quickWindow());
QList<ServerNodeInstance> instanceList; QList<ServerNodeInstance> instanceList;
for (const InstanceContainer &instanceContainer : containerVector) { for (const InstanceContainer &instanceContainer : containerVector) {
ServerNodeInstance instance; ServerNodeInstance instance;
@@ -207,7 +212,6 @@ QList<ServerNodeInstance> NodeInstanceServer::createInstances(const QVector<Inst
m_rootNodeInstance = instance; m_rootNodeInstance = instance;
if (quickView()) if (quickView())
quickView()->setContent(fileUrl(), m_importComponent, m_rootNodeInstance.rootQuickItem()); quickView()->setContent(fileUrl(), m_importComponent, m_rootNodeInstance.rootQuickItem());
resizeCanvasSizeToRootItemSize();
} }
foreach (QQmlContext* context, allSubContextsForObject(instance.internalObject())) foreach (QQmlContext* context, allSubContextsForObject(instance.internalObject()))
@@ -442,7 +446,7 @@ void NodeInstanceServer::removeSharedMemory(const RemoveSharedMemoryCommand &/*c
void NodeInstanceServer::setupImports(const QVector<AddImportContainer> &containerVector) void NodeInstanceServer::setupImports(const QVector<AddImportContainer> &containerVector)
{ {
Q_ASSERT(quickView()); Q_ASSERT(quickWindow());
QSet<QString> importStatementSet; QSet<QString> importStatementSet;
QString qtQuickImport; QString qtQuickImport;
@@ -497,7 +501,8 @@ void NodeInstanceServer::setupOnlyWorkingImports(const QStringList &workingImpor
QByteArray componentCode = workingImportStatementList.join("\n").toUtf8().append("\n"); QByteArray componentCode = workingImportStatementList.join("\n").toUtf8().append("\n");
m_importCode = componentCode; m_importCode = componentCode;
m_importComponent = new QQmlComponent(engine(), quickView()); m_importComponent = new QQmlComponent(engine(), quickWindow());
if (quickView())
quickView()->setContent(fileUrl(), m_importComponent, quickView()->rootObject()); quickView()->setContent(fileUrl(), m_importComponent, quickView()->rootObject());
m_importComponent->setData(componentCode.append("\nItem {}\n"), fileUrl()); m_importComponent->setData(componentCode.append("\nItem {}\n"), fileUrl());
@@ -942,11 +947,9 @@ void NodeInstanceServer::setInstancePropertyVariant(const PropertyValueContainer
if (hasInstanceForId(valueContainer.instanceId())) { if (hasInstanceForId(valueContainer.instanceId())) {
ServerNodeInstance instance = instanceForId(valueContainer.instanceId()); ServerNodeInstance instance = instanceForId(valueContainer.instanceId());
const PropertyName name = valueContainer.name(); const PropertyName name = valueContainer.name();
const QVariant value = valueContainer.value(); const QVariant value = valueContainer.value();
if (activeStateInstance().isValid() && !instance.isSubclassOf("QtQuick/PropertyChanges")) { if (activeStateInstance().isValid() && !instance.isSubclassOf("QtQuick/PropertyChanges")) {
bool stateValueWasUpdated = activeStateInstance().updateStateVariant(instance, name, value); bool stateValueWasUpdated = activeStateInstance().updateStateVariant(instance, name, value);
if (!stateValueWasUpdated) { if (!stateValueWasUpdated) {
@@ -962,6 +965,9 @@ void NodeInstanceServer::setInstancePropertyVariant(const PropertyValueContainer
if (valueContainer.isDynamic() && valueContainer.instanceId() == 0 && engine()) if (valueContainer.isDynamic() && valueContainer.instanceId() == 0 && engine())
rootContext()->setContextProperty(QString::fromUtf8(name), Internal::QmlPrivateGate::fixResourcePaths(value)); rootContext()->setContextProperty(QString::fromUtf8(name), Internal::QmlPrivateGate::fixResourcePaths(value));
if (valueContainer.instanceId() == 0 && (name == "width" || name == "height" || name == "x" || name == "y"))
resizeCanvasToRootItem();
} }
} }

View File

@@ -31,6 +31,7 @@
#include <QSet> #include <QSet>
#include <QStringList> #include <QStringList>
#include <QPointer> #include <QPointer>
#include <QImage>
#ifdef MULTILANGUAGE_TRANSLATIONPROVIDER #ifdef MULTILANGUAGE_TRANSLATIONPROVIDER
#include <multilanguagelink.h> #include <multilanguagelink.h>
@@ -90,6 +91,7 @@ QT_BEGIN_NAMESPACE
class QFileSystemWatcher; class QFileSystemWatcher;
class QQmlView; class QQmlView;
class QQuickView; class QQuickView;
class QQuickWindow;
class QQmlEngine; class QQmlEngine;
class QFileInfo; class QFileInfo;
class QQmlComponent; class QQmlComponent;
@@ -131,6 +133,7 @@ public:
}; };
explicit NodeInstanceServer(NodeInstanceClientInterface *nodeInstanceClient); explicit NodeInstanceServer(NodeInstanceClientInterface *nodeInstanceClient);
~NodeInstanceServer() override;
void createInstances(const CreateInstancesCommand &command) override; void createInstances(const CreateInstancesCommand &command) override;
void changeFileUrl(const ChangeFileUrlCommand &command) override; void changeFileUrl(const ChangeFileUrlCommand &command) override;
@@ -192,6 +195,9 @@ public:
virtual QQmlView *declarativeView() const = 0; virtual QQmlView *declarativeView() const = 0;
virtual QQuickView *quickView() const = 0; virtual QQuickView *quickView() const = 0;
virtual QQuickWindow *quickWindow() const = 0;
virtual QQuickItem *rootItem() const = 0;
virtual void setRootItem(QQuickItem *item) = 0;
void sendDebugOutput(DebugOutputCommand::Type type, const QString &message, qint32 instanceId = 0); void sendDebugOutput(DebugOutputCommand::Type type, const QString &message, qint32 instanceId = 0);
void sendDebugOutput(DebugOutputCommand::Type type, void sendDebugOutput(DebugOutputCommand::Type type,
@@ -211,6 +217,8 @@ public:
virtual void handleInstanceLocked(const ServerNodeInstance &instance, bool enable, bool checkAncestors); virtual void handleInstanceLocked(const ServerNodeInstance &instance, bool enable, bool checkAncestors);
virtual void handleInstanceHidden(const ServerNodeInstance &instance, bool enable, bool checkAncestors); virtual void handleInstanceHidden(const ServerNodeInstance &instance, bool enable, bool checkAncestors);
virtual QImage grabWindow() = 0;
public slots: public slots:
void refreshLocalFileProperty(const QString &path); void refreshLocalFileProperty(const QString &path);
void refreshDummyData(const QString &path); void refreshDummyData(const QString &path);
@@ -288,7 +296,7 @@ protected:
QList<QQmlContext*> allSubContextsForObject(QObject *object); QList<QQmlContext*> allSubContextsForObject(QObject *object);
static QList<QObject*> allSubObjectsForObject(QObject *object); static QList<QObject*> allSubObjectsForObject(QObject *object);
virtual void resizeCanvasSizeToRootItemSize() = 0; virtual void resizeCanvasToRootItem() = 0;
void setupState(qint32 stateInstanceId); void setupState(qint32 stateInstanceId);
private: private:

View File

@@ -70,7 +70,7 @@ void Qt5CaptureImageNodeInstanceServer::collectItemChangesAndSendChangeCommands(
auto rooNodeInstance = rootNodeInstance(); auto rooNodeInstance = rootNodeInstance();
rooNodeInstance.rootQuickItem()->setClip(true); rooNodeInstance.rootQuickItem()->setClip(true);
DesignerSupport::polishItems(quickView()); DesignerSupport::polishItems(quickWindow());
QImage image = renderImage(rooNodeInstance); QImage image = renderImage(rooNodeInstance);

View File

@@ -88,7 +88,7 @@ void Qt5CapturePreviewNodeInstanceServer::collectItemChangesAndSendChangeCommand
if (!inFunction) { if (!inFunction) {
inFunction = true; inFunction = true;
DesignerSupport::polishItems(quickView()); DesignerSupport::polishItems(quickWindow());
QVector<CapturedDataCommand::StateData> stateDatas; QVector<CapturedDataCommand::StateData> stateDatas;
stateDatas.push_back(collectStateData(rootNodeInstance(), nodeInstances(), 0)); stateDatas.push_back(collectStateData(rootNodeInstance(), nodeInstances(), 0));

View File

@@ -87,6 +87,10 @@
#include <QtGui/qevent.h> #include <QtGui/qevent.h>
#include <QtGui/qguiapplication.h> #include <QtGui/qguiapplication.h>
#if QT_VERSION >= QT_VERSION_CHECK(6, 0, 0)
#include <QtQuick/private/qquickrendercontrol_p.h>
#endif
#ifdef QUICK3D_MODULE #ifdef QUICK3D_MODULE
#include <QtQuick3D/private/qquick3dnode_p.h> #include <QtQuick3D/private/qquick3dnode_p.h>
#include <QtQuick3D/private/qquick3dcamera_p.h> #include <QtQuick3D/private/qquick3dcamera_p.h>
@@ -98,6 +102,14 @@
#endif #endif
#endif #endif
// Uncomment to display FPS counter on the lower left corner of edit 3D view
//#define FPS_COUNTER
#ifdef FPS_COUNTER
#include <QtCore/qelapsedtimer.h>
static QElapsedTimer *_fpsTimer = nullptr;
static int _frameCount = 0;
#endif
namespace QmlDesigner { namespace QmlDesigner {
static QVariant objectToVariant(QObject *object) static QVariant objectToVariant(QObject *object)
@@ -135,29 +147,34 @@ static bool isQuick3DMode()
return mode3D; return mode3D;
} }
QQuickView *Qt5InformationNodeInstanceServer::createAuxiliaryQuickView(const QUrl &url, void Qt5InformationNodeInstanceServer::createAuxiliaryQuickView(const QUrl &url,
QQuickItem *&rootItem) RenderViewData &viewData)
{ {
#if QT_VERSION < QT_VERSION_CHECK(6, 0, 0) #if QT_VERSION < QT_VERSION_CHECK(6, 0, 0)
auto view = new QQuickView(quickView()->engine(), quickView()); viewData.window = new QQuickView(quickView()->engine(), quickView());
view->setFormat(quickView()->format()); viewData.window->setFormat(quickView()->format());
DesignerSupport::createOpenGLContext(view); DesignerSupport::createOpenGLContext(static_cast<QQuickView *>(viewData.window.data()));
#else #else
auto view = new QQuickView(quickView()->engine(), nullptr); viewData.renderControl = new QQuickRenderControl;
view->setFormat(quickView()->format()); viewData.window = new QQuickWindow(viewData.renderControl);
viewData.renderControl->initialize();
#endif #endif
QQmlComponent component(engine()); QQmlComponent component(engine());
component.loadUrl(url); component.loadUrl(url);
rootItem = qobject_cast<QQuickItem *>(component.create()); viewData.rootItem = qobject_cast<QQuickItem *>(component.create());
if (!rootItem) { if (!viewData.rootItem) {
qWarning() << "Could not create view for: " << url.toString() << component.errors(); qWarning() << "Could not create view for: " << url.toString() << component.errors();
return nullptr; return;
} }
DesignerSupport::setRootItem(view, rootItem); #if QT_VERSION < QT_VERSION_CHECK(6, 0, 0)
DesignerSupport::setRootItem(static_cast<QQuickView *>(viewData.window.data()), viewData.rootItem);
return view; #else
viewData.window->contentItem()->setSize(viewData.rootItem->size());
viewData.window->setGeometry(0, 0, viewData.rootItem->width(), viewData.rootItem->height());
viewData.rootItem->setParentItem(viewData.window->contentItem());
#endif
} }
void Qt5InformationNodeInstanceServer::updateLockedAndHiddenStates(const QSet<ServerNodeInstance> &instances) void Qt5InformationNodeInstanceServer::updateLockedAndHiddenStates(const QSet<ServerNodeInstance> &instances)
@@ -177,6 +194,65 @@ void Qt5InformationNodeInstanceServer::updateLockedAndHiddenStates(const QSet<Se
} }
} }
void Qt5InformationNodeInstanceServer::handleInputEvents()
{
if (m_editView3DData.window) {
int angleDelta = 0;
for (int i = 0; i < m_pendingInputEventCommands.size(); ++i) {
const InputEventCommand &command = m_pendingInputEventCommands[i];
if (command.type() == QEvent::Wheel) {
if (i < m_pendingInputEventCommands.size() - 1) {
// Peek at next command. If that is also a wheel with same button/modifiers
// state, skip this event and add the angle delta to the next one.
auto nextCommand = m_pendingInputEventCommands[i + 1];
if (nextCommand.type() == QEvent::MouseMove
&& nextCommand.button() == command.button()
&& nextCommand.buttons() == command.buttons()
&& nextCommand.modifiers() == command.modifiers()) {
angleDelta += command.angleDelta();
continue;
}
}
QWheelEvent *we
#if (QT_VERSION >= QT_VERSION_CHECK(5, 12, 0))
= new QWheelEvent(command.pos(), command.pos(), {0, 0},
{0, angleDelta + command.angleDelta()},
command.buttons(), command.modifiers(), Qt::NoScrollPhase,
false);
#else
= new QWheelEvent(command.pos(), command.pos(), {0, 0}, {0, command.angleDelta()},
0, Qt::Horizontal, command.buttons(), command.modifiers(),
Qt::NoScrollPhase, Qt::MouseEventNotSynthesized);
#endif
angleDelta = 0;
QGuiApplication::sendEvent(m_editView3DData.window, we);
} else {
if (command.type() == QEvent::MouseMove && i < m_pendingInputEventCommands.size() - 1) {
// Peek at next command. If that is also a move with only difference being
// the position, skip this event as it is pointless
auto nextCommand = m_pendingInputEventCommands[i + 1];
if (nextCommand.type() == QEvent::MouseMove
&& nextCommand.button() == command.button()
&& nextCommand.buttons() == command.buttons()
&& nextCommand.modifiers() == command.modifiers()) {
continue;
}
}
auto me = new QMouseEvent(command.type(), command.pos(), command.button(),
command.buttons(), command.modifiers());
// We must use sendEvent in Qt 6, as using postEvent allows the associated position
// data stored internally in QMutableEventPoint to potentially be updated by system
// before the event is delivered.
QGuiApplication::sendEvent(m_editView3DData.window, me);
}
}
m_pendingInputEventCommands.clear();
render3DEditView();
}
}
void Qt5InformationNodeInstanceServer::createEditView3D() void Qt5InformationNodeInstanceServer::createEditView3D()
{ {
#ifdef QUICK3D_MODULE #ifdef QUICK3D_MODULE
@@ -199,10 +275,10 @@ void Qt5InformationNodeInstanceServer::createEditView3D()
new QmlDesigner::Internal::IconGizmoImageProvider); new QmlDesigner::Internal::IconGizmoImageProvider);
m_3dHelper = helper; m_3dHelper = helper;
m_editView3D = createAuxiliaryQuickView(QUrl("qrc:/qtquickplugin/mockfiles/EditView3D.qml"), m_editView3DRootItem); createAuxiliaryQuickView(QUrl("qrc:/qtquickplugin/mockfiles/EditView3D.qml"), m_editView3DData);
if (m_editView3DRootItem) if (m_editView3DData.rootItem)
helper->setParent(m_editView3DRootItem); helper->setParent(m_editView3DData.rootItem);
#endif #endif
} }
@@ -373,10 +449,10 @@ void Qt5InformationNodeInstanceServer::handleNode3DDestroyed(QObject *obj)
{ {
#ifdef QUICK3D_MODULE #ifdef QUICK3D_MODULE
if (qobject_cast<QQuick3DCamera *>(obj)) { if (qobject_cast<QQuick3DCamera *>(obj)) {
QMetaObject::invokeMethod(m_editView3DRootItem, "releaseCameraGizmo", QMetaObject::invokeMethod(m_editView3DData.rootItem, "releaseCameraGizmo",
Q_ARG(QVariant, objectToVariant(obj))); Q_ARG(QVariant, objectToVariant(obj)));
} else if (qobject_cast<QQuick3DAbstractLight *>(obj)) { } else if (qobject_cast<QQuick3DAbstractLight *>(obj)) {
QMetaObject::invokeMethod(m_editView3DRootItem, "releaseLightGizmo", QMetaObject::invokeMethod(m_editView3DData.rootItem, "releaseLightGizmo",
Q_ARG(QVariant, objectToVariant(obj))); Q_ARG(QVariant, objectToVariant(obj)));
} }
removeNode3D(obj); removeNode3D(obj);
@@ -392,7 +468,7 @@ void Qt5InformationNodeInstanceServer::updateView3DRect(QObject *view3D)
viewPortrect = QRectF(0., 0., view3D->property("width").toDouble(), viewPortrect = QRectF(0., 0., view3D->property("width").toDouble(),
view3D->property("height").toDouble()); view3D->property("height").toDouble());
} }
QQmlProperty viewPortProperty(m_editView3DRootItem, "viewPortRect", context()); QQmlProperty viewPortProperty(m_editView3DData.rootItem, "viewPortRect", context());
viewPortProperty.write(viewPortrect); viewPortProperty.write(viewPortrect);
} }
@@ -405,7 +481,7 @@ void Qt5InformationNodeInstanceServer::updateActiveSceneToEditView3D()
// Active scene change handling on qml side is async, so a deleted importScene would crash // Active scene change handling on qml side is async, so a deleted importScene would crash
// editView when it updates next. Disable/enable edit view update synchronously to avoid this. // editView when it updates next. Disable/enable edit view update synchronously to avoid this.
QVariant activeSceneVar = objectToVariant(m_active3DScene); QVariant activeSceneVar = objectToVariant(m_active3DScene);
QMetaObject::invokeMethod(m_editView3DRootItem, "enableEditViewUpdate", QMetaObject::invokeMethod(m_editView3DData.rootItem, "enableEditViewUpdate",
Q_ARG(QVariant, activeSceneVar)); Q_ARG(QVariant, activeSceneVar));
ServerNodeInstance sceneInstance = active3DSceneInstance(); ServerNodeInstance sceneInstance = active3DSceneInstance();
@@ -419,7 +495,7 @@ void Qt5InformationNodeInstanceServer::updateActiveSceneToEditView3D()
m_active3DSceneUpdatePending = false; m_active3DSceneUpdatePending = false;
} }
QMetaObject::invokeMethod(m_editView3DRootItem, "setActiveScene", Qt::QueuedConnection, QMetaObject::invokeMethod(m_editView3DData.rootItem, "setActiveScene", Qt::QueuedConnection,
Q_ARG(QVariant, activeSceneVar), Q_ARG(QVariant, activeSceneVar),
Q_ARG(QVariant, QVariant::fromValue(sceneId))); Q_ARG(QVariant, QVariant::fromValue(sceneId)));
@@ -472,11 +548,11 @@ void Qt5InformationNodeInstanceServer::resolveSceneRoots()
if (newRoot != oldRoot) { if (newRoot != oldRoot) {
if (qobject_cast<QQuick3DCamera *>(node)) { if (qobject_cast<QQuick3DCamera *>(node)) {
QMetaObject::invokeMethod(m_editView3DRootItem, "updateCameraGizmoScene", QMetaObject::invokeMethod(m_editView3DData.rootItem, "updateCameraGizmoScene",
Q_ARG(QVariant, objectToVariant(newRoot)), Q_ARG(QVariant, objectToVariant(newRoot)),
Q_ARG(QVariant, objectToVariant(node))); Q_ARG(QVariant, objectToVariant(node)));
} else if (qobject_cast<QQuick3DAbstractLight *>(node)) { } else if (qobject_cast<QQuick3DAbstractLight *>(node)) {
QMetaObject::invokeMethod(m_editView3DRootItem, "updateLightGizmoScene", QMetaObject::invokeMethod(m_editView3DData.rootItem, "updateLightGizmoScene",
Q_ARG(QVariant, objectToVariant(newRoot)), Q_ARG(QVariant, objectToVariant(newRoot)),
Q_ARG(QVariant, objectToVariant(node))); Q_ARG(QVariant, objectToVariant(node)));
} }
@@ -535,30 +611,30 @@ void Qt5InformationNodeInstanceServer::render3DEditView(int count)
void Qt5InformationNodeInstanceServer::doRender3DEditView() void Qt5InformationNodeInstanceServer::doRender3DEditView()
{ {
if (m_editView3DSetupDone) { if (m_editView3DSetupDone) {
if (!m_editView3DContentItem) if (!m_editView3DData.contentItem)
m_editView3DContentItem = getContentItemForRendering(m_editView3DRootItem); m_editView3DData.contentItem = getContentItemForRendering(m_editView3DData.rootItem);
QImage renderImage; QImage renderImage;
updateNodesRecursive(m_editView3DContentItem); updateNodesRecursive(m_editView3DData.contentItem);
#if QT_VERSION < QT_VERSION_CHECK(6, 0, 0) #if QT_VERSION < QT_VERSION_CHECK(6, 0, 0)
if (Internal::QuickItemNodeInstance::unifiedRenderPath()) { if (Internal::QuickItemNodeInstance::unifiedRenderPath()) {
renderImage = m_editView3D->grabWindow(); renderImage = m_editView3DData.window->grabWindow();
} else { } else {
// Fake render loop signaling to update things like QML items as 3D textures // Fake render loop signaling to update things like QML items as 3D textures
m_editView3D->beforeSynchronizing(); m_editView3DData.window->beforeSynchronizing();
m_editView3D->beforeRendering(); m_editView3DData.window->beforeRendering();
QSizeF size = qobject_cast<QQuickItem *>(m_editView3DContentItem)->size(); QSizeF size = qobject_cast<QQuickItem *>(m_editView3DData.contentItem)->size();
QRectF renderRect(QPointF(0., 0.), size); QRectF renderRect(QPointF(0., 0.), size);
renderImage = designerSupport()->renderImageForItem(m_editView3DContentItem, renderImage = designerSupport()->renderImageForItem(m_editView3DData.contentItem,
renderRect, size.toSize()); renderRect, size.toSize());
m_editView3D->afterRendering(); m_editView3DData.window->afterRendering();
} }
#else #else
renderImage = m_editView3D->grabWindow(); renderImage = grabRenderControl(m_editView3DData);
#endif #endif
// There's no instance related to image, so instance id is -1. // There's no instance related to image, so instance id is -1.
@@ -572,6 +648,18 @@ void Qt5InformationNodeInstanceServer::doRender3DEditView()
m_render3DEditViewTimer.start(0); m_render3DEditViewTimer.start(0);
--m_need3DEditViewRender; --m_need3DEditViewRender;
} }
#ifdef FPS_COUNTER
// Force constant rendering for accurate fps count
if (!m_render3DEditViewTimer.isActive())
m_render3DEditViewTimer.start(0);
++_frameCount;
if (_fpsTimer->elapsed() > 1000) {
QQmlProperty fpsProperty(m_editView3DData.rootItem, "fps", context());
fpsProperty.write(_frameCount);
_frameCount = 0;
_fpsTimer->start();
}
#endif
} }
} }
@@ -601,9 +689,9 @@ void Qt5InformationNodeInstanceServer::doRenderModelNodeImageView()
void Qt5InformationNodeInstanceServer::doRenderModelNode3DImageView() void Qt5InformationNodeInstanceServer::doRenderModelNode3DImageView()
{ {
#ifdef QUICK3D_MODULE #ifdef QUICK3D_MODULE
if (m_ModelNode3DImageViewRootItem) { if (m_modelNode3DImageViewData.rootItem) {
if (!m_ModelNode3DImageViewContentItem) if (!m_modelNode3DImageViewData.contentItem)
m_ModelNode3DImageViewContentItem = getContentItemForRendering(m_ModelNode3DImageViewRootItem); m_modelNode3DImageViewData.contentItem = getContentItemForRendering(m_modelNode3DImageViewData.rootItem);
// Key number is selected so that it is unlikely to conflict other ImageContainer use. // Key number is selected so that it is unlikely to conflict other ImageContainer use.
auto imgContainer = ImageContainer(m_modelNodePreviewImageCommand.instanceId(), {}, 2100000001); auto imgContainer = ImageContainer(m_modelNodePreviewImageCommand.instanceId(), {}, 2100000001);
@@ -628,43 +716,48 @@ void Qt5InformationNodeInstanceServer::doRenderModelNode3DImageView()
if (Internal::QuickItemNodeInstance::unifiedRenderPath()) { if (Internal::QuickItemNodeInstance::unifiedRenderPath()) {
// Requested size is already adjusted for target pixel ratio, so we have to adjust // Requested size is already adjusted for target pixel ratio, so we have to adjust
// back if ratio is not default for our window. // back if ratio is not default for our window.
double ratio = m_ModelNode3DImageView->devicePixelRatio(); double ratio = m_modelNode3DImageViewData.window->devicePixelRatio();
renderSize.setWidth(qRound(qreal(renderSize.width()) / ratio)); renderSize.setWidth(qRound(qreal(renderSize.width()) / ratio));
renderSize.setHeight(qRound(qreal(renderSize.height()) / ratio)); renderSize.setHeight(qRound(qreal(renderSize.height()) / ratio));
} }
#if QT_VERSION >= QT_VERSION_CHECK(6, 0, 0)
m_modelNode3DImageViewData.bufferDirty = m_modelNode3DImageViewData.bufferDirty
|| m_modelNode3DImageViewData.rootItem->width() != renderSize.width()
|| m_modelNode3DImageViewData.rootItem->height() != renderSize.height();
#endif
QMetaObject::invokeMethod(m_ModelNode3DImageViewRootItem, "createViewForObject", m_modelNode3DImageViewData.window->resize(renderSize);
Q_ARG(QVariant, objectToVariant(instanceObj)), m_modelNode3DImageViewData.rootItem->setSize(renderSize);
Q_ARG(QVariant, QVariant::fromValue(renderSize.width())),
Q_ARG(QVariant, QVariant::fromValue(renderSize.height())));
QMetaObject::invokeMethod(m_modelNode3DImageViewData.rootItem, "createViewForObject",
Q_ARG(QVariant, objectToVariant(instanceObj)));
bool ready = false; bool ready = false;
int count = 0; // Ensure we don't ever get stuck in an infinite loop int count = 0; // Ensure we don't ever get stuck in an infinite loop
while (!ready && ++count < 10) { while (!ready && ++count < 10) {
updateNodesRecursive(m_ModelNode3DImageViewContentItem); updateNodesRecursive(m_modelNode3DImageViewData.contentItem);
#if QT_VERSION < QT_VERSION_CHECK(6, 0, 0) #if QT_VERSION < QT_VERSION_CHECK(6, 0, 0)
if (Internal::QuickItemNodeInstance::unifiedRenderPath()) { if (Internal::QuickItemNodeInstance::unifiedRenderPath()) {
renderImage = m_ModelNode3DImageView->grabWindow(); renderImage = m_modelNode3DImageViewData.window->grabWindow();
} else { } else {
// Fake render loop signaling to update things like QML items as 3D textures // Fake render loop signaling to update things like QML items as 3D textures
m_ModelNode3DImageView->beforeSynchronizing(); m_modelNode3DImageViewData.window->beforeSynchronizing();
m_ModelNode3DImageView->beforeRendering(); m_modelNode3DImageViewData.window->beforeRendering();
QSizeF size = qobject_cast<QQuickItem *>(m_ModelNode3DImageViewContentItem)->size(); QSizeF size = qobject_cast<QQuickItem *>(m_modelNode3DImageViewData.contentItem)->size();
QRectF renderRect(QPointF(0., 0.), size); QRectF renderRect(QPointF(0., 0.), size);
renderImage = designerSupport()->renderImageForItem(m_ModelNode3DImageViewContentItem, renderImage = designerSupport()->renderImageForItem(m_modelNode3DImageViewData.contentItem,
renderRect, size.toSize()); renderRect, size.toSize());
m_ModelNode3DImageView->afterRendering(); m_modelNode3DImageViewData.window->afterRendering();
} }
#else #else
renderImage = m_ModelNode3DImageView->grabWindow(); renderImage = grabRenderControl(m_modelNode3DImageViewData);
#endif #endif
QMetaObject::invokeMethod(m_ModelNode3DImageViewRootItem, "afterRender"); QMetaObject::invokeMethod(m_modelNode3DImageViewData.rootItem, "afterRender");
ready = QQmlProperty::read(m_ModelNode3DImageViewRootItem, "ready").value<bool>(); ready = QQmlProperty::read(m_modelNode3DImageViewData.rootItem, "ready").value<bool>();
} }
QMetaObject::invokeMethod(m_ModelNode3DImageViewRootItem, "destroyView"); QMetaObject::invokeMethod(m_modelNode3DImageViewData.rootItem, "destroyView");
if (!m_modelNodePreviewImageCommand.componentPath().isEmpty()) { if (!m_modelNodePreviewImageCommand.componentPath().isEmpty()) {
// If component changes, puppet will need a reset anyway, so we can cache the image // If component changes, puppet will need a reset anyway, so we can cache the image
m_modelNodePreviewImageCache.insert(m_modelNodePreviewImageCommand.componentPath(), renderImage); m_modelNodePreviewImageCache.insert(m_modelNodePreviewImageCommand.componentPath(), renderImage);
@@ -705,9 +798,9 @@ static QRectF itemBoundingRect(QQuickItem *item)
void Qt5InformationNodeInstanceServer::doRenderModelNode2DImageView() void Qt5InformationNodeInstanceServer::doRenderModelNode2DImageView()
{ {
if (m_ModelNode2DImageViewRootItem) { if (m_modelNode2DImageViewData.rootItem) {
if (!m_ModelNode2DImageViewContentItem) if (!m_modelNode2DImageViewData.contentItem)
m_ModelNode2DImageViewContentItem = getContentItemForRendering(m_ModelNode2DImageViewRootItem); m_modelNode2DImageViewData.contentItem = getContentItemForRendering(m_modelNode2DImageViewData.rootItem);
// Key number is the same as in 3D case as they produce image for same purpose // Key number is the same as in 3D case as they produce image for same purpose
auto imgContainer = ImageContainer(m_modelNodePreviewImageCommand.instanceId(), {}, 2100000001); auto imgContainer = ImageContainer(m_modelNodePreviewImageCommand.instanceId(), {}, 2100000001);
@@ -730,7 +823,7 @@ void Qt5InformationNodeInstanceServer::doRenderModelNode2DImageView()
return; return;
} }
instanceItem->setParentItem(m_ModelNode2DImageViewContentItem); instanceItem->setParentItem(m_modelNode2DImageViewData.contentItem);
// Some component may expect to always be shown at certain size, so their layouts may // Some component may expect to always be shown at certain size, so their layouts may
// not support scaling, so let's always render at the default size if item has one and // not support scaling, so let's always render at the default size if item has one and
@@ -742,21 +835,28 @@ void Qt5InformationNodeInstanceServer::doRenderModelNode2DImageView()
renderSize = finalSize; renderSize = finalSize;
renderRect = QRectF(QPointF(0., 0.), QSizeF(renderSize)); renderRect = QRectF(QPointF(0., 0.), QSizeF(renderSize));
} }
m_ModelNode2DImageView->resize(renderSize);
m_ModelNode2DImageViewRootItem->setSize(renderSize);
m_ModelNode2DImageViewContentItem->setPosition(QPointF(-renderRect.x(), -renderRect.y()));
updateNodesRecursive(m_ModelNode2DImageViewContentItem); #if QT_VERSION >= QT_VERSION_CHECK(6, 0, 0)
m_modelNode2DImageViewData.bufferDirty = m_modelNode2DImageViewData.bufferDirty
|| m_modelNode2DImageViewData.rootItem->width() != renderSize.width()
|| m_modelNode2DImageViewData.rootItem->height() != renderSize.height();
#endif
m_modelNode2DImageViewData.window->resize(renderSize);
m_modelNode2DImageViewData.rootItem->setSize(renderSize);
m_modelNode2DImageViewData.contentItem->setPosition(QPointF(-renderRect.x(), -renderRect.y()));
updateNodesRecursive(m_modelNode2DImageViewData.contentItem);
#if QT_VERSION < QT_VERSION_CHECK(6, 0, 0) #if QT_VERSION < QT_VERSION_CHECK(6, 0, 0)
if (Internal::QuickItemNodeInstance::unifiedRenderPath()) { if (Internal::QuickItemNodeInstance::unifiedRenderPath()) {
renderImage = m_ModelNode2DImageView->grabWindow(); renderImage = m_modelNode2DImageViewData.window->grabWindow();
} else { } else {
renderImage = designerSupport()->renderImageForItem(m_ModelNode2DImageViewContentItem, renderImage = designerSupport()->renderImageForItem(m_modelNode2DImageViewData.contentItem,
renderRect, renderSize); renderRect, renderSize);
} }
#else #else
renderImage = m_ModelNode2DImageView->grabWindow(); renderImage = grabRenderControl(m_modelNode2DImageViewData);
#endif #endif
if (!imageHasContent(renderImage)) if (!imageHasContent(renderImage))
@@ -788,13 +888,34 @@ Qt5InformationNodeInstanceServer::Qt5InformationNodeInstanceServer(NodeInstanceC
m_propertyChangeTimer.setSingleShot(true); m_propertyChangeTimer.setSingleShot(true);
m_selectionChangeTimer.setSingleShot(true); m_selectionChangeTimer.setSingleShot(true);
m_render3DEditViewTimer.setSingleShot(true); m_render3DEditViewTimer.setSingleShot(true);
m_inputEventTimer.setSingleShot(true);
m_renderModelNodeImageViewTimer.setSingleShot(true); m_renderModelNodeImageViewTimer.setSingleShot(true);
#ifdef FPS_COUNTER
if (!_fpsTimer) {
_fpsTimer = new QElapsedTimer;
_fpsTimer->start();
}
#endif
} }
Qt5InformationNodeInstanceServer::~Qt5InformationNodeInstanceServer() Qt5InformationNodeInstanceServer::~Qt5InformationNodeInstanceServer()
{ {
m_editView3DSetupDone = false;
m_propertyChangeTimer.stop();
m_propertyChangeTimer.stop();
m_selectionChangeTimer.stop();
m_render3DEditViewTimer.stop();
m_inputEventTimer.stop();
for (auto view : qAsConst(m_view3Ds)) for (auto view : qAsConst(m_view3Ds))
QObject::disconnect(view, nullptr, this, nullptr); view->disconnect();
for (auto node : qAsConst(m_3DSceneMap))
node->disconnect();
if (m_editView3DData.rootItem)
QMetaObject::invokeMethod(m_editView3DData.rootItem, "aboutToShutDown", Qt::DirectConnection);
} }
void Qt5InformationNodeInstanceServer::sendTokenBack() void Qt5InformationNodeInstanceServer::sendTokenBack()
@@ -887,29 +1008,14 @@ void Qt5InformationNodeInstanceServer::initializeAuxiliaryViews()
#ifdef QUICK3D_MODULE #ifdef QUICK3D_MODULE
if (isQuick3DMode()) if (isQuick3DMode())
createEditView3D(); createEditView3D();
m_ModelNode3DImageView = createAuxiliaryQuickView(QUrl("qrc:/qtquickplugin/mockfiles/ModelNode3DImageView.qml"), createAuxiliaryQuickView(QUrl("qrc:/qtquickplugin/mockfiles/ModelNode3DImageView.qml"),
m_ModelNode3DImageViewRootItem); m_modelNode3DImageViewData);
#endif #endif
m_ModelNode2DImageView = createAuxiliaryQuickView(QUrl("qrc:/qtquickplugin/mockfiles/ModelNode2DImageView.qml"), createAuxiliaryQuickView(QUrl("qrc:/qtquickplugin/mockfiles/ModelNode2DImageView.qml"),
m_ModelNode2DImageViewRootItem); m_modelNode2DImageViewData);
m_ModelNode2DImageView->setDefaultAlphaBuffer(true); m_modelNode2DImageViewData.window->setDefaultAlphaBuffer(true);
m_ModelNode2DImageView->setColor(Qt::transparent); m_modelNode2DImageViewData.window->setColor(Qt::transparent);
#if QT_VERSION >= QT_VERSION_CHECK(6, 0, 0)
if (!m_editView3D.isNull()) {
m_editView3D->show();
m_editView3D->lower();
}
if (!m_ModelNode3DImageView.isNull()) {
m_ModelNode3DImageView->show();
m_ModelNode3DImageView->lower();
}
if (!m_ModelNode2DImageView.isNull()) {
m_ModelNode2DImageView->show();
m_ModelNode2DImageView->lower();
}
#endif
} }
void Qt5InformationNodeInstanceServer::handleObjectPropertyChangeTimeout() void Qt5InformationNodeInstanceServer::handleObjectPropertyChangeTimeout()
@@ -940,7 +1046,7 @@ void Qt5InformationNodeInstanceServer::createCameraAndLightGizmos(
while (cameraIt != cameras.constEnd()) { while (cameraIt != cameras.constEnd()) {
const auto cameraObjs = cameraIt.value(); const auto cameraObjs = cameraIt.value();
for (auto &obj : cameraObjs) { for (auto &obj : cameraObjs) {
QMetaObject::invokeMethod(m_editView3DRootItem, "addCameraGizmo", QMetaObject::invokeMethod(m_editView3DData.rootItem, "addCameraGizmo",
Q_ARG(QVariant, objectToVariant(cameraIt.key())), Q_ARG(QVariant, objectToVariant(cameraIt.key())),
Q_ARG(QVariant, objectToVariant(obj))); Q_ARG(QVariant, objectToVariant(obj)));
} }
@@ -950,7 +1056,7 @@ void Qt5InformationNodeInstanceServer::createCameraAndLightGizmos(
while (lightIt != lights.constEnd()) { while (lightIt != lights.constEnd()) {
const auto lightObjs = lightIt.value(); const auto lightObjs = lightIt.value();
for (auto &obj : lightObjs) { for (auto &obj : lightObjs) {
QMetaObject::invokeMethod(m_editView3DRootItem, "addLightGizmo", QMetaObject::invokeMethod(m_editView3DData.rootItem, "addLightGizmo",
Q_ARG(QVariant, objectToVariant(lightIt.key())), Q_ARG(QVariant, objectToVariant(lightIt.key())),
Q_ARG(QVariant, objectToVariant(obj))); Q_ARG(QVariant, objectToVariant(obj)));
} }
@@ -1134,7 +1240,7 @@ void Qt5InformationNodeInstanceServer::setup3DEditView(const QList<ServerNodeIns
const QHash<QString, QVariantMap> &toolStates) const QHash<QString, QVariantMap> &toolStates)
{ {
#ifdef QUICK3D_MODULE #ifdef QUICK3D_MODULE
if (!m_editView3DRootItem) if (!m_editView3DData.rootItem)
return; return;
ServerNodeInstance root = rootNodeInstance(); ServerNodeInstance root = rootNodeInstance();
@@ -1142,13 +1248,13 @@ void Qt5InformationNodeInstanceServer::setup3DEditView(const QList<ServerNodeIns
add3DViewPorts(instanceList); add3DViewPorts(instanceList);
add3DScenes(instanceList); add3DScenes(instanceList);
QObject::connect(m_editView3DRootItem, SIGNAL(selectionChanged(QVariant)), QObject::connect(m_editView3DData.rootItem, SIGNAL(selectionChanged(QVariant)),
this, SLOT(handleSelectionChanged(QVariant))); this, SLOT(handleSelectionChanged(QVariant)));
QObject::connect(m_editView3DRootItem, SIGNAL(commitObjectProperty(QVariant, QVariant)), QObject::connect(m_editView3DData.rootItem, SIGNAL(commitObjectProperty(QVariant, QVariant)),
this, SLOT(handleObjectPropertyCommit(QVariant, QVariant))); this, SLOT(handleObjectPropertyCommit(QVariant, QVariant)));
QObject::connect(m_editView3DRootItem, SIGNAL(changeObjectProperty(QVariant, QVariant)), QObject::connect(m_editView3DData.rootItem, SIGNAL(changeObjectProperty(QVariant, QVariant)),
this, SLOT(handleObjectPropertyChange(QVariant, QVariant))); this, SLOT(handleObjectPropertyChange(QVariant, QVariant)));
QObject::connect(m_editView3DRootItem, SIGNAL(notifyActiveSceneChange()), QObject::connect(m_editView3DData.rootItem, SIGNAL(notifyActiveSceneChange()),
this, SLOT(handleActiveSceneChange())); this, SLOT(handleActiveSceneChange()));
QObject::connect(&m_propertyChangeTimer, &QTimer::timeout, QObject::connect(&m_propertyChangeTimer, &QTimer::timeout,
this, &Qt5InformationNodeInstanceServer::handleObjectPropertyChangeTimeout); this, &Qt5InformationNodeInstanceServer::handleObjectPropertyChangeTimeout);
@@ -1156,6 +1262,8 @@ void Qt5InformationNodeInstanceServer::setup3DEditView(const QList<ServerNodeIns
this, &Qt5InformationNodeInstanceServer::handleSelectionChangeTimeout); this, &Qt5InformationNodeInstanceServer::handleSelectionChangeTimeout);
QObject::connect(&m_render3DEditViewTimer, &QTimer::timeout, QObject::connect(&m_render3DEditViewTimer, &QTimer::timeout,
this, &Qt5InformationNodeInstanceServer::doRender3DEditView); this, &Qt5InformationNodeInstanceServer::doRender3DEditView);
QObject::connect(&m_inputEventTimer, &QTimer::timeout,
this, &Qt5InformationNodeInstanceServer::handleInputEvents);
QString lastSceneId; QString lastSceneId;
auto helper = qobject_cast<QmlDesigner::Internal::GeneralHelper *>(m_3dHelper); auto helper = qobject_cast<QmlDesigner::Internal::GeneralHelper *>(m_3dHelper);
@@ -1167,7 +1275,7 @@ void Qt5InformationNodeInstanceServer::setup3DEditView(const QList<ServerNodeIns
} }
if (toolStates.contains(helper->globalStateId())) { if (toolStates.contains(helper->globalStateId())) {
if (toolStates[helper->globalStateId()].contains(helper->rootSizeKey())) if (toolStates[helper->globalStateId()].contains(helper->rootSizeKey()))
m_editView3DRootItem->setSize(toolStates[helper->globalStateId()][helper->rootSizeKey()].value<QSize>()); m_editView3DData.rootItem->setSize(toolStates[helper->globalStateId()][helper->rootSizeKey()].value<QSize>());
if (toolStates[helper->globalStateId()].contains(helper->lastSceneIdKey())) if (toolStates[helper->globalStateId()].contains(helper->lastSceneIdKey()))
lastSceneId = toolStates[helper->globalStateId()][helper->lastSceneIdKey()].toString(); lastSceneId = toolStates[helper->globalStateId()][helper->lastSceneIdKey()].toString();
} }
@@ -1198,7 +1306,7 @@ void Qt5InformationNodeInstanceServer::setup3DEditView(const QList<ServerNodeIns
if (toolStates.contains({})) { if (toolStates.contains({})) {
// Update tool state to an existing no-scene state before updating the active scene to // Update tool state to an existing no-scene state before updating the active scene to
// ensure the previous state is inherited properly in all cases. // ensure the previous state is inherited properly in all cases.
QMetaObject::invokeMethod(m_editView3DRootItem, "updateToolStates", Qt::QueuedConnection, QMetaObject::invokeMethod(m_editView3DData.rootItem, "updateToolStates", Qt::QueuedConnection,
Q_ARG(QVariant, toolStates[{}]), Q_ARG(QVariant, toolStates[{}]),
Q_ARG(QVariant, QVariant::fromValue(false))); Q_ARG(QVariant, QVariant::fromValue(false)));
} }
@@ -1221,12 +1329,12 @@ void Qt5InformationNodeInstanceServer::collectItemChangesAndSendChangeCommands()
if (!inFunction) { if (!inFunction) {
inFunction = true; inFunction = true;
DesignerSupport::polishItems(quickView()); DesignerSupport::polishItems(quickWindow());
QSet<ServerNodeInstance> informationChangedInstanceSet; QSet<ServerNodeInstance> informationChangedInstanceSet;
QVector<InstancePropertyPair> propertyChangedList; QVector<InstancePropertyPair> propertyChangedList;
if (quickView()) { if (quickWindow()) {
foreach (QQuickItem *item, allItems()) { foreach (QQuickItem *item, allItems()) {
if (item && hasInstanceForObject(item)) { if (item && hasInstanceForObject(item)) {
ServerNodeInstance instance = instanceForObject(item); ServerNodeInstance instance = instanceForObject(item);
@@ -1456,13 +1564,13 @@ void Qt5InformationNodeInstanceServer::changeSelection(const ChangeSelectionComm
// Ensure the UI has enough selection box items. If it doesn't yet have them, which can be the // Ensure the UI has enough selection box items. If it doesn't yet have them, which can be the
// case when the first selection processed is a multiselection, we wait a bit as // case when the first selection processed is a multiselection, we wait a bit as
// using the new boxes immediately leads to visual glitches. // using the new boxes immediately leads to visual glitches.
int boxCount = m_editView3DRootItem->property("selectionBoxes").value<QVariantList>().size(); int boxCount = m_editView3DData.rootItem->property("selectionBoxes").value<QVariantList>().size();
if (boxCount < selectedObjs.size()) { if (boxCount < selectedObjs.size()) {
QMetaObject::invokeMethod(m_editView3DRootItem, "ensureSelectionBoxes", QMetaObject::invokeMethod(m_editView3DData.rootItem, "ensureSelectionBoxes",
Q_ARG(QVariant, QVariant::fromValue(selectedObjs.size()))); Q_ARG(QVariant, QVariant::fromValue(selectedObjs.size())));
m_selectionChangeTimer.start(0); m_selectionChangeTimer.start(0);
} else { } else {
QMetaObject::invokeMethod(m_editView3DRootItem, "selectObjects", QMetaObject::invokeMethod(m_editView3DData.rootItem, "selectObjects",
Q_ARG(QVariant, QVariant::fromValue(selectedObjs))); Q_ARG(QVariant, QVariant::fromValue(selectedObjs)));
} }
@@ -1511,27 +1619,10 @@ void Qt5InformationNodeInstanceServer::removeInstances(const RemoveInstancesComm
void Qt5InformationNodeInstanceServer::inputEvent(const InputEventCommand &command) void Qt5InformationNodeInstanceServer::inputEvent(const InputEventCommand &command)
{ {
if (m_editView3D) { if (m_editView3DData.window) {
if (command.type() == QEvent::Wheel) { m_pendingInputEventCommands.append(command);
QWheelEvent *we if (!m_inputEventTimer.isActive())
#if (QT_VERSION >= QT_VERSION_CHECK(5, 12, 0)) m_inputEventTimer.start(0);
= new QWheelEvent(command.pos(), command.pos(), {0, 0}, {0, command.angleDelta()},
command.buttons(), command.modifiers(), Qt::NoScrollPhase,
false);
#else
= new QWheelEvent(command.pos(), command.pos(), {0, 0}, {0, command.angleDelta()},
0, Qt::Horizontal, command.buttons(), command.modifiers(),
Qt::NoScrollPhase, Qt::MouseEventNotSynthesized);
#endif
QGuiApplication::postEvent(m_editView3D, we);
} else {
auto me = new QMouseEvent(command.type(), command.pos(), command.button(),
command.buttons(), command.modifiers());
QGuiApplication::postEvent(m_editView3D, me);
}
render3DEditView();
} }
} }
@@ -1554,7 +1645,7 @@ void Qt5InformationNodeInstanceServer::view3DAction(const View3DActionCommand &c
updatedState.insert("transformMode", 2); updatedState.insert("transformMode", 2);
break; break;
case View3DActionCommand::FitToView: case View3DActionCommand::FitToView:
QMetaObject::invokeMethod(m_editView3DRootItem, "fitToView"); QMetaObject::invokeMethod(m_editView3DData.rootItem, "fitToView");
break; break;
case View3DActionCommand::SelectionModeToggle: case View3DActionCommand::SelectionModeToggle:
updatedState.insert("selectionMode", command.isEnabled() ? 1 : 0); updatedState.insert("selectionMode", command.isEnabled() ? 1 : 0);
@@ -1578,7 +1669,7 @@ void Qt5InformationNodeInstanceServer::view3DAction(const View3DActionCommand &c
} }
if (!updatedState.isEmpty()) { if (!updatedState.isEmpty()) {
QMetaObject::invokeMethod(m_editView3DRootItem, "updateToolStates", QMetaObject::invokeMethod(m_editView3DData.rootItem, "updateToolStates",
Q_ARG(QVariant, updatedState), Q_ARG(QVariant, updatedState),
Q_ARG(QVariant, QVariant::fromValue(false))); Q_ARG(QVariant, QVariant::fromValue(false)));
} }
@@ -1619,7 +1710,7 @@ void Qt5InformationNodeInstanceServer::changeIds(const ChangeIdsCommand &command
qint32 sceneInstanceId = sceneInstance.instanceId(); qint32 sceneInstanceId = sceneInstance.instanceId();
for (const auto &id : command.ids) { for (const auto &id : command.ids) {
if (sceneInstanceId == id.instanceId()) { if (sceneInstanceId == id.instanceId()) {
QMetaObject::invokeMethod(m_editView3DRootItem, "handleActiveSceneIdChange", QMetaObject::invokeMethod(m_editView3DData.rootItem, "handleActiveSceneIdChange",
Qt::QueuedConnection, Qt::QueuedConnection,
Q_ARG(QVariant, QVariant(sceneInstance.id()))); Q_ARG(QVariant, QVariant(sceneInstance.id())));
render3DEditView(); render3DEditView();
@@ -1763,12 +1854,18 @@ void Qt5InformationNodeInstanceServer::update3DViewState(const Update3dViewState
#ifdef QUICK3D_MODULE #ifdef QUICK3D_MODULE
if (command.type() == Update3dViewStateCommand::SizeChange) { if (command.type() == Update3dViewStateCommand::SizeChange) {
if (m_editView3DSetupDone) { if (m_editView3DSetupDone) {
m_editView3DRootItem->setSize(command.size()); m_editView3DData.rootItem->setSize(command.size());
#if QT_VERSION >= QT_VERSION_CHECK(6, 0, 0)
m_editView3DData.window->contentItem()->setSize(m_editView3DData.rootItem->size());
m_editView3DData.window->setGeometry(0, 0, m_editView3DData.rootItem->width(),
m_editView3DData.rootItem->height());
m_editView3DData.bufferDirty = true;
#endif
auto helper = qobject_cast<QmlDesigner::Internal::GeneralHelper *>(m_3dHelper); auto helper = qobject_cast<QmlDesigner::Internal::GeneralHelper *>(m_3dHelper);
if (helper) if (helper)
helper->storeToolState(helper->globalStateId(), helper->rootSizeKey(), QVariant(command.size()), 0); helper->storeToolState(helper->globalStateId(), helper->rootSizeKey(), QVariant(command.size()), 0);
// Queue two renders to make sure icon gizmos update properly // Queue three renders to make sure icon gizmos update properly
render3DEditView(2); render3DEditView(3);
} }
} }
#else #else

View File

@@ -129,19 +129,16 @@ private:
void doRenderModelNodeImageView(); void doRenderModelNodeImageView();
void doRenderModelNode3DImageView(); void doRenderModelNode3DImageView();
void doRenderModelNode2DImageView(); void doRenderModelNode2DImageView();
QQuickView *createAuxiliaryQuickView(const QUrl &url, QQuickItem *&rootItem);
void updateLockedAndHiddenStates(const QSet<ServerNodeInstance> &instances); void updateLockedAndHiddenStates(const QSet<ServerNodeInstance> &instances);
void handleInputEvents();
void createAuxiliaryQuickView(const QUrl &url, RenderViewData &viewData);
RenderViewData m_editView3DData;
RenderViewData m_modelNode3DImageViewData;
RenderViewData m_modelNode2DImageViewData;
QPointer<QQuickView> m_editView3D;
QQuickItem *m_editView3DRootItem = nullptr;
QQuickItem *m_editView3DContentItem = nullptr;
bool m_editView3DSetupDone = false; bool m_editView3DSetupDone = false;
QPointer<QQuickView> m_ModelNode3DImageView;
QQuickItem *m_ModelNode3DImageViewRootItem = nullptr;
QQuickItem *m_ModelNode3DImageViewContentItem = nullptr;
QPointer<QQuickView> m_ModelNode2DImageView;
QQuickItem *m_ModelNode2DImageViewRootItem = nullptr;
QQuickItem *m_ModelNode2DImageViewContentItem = nullptr;
RequestModelNodePreviewImageCommand m_modelNodePreviewImageCommand; RequestModelNodePreviewImageCommand m_modelNodePreviewImageCommand;
QHash<QString, QImage> m_modelNodePreviewImageCache; QHash<QString, QImage> m_modelNodePreviewImageCache;
QSet<QObject *> m_view3Ds; QSet<QObject *> m_view3Ds;
@@ -156,9 +153,11 @@ private:
QTimer m_selectionChangeTimer; QTimer m_selectionChangeTimer;
QTimer m_render3DEditViewTimer; QTimer m_render3DEditViewTimer;
QTimer m_renderModelNodeImageViewTimer; QTimer m_renderModelNodeImageViewTimer;
QTimer m_inputEventTimer;
QVariant m_changedNode; QVariant m_changedNode;
PropertyName m_changedProperty; PropertyName m_changedProperty;
ChangeSelectionCommand m_lastSelectionChangeCommand; ChangeSelectionCommand m_lastSelectionChangeCommand;
QList<InputEventCommand> m_pendingInputEventCommands;
QObject *m_3dHelper = nullptr; QObject *m_3dHelper = nullptr;
int m_need3DEditViewRender = 0; int m_need3DEditViewRender = 0;
}; };

View File

@@ -31,6 +31,7 @@
#include <QQuickItem> #include <QQuickItem>
#include <QQuickView> #include <QQuickView>
#include <QQuickWindow>
#include <designersupportdelegate.h> #include <designersupportdelegate.h>
#include <addimportcontainer.h> #include <addimportcontainer.h>
@@ -40,6 +41,14 @@
#include <QDebug> #include <QDebug>
#include <QOpenGLContext> #include <QOpenGLContext>
#if QT_VERSION >= QT_VERSION_CHECK(6, 0, 0)
#include <QtGui/private/qrhi_p.h>
#include <QtQuick/private/qquickwindow_p.h>
#include <QtQuick/private/qsgrenderer_p.h>
#include <QtQuick/private/qquickrendercontrol_p.h>
#include <QtQuick/private/qquickrendertarget_p.h>
#endif
namespace QmlDesigner { namespace QmlDesigner {
Qt5NodeInstanceServer::Qt5NodeInstanceServer(NodeInstanceClientInterface *nodeInstanceClient) Qt5NodeInstanceServer::Qt5NodeInstanceServer(NodeInstanceClientInterface *nodeInstanceClient)
@@ -50,30 +59,44 @@ Qt5NodeInstanceServer::Qt5NodeInstanceServer(NodeInstanceClientInterface *nodeIn
Qt5NodeInstanceServer::~Qt5NodeInstanceServer() Qt5NodeInstanceServer::~Qt5NodeInstanceServer()
{ {
delete quickView(); delete quickWindow();
} }
QQuickView *Qt5NodeInstanceServer::quickView() const QQuickView *Qt5NodeInstanceServer::quickView() const
{ {
return m_quickView.data(); #if QT_VERSION < QT_VERSION_CHECK(6, 0, 0)
return static_cast<QQuickView *>(m_viewData.window.data());
#else
return nullptr;
#endif
}
QQuickWindow *Qt5NodeInstanceServer::quickWindow() const
{
return m_viewData.window.data();
} }
void Qt5NodeInstanceServer::initializeView() void Qt5NodeInstanceServer::initializeView()
{ {
Q_ASSERT(!quickView()); Q_ASSERT(!quickWindow());
m_quickView = new QQuickView;
#if QT_VERSION < QT_VERSION_CHECK(6, 0, 0) #if QT_VERSION < QT_VERSION_CHECK(6, 0, 0)
auto view = new QQuickView;
m_viewData.window = view;
/* enables grab window without show */ /* enables grab window without show */
QSurfaceFormat surfaceFormat = m_quickView->requestedFormat(); QSurfaceFormat surfaceFormat = view->requestedFormat();
surfaceFormat.setVersion(4, 1); surfaceFormat.setVersion(4, 1);
surfaceFormat.setProfile(QSurfaceFormat::CoreProfile); surfaceFormat.setProfile(QSurfaceFormat::CoreProfile);
QSurfaceFormat::setDefaultFormat(surfaceFormat); QSurfaceFormat::setDefaultFormat(surfaceFormat);
view->setFormat(surfaceFormat);
m_quickView->setFormat(surfaceFormat); DesignerSupport::createOpenGLContext(view);
m_qmlEngine = view->engine();
DesignerSupport::createOpenGLContext(m_quickView.data()); #else
m_viewData.renderControl = new QQuickRenderControl;
m_viewData.window = new QQuickWindow(m_viewData.renderControl);
m_viewData.renderControl->initialize();
m_qmlEngine = new QQmlEngine;
#endif #endif
if (qEnvironmentVariableIsSet("QML_FILE_SELECTORS")) { if (qEnvironmentVariableIsSet("QML_FILE_SELECTORS")) {
@@ -90,16 +113,39 @@ QQmlView *Qt5NodeInstanceServer::declarativeView() const
return nullptr; return nullptr;
} }
QQmlEngine *Qt5NodeInstanceServer::engine() const QQuickItem *Qt5NodeInstanceServer::rootItem() const
{ {
if (quickView()) return m_viewData.rootItem;
return quickView()->engine();
return nullptr;
} }
void Qt5NodeInstanceServer::resizeCanvasSizeToRootItemSize() void Qt5NodeInstanceServer::setRootItem(QQuickItem *item)
{ {
m_viewData.rootItem = item;
#if QT_VERSION < QT_VERSION_CHECK(6, 0, 0)
DesignerSupport::setRootItem(quickView(), item);
#else
quickWindow()->setGeometry(0, 0, item->width(), item->height());
// Insert an extra item above the root to adjust root item position to 0,0 to make entire
// item to be always rendered.
if (!m_viewData.contentItem)
m_viewData.contentItem = new QQuickItem(quickWindow()->contentItem());
m_viewData.contentItem->setPosition(-item->position());
item->setParentItem(m_viewData.contentItem);
#endif
}
QQmlEngine *Qt5NodeInstanceServer::engine() const
{
return m_qmlEngine;
}
void Qt5NodeInstanceServer::resizeCanvasToRootItem()
{
#if QT_VERSION >= QT_VERSION_CHECK(6, 0, 0)
m_viewData.bufferDirty = true;
m_viewData.contentItem->setPosition(-m_viewData.rootItem->position());
#endif
quickWindow()->resize(rootNodeInstance().boundingRect().size().toSize());
} }
void Qt5NodeInstanceServer::resetAllItems() void Qt5NodeInstanceServer::resetAllItems()
@@ -116,7 +162,7 @@ void Qt5NodeInstanceServer::setupScene(const CreateSceneCommand &command)
setupDummyData(command.fileUrl); setupDummyData(command.fileUrl);
setupInstances(command); setupInstances(command);
quickView()->resize(rootNodeInstance().boundingRect().size().toSize()); resizeCanvasToRootItem();
} }
QList<QQuickItem*> subItems(QQuickItem *parentItem) QList<QQuickItem*> subItems(QQuickItem *parentItem)
@@ -138,6 +184,127 @@ QList<QQuickItem*> Qt5NodeInstanceServer::allItems() const
return QList<QQuickItem*>(); return QList<QQuickItem*>();
} }
bool Qt5NodeInstanceServer::initRhi(RenderViewData &viewData)
{
#if QT_VERSION >= QT_VERSION_CHECK(6, 0, 0)
if (!viewData.renderControl) {
qWarning() << __FUNCTION__ << "Render control not created";
return false;
}
if (!viewData.rhi) {
QQuickRenderControlPrivate *rd = QQuickRenderControlPrivate::get(viewData.renderControl);
viewData.rhi = rd->rhi;
if (!viewData.rhi) {
qWarning() << __FUNCTION__ << "Rhi is null";
return false;
}
}
auto cleanRhiResources = [&viewData]() {
// Releasing cached resources is a workaround for bug QTBUG-88761
auto renderer = QQuickWindowPrivate::get(viewData.window)->renderer;
if (renderer)
renderer->releaseCachedResources();
if (viewData.rpDesc) {
viewData.rpDesc->deleteLater();
viewData.rpDesc = nullptr;
}
if (viewData.texTarget) {
viewData.texTarget->deleteLater();
viewData.texTarget = nullptr;
}
if (viewData.buffer) {
viewData.buffer->deleteLater();
viewData.buffer = nullptr;
}
if (viewData.texture) {
viewData.texture->deleteLater();
viewData.texture = nullptr;
}
};
if (viewData.bufferDirty) {
cleanRhiResources();
viewData.bufferDirty = false;
}
const QSize size = viewData.window->size();
viewData.texture = viewData.rhi->newTexture(QRhiTexture::RGBA8, size, 1,
QRhiTexture::RenderTarget | QRhiTexture::UsedAsTransferSource);
if (!viewData.texture->create()) {
qWarning() << __FUNCTION__ << "QRhiTexture creation failed";
cleanRhiResources();
return false;
}
viewData.buffer = viewData.rhi->newRenderBuffer(QRhiRenderBuffer::DepthStencil, size, 1);
if (!viewData.buffer->create()) {
qWarning() << __FUNCTION__ << "Depth/stencil buffer creation failed";
cleanRhiResources();
return false;
}
QRhiTextureRenderTargetDescription rtDesc(QRhiColorAttachment(viewData.texture));
rtDesc.setDepthStencilBuffer(viewData.buffer);
viewData.texTarget = viewData.rhi->newTextureRenderTarget(rtDesc);
viewData.rpDesc = viewData.texTarget->newCompatibleRenderPassDescriptor();
viewData.texTarget->setRenderPassDescriptor(viewData.rpDesc);
if (!viewData.texTarget->create()) {
qWarning() << __FUNCTION__ << "Texture render target creation failed";
cleanRhiResources();
return false;
}
// redirect Qt Quick rendering into our texture
viewData.window->setRenderTarget(QQuickRenderTarget::fromRhiRenderTarget(viewData.texTarget));
#endif
return true;
}
QImage Qt5NodeInstanceServer::grabRenderControl(RenderViewData &viewData)
{
QImage renderImage;
#if QT_VERSION >= QT_VERSION_CHECK(6, 0, 0)
if (viewData.bufferDirty && !initRhi(viewData))
return renderImage;
viewData.renderControl->polishItems();
viewData.renderControl->beginFrame();
viewData.renderControl->sync();
viewData.renderControl->render();
bool readCompleted = false;
QRhiReadbackResult readResult;
readResult.completed = [&] {
readCompleted = true;
QImage wrapperImage(reinterpret_cast<const uchar *>(readResult.data.constData()),
readResult.pixelSize.width(), readResult.pixelSize.height(),
QImage::Format_RGBA8888_Premultiplied);
if (viewData.rhi->isYUpInFramebuffer())
renderImage = wrapperImage.mirrored();
else
renderImage = wrapperImage.copy();
};
QRhiResourceUpdateBatch *readbackBatch = viewData.rhi->nextResourceUpdateBatch();
readbackBatch->readBackTexture(viewData.texture, &readResult);
QQuickRenderControlPrivate *rd = QQuickRenderControlPrivate::get(viewData.renderControl);
rd->cb->resourceUpdate(readbackBatch);
viewData.renderControl->endFrame();
#endif
return renderImage;
}
QImage Qt5NodeInstanceServer::grabWindow()
{
if (m_viewData.rootItem)
return grabRenderControl(m_viewData);
return {};
}
void Qt5NodeInstanceServer::refreshBindings() void Qt5NodeInstanceServer::refreshBindings()
{ {
DesignerSupport::refreshExpressions(context()); DesignerSupport::refreshExpressions(context());

View File

@@ -26,12 +26,22 @@
#pragma once #pragma once
#include <QtGlobal> #include <QtGlobal>
#include <QtQuick/qquickwindow.h>
#include "nodeinstanceserver.h" #include "nodeinstanceserver.h"
#include <designersupportdelegate.h> #include <designersupportdelegate.h>
QT_BEGIN_NAMESPACE QT_BEGIN_NAMESPACE
class QQuickItem; class QQuickItem;
class QQmlEngine;
#if QT_VERSION >= QT_VERSION_CHECK(6, 0, 0)
class QQuickRenderControl;
class QRhi;
class QRhiTexture;
class QRhiRenderBuffer;
class QRhiTextureRenderTarget;
class QRhiRenderPassDescriptor;
#endif
QT_END_NAMESPACE QT_END_NAMESPACE
namespace QmlDesigner { namespace QmlDesigner {
@@ -44,7 +54,11 @@ public:
~Qt5NodeInstanceServer() override; ~Qt5NodeInstanceServer() override;
QQuickView *quickView() const override; QQuickView *quickView() const override;
QQuickWindow *quickWindow() const override;
QQmlView *declarativeView() const override; QQmlView *declarativeView() const override;
QQuickItem *rootItem() const override;
void setRootItem(QQuickItem *item) override;
QQmlEngine *engine() const override; QQmlEngine *engine() const override;
void refreshBindings() override; void refreshBindings() override;
@@ -54,16 +68,37 @@ public:
void clearScene(const ClearSceneCommand &command) override; void clearScene(const ClearSceneCommand &command) override;
void reparentInstances(const ReparentInstancesCommand &command) override; void reparentInstances(const ReparentInstancesCommand &command) override;
QImage grabWindow() override;
protected: protected:
void initializeView() override; void initializeView() override;
void resizeCanvasSizeToRootItemSize() override; void resizeCanvasToRootItem() override;
void resetAllItems(); void resetAllItems();
void setupScene(const CreateSceneCommand &command) override; void setupScene(const CreateSceneCommand &command) override;
QList<QQuickItem*> allItems() const; QList<QQuickItem*> allItems() const;
struct RenderViewData {
QPointer<QQuickWindow> window = nullptr;
QQuickItem *rootItem = nullptr;
QQuickItem *contentItem = nullptr;
#if QT_VERSION >= QT_VERSION_CHECK(6, 0, 0)
bool bufferDirty = true;
QQuickRenderControl *renderControl = nullptr;
QRhi *rhi = nullptr;
QRhiTexture *texture = nullptr;
QRhiRenderBuffer *buffer = nullptr;
QRhiTextureRenderTarget *texTarget = nullptr;
QRhiRenderPassDescriptor *rpDesc = nullptr;
#endif
};
virtual bool initRhi(RenderViewData &viewData);
virtual QImage grabRenderControl(RenderViewData &viewData);
private: private:
QPointer<QQuickView> m_quickView; RenderViewData m_viewData;
DesignerSupport m_designerSupport; DesignerSupport m_designerSupport;
QQmlEngine *m_qmlEngine = nullptr;
}; };
} // QmlDesigner } // QmlDesigner

View File

@@ -71,7 +71,7 @@ void Qt5PreviewNodeInstanceServer::collectItemChangesAndSendChangeCommands()
if (!inFunction && nodeInstanceClient()->bytesToWrite() < 10000) { if (!inFunction && nodeInstanceClient()->bytesToWrite() < 10000) {
inFunction = true; inFunction = true;
DesignerSupport::polishItems(quickView()); DesignerSupport::polishItems(quickWindow());
QVector<ImageContainer> imageContainerVector; QVector<ImageContainer> imageContainerVector;
imageContainerVector.append(ImageContainer(0, renderPreviewImage(), -1)); imageContainerVector.append(ImageContainer(0, renderPreviewImage(), -1));

View File

@@ -74,9 +74,9 @@ void Qt5RenderNodeInstanceServer::collectItemChangesAndSendChangeCommands()
if (!inFunction) { if (!inFunction) {
inFunction = true; inFunction = true;
DesignerSupport::polishItems(quickView()); DesignerSupport::polishItems(quickWindow());
if (quickView() && nodeInstanceClient()->bytesToWrite() < 10000) { if (quickWindow() && nodeInstanceClient()->bytesToWrite() < 10000) {
foreach (QQuickItem *item, allItems()) { foreach (QQuickItem *item, allItems()) {
if (item) { if (item) {
if (hasInstanceForObject(item)) { if (hasInstanceForObject(item)) {

View File

@@ -257,13 +257,13 @@ void Qt5TestNodeInstanceServer::removeSharedMemory(const RemoveSharedMemoryComma
void QmlDesigner::Qt5TestNodeInstanceServer::collectItemChangesAndSendChangeCommands() void QmlDesigner::Qt5TestNodeInstanceServer::collectItemChangesAndSendChangeCommands()
{ {
DesignerSupport::polishItems(quickView()); DesignerSupport::polishItems(quickWindow());
QSet<ServerNodeInstance> informationChangedInstanceSet; QSet<ServerNodeInstance> informationChangedInstanceSet;
QVector<InstancePropertyPair> propertyChangedList; QVector<InstancePropertyPair> propertyChangedList;
QSet<ServerNodeInstance> parentChangedSet; QSet<ServerNodeInstance> parentChangedSet;
if (quickView()) { if (quickWindow()) {
foreach (QQuickItem *item, allItems()) { foreach (QQuickItem *item, allItems()) {
if (item && hasInstanceForObject(item)) { if (item && hasInstanceForObject(item)) {
ServerNodeInstance instance = instanceForObject(item); ServerNodeInstance instance = instanceForObject(item);

View File

@@ -174,11 +174,10 @@ void QuickItemNodeInstance::initialize(const ObjectNodeInstance::Pointer &object
InstanceContainer::NodeFlags flags) InstanceContainer::NodeFlags flags)
{ {
if (instanceId() == 0) { if (instanceId() == 0)
DesignerSupport::setRootItem(nodeInstanceServer()->quickView(), quickItem()); nodeInstanceServer()->setRootItem(quickItem());
} else { else
quickItem()->setParentItem(qobject_cast<QQuickItem*>(nodeInstanceServer()->quickView()->rootObject())); quickItem()->setParentItem(nodeInstanceServer()->rootItem());
}
if (quickItem()->window() && checkIfRefFromEffect(instanceId())) { if (quickItem()->window() && checkIfRefFromEffect(instanceId())) {
designerSupport()->refFromEffectItem(quickItem(), designerSupport()->refFromEffectItem(quickItem(),
@@ -420,19 +419,19 @@ QImage QuickItemNodeInstance::renderImage() const
#if QT_VERSION < QT_VERSION_CHECK(6, 0, 0) #if QT_VERSION < QT_VERSION_CHECK(6, 0, 0)
if (s_unifiedRenderPath) { if (s_unifiedRenderPath) {
renderImage = nodeInstanceServer()->quickView()->grabWindow(); renderImage = nodeInstanceServer()->quickWindow()->grabWindow();
} else { } else {
// Fake render loop signaling to update things like QML items as 3D textures // Fake render loop signaling to update things like QML items as 3D textures
nodeInstanceServer()->quickView()->beforeSynchronizing(); nodeInstanceServer()->quickWindow()->beforeSynchronizing();
nodeInstanceServer()->quickView()->beforeRendering(); nodeInstanceServer()->quickWindow()->beforeRendering();
renderImage = designerSupport()->renderImageForItem(quickItem(), renderBoundingRect, size); renderImage = designerSupport()->renderImageForItem(quickItem(), renderBoundingRect, size);
nodeInstanceServer()->quickView()->afterRendering(); nodeInstanceServer()->quickWindow()->afterRendering();
} }
renderImage.setDevicePixelRatio(devicePixelRatio); renderImage.setDevicePixelRatio(devicePixelRatio);
#else #else
renderImage = nodeInstanceServer()->quickView()->grabWindow(); renderImage = nodeInstanceServer()->grabWindow();
renderImage = renderImage.copy(renderBoundingRect.toRect()); renderImage = renderImage.copy(renderBoundingRect.toRect());
/* When grabbing an offscren window the device pixel ratio is 1 */ /* When grabbing an offscren window the device pixel ratio is 1 */
renderImage.setDevicePixelRatio(1); renderImage.setDevicePixelRatio(1);
@@ -452,20 +451,20 @@ QImage QuickItemNodeInstance::renderPreviewImage(const QSize &previewImageSize)
QImage image; QImage image;
#if QT_VERSION < QT_VERSION_CHECK(6, 0, 0) #if QT_VERSION < QT_VERSION_CHECK(6, 0, 0)
if (s_unifiedRenderPath) { if (s_unifiedRenderPath) {
image = nodeInstanceServer()->quickView()->grabWindow(); image = nodeInstanceServer()->quickWindow()->grabWindow();
} else { } else {
// Fake render loop signaling to update things like QML items as 3D textures // Fake render loop signaling to update things like QML items as 3D textures
nodeInstanceServer()->quickView()->beforeSynchronizing(); nodeInstanceServer()->quickWindow()->beforeSynchronizing();
nodeInstanceServer()->quickView()->beforeRendering(); nodeInstanceServer()->quickWindow()->beforeRendering();
image = designerSupport()->renderImageForItem(quickItem(), image = designerSupport()->renderImageForItem(quickItem(),
previewItemBoundingRect, previewItemBoundingRect,
size); size);
nodeInstanceServer()->quickView()->afterRendering(); nodeInstanceServer()->quickWindow()->afterRendering();
} }
#else #else
image = nodeInstanceServer()->quickView()->grabWindow(); image = nodeInstanceServer()->grabWindow();
image = image.copy(previewItemBoundingRect.toRect()); image = image.copy(previewItemBoundingRect.toRect());
#endif #endif

View File

@@ -11,10 +11,14 @@ int main(int argc, char *argv[])
qputenv("QT_QPA_EGLFS_PHYSICAL_WIDTH", QByteArray("213")); qputenv("QT_QPA_EGLFS_PHYSICAL_WIDTH", QByteArray("213"));
qputenv("QT_QPA_EGLFS_PHYSICAL_HEIGHT", QByteArray("120")); qputenv("QT_QPA_EGLFS_PHYSICAL_HEIGHT", QByteArray("120"));
#if QT_VERSION < QT_VERSION_CHECK(6, 0, 0)
QCoreApplication::setAttribute(Qt::AA_EnableHighDpiScaling); QCoreApplication::setAttribute(Qt::AA_EnableHighDpiScaling);
#endif
} }
@else @else
#if QT_VERSION < QT_VERSION_CHECK(6, 0, 0)
QCoreApplication::setAttribute(Qt::AA_EnableHighDpiScaling); QCoreApplication::setAttribute(Qt::AA_EnableHighDpiScaling);
#endif
@endif @endif
QGuiApplication app(argc, argv); QGuiApplication app(argc, argv);

View File

@@ -25,10 +25,14 @@
#include "qmldirparser_p.h" #include "qmldirparser_p.h"
#include <utils/qtcassert.h>
#include <QtCore/QtDebug> #include <QtCore/QtDebug>
QT_QML_BEGIN_NAMESPACE QT_QML_BEGIN_NAMESPACE
using namespace LanguageUtils;
static int parseInt(const QStringView &str, bool *ok) static int parseInt(const QStringView &str, bool *ok)
{ {
int pos = 0; int pos = 0;
@@ -60,6 +64,33 @@ static bool parseVersion(const QString &str, int *major, int *minor)
return false; return false;
} }
static ComponentVersion parseImportVersion(const QString &str)
{
int minor = -1;
int major = -1;
const int dotIndex = str.indexOf(QLatin1Char('.'));
bool ok = false;
if (dotIndex != -1 && str.indexOf(QLatin1Char('.'), dotIndex + 1) == -1) {
major = parseInt(QStringView(str.constData(), dotIndex), &ok);
if (ok) {
if (str.length() > dotIndex + 1) {
minor = parseInt(QStringView(str.constData() + dotIndex + 1, str.length() - dotIndex - 1),
&ok);
if (!ok)
minor = ComponentVersion::NoVersion;
} else {
minor = ComponentVersion::MaxVersion;
}
}
} else if (str.length() > 0) {
QTC_ASSERT(str != QLatin1String("auto"), return ComponentVersion(-1, -1));
major = parseInt(QStringView(str.constData(), str.length()),
&ok);
minor = ComponentVersion::MaxVersion;
}
return ComponentVersion(major, minor);
}
void QmlDirParser::clear() void QmlDirParser::clear()
{ {
_errors.clear(); _errors.clear();
@@ -97,6 +128,50 @@ bool QmlDirParser::parse(const QString &source)
quint16 lineNumber = 0; quint16 lineNumber = 0;
bool firstLine = true; bool firstLine = true;
auto readImport = [&](const QString *sections, int sectionCount, Import::Flags flags) {
Import import;
if (sectionCount == 2) {
import = Import(sections[1], ComponentVersion(), flags);
} else if (sectionCount == 3) {
if (sections[2] == QLatin1String("auto")) {
import = Import(sections[1], ComponentVersion(), flags | Import::Auto);
} else {
const auto version = parseImportVersion(sections[2]);
if (version.isValid()) {
import = Import(sections[1], version, flags);
} else {
reportError(lineNumber, 0,
QStringLiteral("invalid version %1, expected <major>.<minor>")
.arg(sections[2]));
return false;
}
}
} else {
reportError(lineNumber, 0,
QStringLiteral("%1 requires 1 or 2 arguments, but %2 were provided")
.arg(sections[0]).arg(sectionCount - 1));
return false;
}
if (sections[0] == QStringLiteral("import"))
_imports.append(import);
else
_dependencies.append(import);
return true;
};
auto readPlugin = [&](const QString *sections, int sectionCount, bool isOptional) {
if (sectionCount < 2 || sectionCount > 3) {
reportError(lineNumber, 0, QStringLiteral("plugin directive requires one or two "
"arguments, but %1 were provided")
.arg(sectionCount - 1));
return false;
}
const Plugin entry(sections[1], sections[2], isOptional);
_plugins.append(entry);
return true;
};
const QChar *ch = source.constData(); const QChar *ch = source.constData();
while (!ch->isNull()) { while (!ch->isNull()) {
++lineNumber; ++lineNumber;
@@ -163,16 +238,26 @@ bool QmlDirParser::parse(const QString &source)
_typeNamespace = sections[1]; _typeNamespace = sections[1];
} else if (sections[0] == QLatin1String("plugin")) { } else if (sections[0] == QLatin1String("plugin")) {
if (sectionCount < 2 || sectionCount > 3) { if (!readPlugin(sections, sectionCount, false))
reportError(lineNumber, 0, continue;
QStringLiteral("plugin directive requires one or two arguments, but %1 were provided").arg(sectionCount - 1)); } else if (sections[0] == QLatin1String("optional")) {
if (sectionCount < 2) {
reportError(lineNumber, 0, QStringLiteral("optional directive requires further "
"arguments, but none were provided."));
continue; continue;
} }
const Plugin entry(sections[1], sections[2]); if (sections[1] == QStringLiteral("plugin")) {
if (!readPlugin(sections + 1, sectionCount - 1, true))
_plugins.append(entry); continue;
} else if (sections[1] == QLatin1String("import")) {
if (!readImport(sections + 1, sectionCount - 1, Import::Optional))
continue;
} else {
reportError(lineNumber, 0, QStringLiteral("only import and plugin can be optional, "
"not %1.").arg(sections[1]));
continue;
}
} else if (sections[0] == QLatin1String("classname")) { } else if (sections[0] == QLatin1String("classname")) {
if (sectionCount < 2) { if (sectionCount < 2) {
@@ -233,28 +318,9 @@ bool QmlDirParser::parse(const QString &source)
reportError(lineNumber, 0, QStringLiteral("designersupported does not expect any argument")); reportError(lineNumber, 0, QStringLiteral("designersupported does not expect any argument"));
else else
_designerSupported = true; _designerSupported = true;
} else if (sections[0] == QLatin1String("depends")) { } else if (sections[0] == QLatin1String("depends") || sections[0] == QLatin1String("import")) {
if (sectionCount != 3) { if (!readImport(sections, sectionCount, Import::Default))
reportError(lineNumber, 0,
QStringLiteral("depends requires 2 arguments, but %1 were provided").arg(sectionCount - 1));
continue; continue;
}
int major, minor;
if (parseVersion(sections[2], &major, &minor)) {
Component entry(sections[1], QString(), major, minor);
entry.internal = true;
_dependencies.insert(entry.typeName, entry);
} else {
reportError(lineNumber, 0, QStringLiteral("invalid version %1, expected <major>.<minor>").arg(sections[2]));
}
} else if (sections[0] == QLatin1String("import")) {
if (sectionCount != 2) {
reportError(lineNumber, 0,
QStringLiteral("import requires 2 arguments, but %1 were provided").arg(sectionCount - 1));
continue;
}
_imports << sections[1];
} else if (sectionCount == 2) { } else if (sectionCount == 2) {
// No version specified (should only be used for relative qmldir files) // No version specified (should only be used for relative qmldir files)
const Component entry(sections[0], sections[1], -1, -1); const Component entry(sections[0], sections[1], -1, -1);
@@ -342,12 +408,12 @@ QMultiHash<QString, QmlDirParser::Component> QmlDirParser::components() const
return _components; return _components;
} }
QHash<QString, QmlDirParser::Component> QmlDirParser::dependencies() const QList<QmlDirParser::Import> QmlDirParser::dependencies() const
{ {
return _dependencies; return _dependencies;
} }
QStringList QmlDirParser::imports() const QList<QmlDirParser::Import> QmlDirParser::imports() const
{ {
return _imports; return _imports;
} }

View File

@@ -39,6 +39,9 @@
#include <QtCore/QUrl> #include <QtCore/QUrl>
#include <QtCore/QHash> #include <QtCore/QHash>
#include <QtCore/QDebug> #include <QtCore/QDebug>
#include <languageutils/componentversion.h>
#include "qmljs/parser/qmljsglobal_p.h" #include "qmljs/parser/qmljsglobal_p.h"
#include "qmljs/parser/qmljsengine_p.h" #include "qmljs/parser/qmljsengine_p.h"
#include "qmljs/parser/qmljsdiagnosticmessage_p.h" #include "qmljs/parser/qmljsdiagnosticmessage_p.h"
@@ -72,14 +75,15 @@ public:
{ {
Plugin() = default; Plugin() = default;
Plugin(const QString &name, const QString &path) Plugin(const QString &name, const QString &path, bool optional)
: name(name), path(path) : name(name), path(path), optional(optional)
{ {
checkNonRelative("Plugin", name, path); checkNonRelative("Plugin", name, path);
} }
QString name; QString name;
QString path; QString path;
bool optional = false;
}; };
struct Component struct Component
@@ -117,9 +121,29 @@ public:
int minorVersion = 0; int minorVersion = 0;
}; };
struct Import
{
enum Flag {
Default = 0x0,
Auto = 0x1, // forward the version of the importing module
Optional = 0x2 // is not automatically imported but only a tooling hint
};
Q_DECLARE_FLAGS(Flags, Flag)
Import() = default;
Import(QString module, LanguageUtils::ComponentVersion version, Flags flags)
: module(module), version(version), flags(flags)
{
}
QString module;
LanguageUtils::ComponentVersion version; // invalid version is latest version, unless Flag::Auto
Flags flags;
};
QMultiHash<QString,Component> components() const; QMultiHash<QString,Component> components() const;
QHash<QString,Component> dependencies() const; QList<Import> dependencies() const;
QStringList imports() const; QList<Import> imports() const;
QList<Script> scripts() const; QList<Script> scripts() const;
QList<Plugin> plugins() const; QList<Plugin> plugins() const;
bool designerSupported() const; bool designerSupported() const;
@@ -145,8 +169,8 @@ private:
QList<QmlJS::DiagnosticMessage> _errors; QList<QmlJS::DiagnosticMessage> _errors;
QString _typeNamespace; QString _typeNamespace;
QMultiHash<QString,Component> _components; QMultiHash<QString,Component> _components;
QHash<QString,Component> _dependencies; QList<Import> _dependencies;
QStringList _imports; QList<Import> _imports;
QList<Script> _scripts; QList<Script> _scripts;
QList<Plugin> _plugins; QList<Plugin> _plugins;
bool _designerSupported = false; bool _designerSupported = false;

View File

@@ -447,8 +447,8 @@ QByteArray LibraryInfo::calculateFingerprint() const
len = _imports.size(); len = _imports.size();
hash.addData(reinterpret_cast<const char *>(&len), sizeof(len)); hash.addData(reinterpret_cast<const char *>(&len), sizeof(len));
foreach (const QString &import, _imports) foreach (const QmlDirParser::Import &import, _imports)
hash.addData(import.toUtf8()); // import order matters, keep order-dependent hash.addData(import.module.toUtf8()); // import order matters, keep order-dependent
QByteArray res(hash.result()); QByteArray res(hash.result());
res.append('L'); res.append('L');

View File

@@ -158,7 +158,7 @@ private:
FakeMetaObjectList _metaObjects; FakeMetaObjectList _metaObjects;
QList<ModuleApiInfo> _moduleApis; QList<ModuleApiInfo> _moduleApis;
QStringList _dependencies; // from qmltypes "dependencies: [...]" QStringList _dependencies; // from qmltypes "dependencies: [...]"
QStringList _imports; // from qmldir "import" commands QList<QmlDirParser::Import> _imports; // from qmldir "import" commands
QByteArray _fingerprint; QByteArray _fingerprint;
PluginTypeInfoStatus _dumpStatus = NoTypeInfo; PluginTypeInfoStatus _dumpStatus = NoTypeInfo;
@@ -204,10 +204,10 @@ public:
void setDependencies(const QStringList &deps) void setDependencies(const QStringList &deps)
{ _dependencies = deps; } { _dependencies = deps; }
QStringList imports() const QList<QmlDirParser::Import> imports() const
{ return _imports; } { return _imports; }
void setImports(const QStringList &imports) void setImports(const QList<QmlDirParser::Import> &imports)
{ _imports = imports; } { _imports = imports; }
bool isValid() const bool isValid() const

View File

@@ -94,7 +94,8 @@ public:
bool importLibrary(const Document::Ptr &doc, bool importLibrary(const Document::Ptr &doc,
const QString &libraryPath, const QString &libraryPath,
Import *import, ObjectValue *targetObject, Import *import, ObjectValue *targetObject,
const QString &importPath = QString()); const QString &importPath = QString(),
bool optional = false);
void loadQmldirComponents(ObjectValue *import, void loadQmldirComponents(ObjectValue *import,
LanguageUtils::ComponentVersion version, LanguageUtils::ComponentVersion version,
const LibraryInfo &libraryInfo, const LibraryInfo &libraryInfo,
@@ -465,7 +466,9 @@ bool LinkPrivate::importLibrary(const Document::Ptr &doc,
const QString &libraryPath, const QString &libraryPath,
Import *import, Import *import,
ObjectValue *targetObject, ObjectValue *targetObject,
const QString &importPath) const QString &importPath,
bool optional
)
{ {
const ImportInfo &importInfo = import->info; const ImportInfo &importInfo = import->info;
@@ -486,15 +489,21 @@ bool LinkPrivate::importLibrary(const Document::Ptr &doc,
// Note: Since this works on the same targetObject, the ModuleApi setPrototype() // Note: Since this works on the same targetObject, the ModuleApi setPrototype()
// logic will not work. But ModuleApi isn't used in Qt versions that use import // logic will not work. But ModuleApi isn't used in Qt versions that use import
// commands in qmldir files, and is pending removal in Qt 6. // commands in qmldir files, and is pending removal in Qt 6.
for (const auto &importName : libraryInfo.imports()) { for (const auto &toImport : libraryInfo.imports()) {
QString importName = toImport.module;
ComponentVersion vNow = toImport.version;
// there was a period in which no version == auto, should we add || !vNow.isValid() to the if?
if (toImport.flags & QmlDirParser::Import::Auto)
vNow = version;
Import subImport; Import subImport;
subImport.valid = true; subImport.valid = true;
subImport.info = ImportInfo::moduleImport(importName, version, importInfo.as(), importInfo.ast()); subImport.info = ImportInfo::moduleImport(importName, vNow, importInfo.as(), importInfo.ast());
subImport.libraryPath = modulePath(importName, version.toString(), m_importPaths); subImport.libraryPath = modulePath(importName, vNow.toString(), m_importPaths);
bool subImportFound = importLibrary(doc, subImport.libraryPath, &subImport, targetObject, importPath); bool subImportFound = importLibrary(doc, subImport.libraryPath, &subImport, targetObject, importPath, true);
if (!subImportFound && errorLoc.isValid()) { if (!subImportFound && errorLoc.isValid()) {
import->valid = false; import->valid = false;
if (!(optional || (toImport.flags & QmlDirParser::Import::Optional)))
error(doc, errorLoc, error(doc, errorLoc,
Link::tr( Link::tr(
"Implicit import '%1' of QML module '%2' not found.\n\n" "Implicit import '%1' of QML module '%2' not found.\n\n"
@@ -529,11 +538,11 @@ bool LinkPrivate::importLibrary(const Document::Ptr &doc,
QString(), version.toString()); QString(), version.toString());
} }
} }
if (errorLoc.isValid()) { if (!optional && errorLoc.isValid()) {
appendDiagnostic(doc, DiagnosticMessage( appendDiagnostic(doc, DiagnosticMessage(
Severity::ReadingTypeInfoWarning, errorLoc, Severity::ReadingTypeInfoWarning, errorLoc,
Link::tr("QML module contains C++ plugins, " Link::tr("QML module contains C++ plugins, "
"currently reading type information..."))); "currently reading type information... %1").arg(import->info.name())));
import->valid = false; import->valid = false;
} }
} else if (libraryInfo.pluginTypeInfoStatus() == LibraryInfo::DumpError } else if (libraryInfo.pluginTypeInfoStatus() == LibraryInfo::DumpError
@@ -541,7 +550,7 @@ bool LinkPrivate::importLibrary(const Document::Ptr &doc,
// Only underline import if package isn't described in .qmltypes anyway // Only underline import if package isn't described in .qmltypes anyway
// and is not a private package // and is not a private package
QString packageName = importInfo.name(); QString packageName = importInfo.name();
if (errorLoc.isValid() if (!optional && errorLoc.isValid()
&& (packageName.isEmpty() && (packageName.isEmpty()
|| !m_valueOwner->cppQmlTypes().hasModule(packageName)) || !m_valueOwner->cppQmlTypes().hasModule(packageName))
&& !packageName.endsWith(QLatin1String("private"), Qt::CaseInsensitive)) { && !packageName.endsWith(QLatin1String("private"), Qt::CaseInsensitive)) {

View File

@@ -554,11 +554,12 @@ static void applyQt515MissingImportWorkaround(const QString &path, LibraryInfo &
return; return;
if (isQtQuick) { if (isQtQuick) {
info.setImports(QStringList(QStringLiteral("QtQml"))); info.setImports(QList<QmlDirParser::Import>(
{QmlDirParser::Import("QtQml", ComponentVersion(), {})}));
} else if (isQtQml) { } else if (isQtQml) {
info.setImports(QStringList( info.setImports(QList<QmlDirParser::Import>(
{ QStringLiteral("QtQml.Models"), { QmlDirParser::Import("QtQml.Models", ComponentVersion(), {}),
QStringLiteral("QtQml.WorkerScript") })); QmlDirParser::Import("QtQml.WorkerScript", ComponentVersion(), {}) }));
} }
} }

View File

@@ -490,8 +490,7 @@ AndroidBuildApkStep::AndroidBuildApkStep(BuildStepList *parent, Utils::Id id)
sdkManager()->latestAndroidSdkPlatform())) sdkManager()->latestAndroidSdkPlatform()))
{ {
setImmutable(true); setImmutable(true);
setDisplayName("<b>" + tr("Build Android APK") + "</b>"); setDisplayName(tr("Build Android APK"));
setSummaryText(displayName());
} }
bool AndroidBuildApkStep::init() bool AndroidBuildApkStep::init()
@@ -899,6 +898,9 @@ void AndroidBuildApkStep::stdError(const QString &output)
QString newOutput = output; QString newOutput = output;
newOutput.remove(QRegularExpression("^(\\n)+")); newOutput.remove(QRegularExpression("^(\\n)+"));
if (newOutput.isEmpty())
return;
if (newOutput.startsWith("warning", Qt::CaseInsensitive) if (newOutput.startsWith("warning", Qt::CaseInsensitive)
|| newOutput.startsWith("note", Qt::CaseInsensitive)) || newOutput.startsWith("note", Qt::CaseInsensitive))
TaskHub::addTask(BuildSystemTask(Task::Warning, newOutput)); TaskHub::addTask(BuildSystemTask(Task::Warning, newOutput));

View File

@@ -556,6 +556,9 @@ void AndroidDeployQtStep::stdError(const QString &line)
QString newOutput = line; QString newOutput = line;
newOutput.remove(QRegularExpression("^(\\n)+")); newOutput.remove(QRegularExpression("^(\\n)+"));
if (newOutput.isEmpty())
return;
if (newOutput.startsWith("warning", Qt::CaseInsensitive) if (newOutput.startsWith("warning", Qt::CaseInsensitive)
|| newOutput.startsWith("note", Qt::CaseInsensitive)) || newOutput.startsWith("note", Qt::CaseInsensitive))
TaskHub::addTask(DeploymentTask(Task::Warning, newOutput)); TaskHub::addTask(DeploymentTask(Task::Warning, newOutput));

View File

@@ -255,6 +255,17 @@ static QImage scaleWithoutStretching(const QImage& original, const QSize& target
return ret; return ret;
} }
static bool similarFilesExist(const QString &path)
{
QFileInfo fileInfo(path);
QDir imageDir(fileInfo.absolutePath());
QString baseName(fileInfo.completeBaseName());
baseName.append(QLatin1String(".*"));
imageDir.setNameFilters({baseName});
auto entries = imageDir.entryList();
return !entries.empty();
}
void AndroidManifestEditorIconWidget::copyIcon() void AndroidManifestEditorIconWidget::copyIcon()
{ {
if (m_targetIconPath.isEmpty()) if (m_targetIconPath.isEmpty())
@@ -269,6 +280,7 @@ void AndroidManifestEditorIconWidget::copyIcon()
if (m_iconPath != targetPath) if (m_iconPath != targetPath)
removeIcon(); removeIcon();
if (original.isNull()) { if (original.isNull()) {
if (!similarFilesExist(m_iconPath))
m_iconPath.clear(); m_iconPath.clear();
return; return;
} }

View File

@@ -25,6 +25,8 @@
#include "androidsdkdownloader.h" #include "androidsdkdownloader.h"
#include <coreplugin/icore.h>
#include <QDir> #include <QDir>
#include <QDirIterator> #include <QDirIterator>
#include <QLoggingCategory> #include <QLoggingCategory>
@@ -85,8 +87,9 @@ void AndroidSdkDownloader::downloadAndExtractSdk(const QString &jdkPath, const Q
connect(m_reply, &QNetworkReply::sslErrors, this, &AndroidSdkDownloader::sslErrors); connect(m_reply, &QNetworkReply::sslErrors, this, &AndroidSdkDownloader::sslErrors);
#endif #endif
m_progressDialog = new QProgressDialog(tr("Downloading SDK Tools package..."), tr("Cancel"), 0, 100); m_progressDialog = new QProgressDialog(tr("Downloading SDK Tools package..."), tr("Cancel"),
m_progressDialog->setWindowModality(Qt::WindowModal); 0, 100, Core::ICore::dialogParent());
m_progressDialog->setWindowModality(Qt::ApplicationModal);
m_progressDialog->setWindowTitle(dialogTitle()); m_progressDialog->setWindowTitle(dialogTitle());
m_progressDialog->setFixedSize(m_progressDialog->sizeHint()); m_progressDialog->setFixedSize(m_progressDialog->sizeHint());

View File

@@ -331,11 +331,6 @@ ToolChain::MacroInspectionRunner IarToolChain::createMacroInspectionRunner() con
}; };
} }
Macros IarToolChain::predefinedMacros(const QStringList &cxxflags) const
{
return createMacroInspectionRunner()(cxxflags).macros;
}
Utils::LanguageExtensions IarToolChain::languageExtensions(const QStringList &) const Utils::LanguageExtensions IarToolChain::languageExtensions(const QStringList &) const
{ {
return LanguageExtension::None; return LanguageExtension::None;
@@ -371,13 +366,6 @@ ToolChain::BuiltInHeaderPathsRunner IarToolChain::createBuiltInHeaderPathsRunner
}; };
} }
HeaderPaths IarToolChain::builtInHeaderPaths(const QStringList &cxxFlags,
const FilePath &fileName,
const Environment &env) const
{
return createBuiltInHeaderPathsRunner(env)(cxxFlags, fileName.toString(), "");
}
void IarToolChain::addToEnvironment(Environment &env) const void IarToolChain::addToEnvironment(Environment &env) const
{ {
if (!compilerCommand().isEmpty()) { if (!compilerCommand().isEmpty()) {

View File

@@ -56,15 +56,11 @@ public:
bool isValid() const final; bool isValid() const final;
MacroInspectionRunner createMacroInspectionRunner() const final; MacroInspectionRunner createMacroInspectionRunner() const final;
ProjectExplorer::Macros predefinedMacros(const QStringList &cxxflags) const final;
Utils::LanguageExtensions languageExtensions(const QStringList &cxxflags) const final; Utils::LanguageExtensions languageExtensions(const QStringList &cxxflags) const final;
Utils::WarningFlags warningFlags(const QStringList &cxxflags) const final; Utils::WarningFlags warningFlags(const QStringList &cxxflags) const final;
BuiltInHeaderPathsRunner createBuiltInHeaderPathsRunner(const Utils::Environment &) const final; BuiltInHeaderPathsRunner createBuiltInHeaderPathsRunner(const Utils::Environment &) const final;
ProjectExplorer::HeaderPaths builtInHeaderPaths(const QStringList &cxxFlags,
const Utils::FilePath &,
const Utils::Environment &env) const final;
void addToEnvironment(Utils::Environment &env) const final; void addToEnvironment(Utils::Environment &env) const final;
QList<Utils::OutputLineParser *> createOutputParsers() const final; QList<Utils::OutputLineParser *> createOutputParsers() const final;

View File

@@ -462,11 +462,6 @@ ToolChain::MacroInspectionRunner KeilToolChain::createMacroInspectionRunner() co
}; };
} }
Macros KeilToolChain::predefinedMacros(const QStringList &cxxflags) const
{
return createMacroInspectionRunner()(cxxflags).macros;
}
Utils::LanguageExtensions KeilToolChain::languageExtensions(const QStringList &) const Utils::LanguageExtensions KeilToolChain::languageExtensions(const QStringList &) const
{ {
return LanguageExtension::None; return LanguageExtension::None;
@@ -496,13 +491,6 @@ ToolChain::BuiltInHeaderPathsRunner KeilToolChain::createBuiltInHeaderPathsRunne
}; };
} }
HeaderPaths KeilToolChain::builtInHeaderPaths(const QStringList &cxxFlags,
const FilePath &fileName,
const Environment &env) const
{
return createBuiltInHeaderPathsRunner(env)(cxxFlags, fileName.toString(), "");
}
void KeilToolChain::addToEnvironment(Environment &env) const void KeilToolChain::addToEnvironment(Environment &env) const
{ {
if (!compilerCommand().isEmpty()) { if (!compilerCommand().isEmpty()) {

View File

@@ -56,16 +56,12 @@ public:
bool isValid() const final; bool isValid() const final;
MacroInspectionRunner createMacroInspectionRunner() const final; MacroInspectionRunner createMacroInspectionRunner() const final;
ProjectExplorer::Macros predefinedMacros(const QStringList &cxxflags) const final;
Utils::LanguageExtensions languageExtensions(const QStringList &cxxflags) const final; Utils::LanguageExtensions languageExtensions(const QStringList &cxxflags) const final;
Utils::WarningFlags warningFlags(const QStringList &cxxflags) const final; Utils::WarningFlags warningFlags(const QStringList &cxxflags) const final;
BuiltInHeaderPathsRunner createBuiltInHeaderPathsRunner( BuiltInHeaderPathsRunner createBuiltInHeaderPathsRunner(
const Utils::Environment &) const final; const Utils::Environment &) const final;
ProjectExplorer::HeaderPaths builtInHeaderPaths(const QStringList &cxxFlags,
const Utils::FilePath &,
const Utils::Environment &env) const final;
void addToEnvironment(Utils::Environment &env) const final; void addToEnvironment(Utils::Environment &env) const final;
QList<Utils::OutputLineParser *> createOutputParsers() const final; QList<Utils::OutputLineParser *> createOutputParsers() const final;

View File

@@ -248,11 +248,6 @@ ToolChain::MacroInspectionRunner SdccToolChain::createMacroInspectionRunner() co
}; };
} }
Macros SdccToolChain::predefinedMacros(const QStringList &cxxflags) const
{
return createMacroInspectionRunner()(cxxflags).macros;
}
Utils::LanguageExtensions SdccToolChain::languageExtensions(const QStringList &) const Utils::LanguageExtensions SdccToolChain::languageExtensions(const QStringList &) const
{ {
return LanguageExtension::None; return LanguageExtension::None;
@@ -278,13 +273,6 @@ ToolChain::BuiltInHeaderPathsRunner SdccToolChain::createBuiltInHeaderPathsRunne
}; };
} }
HeaderPaths SdccToolChain::builtInHeaderPaths(const QStringList &cxxFlags,
const FilePath &fileName,
const Environment &env) const
{
return createBuiltInHeaderPathsRunner(env)(cxxFlags, fileName.toString(), "");
}
void SdccToolChain::addToEnvironment(Environment &env) const void SdccToolChain::addToEnvironment(Environment &env) const
{ {
if (!compilerCommand().isEmpty()) { if (!compilerCommand().isEmpty()) {

View File

@@ -55,16 +55,12 @@ public:
bool isValid() const final; bool isValid() const final;
MacroInspectionRunner createMacroInspectionRunner() const final; MacroInspectionRunner createMacroInspectionRunner() const final;
ProjectExplorer::Macros predefinedMacros(const QStringList &cxxflags) const final;
Utils::LanguageExtensions languageExtensions(const QStringList &cxxflags) const final; Utils::LanguageExtensions languageExtensions(const QStringList &cxxflags) const final;
Utils::WarningFlags warningFlags(const QStringList &cxxflags) const final; Utils::WarningFlags warningFlags(const QStringList &cxxflags) const final;
BuiltInHeaderPathsRunner createBuiltInHeaderPathsRunner( BuiltInHeaderPathsRunner createBuiltInHeaderPathsRunner(
const Utils::Environment &) const final; const Utils::Environment &) const final;
ProjectExplorer::HeaderPaths builtInHeaderPaths(const QStringList &cxxFlags,
const Utils::FilePath &,
const Utils::Environment &env) const final;
void addToEnvironment(Utils::Environment &env) const final; void addToEnvironment(Utils::Environment &env) const final;
QList<Utils::OutputLineParser *> createOutputParsers() const final; QList<Utils::OutputLineParser *> createOutputParsers() const final;

View File

@@ -64,7 +64,7 @@ using namespace Core;
namespace BinEditor { namespace BinEditor {
namespace Internal { namespace Internal {
const QChar MidpointChar = QLatin1Char(0xB7); const QChar MidpointChar(u'\u00B7');
static QByteArray calculateHexPattern(const QByteArray &pattern) static QByteArray calculateHexPattern(const QByteArray &pattern)
{ {

View File

@@ -837,12 +837,16 @@ FilePath CMakeBuildSystem::workDirectory(const BuildDirParameters &parameters)
{ {
const Utils::FilePath bdir = parameters.buildDirectory; const Utils::FilePath bdir = parameters.buildDirectory;
const CMakeTool *cmake = parameters.cmakeTool(); const CMakeTool *cmake = parameters.cmakeTool();
// use the build directory if it already exists anyhow
if (bdir.exists()) { if (bdir.exists()) {
m_buildDirToTempDir.erase(bdir); m_buildDirToTempDir.erase(bdir);
return bdir; return bdir;
} }
if (cmake && cmake->autoCreateBuildDirectory()) { // use the build directory if the cmake tool settings are set to automatically create them,
// or if the configuration was changed by the user
if ((cmake && cmake->autoCreateBuildDirectory()) || !parameters.extraCMakeArguments.isEmpty()) {
if (!cmakeBuildConfiguration()->createBuildDirectory()) if (!cmakeBuildConfiguration()->createBuildDirectory())
handleParsingFailed( handleParsingFailed(
tr("Failed to create build directory \"%1\".").arg(bdir.toUserOutput())); tr("Failed to create build directory \"%1\".").arg(bdir.toUserOutput()));

View File

@@ -153,6 +153,9 @@ OutputWindow::OutputWindow(Context context, const QString &settingsKey, QWidget
EditorManager::openEditorAt(fp.toString(), line, column); EditorManager::openEditorAt(fp.toString(), line, column);
}); });
connect(verticalScrollBar(), &QAbstractSlider::sliderMoved,
this, &OutputWindow::updateAutoScroll);
undoAction->setEnabled(false); undoAction->setEnabled(false);
redoAction->setEnabled(false); redoAction->setEnabled(false);
cutAction->setEnabled(false); cutAction->setEnabled(false);
@@ -219,9 +222,8 @@ void OutputWindow::resizeEvent(QResizeEvent *e)
{ {
//Keep scrollbar at bottom of window while resizing, to ensure we keep scrolling //Keep scrollbar at bottom of window while resizing, to ensure we keep scrolling
//This can happen if window is resized while building, or if the horizontal scrollbar appears //This can happen if window is resized while building, or if the horizontal scrollbar appears
bool atBottom = isScrollbarAtBottom();
QPlainTextEdit::resizeEvent(e); QPlainTextEdit::resizeEvent(e);
if (atBottom) if (d->scrollToBottom)
scrollToBottom(); scrollToBottom();
} }
@@ -252,7 +254,6 @@ void OutputWindow::showEvent(QShowEvent *e)
QPlainTextEdit::showEvent(e); QPlainTextEdit::showEvent(e);
if (d->scrollToBottom) if (d->scrollToBottom)
verticalScrollBar()->setValue(verticalScrollBar()->maximum()); verticalScrollBar()->setValue(verticalScrollBar()->maximum());
d->scrollToBottom = false;
} }
void OutputWindow::wheelEvent(QWheelEvent *e) void OutputWindow::wheelEvent(QWheelEvent *e)
@@ -272,6 +273,7 @@ void OutputWindow::wheelEvent(QWheelEvent *e)
} }
} }
QAbstractScrollArea::wheelEvent(e); QAbstractScrollArea::wheelEvent(e);
updateAutoScroll();
updateMicroFocus(); updateMicroFocus();
} }
@@ -348,8 +350,6 @@ void OutputWindow::updateFilterProperties(
void OutputWindow::filterNewContent() void OutputWindow::filterNewContent()
{ {
bool atBottom = isScrollbarAtBottom();
QTextBlock lastBlock = document()->findBlockByNumber(d->lastFilteredBlockNumber); QTextBlock lastBlock = document()->findBlockByNumber(d->lastFilteredBlockNumber);
if (!lastBlock.isValid()) if (!lastBlock.isValid())
lastBlock = document()->begin(); lastBlock = document()->begin();
@@ -381,7 +381,7 @@ void OutputWindow::filterNewContent()
// FIXME: Why on earth is this necessary? We should probably do something else instead... // FIXME: Why on earth is this necessary? We should probably do something else instead...
setDocument(document()); setDocument(document());
if (atBottom) if (d->scrollToBottom)
scrollToBottom(); scrollToBottom();
} }
@@ -432,11 +432,9 @@ void OutputWindow::handleOutputChunk(const QString &output, OutputFormat format)
} }
} }
const bool atBottom = isScrollbarAtBottom() || d->scrollTimer.isActive();
d->scrollToBottom = true;
d->formatter.appendMessage(out, format); d->formatter.appendMessage(out, format);
if (atBottom) { if (d->scrollToBottom) {
if (d->lastMessage.elapsed() < 5) { if (d->lastMessage.elapsed() < 5) {
d->scrollTimer.start(); d->scrollTimer.start();
} else { } else {
@@ -449,6 +447,11 @@ void OutputWindow::handleOutputChunk(const QString &output, OutputFormat format)
enableUndoRedo(); enableUndoRedo();
} }
void OutputWindow::updateAutoScroll()
{
d->scrollToBottom = isScrollbarAtBottom();
}
void OutputWindow::setMaxCharCount(int count) void OutputWindow::setMaxCharCount(int count)
{ {
d->maxCharCount = count; d->maxCharCount = count;
@@ -505,6 +508,7 @@ QMimeData *OutputWindow::createMimeDataFromSelection() const
void OutputWindow::clear() void OutputWindow::clear()
{ {
d->formatter.clear(); d->formatter.clear();
d->scrollToBottom = true;
} }
void OutputWindow::flush() void OutputWindow::flush()

View File

@@ -109,6 +109,7 @@ private:
void filterNewContent(); void filterNewContent();
void handleNextOutputChunk(); void handleNextOutputChunk();
void handleOutputChunk(const QString &output, Utils::OutputFormat format); void handleOutputChunk(const QString &output, Utils::OutputFormat format);
void updateAutoScroll();
Internal::OutputWindowPrivate *d = nullptr; Internal::OutputWindowPrivate *d = nullptr;
}; };

View File

@@ -43,9 +43,9 @@ static QByteArray overwrittenToolchainDefines(const ProjectPart &projectPart)
// MSVC's predefined macros like __FUNCSIG__ expand to itself. // MSVC's predefined macros like __FUNCSIG__ expand to itself.
// We can't parse this, so redefine to the empty string literal. // We can't parse this, so redefine to the empty string literal.
if (projectPart.toolchainType == ProjectExplorer::Constants::MSVC_TOOLCHAIN_TYPEID) { if (projectPart.toolchainType == ProjectExplorer::Constants::MSVC_TOOLCHAIN_TYPEID) {
defines += "#define __FUNCSIG__ \"\"\n" defines += "#define __FUNCSIG__ \"void __cdecl someLegalAndLongishFunctionNameThatWorksAroundQTCREATORBUG-24580(void)\"\n"
"#define __FUNCDNAME__ \"\"\n" "#define __FUNCDNAME__ \"?someLegalAndLongishFunctionNameThatWorksAroundQTCREATORBUG-24580@@YAXXZ\"\n"
"#define __FUNCTION__ \"\"\n"; "#define __FUNCTION__ \"someLegalAndLongishFunctionNameThatWorksAroundQTCREATORBUG-24580\"\n";
} }
return defines; return defines;

View File

@@ -356,7 +356,7 @@ void CompilerOptionsBuilder::addHeaderPathOptions()
for (const HeaderPath &headerPath : filter.systemHeaderPaths) for (const HeaderPath &headerPath : filter.systemHeaderPaths)
addIncludeDirOptionForPath(headerPath); addIncludeDirOptionForPath(headerPath);
if (m_useTweakedHeaderPaths == UseTweakedHeaderPaths::Yes) { if (m_useTweakedHeaderPaths != UseTweakedHeaderPaths::No) {
QTC_CHECK(!m_clangVersion.isEmpty() QTC_CHECK(!m_clangVersion.isEmpty()
&& "Clang resource directory is required with UseTweakedHeaderPaths::Yes."); && "Clang resource directory is required with UseTweakedHeaderPaths::Yes.");
@@ -657,9 +657,9 @@ void CompilerOptionsBuilder::undefineCppLanguageFeatureMacrosForMsvc2015()
void CompilerOptionsBuilder::addDefineFunctionMacrosMsvc() void CompilerOptionsBuilder::addDefineFunctionMacrosMsvc()
{ {
if (m_projectPart.toolchainType == ProjectExplorer::Constants::MSVC_TOOLCHAIN_TYPEID) { if (m_projectPart.toolchainType == ProjectExplorer::Constants::MSVC_TOOLCHAIN_TYPEID) {
addMacros({{"__FUNCSIG__", "\"\""}, addMacros({{"__FUNCSIG__", "\"void __cdecl someLegalAndLongishFunctionNameThatWorksAroundQTCREATORBUG-24580(void)\""},
{"__FUNCTION__", "\"\""}, {"__FUNCTION__", "\"someLegalAndLongishFunctionNameThatWorksAroundQTCREATORBUG-24580\""},
{"__FUNCDNAME__", "\"\""}}); {"__FUNCDNAME__", "\"?someLegalAndLongishFunctionNameThatWorksAroundQTCREATORBUG-24580@@YAXXZ\""}});
} }
} }

View File

@@ -108,9 +108,8 @@ bool FileIterationOrder::isValid() const
static int commonPrefixLength(const QString &filePath1, const QString &filePath2) static int commonPrefixLength(const QString &filePath1, const QString &filePath2)
{ {
const auto mismatches = std::mismatch(filePath1.begin(), const auto mismatches = std::mismatch(filePath1.begin(), filePath1.end(),
filePath1.end(), filePath2.begin(), filePath2.end());
filePath2.begin());
return mismatches.first - filePath1.begin(); return mismatches.first - filePath1.begin();
} }

View File

@@ -4165,7 +4165,7 @@ void GdbEngine::setupInferior()
} }
if (!symbolFile.isEmpty()) { if (!symbolFile.isEmpty()) {
runCommand({"-file-symbol-file \"" + symbolFile + '"', runCommand({"-file-exec-and-symbols \"" + symbolFile + '"',
CB(handleFileExecAndSymbols)}); CB(handleFileExecAndSymbols)});
} }
@@ -4197,7 +4197,7 @@ void GdbEngine::setupInferior()
// Do that first, otherwise no symbols are loaded. // Do that first, otherwise no symbols are loaded.
QFileInfo fi = executable.toFileInfo(); QFileInfo fi = executable.toFileInfo();
QString path = fi.absoluteFilePath(); QString path = fi.absoluteFilePath();
runCommand({"-file-exec-and-symbols \"" + path + '"', runCommand({"-file-symbol-file \"" + path + '"',
CB(handleFileExecAndSymbols)}); CB(handleFileExecAndSymbols)});
} else if (isTermEngine()) { } else if (isTermEngine()) {

View File

@@ -66,11 +66,6 @@ ToolChain::MacroInspectionRunner NimToolChain::createMacroInspectionRunner() con
return ToolChain::MacroInspectionRunner(); return ToolChain::MacroInspectionRunner();
} }
Macros NimToolChain::predefinedMacros(const QStringList &) const
{
return Macros();
}
LanguageExtensions NimToolChain::languageExtensions(const QStringList &) const LanguageExtensions NimToolChain::languageExtensions(const QStringList &) const
{ {
return LanguageExtension::None; return LanguageExtension::None;
@@ -87,12 +82,6 @@ ToolChain::BuiltInHeaderPathsRunner NimToolChain::createBuiltInHeaderPathsRunner
return ToolChain::BuiltInHeaderPathsRunner(); return ToolChain::BuiltInHeaderPathsRunner();
} }
HeaderPaths NimToolChain::builtInHeaderPaths(const QStringList &, const FilePath &,
const Environment &) const
{
return {};
}
void NimToolChain::addToEnvironment(Environment &env) const void NimToolChain::addToEnvironment(Environment &env) const
{ {
if (isValid()) if (isValid())

View File

@@ -41,15 +41,11 @@ public:
bool isValid() const override; bool isValid() const override;
MacroInspectionRunner createMacroInspectionRunner() const override; MacroInspectionRunner createMacroInspectionRunner() const override;
ProjectExplorer::Macros predefinedMacros(const QStringList &flags) const final;
Utils::LanguageExtensions languageExtensions(const QStringList &flags) const final; Utils::LanguageExtensions languageExtensions(const QStringList &flags) const final;
Utils::WarningFlags warningFlags(const QStringList &flags) const final; Utils::WarningFlags warningFlags(const QStringList &flags) const final;
BuiltInHeaderPathsRunner createBuiltInHeaderPathsRunner( BuiltInHeaderPathsRunner createBuiltInHeaderPathsRunner(
const Utils::Environment &) const override; const Utils::Environment &) const override;
ProjectExplorer::HeaderPaths builtInHeaderPaths(const QStringList &flags,
const Utils::FilePath &sysRoot,
const Utils::Environment &) const final;
void addToEnvironment(Utils::Environment &env) const final; void addToEnvironment(Utils::Environment &env) const final;
Utils::FilePath makeCommand(const Utils::Environment &env) const final; Utils::FilePath makeCommand(const Utils::Environment &env) const final;
QString compilerVersion() const; QString compilerVersion() const;

View File

@@ -109,11 +109,6 @@ ToolChain::MacroInspectionRunner CustomToolChain::createMacroInspectionRunner()
}; };
} }
Macros CustomToolChain::predefinedMacros(const QStringList &cxxflags) const
{
return createMacroInspectionRunner()(cxxflags).macros;
}
Utils::LanguageExtensions CustomToolChain::languageExtensions(const QStringList &) const Utils::LanguageExtensions CustomToolChain::languageExtensions(const QStringList &) const
{ {
return LanguageExtension::None; return LanguageExtension::None;
@@ -156,13 +151,6 @@ ToolChain::BuiltInHeaderPathsRunner CustomToolChain::createBuiltInHeaderPathsRun
}; };
} }
HeaderPaths CustomToolChain::builtInHeaderPaths(const QStringList &cxxFlags,
const FilePath &fileName,
const Environment &env) const
{
return createBuiltInHeaderPathsRunner(env)(cxxFlags, fileName.toString(), "");
}
void CustomToolChain::addToEnvironment(Environment &env) const void CustomToolChain::addToEnvironment(Environment &env) const
{ {
if (!m_compilerCommand.isEmpty()) { if (!m_compilerCommand.isEmpty()) {

View File

@@ -67,7 +67,6 @@ public:
bool isValid() const override; bool isValid() const override;
MacroInspectionRunner createMacroInspectionRunner() const override; MacroInspectionRunner createMacroInspectionRunner() const override;
Macros predefinedMacros(const QStringList &cxxflags) const override;
Utils::LanguageExtensions languageExtensions(const QStringList &cxxflags) const override; Utils::LanguageExtensions languageExtensions(const QStringList &cxxflags) const override;
Utils::WarningFlags warningFlags(const QStringList &cxxflags) const override; Utils::WarningFlags warningFlags(const QStringList &cxxflags) const override;
const Macros &rawPredefinedMacros() const; const Macros &rawPredefinedMacros() const;
@@ -75,9 +74,6 @@ public:
BuiltInHeaderPathsRunner createBuiltInHeaderPathsRunner( BuiltInHeaderPathsRunner createBuiltInHeaderPathsRunner(
const Utils::Environment &) const override; const Utils::Environment &) const override;
HeaderPaths builtInHeaderPaths(const QStringList &cxxFlags,
const Utils::FilePath &,
const Utils::Environment &env) const override;
void addToEnvironment(Utils::Environment &env) const override; void addToEnvironment(Utils::Environment &env) const override;
QStringList suggestedMkspecList() const override; QStringList suggestedMkspecList() const override;
QList<Utils::OutputLineParser *> createOutputParsers() const override; QList<Utils::OutputLineParser *> createOutputParsers() const override;

View File

@@ -427,7 +427,16 @@ ToolChain::MacroInspectionRunner GccToolChain::createMacroInspectionRunner() con
MacrosCache macroCache = predefinedMacrosCache(); MacrosCache macroCache = predefinedMacrosCache();
Utils::Id lang = language(); Utils::Id lang = language();
// This runner must be thread-safe! /*
* Asks compiler for set of predefined macros
* flags are the compiler flags collected from project settings
* returns the list of defines, one per line, e.g. "#define __GXX_WEAK__ 1"
* Note: changing compiler flags sometimes changes macros set, e.g. -fopenmp
* adds _OPENMP macro, for full list of macro search by word "when" on this page:
* http://gcc.gnu.org/onlinedocs/cpp/Common-Predefined-Macros.html
*
* This runner must be thread-safe!
*/
return [env, compilerCommand = compilerCommand(), return [env, compilerCommand = compilerCommand(),
platformCodeGenFlags, reinterpretOptions, macroCache, lang] platformCodeGenFlags, reinterpretOptions, macroCache, lang]
(const QStringList &flags) { (const QStringList &flags) {
@@ -458,20 +467,6 @@ ToolChain::MacroInspectionRunner GccToolChain::createMacroInspectionRunner() con
}; };
} }
/**
* @brief Asks compiler for set of predefined macros
* @param cxxflags - compiler flags collected from project settings
* @return defines list, one per line, e.g. "#define __GXX_WEAK__ 1"
*
* @note changing compiler flags sometimes changes macros set, e.g. -fopenmp
* adds _OPENMP macro, for full list of macro search by word "when" on this page:
* http://gcc.gnu.org/onlinedocs/cpp/Common-Predefined-Macros.html
*/
ProjectExplorer::Macros GccToolChain::predefinedMacros(const QStringList &cxxflags) const
{
return createMacroInspectionRunner()(cxxflags).macros;
}
/** /**
* @brief Parses gcc flags -std=*, -fopenmp, -fms-extensions. * @brief Parses gcc flags -std=*, -fopenmp, -fms-extensions.
* @see http://gcc.gnu.org/onlinedocs/gcc/C-Dialect-Options.html * @see http://gcc.gnu.org/onlinedocs/gcc/C-Dialect-Options.html
@@ -645,16 +640,6 @@ ToolChain::BuiltInHeaderPathsRunner GccToolChain::createBuiltInHeaderPathsRunner
}; };
} }
HeaderPaths GccToolChain::builtInHeaderPaths(const QStringList &flags,
const FilePath &sysRootPath,
const Environment &env) const
{
return createBuiltInHeaderPathsRunner(env)(flags,
sysRootPath.isEmpty() ? sysRoot()
: sysRootPath.toString(),
originalTargetTriple());
}
void GccToolChain::addCommandPathToEnvironment(const FilePath &command, Environment &env) void GccToolChain::addCommandPathToEnvironment(const FilePath &command, Environment &env)
{ {
const Utils::FilePath compilerDir = command.parentDir(); const Utils::FilePath compilerDir = command.parentDir();
@@ -845,7 +830,7 @@ GccToolChain::DetectedAbisResult GccToolChain::detectSupportedAbis() const
{ {
Environment env = Environment::systemEnvironment(); Environment env = Environment::systemEnvironment();
addToEnvironment(env); addToEnvironment(env);
ProjectExplorer::Macros macros = predefinedMacros(QStringList()); ProjectExplorer::Macros macros = createMacroInspectionRunner()({}).macros;
return guessGccAbi(findLocalCompiler(compilerCommand(), env), return guessGccAbi(findLocalCompiler(compilerCommand(), env),
env.toStringList(), env.toStringList(),
macros, macros,

View File

@@ -83,12 +83,7 @@ public:
const QString &directoryPath) const override; const QString &directoryPath) const override;
MacroInspectionRunner createMacroInspectionRunner() const override; MacroInspectionRunner createMacroInspectionRunner() const override;
Macros predefinedMacros(const QStringList &cxxflags) const override;
BuiltInHeaderPathsRunner createBuiltInHeaderPathsRunner(const Utils::Environment &env) const override; BuiltInHeaderPathsRunner createBuiltInHeaderPathsRunner(const Utils::Environment &env) const override;
HeaderPaths builtInHeaderPaths(const QStringList &flags,
const Utils::FilePath &sysRootPath,
const Utils::Environment &env) const override;
void addToEnvironment(Utils::Environment &env) const override; void addToEnvironment(Utils::Environment &env) const override;
Utils::FilePath makeCommand(const Utils::Environment &environment) const override; Utils::FilePath makeCommand(const Utils::Environment &environment) const override;

View File

@@ -591,10 +591,10 @@ Macros MsvcToolChain::msvcPredefinedMacros(const QStringList &cxxflags,
QStringList toProcess; QStringList toProcess;
for (const QString &arg : cxxflags) { for (const QString &arg : cxxflags) {
if (arg.startsWith(QLatin1String("/D"))) { if (arg.startsWith("/D") || arg.startsWith("-D")) {
const QString define = arg.mid(2); const QString define = arg.mid(2);
predefinedMacros.append(Macro::fromKeyValue(define)); predefinedMacros.append(Macro::fromKeyValue(define));
} else if (arg.startsWith(QLatin1String("/U"))) { } else if (arg.startsWith("/U") || arg.startsWith("-U")) {
predefinedMacros.append( predefinedMacros.append(
{arg.mid(2).toLocal8Bit(), ProjectExplorer::MacroType::Undefine}); {arg.mid(2).toLocal8Bit(), ProjectExplorer::MacroType::Undefine});
} else { } else {
@@ -991,11 +991,6 @@ ToolChain::MacroInspectionRunner MsvcToolChain::createMacroInspectionRunner() co
}; };
} }
Macros MsvcToolChain::predefinedMacros(const QStringList &cxxflags) const
{
return createMacroInspectionRunner()(cxxflags).macros;
}
Utils::LanguageExtensions MsvcToolChain::languageExtensions(const QStringList &cxxflags) const Utils::LanguageExtensions MsvcToolChain::languageExtensions(const QStringList &cxxflags) const
{ {
using Utils::LanguageExtension; using Utils::LanguageExtension;
@@ -1081,13 +1076,6 @@ ToolChain::BuiltInHeaderPathsRunner MsvcToolChain::createBuiltInHeaderPathsRunne
}; };
} }
HeaderPaths MsvcToolChain::builtInHeaderPaths(const QStringList &cxxflags,
const Utils::FilePath &sysRoot,
const Environment &env) const
{
return createBuiltInHeaderPathsRunner(env)(cxxflags, sysRoot.toString(), "");
}
void MsvcToolChain::addToEnvironment(Utils::Environment &env) const void MsvcToolChain::addToEnvironment(Utils::Environment &env) const
{ {
// We cache the full environment (incoming + modifications by setup script). // We cache the full environment (incoming + modifications by setup script).

View File

@@ -74,16 +74,12 @@ public:
std::unique_ptr<ToolChainConfigWidget> createConfigurationWidget() override; std::unique_ptr<ToolChainConfigWidget> createConfigurationWidget() override;
MacroInspectionRunner createMacroInspectionRunner() const override; MacroInspectionRunner createMacroInspectionRunner() const override;
Macros predefinedMacros(const QStringList &cxxflags) const override;
Utils::LanguageExtensions languageExtensions(const QStringList &cxxflags) const override; Utils::LanguageExtensions languageExtensions(const QStringList &cxxflags) const override;
Utils::WarningFlags warningFlags(const QStringList &cflags) const override; Utils::WarningFlags warningFlags(const QStringList &cflags) const override;
QStringList includedFiles(const QStringList &flags, QStringList includedFiles(const QStringList &flags,
const QString &directoryPath) const override; const QString &directoryPath) const override;
BuiltInHeaderPathsRunner createBuiltInHeaderPathsRunner( BuiltInHeaderPathsRunner createBuiltInHeaderPathsRunner(
const Utils::Environment &env) const override; const Utils::Environment &env) const override;
HeaderPaths builtInHeaderPaths(const QStringList &cxxflags,
const Utils::FilePath &sysRoot,
const Utils::Environment &env) const override;
void addToEnvironment(Utils::Environment &env) const override; void addToEnvironment(Utils::Environment &env) const override;
Utils::FilePath makeCommand(const Utils::Environment &environment) const override; Utils::FilePath makeCommand(const Utils::Environment &environment) const override;

View File

@@ -123,15 +123,11 @@ public:
// A MacroInspectionRunner is created in the ui thread and runs in another thread. // A MacroInspectionRunner is created in the ui thread and runs in another thread.
using MacroInspectionRunner = std::function<MacroInspectionReport(const QStringList &cxxflags)>; using MacroInspectionRunner = std::function<MacroInspectionReport(const QStringList &cxxflags)>;
virtual MacroInspectionRunner createMacroInspectionRunner() const = 0; virtual MacroInspectionRunner createMacroInspectionRunner() const = 0;
virtual Macros predefinedMacros(const QStringList &cxxflags) const = 0;
// A BuiltInHeaderPathsRunner is created in the ui thread and runs in another thread. // A BuiltInHeaderPathsRunner is created in the ui thread and runs in another thread.
using BuiltInHeaderPathsRunner = std::function<HeaderPaths( using BuiltInHeaderPathsRunner = std::function<HeaderPaths(
const QStringList &cxxflags, const QString &sysRoot, const QString &originalTargetTriple)>; const QStringList &cxxflags, const QString &sysRoot, const QString &originalTargetTriple)>;
virtual BuiltInHeaderPathsRunner createBuiltInHeaderPathsRunner(const Utils::Environment &env) const = 0; virtual BuiltInHeaderPathsRunner createBuiltInHeaderPathsRunner(const Utils::Environment &env) const = 0;
virtual HeaderPaths builtInHeaderPaths(const QStringList &cxxflags,
const Utils::FilePath &sysRoot,
const Utils::Environment &env) const = 0;
virtual void addToEnvironment(Utils::Environment &env) const = 0; virtual void addToEnvironment(Utils::Environment &env) const = 0;
virtual Utils::FilePath makeCommand(const Utils::Environment &env) const = 0; virtual Utils::FilePath makeCommand(const Utils::Environment &env) const = 0;

View File

@@ -316,12 +316,9 @@ public:
bool isValid() const override { return m_valid; } bool isValid() const override { return m_valid; }
MacroInspectionRunner createMacroInspectionRunner() const override { return MacroInspectionRunner(); } MacroInspectionRunner createMacroInspectionRunner() const override { return MacroInspectionRunner(); }
Macros predefinedMacros(const QStringList &cxxflags) const override { Q_UNUSED(cxxflags) return Macros(); }
LanguageExtensions languageExtensions(const QStringList &cxxflags) const override { Q_UNUSED(cxxflags) return LanguageExtension::None; } LanguageExtensions languageExtensions(const QStringList &cxxflags) const override { Q_UNUSED(cxxflags) return LanguageExtension::None; }
WarningFlags warningFlags(const QStringList &cflags) const override { Q_UNUSED(cflags) return WarningFlags::NoWarnings; } WarningFlags warningFlags(const QStringList &cflags) const override { Q_UNUSED(cflags) return WarningFlags::NoWarnings; }
BuiltInHeaderPathsRunner createBuiltInHeaderPathsRunner(const Utils::Environment &) const override { return BuiltInHeaderPathsRunner(); } BuiltInHeaderPathsRunner createBuiltInHeaderPathsRunner(const Utils::Environment &) const override { return BuiltInHeaderPathsRunner(); }
HeaderPaths builtInHeaderPaths(const QStringList &cxxflags, const FilePath &sysRoot, const Utils::Environment &) const override
{ Q_UNUSED(cxxflags) Q_UNUSED(sysRoot) return {}; }
void addToEnvironment(Environment &env) const override { Q_UNUSED(env) } void addToEnvironment(Environment &env) const override { Q_UNUSED(env) }
FilePath makeCommand(const Environment &) const override { return FilePath::fromString("make"); } FilePath makeCommand(const Environment &) const override { return FilePath::fromString("make"); }
QList<OutputLineParser *> createOutputParsers() const override { return {}; } QList<OutputLineParser *> createOutputParsers() const override { return {}; }

View File

@@ -103,11 +103,12 @@ TreeScanner::Result TreeScanner::result() const
TreeScanner::Result TreeScanner::release() TreeScanner::Result TreeScanner::release()
{ {
if (isFinished()) { if (isFinished() && m_scanFuture.resultCount() > 0) {
auto result = m_scanFuture.result(); auto result = m_scanFuture.result();
m_scanFuture = Future(); m_scanFuture = Future();
return result; return result;
} }
m_scanFuture = Future();
return Result(); return Result();
} }

View File

@@ -39,6 +39,7 @@
#include <projectexplorer/projectexplorer.h> #include <projectexplorer/projectexplorer.h>
#include <projectexplorer/projectexplorerconstants.h> #include <projectexplorer/projectexplorerconstants.h>
#include <projectexplorer/target.h> #include <projectexplorer/target.h>
#include <projectexplorer/taskhub.h>
#include <qtsupport/profilereader.h> #include <qtsupport/profilereader.h>
#include <texteditor/icodestylepreferences.h> #include <texteditor/icodestylepreferences.h>
#include <texteditor/tabsettings.h> #include <texteditor/tabsettings.h>
@@ -774,7 +775,7 @@ QPair<ProFile *, QStringList> QmakePriFile::readProFile()
&contents, &contents,
&m_textFormat, &m_textFormat,
&errorMsg) != TextFileFormat::ReadSuccess) { &errorMsg) != TextFileFormat::ReadSuccess) {
QmakeBuildSystem::proFileParseError(errorMsg); QmakeBuildSystem::proFileParseError(errorMsg, filePath());
return qMakePair(includeFile, lines); return qMakePair(includeFile, lines);
} }
lines = contents.split('\n'); lines = contents.split('\n');
@@ -1655,7 +1656,7 @@ void QmakeProFile::applyEvaluate(QmakeEvalResult *evalResult)
} }
foreach (const QString &error, evalResult->errors) foreach (const QString &error, evalResult->errors)
QmakeBuildSystem::proFileParseError(error); QmakeBuildSystem::proFileParseError(error, filePath());
// we are changing what is executed in that case // we are changing what is executed in that case
if (result->state == QmakeEvalResult::EvalFail || m_buildSystem->wasEvaluateCanceled()) { if (result->state == QmakeEvalResult::EvalFail || m_buildSystem->wasEvaluateCanceled()) {
@@ -1666,8 +1667,10 @@ void QmakeProFile::applyEvaluate(QmakeEvalResult *evalResult)
if (result->state == QmakeEvalResult::EvalFail) { if (result->state == QmakeEvalResult::EvalFail) {
QmakeBuildSystem::proFileParseError( QmakeBuildSystem::proFileParseError(
QCoreApplication::translate("QmakeProFile", "Error while parsing file %1. Giving up.") QCoreApplication::translate("QmakeProFile",
.arg(filePath().toUserOutput())); "Error while parsing file %1. Giving up.")
.arg(filePath().toUserOutput()),
filePath());
if (m_projectType == ProjectType::Invalid) if (m_projectType == ProjectType::Invalid)
return; return;

View File

@@ -649,6 +649,7 @@ bool QmakeBuildSystem::wasEvaluateCanceled()
void QmakeBuildSystem::asyncUpdate() void QmakeBuildSystem::asyncUpdate()
{ {
TaskHub::clearTasks(ProjectExplorer::Constants::TASK_CATEGORY_BUILDSYSTEM);
setParseDelay(UPDATE_INTERVAL); setParseDelay(UPDATE_INTERVAL);
TRACE(""); TRACE("");
@@ -674,7 +675,7 @@ void QmakeBuildSystem::asyncUpdate()
"have a valid Qt.") "have a valid Qt.")
.arg(project()->displayName(), k->displayName()) .arg(project()->displayName(), k->displayName())
: tr("Cannot parse project \"%1\": No kit selected.").arg(project()->displayName()); : tr("Cannot parse project \"%1\": No kit selected.").arg(project()->displayName());
proFileParseError(errorMessage); proFileParseError(errorMessage, project()->projectFilePath());
m_asyncUpdateFutureInterface.reportCanceled(); m_asyncUpdateFutureInterface.reportCanceled();
m_asyncUpdateFutureInterface.reportFinished(); m_asyncUpdateFutureInterface.reportFinished();
return; return;
@@ -764,9 +765,9 @@ FilePath QmakeBuildSystem::buildDir(const FilePath &proFilePath) const
return FilePath::fromString(QDir::cleanPath(QDir(buildDir).absoluteFilePath(relativeDir))); return FilePath::fromString(QDir::cleanPath(QDir(buildDir).absoluteFilePath(relativeDir)));
} }
void QmakeBuildSystem::proFileParseError(const QString &errorMessage) void QmakeBuildSystem::proFileParseError(const QString &errorMessage, const FilePath &filePath)
{ {
Core::MessageManager::write(errorMessage); TaskHub::addTask(BuildSystemTask(Task::Error, errorMessage, filePath));
} }
QtSupport::ProFileReader *QmakeBuildSystem::createProFileReader(const QmakeProFile *qmakeProFile) QtSupport::ProFileReader *QmakeBuildSystem::createProFileReader(const QmakeProFile *qmakeProFile)

View File

@@ -158,7 +158,7 @@ public:
void watchFolders(const QStringList &l, QmakePriFile *file); void watchFolders(const QStringList &l, QmakePriFile *file);
void unwatchFolders(const QStringList &l, QmakePriFile *file); void unwatchFolders(const QStringList &l, QmakePriFile *file);
static void proFileParseError(const QString &errorMessage); static void proFileParseError(const QString &errorMessage, const Utils::FilePath &filePath);
enum AsyncUpdateState { Base, AsyncFullUpdatePending, AsyncPartialUpdatePending, AsyncUpdateInProgress, ShuttingDown }; enum AsyncUpdateState { Base, AsyncFullUpdatePending, AsyncPartialUpdatePending, AsyncUpdateInProgress, ShuttingDown };
AsyncUpdateState asyncUpdateState() const; AsyncUpdateState asyncUpdateState() const;

View File

@@ -236,6 +236,7 @@ void FormEditorView::temporaryBlockView(int duration)
timer->start(duration); timer->start(duration);
connect(timer, &QTimer::timeout, this, [this]() { connect(timer, &QTimer::timeout, this, [this]() {
if (m_formEditorWidget && m_formEditorWidget->graphicsView())
m_formEditorWidget->graphicsView()->setUpdatesEnabled(true); m_formEditorWidget->graphicsView()->setUpdatesEnabled(true);
}); });
} }

View File

@@ -458,8 +458,12 @@ QProcessEnvironment PuppetCreator::processEnvironment() const
environment.set("QML_BAD_GUI_RENDER_LOOP", "true"); environment.set("QML_BAD_GUI_RENDER_LOOP", "true");
environment.set("QML_PUPPET_MODE", "true"); environment.set("QML_PUPPET_MODE", "true");
environment.set("QML_DISABLE_DISK_CACHE", "true"); environment.set("QML_DISABLE_DISK_CACHE", "true");
#if QT_VERSION < QT_VERSION_CHECK(6, 0, 0)
if (!environment.hasKey("QT_SCREEN_SCALE_FACTORS") && !environment.hasKey("QT_SCALE_FACTOR") if (!environment.hasKey("QT_SCREEN_SCALE_FACTORS") && !environment.hasKey("QT_SCALE_FACTOR")
&& QApplication::testAttribute(Qt::AA_EnableHighDpiScaling)) && QApplication::testAttribute(Qt::AA_EnableHighDpiScaling))
#else
if (!environment.hasKey("QT_SCREEN_SCALE_FACTORS") && !environment.hasKey("QT_SCALE_FACTOR"))
#endif
environment.set("QT_AUTO_SCREEN_SCALE_FACTOR", "1"); environment.set("QT_AUTO_SCREEN_SCALE_FACTOR", "1");
#ifndef QMLDESIGNER_TEST #ifndef QMLDESIGNER_TEST

View File

@@ -26,10 +26,12 @@
#include "profilereader.h" #include "profilereader.h"
#include <coreplugin/icore.h> #include <coreplugin/icore.h>
#include <projectexplorer/taskhub.h>
#include <QCoreApplication> #include <QCoreApplication>
#include <QDebug> #include <QDebug>
using namespace ProjectExplorer;
using namespace QtSupport; using namespace QtSupport;
static QString format(const QString &fileName, int lineNo, const QString &msg) static QString format(const QString &fileName, int lineNo, const QString &msg)
@@ -53,7 +55,7 @@ ProMessageHandler::ProMessageHandler(bool verbose, bool exact)
ProMessageHandler::~ProMessageHandler() ProMessageHandler::~ProMessageHandler()
{ {
if (!m_messages.isEmpty()) if (!m_messages.isEmpty())
Core::MessageManager::writeMessages(m_messages); Core::MessageManager::writeMessages(m_messages, Core::MessageManager::Flash);
} }
@@ -61,14 +63,22 @@ ProMessageHandler::~ProMessageHandler()
void ProMessageHandler::message(int type, const QString &msg, const QString &fileName, int lineNo) void ProMessageHandler::message(int type, const QString &msg, const QString &fileName, int lineNo)
{ {
if ((type & CategoryMask) == ErrorMessage && ((type & SourceMask) == SourceParser || m_verbose)) { if ((type & CategoryMask) == ErrorMessage && ((type & SourceMask) == SourceParser || m_verbose)) {
appendMessage(format(fileName, lineNo, msg)); // parse error in qmake files
TaskHub::addTask(
BuildSystemTask(Task::Error, msg, Utils::FilePath::fromString(fileName), lineNo));
} }
} }
void ProMessageHandler::fileMessage(int type, const QString &msg) void ProMessageHandler::fileMessage(int type, const QString &msg)
{ {
Q_UNUSED(type) // message(), warning() or error() calls in qmake files
if (m_verbose) if (!m_verbose)
return;
if (type == QMakeHandler::ErrorMessage)
TaskHub::addTask(BuildSystemTask(Task::Error, msg));
else if (type == QMakeHandler::WarningMessage)
TaskHub::addTask(BuildSystemTask(Task::Warning, msg));
else
appendMessage(msg); appendMessage(msg);
} }

View File

@@ -2704,7 +2704,7 @@ void tst_Dumpers::dumper_data()
+ Check("l3", "<2 items>", "@QList<@QString>") + Check("l3", "<2 items>", "@QList<@QString>")
+ Check("l3.0", "[0]", "\"1\"", "@QString") + Check("l3.0", "[0]", "\"1\"", "@QString")
+ Check("l4", "<2 items>", "@QStringList") + Check("l4", "<2 items>", TypePattern("@QList<@QString>|@QStringList"))
+ Check("l4.0", "[0]", "\"1\"", "@QString") + Check("l4.0", "[0]", "\"1\"", "@QString")
+ Check("l5", "<3 items>", "@QList<int*>") + Check("l5", "<3 items>", "@QList<int*>")
@@ -2721,7 +2721,7 @@ void tst_Dumpers::dumper_data()
+ Check5("l8", "<2 items>", "@QList<@QStringList>") + Check5("l8", "<2 items>", "@QList<@QStringList>")
+ Check6("l8", "<2 items>", "@QList<@QList<@QString>>") + Check6("l8", "<2 items>", "@QList<@QList<@QString>>")
+ Check("sl", "<1 items>", "@QStringList") + Check("sl", "<1 items>", TypePattern("@QList<@QString>|@QStringList"))
+ Check5("l8.1", "[1]", "<1 items>", "@QStringList") + Check5("l8.1", "[1]", "<1 items>", "@QStringList")
+ Check6("l8.1", "[1]", "<1 items>", "@QList<@QString>") + Check6("l8.1", "[1]", "<1 items>", "@QList<@QString>")
+ Check("l8.1.0", "[0]", "\"aaa\"", "@QString") + Check("l8.1.0", "[0]", "\"aaa\"", "@QString")
@@ -3904,7 +3904,7 @@ void tst_Dumpers::dumper_data()
+ Check("s8", "\"el\"", "@QStringRef") % Qt5 + Check("s8", "\"el\"", "@QStringRef") % Qt5
+ Check("s9", "(null)", "@QStringRef") % Qt5 + Check("s9", "(null)", "@QStringRef") % Qt5
+ Check("l", "<2 items>", "@QStringList") + Check("l", "<2 items>", TypePattern("@QList<@QString>|@QStringList"))
+ Check("l.0", "[0]", "\" big, \"", "@QString") + Check("l.0", "[0]", "\" big, \"", "@QString")
+ Check("l.1", "[1]", "\" World \"", "@QString") + Check("l.1", "[1]", "\" World \"", "@QString")
@@ -4042,12 +4042,12 @@ void tst_Dumpers::dumper_data()
//+ Check("v1", "\"Some string\"", "@QVariant (QString)") //+ Check("v1", "\"Some string\"", "@QVariant (QString)")
+ CheckType("v1", "@QVariant (QString)") + CheckType("v1", "@QVariant (QString)")
+ Check("my", "<2 items>", TypeDef("@QMap<unsigned int,@QStringList>", "MyType")) + Check("my", "<2 items>", TypePattern("@QMap<unsigned int,@QStringList>|@QMap<unsigned int,@List<@QString>>|MyType"))
+ Check("my.0.key", "1", "unsigned int") + Check("my.0.key", "1", "unsigned int")
+ Check("my.0.value", "<1 items>", "@QStringList") + Check("my.0.value", "<1 items>", TypePattern("@QList<@QString>|@QStringList"))
+ Check("my.0.value.0", "[0]", "\"Hello\"", "@QString") + Check("my.0.value.0", "[0]", "\"Hello\"", "@QString")
+ Check("my.1.key", "3", "unsigned int") + Check("my.1.key", "3", "unsigned int")
+ Check("my.1.value", "<1 items>", "@QStringList") + Check("my.1.value", "<1 items>", TypePattern("@QList<@QString>|@QStringList"))
+ Check("my.1.value.0", "[0]", "\"World\"", "@QString") + Check("my.1.value.0", "[0]", "\"World\"", "@QString")
//+ CheckType("v2", "@QVariant (MyType)") //+ CheckType("v2", "@QVariant (MyType)")
+ Check("v2.data.0.key", "1", "unsigned int") % NeedsInferiorCall + Check("v2.data.0.key", "1", "unsigned int") % NeedsInferiorCall
@@ -4405,40 +4405,40 @@ void tst_Dumpers::dumper_data()
+ BigArrayProfile() + BigArrayProfile()
+ Check("v1", "<10000 items>", "@QVector<int>") + Check("v1", "<10000 items>", TypePattern("@QList<int>|@QVector<int>"))
+ Check("v1.0", "[0]", "0", "int") + Check("v1.0", "[0]", "0", "int")
+ Check("v1.8999", "[8999]", "80982001", "int") + Check("v1.8999", "[8999]", "80982001", "int")
+ Check("v2", "<2 items>", "@QVector<Foo>") + Check("v2", "<2 items>", TypePattern("@QList<Foo>|@QVector<Foo>"))
+ Check("v2.0", "[0]", "", "Foo") + Check("v2.0", "[0]", "", "Foo")
+ Check("v2.0.a", "1", "int") + Check("v2.0.a", "1", "int")
+ Check("v2.1", "[1]", "", "Foo") + Check("v2.1", "[1]", "", "Foo")
+ Check("v2.1.a", "2", "int") + Check("v2.1.a", "2", "int")
+ Check("v3", "<2 items>", TypeDef("@QVector<Foo>", "FooVector")) + Check("v3", "<2 items>", TypePattern("@QVector<Foo>|@QList<Foo>|FooVector"))
+ Check("v3.0", "[0]", "", "Foo") + Check("v3.0", "[0]", "", "Foo")
+ Check("v3.0.a", "1", "int") + Check("v3.0.a", "1", "int")
+ Check("v3.1", "[1]", "", "Foo") + Check("v3.1", "[1]", "", "Foo")
+ Check("v3.1.a", "2", "int") + Check("v3.1.a", "2", "int")
+ Check("v4", "<3 items>", "@QVector<Foo*>") + Check("v4", "<3 items>", TypePattern("@QList<Foo \\*>|@QVector<Foo\\*>"))
+ CheckType("v4.0", "[0]", "Foo") + CheckType("v4.0", "[0]", "Foo")
+ Check("v4.0.a", "1", "int") + Check("v4.0.a", "1", "int")
+ Check("v4.1", "[1]", "0x0", "Foo *") + Check("v4.1", "[1]", "0x0", "Foo *")
+ CheckType("v4.2", "[2]", "Foo") + CheckType("v4.2", "[2]", "Foo")
+ Check("v4.2.a", "5", "int") + Check("v4.2.a", "5", "int")
+ Check("v5", "<2 items>", "@QVector<bool>") + Check("v5", "<2 items>", TypePattern("@QList<bool>|@QVector<bool>"))
+ Check("v5.0", "[0]", "1", "bool") + Check("v5.0", "[0]", "1", "bool")
+ Check("v5.1", "[1]", "0", "bool") + Check("v5.1", "[1]", "0", "bool")
+ CheckType("pv", "@QVector<@QList<int>>") + CheckType("pv", TypePattern("@QList<@QList<int>>|@QVector<@QList<int>>"))
+ Check("pv.0", "[0]", "<1 items>", "@QList<int>") + Check("pv.0", "[0]", "<1 items>", "@QList<int>")
+ Check("pv.0.0", "[0]", "1", "int") + Check("pv.0.0", "[0]", "1", "int")
+ Check("pv.1", "[1]", "<2 items>", "@QList<int>") + Check("pv.1", "[1]", "<2 items>", "@QList<int>")
+ Check("pv.1.0", "[0]", "2", "int") + Check("pv.1.0", "[0]", "2", "int")
+ Check("pv.1.1", "[1]", "3", "int") + Check("pv.1.1", "[1]", "3", "int")
+ Check("v6", "<2 items>", "@QVector<@QList<int>>") + Check("v6", "<2 items>", TypePattern("@QList<@QList<int>>|@QVector<@QList<int>>"))
+ Check("v6.0", "[0]", "<1 items>", "@QList<int>") + Check("v6.0", "[0]", "<1 items>", "@QList<int>")
+ Check("v6.0.0", "[0]", "1", "int") + Check("v6.0.0", "[0]", "1", "int")
+ Check("v6.1", "[1]", "<2 items>", "@QList<int>") + Check("v6.1", "[1]", "<2 items>", "@QList<int>")
@@ -4931,14 +4931,14 @@ void tst_Dumpers::dumper_data()
+ Check("map2.1.second", "", "Foo") + Check("map2.1.second", "", "Foo")
+ Check("map2.1.second.a", "33", "int") + Check("map2.1.second.a", "33", "int")
+ Check("map3", "<2 items>", "std::map<unsigned int, @QStringList>") + Check("map3", "<2 items>", TypePattern("std::map<unsigned int, @QList<@QString>>|std::map<unsigned int, @QStringList>"))
+ Check("map3.0", "[0] 11", "<1 items>", "") + Check("map3.0", "[0] 11", "<1 items>", "")
+ Check("map3.0.first", "11", "unsigned int") + Check("map3.0.first", "11", "unsigned int")
+ Check("map3.0.second", "<1 items>", "@QStringList") + Check("map3.0.second", "<1 items>", TypePattern("@QList<@QString>|@QStringList"))
+ Check("map3.0.second.0", "[0]", "\"11\"", "@QString") + Check("map3.0.second.0", "[0]", "\"11\"", "@QString")
+ Check("map3.1", "[1] 22", "<1 items>", "") + Check("map3.1", "[1] 22", "<1 items>", "")
+ Check("map3.1.first", "22", "unsigned int") + Check("map3.1.first", "22", "unsigned int")
+ Check("map3.1.second", "<1 items>", "@QStringList") + Check("map3.1.second", "<1 items>", TypePattern("@QList<@QString>|@QStringList"))
+ Check("map3.1.second.0", "[0]", "\"22\"", "@QString") + Check("map3.1.second.0", "[0]", "\"22\"", "@QString")
+ Check("map4.1.second.0", "[0]", "\"22\"", "@QString") + Check("map4.1.second.0", "[0]", "\"22\"", "@QString")
@@ -6611,7 +6611,7 @@ void tst_Dumpers::dumper_data()
+ Check("i0", "<uninitialized>", "boost::optional<int>") + Check("i0", "<uninitialized>", "boost::optional<int>")
+ Check("i1", "1", "boost::optional<int>") + Check("i1", "1", "boost::optional<int>")
+ Check("sl", "<3 items>", "boost::optional<@QStringList>"); + Check("sl", "<3 items>", TypePattern("boost::optional<@QList<@QString>>|boost::optional<@QStringList>"));
QTest::newRow("BoostSharedPtr") QTest::newRow("BoostSharedPtr")