Merge remote-tracking branch 'origin/8.0' into 9.0

Conflicts:
	doc/qtcreator/src/qtquick/qt-design-viewer.qdoc
	src/plugins/qmldesigner/components/assetslibrary/assetslibrarywidget.cpp
	src/plugins/qmldesigner/components/edit3d/edit3dwidget.cpp
	src/plugins/qmldesigner/components/materialbrowser/materialbrowserview.cpp
	src/plugins/qmldesigner/components/navigator/choosefrompropertylistdialog.cpp
	src/plugins/qmldesigner/components/navigator/navigatortreemodel.cpp
	src/plugins/qmldesigner/designercore/model/abstractview.cpp
	src/plugins/qmldesigner/designercore/model/import.cpp
	src/plugins/qmldesigner/designercore/model/model_p.h
	src/plugins/qmldesigner/designercore/model/texttomodelmerger.cpp
	src/plugins/qmlprojectmanager/qmlproject.cpp

Change-Id: I4236bf0da9306abf201f4679259e72dd7c1eddbe
This commit is contained in:
Eike Ziller
2022-11-01 15:38:49 +01:00
80 changed files with 888 additions and 396 deletions

View File

@@ -3,13 +3,8 @@
/*!
\page qt-design-viewer.html
\if defined(qtdesignstudio)
\previouspage creator-live-preview-android.html
\nextpage studio-exporting-and-importing.html
\else
\previouspage creator-live-preview-devices.html
\nextpage creator-building-targets.html
\endif
\title Previewing in Browsers
@@ -24,24 +19,17 @@
However, the actual performance of the application once started is
indistinguishable from the same application running on the desktop.
\if defined(qtdesignstudio)
To create a resource file out of your project, select \uicontrol Build >
\uicontrol {Generate Resource File} in \QC. Then upload the package into
\QDV.
\else
You can run \l{Creating Qt Quick UI Projects}{Qt Quick UI projects}, which
have a .qmlproject file that define the main QML file and the import paths.
Compress the project folder into a ZIP file that you upload to \QDV.
\endif
The loaded applications remain locally in your browser. No data is uploaded
into the cloud.
To preview an application in a web browser:
\list
\li In the browser, open \l{http://qt-webassembly.io/designviewer/}
{\QDV}.
\list 1
\li In the browser, open \l{ https://designviewer.qt.io/}{\QDV}.
\li Drag and drop your application package to \QDV, or click the load
icon to browse for your file.
\endlist

View File

@@ -57,10 +57,15 @@
You can preview Android applications live using an Android
emulator.
\endif
\li \l{Sharing Applications Online}
You can share applications online and view them in a web browser.
\else
\li \l{Previewing in Browsers}
You can open \l{https://qt-webassembly.io/designviewer/}{\QDV}
You can open \l{https://designviewer.qt.io/}{\QDV}
in a browser and load applications to it.
\endif
\endlist
*/

Binary file not shown.

After

Width:  |  Height:  |  Size: 10 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 12 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 50 KiB

After

Width:  |  Height:  |  Size: 25 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 51 KiB

After

Width:  |  Height:  |  Size: 23 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 14 KiB

After

Width:  |  Height:  |  Size: 10 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 28 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 12 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 6.3 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 94 B

Binary file not shown.

Before

Width:  |  Height:  |  Size: 22 KiB

After

Width:  |  Height:  |  Size: 12 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 12 KiB

After

Width:  |  Height:  |  Size: 9.1 KiB

View File

@@ -0,0 +1,43 @@
// Copyright (C) 2019 The Qt Company Ltd.
// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GFDL-1.3-no-invariants-only
/*!
\page qt-design-viewer.html
\previouspage creator-live-preview-android.html
\nextpage studio-exporting-and-importing.html
\title Sharing Applications Online
\image qt-design-viewer.webp
In \QDS, you can share your applications in most widely-used web browsers,
such as Apple Safari, Google Chrome, Microsoft Edge, and Mozilla Firefox,
on the desktop and on mobile devices.
The application shared online runs in Qt Design Viewer, which is a QML
viewer that runs in your web browser.
The startup and compilation time depend on your browser and configuration.
However, the actual performance of the application once started is
indistinguishable from the same application running on the desktop.
The loaded applications remain locally in your browser. No data is uploaded
into the cloud.
\section1 Sharing your Application Online
To share your \QDS application online:
\list 1
\li Open the application in \QDS.
\li Select \uicontrol File > \uicontrol {Share Application Online}.
\li In the dialog, select \uicontrol Share.
\image share-online.webp
\endlist
In the dialog, you can now open the application in a web
browser, copy the link to share with others, or manage your shared
applications.
\image share-online-manage.webp
*/

View File

@@ -131,7 +131,7 @@
\li \l{Previewing on Desktop}
\li \l{Previewing on Devices}
\li \l{Previewing Android Applications}
\li \l{Previewing in Browsers}
\li \l{Sharing Applications Online}
\endlist
\li \l {Asset Creation with Other Tools}
\list

View File

@@ -5,6 +5,7 @@
\page qtquick-states-view.html
\previouspage qtquick-connection-view.html
\nextpage studio-translations.html
\sa {Working with States}
\title States
@@ -25,48 +26,4 @@
\youtube FzmLuRHQXaw
\section1 Summary of States View Actions
To open the \uicontrol Actions menu, select
\inlineimage icons/action-icon.png
. The actions available in the menu depend on the current context. For
example, the option for editing an annotation becomes available after
you add an annotation.
\table
\header
\li Action
\li Purpose
\li Read More
\row
\li \uicontrol {Set when Condition}
\li Determines when a state should be applied.
\li \l{Applying States}
\row
\li \uicontrol {Reset when Condition}
\li Removes \c when condition for the state.
\li \l{Applying States}
\row
\li \uicontrol {Set as Default}
\li Sets the current state as the startup state of the application.
\li \l{Setting the Default State}
\row
\li\uicontrol {Reset Default}
\li Resets the current state as the default state.
\li \l{Setting the Default State}
\row
\li \uicontrol {Add Annotation}
\li Opens the \uicontrol {Annotation Editor} when you can add an
annotation for the states that you create.
\li \l{Annotating Designs}
\row
\li \uicontrol {Edit Annotation}
\li Opens the \uicontrol {Annotation Editor} where you can edit the
annotation for the state.
\li \l{Annotating Designs}
\row
\li \uicontrol {Add Annotation}
\li Removes the annotation for the state.
\li \l{Annotating Designs}
\endtable
*/

View File

@@ -19,9 +19,9 @@
\image qmldesigner-transitions.png "States view"
Click the new state to switch to it in the \l {2D} view, and then modify the
values of the properties of components or component instances in
\l Properties.
Click the new state to switch to it in the \l {2D} and \l{3D} views, and
then modify the values of the properties of components or component
instances in \l Properties.
For example, to change the appearance of a button, you can define states in
the button component to hide the button image and show another image in its
@@ -60,21 +60,17 @@
\section1 Setting the Default State
To determine the startup state of the application,
select \inlineimage icons/action-icon.png
to open the \uicontrol Actions menu, and then select
\uicontrol {Set as Default}.
The default state determines the startup state of the application.
To reset the state later, select \uicontrol Actions >
\uicontrol {Reset Default}.
To set a state to the default state, select \uicontrol Default.
\section1 Applying States
To determine when a state should be applied, select \uicontrol Actions >
\uicontrol {Set when Condition}. In \uicontrol {Binding Editor}, specify
a \l [QtQuick]{State::when}{when} property for the state. Set the value of
the property to a boolean expression that evaluates to \c true when you want
the state to be applied.
To determine when a state is applied, select \inlineimage icons/edit.png
in the \uicontrol {When Condition} field. In \uicontrol {Binding Editor},
specify a \l [QtQuick]{State::when}{when} property for the state. Set the
value of the property to a boolean expression that evaluates to \c true when
you want the state to be applied.
This enables you to evaluate the truthfulness of several components'
properties and move the UI to the state in which these conditions apply.
@@ -170,10 +166,40 @@
\li Create additional states for each view and set the visibility
or opacity of the components in the view.
\li To determine which state is applied when the application starts,
select \uicontrol Actions > \uicontrol {Set as Default}.
select \uicontrol Default.
\endlist
\if defined(qtcreator)
\include qtquick-states-scxml.qdocinc scxml state machines
\endif
\section1 State Groups
With state groups, you can change the state of certain components
independently of other components and their states in the same view.
Each state group has its own property changes and transitions.
By default, there is one root state group.
\section1 Extending States
When a state extends another state, it inherits all the changes of that
state. The state being extended is treated as the base state in regards to
the changes specified by the extending state.
Using extended states can make the user interface and your QML code
cleaner.
Below is an example where the only change between \e State1 and \e State2
is the brightness of \e directionalLight.
Here, extended states are not used:
\image no-extended-state.webp
Here, \e State2 is extended from \e State1:
\image extended-state.webp
*/

View File

@@ -162,6 +162,7 @@ ScrollView { // TODO: experiment using ListView instead of ScrollView + Column
readonly property string suffix: fileName.substr(-4)
readonly property bool isFont: suffix === ".ttf" || suffix === ".otf"
readonly property bool isEffect: suffix === ".qep"
property bool currFileSelected: false
MouseArea {
@@ -222,6 +223,14 @@ ScrollView { // TODO: experiment using ListView instead of ScrollView + Column
}
}
onDoubleClicked: (mouse) => {
forceActiveFocus()
allowTooltip = false
tooltipBackend.hideTooltip()
if (mouse.button === Qt.LeftButton && isEffect)
rootView.openEffectMaker(filePath)
}
ToolTip {
visible: !isFont && mouseArea.containsMouse && !contextMenu.visible
text: filePath

View File

@@ -241,10 +241,15 @@ Item {
delegate: Section {
width: root.width
caption: bundleCategory
caption: bundleCategoryName
addTopPadding: false
sectionBackgroundColor: "transparent"
visible: bundleCategoryVisible
expanded: bundleCategoryExpanded
expandOnClick: false
onToggleExpand: bundleCategoryExpanded = !bundleCategoryExpanded
onExpand: bundleCategoryExpanded = true
onCollapse: bundleCategoryExpanded = false
Grid {
width: scrollView.width
@@ -254,7 +259,7 @@ Item {
columns: root.width / root.cellWidth
Repeater {
model: bundleMaterialsModel
model: bundleCategoryMaterials
delegate: BundleMaterialItem {
width: root.cellWidth

View File

@@ -80,6 +80,10 @@ StudioControls.Menu {
root.matSectionsModel = root.matSectionsModel.concat(materialBrowserModel.principledMaterialSections);
break;
case "SpecularGlossyMaterial":
root.matSectionsModel = root.matSectionsModel.concat(materialBrowserModel.specularGlossyMaterialSections);
break;
case "CustomMaterial":
root.matSectionsModel = root.matSectionsModel.concat(materialBrowserModel.customMaterialSections);
break;

View File

@@ -401,6 +401,7 @@ Item {
ListElement { name: "Qt 5.15" }
ListElement { name: "Qt 6.2" }
ListElement { name: "Qt 6.3" }
ListElement { name: "Qt 6.4" }
}
onActivated: (index) => {

View File

@@ -50,10 +50,19 @@ Item {
Connections {
target: Controller
function onCollapseAll() {
if (collapsible)
if (collapsible) {
if (section.expandOnClick)
section.expanded = false
else
section.collapse()
}
}
function onExpandAll() {
if (section.expandOnClick)
section.expanded = true
else
section.expand()
}
function onExpandAll() { section.expanded = true }
}
signal drop(var drag)
@@ -61,6 +70,8 @@ Item {
signal dropExit()
signal showContextMenu()
signal toggleExpand()
signal expand()
signal collapse()
DropArea {
id: dropArea

View File

@@ -49,126 +49,128 @@ QtObject {
readonly property string centerHorizontal: "\u0042"
readonly property string centerVertical: "\u0043"
readonly property string closeCross: "\u0044"
readonly property string colorPopupClose: "\u0045"
readonly property string columnsAndRows: "\u0046"
readonly property string copyStyle: "\u0047"
readonly property string cornerA: "\u0048"
readonly property string cornerB: "\u0049"
readonly property string cornersAll: "\u004A"
readonly property string curveDesigner: "\u004B"
readonly property string curveEditor: "\u004C"
readonly property string customMaterialEditor: "\u004D"
readonly property string decisionNode: "\u004E"
readonly property string deleteColumn: "\u004F"
readonly property string deleteMaterial: "\u0050"
readonly property string deleteRow: "\u0051"
readonly property string deleteTable: "\u0052"
readonly property string detach: "\u0053"
readonly property string distributeBottom: "\u0054"
readonly property string distributeCenterHorizontal: "\u0055"
readonly property string distributeCenterVertical: "\u0056"
readonly property string distributeLeft: "\u0057"
readonly property string distributeOriginBottomRight: "\u0058"
readonly property string distributeOriginCenter: "\u0059"
readonly property string distributeOriginNone: "\u005A"
readonly property string distributeOriginTopLeft: "\u005B"
readonly property string distributeRight: "\u005C"
readonly property string distributeSpacingHorizontal: "\u005D"
readonly property string distributeSpacingVertical: "\u005E"
readonly property string distributeTop: "\u005F"
readonly property string download: "\u0060"
readonly property string downloadUnavailable: "\u0061"
readonly property string downloadUpdate: "\u0062"
readonly property string downloaded: "\u0063"
readonly property string edit: "\u0064"
readonly property string eyeDropper: "\u0065"
readonly property string favorite: "\u0066"
readonly property string flowAction: "\u0067"
readonly property string flowTransition: "\u0068"
readonly property string fontStyleBold: "\u0069"
readonly property string fontStyleItalic: "\u006A"
readonly property string fontStyleStrikethrough: "\u006B"
readonly property string fontStyleUnderline: "\u006C"
readonly property string gradient: "\u006D"
readonly property string gridView: "\u006E"
readonly property string idAliasOff: "\u006F"
readonly property string idAliasOn: "\u0070"
readonly property string imported: "\u0071"
readonly property string infinity: "\u0072"
readonly property string keyframe: "\u0073"
readonly property string linkTriangle: "\u0074"
readonly property string linked: "\u0075"
readonly property string listView: "\u0076"
readonly property string lockOff: "\u0077"
readonly property string lockOn: "\u0078"
readonly property string materialPreviewEnvironment: "\u0079"
readonly property string materialPreviewModel: "\u007A"
readonly property string mergeCells: "\u007B"
readonly property string minus: "\u007C"
readonly property string mirror: "\u007D"
readonly property string newMaterial: "\u007E"
readonly property string openMaterialBrowser: "\u007F"
readonly property string orientation: "\u0080"
readonly property string paddingEdge: "\u0081"
readonly property string paddingFrame: "\u0082"
readonly property string pasteStyle: "\u0083"
readonly property string pause: "\u0084"
readonly property string pin: "\u0085"
readonly property string play: "\u0086"
readonly property string plus: "\u0087"
readonly property string promote: "\u0088"
readonly property string readOnly: "\u0089"
readonly property string redo: "\u008A"
readonly property string rotationFill: "\u008B"
readonly property string rotationOutline: "\u008C"
readonly property string search: "\u008D"
readonly property string sectionToggle: "\u008E"
readonly property string splitColumns: "\u008F"
readonly property string splitRows: "\u0090"
readonly property string startNode: "\u0091"
readonly property string testIcon: "\u0092"
readonly property string textAlignBottom: "\u0093"
readonly property string textAlignCenter: "\u0094"
readonly property string textAlignJustified: "\u0095"
readonly property string textAlignLeft: "\u0096"
readonly property string textAlignMiddle: "\u0097"
readonly property string textAlignRight: "\u0098"
readonly property string textAlignTop: "\u0099"
readonly property string textBulletList: "\u009A"
readonly property string textFullJustification: "\u009B"
readonly property string textNumberedList: "\u009D"
readonly property string tickIcon: "\u009E"
readonly property string translationCreateFiles: "\u009F"
readonly property string translationCreateReport: "\u00A0"
readonly property string translationExport: "\u00A1"
readonly property string translationImport: "\u00A2"
readonly property string translationSelectLanguages: "\u00A3"
readonly property string translationTest: "\u00A4"
readonly property string transparent: "\u00A5"
readonly property string triState: "\u00A6"
readonly property string triangleArcA: "\u00A7"
readonly property string triangleArcB: "\u00A8"
readonly property string triangleCornerA: "\u00A9"
readonly property string triangleCornerB: "\u00AA"
readonly property string unLinked: "\u00AB"
readonly property string undo: "\u00AC"
readonly property string unpin: "\u00AE"
readonly property string upDownIcon: "\u00AF"
readonly property string upDownSquare2: "\u00B0"
readonly property string visibilityOff: "\u00B1"
readonly property string visibilityOn: "\u00B2"
readonly property string wildcard: "\u00B3"
readonly property string wizardsAutomotive: "\u00B4"
readonly property string wizardsDesktop: "\u00B5"
readonly property string wizardsGeneric: "\u00B6"
readonly property string wizardsMcuEmpty: "\u00B7"
readonly property string wizardsMcuGraph: "\u00B8"
readonly property string wizardsMobile: "\u00B9"
readonly property string wizardsUnknown: "\u00BA"
readonly property string zoomAll: "\u00BB"
readonly property string zoomIn: "\u00BC"
readonly property string zoomOut: "\u00BD"
readonly property string zoomSelection: "\u00BE"
readonly property string closeLink: "\u0045"
readonly property string colorPopupClose: "\u0046"
readonly property string columnsAndRows: "\u0047"
readonly property string copyLink: "\u0048"
readonly property string copyStyle: "\u0049"
readonly property string cornerA: "\u004A"
readonly property string cornerB: "\u004B"
readonly property string cornersAll: "\u004C"
readonly property string curveDesigner: "\u004D"
readonly property string curveEditor: "\u004E"
readonly property string customMaterialEditor: "\u004F"
readonly property string decisionNode: "\u0050"
readonly property string deleteColumn: "\u0051"
readonly property string deleteMaterial: "\u0052"
readonly property string deleteRow: "\u0053"
readonly property string deleteTable: "\u0054"
readonly property string detach: "\u0055"
readonly property string distributeBottom: "\u0056"
readonly property string distributeCenterHorizontal: "\u0057"
readonly property string distributeCenterVertical: "\u0058"
readonly property string distributeLeft: "\u0059"
readonly property string distributeOriginBottomRight: "\u005A"
readonly property string distributeOriginCenter: "\u005B"
readonly property string distributeOriginNone: "\u005C"
readonly property string distributeOriginTopLeft: "\u005D"
readonly property string distributeRight: "\u005E"
readonly property string distributeSpacingHorizontal: "\u005F"
readonly property string distributeSpacingVertical: "\u0060"
readonly property string distributeTop: "\u0061"
readonly property string download: "\u0062"
readonly property string downloadUnavailable: "\u0063"
readonly property string downloadUpdate: "\u0064"
readonly property string downloaded: "\u0065"
readonly property string edit: "\u0066"
readonly property string eyeDropper: "\u0067"
readonly property string favorite: "\u0068"
readonly property string flowAction: "\u0069"
readonly property string flowTransition: "\u006A"
readonly property string fontStyleBold: "\u006B"
readonly property string fontStyleItalic: "\u006C"
readonly property string fontStyleStrikethrough: "\u006D"
readonly property string fontStyleUnderline: "\u006E"
readonly property string gradient: "\u006F"
readonly property string gridView: "\u0070"
readonly property string idAliasOff: "\u0071"
readonly property string idAliasOn: "\u0072"
readonly property string infinity: "\u0073"
readonly property string keyframe: "\u0074"
readonly property string linkTriangle: "\u0075"
readonly property string linked: "\u0076"
readonly property string listView: "\u0077"
readonly property string lockOff: "\u0078"
readonly property string lockOn: "\u0079"
readonly property string materialPreviewEnvironment: "\u007A"
readonly property string materialPreviewModel: "\u007B"
readonly property string mergeCells: "\u007C"
readonly property string minus: "\u007D"
readonly property string mirror: "\u007E"
readonly property string newMaterial: "\u007F"
readonly property string openLink: "\u0080"
readonly property string openMaterialBrowser: "\u0081"
readonly property string orientation: "\u0082"
readonly property string paddingEdge: "\u0083"
readonly property string paddingFrame: "\u0084"
readonly property string pasteStyle: "\u0085"
readonly property string pause: "\u0086"
readonly property string pin: "\u0087"
readonly property string play: "\u0088"
readonly property string plus: "\u0089"
readonly property string promote: "\u008A"
readonly property string readOnly: "\u008B"
readonly property string redo: "\u008C"
readonly property string rotationFill: "\u008D"
readonly property string rotationOutline: "\u008E"
readonly property string search: "\u008F"
readonly property string sectionToggle: "\u0090"
readonly property string splitColumns: "\u0091"
readonly property string splitRows: "\u0092"
readonly property string startNode: "\u0093"
readonly property string testIcon: "\u0094"
readonly property string textAlignBottom: "\u0095"
readonly property string textAlignCenter: "\u0096"
readonly property string textAlignJustified: "\u0097"
readonly property string textAlignLeft: "\u0098"
readonly property string textAlignMiddle: "\u0099"
readonly property string textAlignRight: "\u009A"
readonly property string textAlignTop: "\u009B"
readonly property string textBulletList: "\u009D"
readonly property string textFullJustification: "\u009E"
readonly property string textNumberedList: "\u009F"
readonly property string tickIcon: "\u00A0"
readonly property string translationCreateFiles: "\u00A1"
readonly property string translationCreateReport: "\u00A2"
readonly property string translationExport: "\u00A3"
readonly property string translationImport: "\u00A4"
readonly property string translationSelectLanguages: "\u00A5"
readonly property string translationTest: "\u00A6"
readonly property string transparent: "\u00A7"
readonly property string triState: "\u00A8"
readonly property string triangleArcA: "\u00A9"
readonly property string triangleArcB: "\u00AA"
readonly property string triangleCornerA: "\u00AB"
readonly property string triangleCornerB: "\u00AC"
readonly property string unLinked: "\u00AE"
readonly property string undo: "\u00AF"
readonly property string unpin: "\u00B0"
readonly property string upDownIcon: "\u00B1"
readonly property string upDownSquare2: "\u00B2"
readonly property string visibilityOff: "\u00B3"
readonly property string visibilityOn: "\u00B4"
readonly property string wildcard: "\u00B5"
readonly property string wizardsAutomotive: "\u00B6"
readonly property string wizardsDesktop: "\u00B7"
readonly property string wizardsGeneric: "\u00B8"
readonly property string wizardsMcuEmpty: "\u00B9"
readonly property string wizardsMcuGraph: "\u00BA"
readonly property string wizardsMobile: "\u00BB"
readonly property string wizardsUnknown: "\u00BC"
readonly property string zoomAll: "\u00BD"
readonly property string zoomIn: "\u00BE"
readonly property string zoomOut: "\u00BF"
readonly property string zoomSelection: "\u00C0"
readonly property font iconFont: Qt.font({
"family": controlIcons.name,

View File

@@ -264,6 +264,14 @@
'TargetQuickVersion': '6.3',
'TargetQuick3DVersion': '6.3'
})"
},
{
"trKey": "Qt 6.4",
"value":
"({
'TargetQuickVersion': '6.4',
'TargetQuick3DVersion': '6.4'
})"
}
]
}

View File

@@ -261,6 +261,13 @@
"({
'TargetQuickVersion': '6.3'
})"
},
{
"trKey": "Qt 6.4",
"value":
"({
'TargetQuickVersion': '6.4'
})"
}
]
}

View File

@@ -71,6 +71,7 @@ Project {
Environment {
QT_QUICK_CONTROLS_CONF: "qtquickcontrols2.conf"
QT_AUTO_SCREEN_SCALE_FACTOR: "1"
QML_COMPAT_RESOLVE_URLS_ON_ASSIGNMENT: "1"
@if %{IsQt6Project}
@else
QMLSCENE_CORE_PROFILE: "true" // Required for macOS, but can create issues on embedded Linux
@@ -99,7 +100,7 @@ Project {
/* Required for deployment */
targetDirectory: "/opt/%{ProjectName}"
qdsVersion: "3.7"
qdsVersion: "3.8"
quickVersion: "%{QtQuickVersion}"

View File

@@ -15,4 +15,5 @@ void set_qt_environment()
qputenv("QT_ENABLE_HIGHDPI_SCALING", "0");
qputenv("QT_LOGGING_RULES", "qt.qml.connections=false");
qputenv("QT_QUICK_CONTROLS_CONF", ":/qtquickcontrols2.conf");
qputenv("QML_COMPAT_RESOLVE_URLS_ON_ASSIGNMENT", "1");
}

View File

@@ -259,6 +259,13 @@
"({
'TargetQuickVersion': '6.3'
})"
},
{
"trKey": "Qt 6.4",
"value":
"({
'TargetQuickVersion': '6.4'
})"
}
]
}

View File

@@ -18,6 +18,8 @@
{ "key": "ProjectPluginClassName", "value": "%{ProjectName}Plugin" },
{ "key": "QmlProjectFileName", "value": "%{JS: Util.fileName('%{ProjectName}', 'qmlproject')}" },
{ "key": "ImportModuleName", "value": "%{ProjectName}" },
{ "key": "UIClassName", "value": "Screen01" },
{ "key": "UIClassFileName", "value": "%{JS: Util.fileName('%{UIClassName}', 'ui.qml')}" },
{ "key": "IsQt6Project", "value": "%{JS: value('QtQuickVersion') !== '2.15' }" },
{ "key": "QtQuickVersion", "value": "%{JS: %{TargetQtVersion}.TargetQuickVersion}" },
{ "key": "QtQuickFeature", "value": "QtSupport.Wizards.FeatureQtQuick.%{QtQuickVersion}" },
@@ -216,6 +218,13 @@
"({
'TargetQuickVersion': '6.3'
})"
},
{
"trKey": "Qt 6.4",
"value":
"({
'TargetQuickVersion': '6.4'
})"
}
]
}

View File

@@ -216,6 +216,13 @@
"({
'TargetQuickVersion': '6.3'
})"
},
{
"trKey": "Qt 6.4",
"value":
"({
'TargetQuickVersion': '6.4'
})"
}
]
}

View File

@@ -216,6 +216,13 @@
"({
'TargetQuickVersion': '6.3'
})"
},
{
"trKey": "Qt 6.4",
"value":
"({
'TargetQuickVersion': '6.4'
})"
}
]
}

View File

@@ -0,0 +1,40 @@
{
"version": 1,
"supportedProjectTypes": [ ],
"id": "J.QEP",
"category": "U.QEP",
"trDescription": "Creates an Effect Maker file.",
"trDisplayName": "Effect File (Effect Maker)",
"trDisplayCategory": "Effects",
"iconText": "qep",
"platformIndependent": true,
"enabled": true,
"options": { "key": "DefaultSuffix", "value": "qep" },
"pages" :
[
{
"trDisplayName": "Location",
"trShortTitle": "Location",
"typeId": "File"
},
{
"trDisplayName": "Project Management",
"trShortTitle": "Summary",
"typeId": "Summary"
}
],
"generators" :
[
{
"typeId": "File",
"data":
{
"source": "file.qep",
"target": "%{JS: Util.fileName(value('TargetPath'), value('DefaultSuffix'))}",
"openInEditor": false
}
}
]
}

View File

@@ -181,7 +181,8 @@ bool AndroidDeployQtStep::init()
}
const QtSupport::QtVersion * const qt = QtSupport::QtKitAspect::qtVersion(kit());
if (qt && qt->supportsMultipleQtAbis() && !selectedAbis.contains(info.cpuAbi.first())) {
if (qt && qt->supportsMultipleQtAbis() && !info.cpuAbi.isEmpty() &&
!selectedAbis.contains(info.cpuAbi.first())) {
TaskHub::addTask(DeploymentTask(Task::Warning,
Tr::tr("Android: The main ABI of the deployment device (%1) is not selected. The app "
"execution or debugging might not work properly. Add it from Projects > Build > "

View File

@@ -68,7 +68,7 @@ void DocumentLocatorFilter::updateSymbols(const DocumentUri &uri,
return;
QMutexLocker locker(&m_mutex);
m_currentSymbols = symbols;
emit symbolsUpToDate({});
emit symbolsUpToDate(QPrivateSignal());
}
void DocumentLocatorFilter::resetSymbols()

View File

@@ -7,6 +7,7 @@ QtcPlugin {
Depends { name: "Qt.widgets" }
Depends { name: "Qt.testlib"; condition: qtc.testsEnabled }
Depends { name: "Utils" }
Depends { name: "app_version_header" }
Depends { name: "Core" }
Depends { name: "BareMetal" }

View File

@@ -208,7 +208,7 @@ QObject *AssetsLibraryModel::rootDir() const
bool AssetsLibraryModel::isEmpty() const
{
return m_isEmpty;
};
}
void AssetsLibraryModel::setIsEmpty(bool empty)
{
@@ -216,7 +216,7 @@ void AssetsLibraryModel::setIsEmpty(bool empty)
m_isEmpty = empty;
emit isEmptyChanged();
}
};
}
QVariant AssetsLibraryModel::data(const QModelIndex &index, int role) const
{
@@ -374,6 +374,13 @@ const QStringList &AssetsLibraryModel::supportedTexture3DSuffixes()
return retList;
}
const QStringList &AssetsLibraryModel::supportedEffectMakerSuffixes()
{
// These are file types only supported by Effect Maker
static QStringList retList {"*.qep"};
return retList;
}
const QSet<QString> &AssetsLibraryModel::supportedSuffixes()
{
static QSet<QString> allSuffixes;
@@ -388,6 +395,7 @@ const QSet<QString> &AssetsLibraryModel::supportedSuffixes()
insertSuffixes(supportedAudioSuffixes());
insertSuffixes(supportedVideoSuffixes());
insertSuffixes(supportedTexture3DSuffixes());
insertSuffixes(supportedEffectMakerSuffixes());
}
return allSuffixes;
}

View File

@@ -44,6 +44,7 @@ public:
static const QStringList &supportedAudioSuffixes();
static const QStringList &supportedVideoSuffixes();
static const QStringList &supportedTexture3DSuffixes();
static const QStringList &supportedEffectMakerSuffixes();
static const QSet<QString> &supportedSuffixes();
const QSet<QString> &previewableSuffixes() const;

View File

@@ -22,11 +22,18 @@
#include <utils/qtcassert.h>
#include <utils/stylehelper.h>
#include <utils/utilsicons.h>
#include "utils/environment.h"
#include "utils/filepath.h"
#include "utils/qtcprocess.h"
#include <coreplugin/coreconstants.h>
#include <coreplugin/icore.h>
#include <coreplugin/messagebox.h>
#include <projectexplorer/projecttree.h>
#include <projectexplorer/target.h>
#include <projectexplorer/project.h>
#include <QApplication>
#include <QDrag>
#include <QFileDialog>
@@ -43,6 +50,9 @@
#include <QQmlContext>
#include <QQuickItem>
#include <qtsupport/baseqtversion.h>
#include <qtsupport/qtkitinformation.h>
namespace QmlDesigner {
static QString propertyEditorResourcesPath()
@@ -126,6 +136,11 @@ AssetsLibraryWidget::AssetsLibraryWidget(AsynchronousImageCache &asynchronousFon
m_assetCompressionTimer.start();
});
connect(m_fileSystemWatcher, &Utils::FileSystemWatcher::fileChanged,
[](const QString &changeFilePath) {
QmlDesignerPlugin::instance()->emitAssetChanged(changeFilePath);
});
auto layout = new QVBoxLayout(this);
layout->setContentsMargins({});
layout->setSpacing(0);
@@ -225,6 +240,48 @@ QSet<QString> AssetsLibraryWidget::supportedAssetSuffixes(bool complex)
return suffixes;
}
void AssetsLibraryWidget::openEffectMaker(const QString &filePath)
{
const ProjectExplorer::Target *target = ProjectExplorer::ProjectTree::currentTarget();
if (!target) {
qWarning() << __FUNCTION__ << "No project open";
return;
}
Utils::FilePath projectPath = target->project()->projectDirectory();
QString effectName = QFileInfo(filePath).baseName();
QString effectResDir = "asset_imports/Effects/" + effectName;
Utils::FilePath effectResPath = projectPath.resolvePath(effectResDir);
if (!effectResPath.exists())
QDir(projectPath.toString()).mkpath(effectResDir);
const QtSupport::QtVersion *baseQtVersion = QtSupport::QtKitAspect::qtVersion(target->kit());
if (baseQtVersion) {
auto effectMakerPath = baseQtVersion->binPath().pathAppended("QQEffectMaker").withExecutableSuffix();
if (!effectMakerPath.exists()) {
qWarning() << __FUNCTION__ << "Cannot find EffectMaker app";
return;
}
Utils::FilePath effectPath = Utils::FilePath::fromString(filePath);
QString effectContents = QString::fromUtf8(effectPath.fileContents().value_or(QByteArray()));
QStringList arguments;
arguments << filePath;
if (effectContents.isEmpty())
arguments << "--create";
arguments << "--exportpath" << effectResPath.toString();
Utils::Environment env = Utils::Environment::systemEnvironment();
if (env.osType() == Utils::OsTypeMac)
env.appendOrSet("QSG_RHI_BACKEND", "metal");
m_qqemProcess.reset(new Utils::QtcProcess);
m_qqemProcess->setEnvironment(env);
m_qqemProcess->setCommand({ effectMakerPath, arguments });
m_qqemProcess->start();
}
}
void AssetsLibraryWidget::setModel(Model *model)
{
m_model = model;
@@ -296,6 +353,9 @@ QPair<QString, QByteArray> AssetsLibraryWidget::getAssetTypeAndData(const QStrin
} else if (AssetsLibraryModel::supportedTexture3DSuffixes().contains(suffix)) {
// Data: Image format (suffix)
return {Constants::MIME_TYPE_ASSET_TEXTURE3D, suffix.toUtf8()};
} else if (AssetsLibraryModel::supportedEffectMakerSuffixes().contains(suffix)) {
// Data: Effect Maker format (suffix)
return {Constants::MIME_TYPE_ASSET_EFFECT, suffix.toUtf8()};
}
}
return {};

View File

@@ -20,7 +20,10 @@ QT_BEGIN_NAMESPACE
class QShortcut;
QT_END_NAMESPACE
namespace Utils { class FileSystemWatcher; }
namespace Utils {
class FileSystemWatcher;
class QtcProcess;
}
namespace QmlDesigner {
@@ -61,6 +64,7 @@ public:
const QList<QUrl> &complexFilePaths,
const QString &targetDirPath = {});
Q_INVOKABLE QSet<QString> supportedAssetSuffixes(bool complex);
Q_INVOKABLE void openEffectMaker(const QString &filePath);
signals:
void itemActivated(const QString &itemName);
@@ -92,6 +96,8 @@ private:
bool m_updateRetry = false;
QString m_filterText;
QPoint m_dragStartPoint;
std::unique_ptr<Utils::QtcProcess> m_qqemProcess;
};
} // namespace QmlDesigner

View File

@@ -293,7 +293,8 @@ void ActionEditor::updateWindowName(const QString &targetName)
}
void ActionEditor::invokeEditor(SignalHandlerProperty signalHandler,
std::function<void(SignalHandlerProperty)> onReject,
std::function<void(SignalHandlerProperty)> removeSignalFunction,
bool removeOnReject,
QObject * parent)
{
if (!signalHandler.isValid())
@@ -324,14 +325,22 @@ void ActionEditor::invokeEditor(SignalHandlerProperty signalHandler,
if (!editor)
return;
if (editor->m_modelNode.isValid()) {
editor->m_modelNode.view()->executeInTransaction("ActionEditor::"
editor->m_modelNode.view()
->executeInTransaction("ActionEditor::"
"invokeEditorAccepted",
[=]() {
if (!editor)
return;
const QString newSource = editor->connectionValue();
if ((newSource.isNull() || newSource.trimmed().isEmpty())
&& removeSignalFunction) {
removeSignalFunction(signalHandler);
} else {
editor->m_modelNode
.signalHandlerProperty(
signalHandler.name())
.setSource(
editor->connectionValue());
.signalHandlerProperty(signalHandler.name())
.setSource(newSource);
}
});
}
@@ -344,10 +353,10 @@ void ActionEditor::invokeEditor(SignalHandlerProperty signalHandler,
if (!editor)
return;
if (onReject) {
if (removeOnReject && removeSignalFunction) {
editor->m_modelNode.view()->executeInTransaction("ActionEditor::"
"invokeEditorOnRejectFunc",
[=]() { onReject(signalHandler); });
[=]() { removeSignalFunction(signalHandler); });
}
//closing editor widget somewhy triggers rejected() signal 2nd time. Lets disconect before it affects us:

View File

@@ -46,7 +46,8 @@ public:
Q_INVOKABLE void updateWindowName(const QString &targetName = {});
static void invokeEditor(SignalHandlerProperty signalHandler,
std::function<void(SignalHandlerProperty)> onReject = nullptr,
std::function<void(SignalHandlerProperty)> removeSignalFunction = nullptr,
bool removeOnReject = false,
QObject *parent = nullptr);
signals:

View File

@@ -211,8 +211,8 @@ const char addShadersDisplayString[] = QT_TRANSLATE_NOOP("QmlDesignerAddResource
const char add3DAssetsDisplayString[] = QT_TRANSLATE_NOOP("QmlDesignerAddResources", "3D Assets");
const char addQt3DSPresentationsDisplayString[] = QT_TRANSLATE_NOOP("QmlDesignerAddResources",
"Qt 3D Studio Presentations");
const char addCustomEffectDialogDisplayString[] = QT_TRANSLATE_NOOP("QmlDesignerAddResources", "Add Custom Effect");
const char addCustomEffectDialogDisplayString[] = QT_TRANSLATE_NOOP("QmlDesignerAddResources",
"Effect Maker Files");
} //ComponentCoreConstants

View File

@@ -549,6 +549,8 @@ ModelNode createNewConnection(ModelNode targetNode)
void removeSignal(SignalHandlerProperty signalHandler)
{
if (!signalHandler.isValid())
return;
auto connectionNode = signalHandler.parentModelNode();
auto connectionSignals = connectionNode.signalProperties();
if (connectionSignals.size() > 1) {
@@ -662,10 +664,14 @@ public:
QString(
QT_TRANSLATE_NOOP("QmlDesignerContextMenu", "Open Connections Editor")),
[=](const SelectionContext &) {
signalHandler.parentModelNode().view()->executeInTransaction(
"ConnectionsModelNodeActionGroup::"
signalHandler.parentModelNode()
.view()
->executeInTransaction("ConnectionsModelNodeActionGroup::"
"openConnectionsEditor",
[signalHandler]() { ActionEditor::invokeEditor(signalHandler); });
[signalHandler]() {
ActionEditor::invokeEditor(signalHandler,
removeSignal);
});
});
activeSignalHandlerGroup->addAction(openEditorAction);
@@ -728,7 +734,7 @@ public:
newHandler.setSource(
QString("console.log(\"%1.%2\")").arg(currentNode.id(), signalStr));
ActionEditor::invokeEditor(newHandler, removeSignal);
ActionEditor::invokeEditor(newHandler, removeSignal, true);
});
});
newSignal->addAction(openEditorAction);

View File

@@ -1607,10 +1607,23 @@ void updateImported3DAsset(const SelectionContext &selectionContext)
if (selectionContext.view()) {
selectionContext.view()->emitCustomNotification(
"UpdateImported3DAsset", {selectionContext.currentSingleSelectedNode()});
}
}
Utils::FilePath getEffectsDirectory()
{
QString defaultDir = "asset_imports/Effects";
Utils::FilePath projectPath = QmlDesignerPlugin::instance()->documentManager().currentProjectDirPath();
Utils::FilePath effectsPath = projectPath.pathAppended(defaultDir);
if (!effectsPath.exists()) {
QDir dir(projectPath.toString());
dir.mkpath(defaultDir);
}
return effectsPath;
}
} // namespace ModelNodeOperations
} //QmlDesigner

View File

@@ -5,6 +5,8 @@
#include "selectioncontext.h"
#include <utils/fileutils.h>
namespace QmlDesigner {
enum class AddFilesResult { Succeeded, Failed, Cancelled };
@@ -55,7 +57,7 @@ void addItemToStackedContainer(const SelectionContext &selectionContext);
void increaseIndexOfStackedContainer(const SelectionContext &selectionContext);
void decreaseIndexOfStackedContainer(const SelectionContext &selectionContext);
void addTabBarToStackedContainer(const SelectionContext &selectionContext);
AddFilesResult addFilesToProject(const QStringList &fileNames, const QString &defaultDirectory);
QMLDESIGNERCORE_EXPORT AddFilesResult addFilesToProject(const QStringList &fileNames, const QString &defaultDirectory);
AddFilesResult addImageToProject(const QStringList &fileNames, const QString &directory);
AddFilesResult addFontToProject(const QStringList &fileNames, const QString &directory);
AddFilesResult addSoundToProject(const QStringList &fileNames, const QString &directory);
@@ -76,6 +78,8 @@ void addMouseAreaFill(const SelectionContext &selectionContext);
void openSignalDialog(const SelectionContext &selectionContext);
void updateImported3DAsset(const SelectionContext &selectionContext);
QMLDESIGNERCORE_EXPORT Utils::FilePath getEffectsDirectory();
// ModelNodePreviewImageOperations
QVariant previewImageDataForGenericNode(const ModelNode &modelNode);
QVariant previewImageDataForImageNode(const ModelNode &modelNode);

View File

@@ -57,8 +57,10 @@ public:
centerHorizontal,
centerVertical,
closeCross,
closeLink,
colorPopupClose,
columnsAndRows,
copyLink,
copyStyle,
cornerA,
cornerB,
@@ -101,7 +103,6 @@ public:
gridView,
idAliasOff,
idAliasOn,
imported,
infinity,
keyframe,
linkTriangle,
@@ -115,6 +116,7 @@ public:
minus,
mirror,
newMaterial,
openLink,
openMaterialBrowser,
orientation,
paddingEdge,

View File

@@ -226,7 +226,7 @@ void Edit3DWidget::onCreateAction()
// QString::number(entry.majorVersion())
// + QLatin1Char('.')
// + QString::number(entry.minorVersion()));
// if (!m_view->model()->hasImport(import))
// if (!m_view->model()->hasImport(import, true, true))
// m_view->model()->changeImports({import}, {});
// int activeScene = m_view->rootModelNode().auxiliaryData("active3dScene@Internal").toInt();

View File

@@ -220,7 +220,8 @@ void AbstractFormEditorTool::dragEnterEvent(const QList<QGraphicsItem*> &itemLis
for (const QString &assetPath : assetPaths) {
QString assetType = AssetsLibraryWidget::getAssetTypeAndData(assetPath).first;
if (assetType == Constants::MIME_TYPE_ASSET_IMAGE
|| assetType == Constants::MIME_TYPE_ASSET_FONT) {
|| assetType == Constants::MIME_TYPE_ASSET_FONT
|| assetType == Constants::MIME_TYPE_ASSET_EFFECT) {
hasValidAssets = true;
break;
}

View File

@@ -218,14 +218,39 @@ static bool hasItemLibraryInfo(const QMimeData *mimeData)
return mimeData->hasFormat(Constants::MIME_TYPE_ITEM_LIBRARY_INFO);
}
void DragTool::dropEvent(const QList<QGraphicsItem *> &/*itemList*/, QGraphicsSceneDragDropEvent *event)
void DragTool::dropEvent(const QList<QGraphicsItem *> &itemList, QGraphicsSceneDragDropEvent *event)
{
if (canBeDropped(event->mimeData())) {
event->accept();
end(generateUseSnapping(event->modifiers()));
QString effectPath;
const QStringList assetPaths = QString::fromUtf8(event->mimeData()
->data(Constants::MIME_TYPE_ASSETS)).split(',');
for (auto &path : assetPaths) {
auto assetType = AssetsLibraryWidget::getAssetTypeAndData(path).first;
if (assetType == Constants::MIME_TYPE_ASSET_EFFECT) {
effectPath = path;
break;
}
}
bool resetPuppet = false;
for (auto &node : m_dragNodes) {
if (!effectPath.isEmpty()) {
FormEditorItem *targetContainerFormEditorItem = targetContainerOrRootItem(itemList);
if (targetContainerFormEditorItem) {
QmlItemNode parentQmlItemNode = targetContainerFormEditorItem->qmlItemNode();
QString effectName = QFileInfo(effectPath).baseName();
QmlItemNode effectNode = QmlItemNode::createQmlItemNodeForEffect(view(), parentQmlItemNode, effectName);
view()->setSelectedModelNodes({effectNode});
view()->resetPuppet();
commitTransaction();
}
} else {
for (QmlItemNode &node : m_dragNodes) {
if (node.isValid()) {
if ((node.instanceParentItem().isValid()
&& node.instanceParent().modelNode().metaInfo().isLayoutable())
@@ -250,6 +275,7 @@ void DragTool::dropEvent(const QList<QGraphicsItem *> &/*itemList*/, QGraphicsSc
view()->setSelectedModelNodes(nodeList);
}
m_dragNodes.clear();
}
view()->changeToSelectionTool();
}
@@ -325,10 +351,17 @@ void DragTool::createDragNodes(const QMimeData *mimeData, const QPointF &scenePo
void DragTool::dragMoveEvent(const QList<QGraphicsItem *> &itemList, QGraphicsSceneDragDropEvent *event)
{
if (!m_blockMove && !m_isAborted && canBeDropped(event->mimeData())) {
FormEditorItem *targetContainerItem = targetContainerOrRootItem(itemList);
const QStringList assetPaths = QString::fromUtf8(event->mimeData()
->data(Constants::MIME_TYPE_ASSETS)).split(',');
QString assetType = AssetsLibraryWidget::getAssetTypeAndData(assetPaths[0]).first;
if (!m_blockMove
&& !m_isAborted
&& canBeDropped(event->mimeData())
&& assetType != Constants::MIME_TYPE_ASSET_EFFECT) {
event->accept();
if (!m_dragNodes.isEmpty()) {
FormEditorItem *targetContainerItem = targetContainerOrRootItem(itemList);
if (targetContainerItem) {
move(event->scenePos(), itemList);
} else {
@@ -342,7 +375,7 @@ void DragTool::dragMoveEvent(const QList<QGraphicsItem *> &itemList, QGraphicsSc
} else {
createDragNodes(event->mimeData(), event->scenePos(), itemList);
}
} else {
} else if (assetType != Constants::MIME_TYPE_ASSET_EFFECT) {
event->ignore();
}
}

View File

@@ -72,6 +72,11 @@ bool BundleMaterialCategory::visible() const
return m_visible;
}
bool BundleMaterialCategory::expanded() const
{
return m_expanded;
}
QList<BundleMaterial *> BundleMaterialCategory::categoryMaterials() const
{
return m_categoryMaterials;

View File

@@ -35,8 +35,11 @@ class BundleMaterialCategory : public QObject
{
Q_OBJECT
Q_PROPERTY(QString categoryName MEMBER m_name CONSTANT)
Q_PROPERTY(bool categoryVisible MEMBER m_visible NOTIFY categoryVisibleChanged)
Q_PROPERTY(QString bundleCategoryName MEMBER m_name CONSTANT)
Q_PROPERTY(bool bundleCategoryVisible MEMBER m_visible NOTIFY categoryVisibleChanged)
Q_PROPERTY(bool bundleCategoryExpanded MEMBER m_expanded NOTIFY categoryExpandChanged)
Q_PROPERTY(QList<BundleMaterial *> bundleCategoryMaterials MEMBER m_categoryMaterials
NOTIFY bundleMaterialsModelChanged)
public:
BundleMaterialCategory(QObject *parent, const QString &name);
@@ -47,14 +50,18 @@ public:
QString name() const;
bool visible() const;
bool expanded() const;
QList<BundleMaterial *> categoryMaterials() const;
signals:
void categoryVisibleChanged();
void categoryExpandChanged();
void bundleMaterialsModelChanged();
private:
QString m_name;
bool m_visible = true;
bool m_expanded = true;
QList<BundleMaterial *> m_categoryMaterials;
};

View File

@@ -54,17 +54,26 @@ QVariant MaterialBrowserBundleModel::data(const QModelIndex &index, int role) co
QTC_ASSERT(index.isValid() && index.row() < m_bundleCategories.count(), return {});
QTC_ASSERT(roleNames().contains(role), return {});
return m_bundleCategories.at(index.row())->property(roleNames().value(role));
}
bool MaterialBrowserBundleModel::setData(const QModelIndex &index, const QVariant &value, int role)
{
if (!index.isValid() || !roleNames().contains(role))
return false;
QByteArray roleName = roleNames().value(role);
if (roleName == "bundleCategory")
return m_bundleCategories.at(index.row())->name();
BundleMaterialCategory *bundleCategory = m_bundleCategories.at(index.row());
QVariant currValue = bundleCategory->property(roleName);
if (roleName == "bundleCategoryVisible")
return m_bundleCategories.at(index.row())->visible();
if (currValue != value) {
bundleCategory->setProperty(roleName, value);
if (roleName == "bundleMaterialsModel")
return QVariant::fromValue(m_bundleCategories.at(index.row())->categoryMaterials());
emit dataChanged(index, index, {role});
return true;
}
return {};
return false;
}
bool MaterialBrowserBundleModel::isValidIndex(int idx) const
@@ -75,16 +84,17 @@ bool MaterialBrowserBundleModel::isValidIndex(int idx) const
QHash<int, QByteArray> MaterialBrowserBundleModel::roleNames() const
{
static const QHash<int, QByteArray> roles {
{Qt::UserRole + 1, "bundleCategory"},
{Qt::UserRole + 1, "bundleCategoryName"},
{Qt::UserRole + 2, "bundleCategoryVisible"},
{Qt::UserRole + 3, "bundleMaterialsModel"}
{Qt::UserRole + 3, "bundleCategoryExpanded"},
{Qt::UserRole + 4, "bundleCategoryMaterials"}
};
return roles;
}
void MaterialBrowserBundleModel::loadMaterialBundle()
{
if (m_matBundleExists || m_probeMatBundleDir)
if (m_matBundleLoaded || m_probeMatBundleDir)
return;
QDir matBundleDir(qEnvironmentVariable("MATERIAL_BUNDLE_PATH"));
@@ -120,7 +130,7 @@ void MaterialBrowserBundleModel::loadMaterialBundle()
}
}
m_matBundleExists = true;
m_matBundleLoaded = true;
QString bundleId = m_matBundleObj.value("id").toString();
@@ -174,20 +184,6 @@ void MaterialBrowserBundleModel::loadMaterialBundle()
});
}
bool MaterialBrowserBundleModel::hasQuick3DImport() const
{
return m_hasQuick3DImport;
}
void MaterialBrowserBundleModel::setHasQuick3DImport(bool b)
{
if (b == m_hasQuick3DImport)
return;
m_hasQuick3DImport = b;
emit hasQuick3DImportChanged();
}
bool MaterialBrowserBundleModel::hasMaterialRoot() const
{
return m_hasMaterialRoot;
@@ -202,6 +198,11 @@ void MaterialBrowserBundleModel::setHasMaterialRoot(bool b)
emit hasMaterialRootChanged();
}
bool MaterialBrowserBundleModel::matBundleExists() const
{
return m_matBundleLoaded && m_quick3dMajorVersion == 6 && m_quick3dMinorVersion >= 3;
}
Internal::BundleImporter *MaterialBrowserBundleModel::bundleImporter() const
{
return m_importer;
@@ -243,6 +244,17 @@ void MaterialBrowserBundleModel::updateImportedState(const QStringList &imported
resetModel();
}
void MaterialBrowserBundleModel::setQuick3DImportVersion(int major, int minor)
{
bool bundleExisted = matBundleExists();
m_quick3dMajorVersion = major;
m_quick3dMinorVersion = minor;
if (bundleExisted != matBundleExists())
emit matBundleExistsChanged();
}
void MaterialBrowserBundleModel::resetModel()
{
beginResetModel();

View File

@@ -46,9 +46,8 @@ class MaterialBrowserBundleModel : public QAbstractListModel
{
Q_OBJECT
Q_PROPERTY(bool matBundleExists MEMBER m_matBundleExists CONSTANT)
Q_PROPERTY(bool matBundleExists READ matBundleExists NOTIFY matBundleExistsChanged)
Q_PROPERTY(bool isEmpty MEMBER m_isEmpty NOTIFY isEmptyChanged)
Q_PROPERTY(bool hasQuick3DImport READ hasQuick3DImport WRITE setHasQuick3DImport NOTIFY hasQuick3DImportChanged)
Q_PROPERTY(bool hasMaterialRoot READ hasMaterialRoot WRITE setHasMaterialRoot NOTIFY hasMaterialRootChanged)
Q_PROPERTY(bool importerRunning MEMBER m_importerRunning NOTIFY importerRunningChanged)
@@ -57,17 +56,19 @@ public:
int rowCount(const QModelIndex &parent = QModelIndex()) const override;
QVariant data(const QModelIndex &index, int role = Qt::DisplayRole) const override;
bool setData(const QModelIndex &index, const QVariant &value, int role) override;
QHash<int, QByteArray> roleNames() const override;
void setSearchText(const QString &searchText);
void updateImportedState(const QStringList &importedMats);
bool hasQuick3DImport() const;
void setHasQuick3DImport(bool b);
void setQuick3DImportVersion(int major, int minor);
bool hasMaterialRoot() const;
void setHasMaterialRoot(bool b);
bool matBundleExists() const;
Internal::BundleImporter *bundleImporter() const;
void resetModel();
@@ -86,6 +87,7 @@ signals:
void bundleMaterialAboutToUnimport(const QmlDesigner::TypeName &type);
void bundleMaterialUnimported(const QmlDesigner::NodeMetaInfo &metaInfo);
void importerRunningChanged();
void matBundleExistsChanged();
private:
void loadMaterialBundle();
@@ -97,11 +99,13 @@ private:
Internal::BundleImporter *m_importer = nullptr;
bool m_isEmpty = true;
bool m_hasQuick3DImport = false;
bool m_hasMaterialRoot = false;
bool m_matBundleExists = false;
bool m_matBundleLoaded = false;
bool m_probeMatBundleDir = false;
bool m_importerRunning = false;
int m_quick3dMajorVersion = -1;
int m_quick3dMinorVersion = -1;
};
} // namespace QmlDesigner

View File

@@ -83,9 +83,7 @@ bool MaterialBrowserModel::loadPropertyGroups(const QString &path)
{
bool ok = true;
if (m_propertyGroupsObj.isEmpty()) {
QFile matPropsFile(path);
if (!matPropsFile.open(QIODevice::ReadOnly)) {
qWarning("Couldn't open propertyGroups.json");
ok = false;
@@ -100,24 +98,39 @@ bool MaterialBrowserModel::loadPropertyGroups(const QString &path)
m_propertyGroupsObj = matPropsJsonDoc.object();
}
}
}
m_defaultMaterialSections.clear();
m_principledMaterialSections.clear();
m_specularGlossyMaterialSections.clear();
m_customMaterialSections.clear();
if (ok) {
m_defaultMaterialSections.append(m_propertyGroupsObj.value("DefaultMaterial").toObject().keys());
m_principledMaterialSections.append(m_propertyGroupsObj.value("PrincipledMaterial").toObject().keys());
m_specularGlossyMaterialSections.append(m_propertyGroupsObj.value("SpecularGlossyMaterial").toObject().keys());
QStringList customMatSections = m_propertyGroupsObj.value("CustomMaterial").toObject().keys();
if (customMatSections.size() > 1) // as of now custom material has only 1 section, so we don't add it
m_customMaterialSections.append(customMatSections);
} else {
m_propertyGroupsObj = {};
}
emit materialSectionsChanged();
return ok;
}
void MaterialBrowserModel::unloadPropertyGroups()
{
if (!m_propertyGroupsObj.isEmpty()) {
m_propertyGroupsObj = {};
m_defaultMaterialSections.clear();
m_principledMaterialSections.clear();
m_specularGlossyMaterialSections.clear();
m_customMaterialSections.clear();
emit materialSectionsChanged();
}
}
QHash<int, QByteArray> MaterialBrowserModel::roleNames() const
{
static const QHash<int, QByteArray> roles {
@@ -381,6 +394,7 @@ void MaterialBrowserModel::copyMaterialProperties(int idx, const QString &sectio
}
}
validProps.remove("objectName");
validProps.remove("data");
if (m_allPropsCopied || dynamicPropsCopied || m_propertyGroupsObj.empty()) {
copiedProps = validProps.values();

View File

@@ -25,6 +25,7 @@ class MaterialBrowserModel : public QAbstractListModel
Q_PROPERTY(QString copiedMaterialType READ copiedMaterialType WRITE setCopiedMaterialType NOTIFY copiedMaterialTypeChanged)
Q_PROPERTY(QStringList defaultMaterialSections MEMBER m_defaultMaterialSections NOTIFY materialSectionsChanged)
Q_PROPERTY(QStringList principledMaterialSections MEMBER m_principledMaterialSections NOTIFY materialSectionsChanged)
Q_PROPERTY(QStringList specularGlossyMaterialSections MEMBER m_specularGlossyMaterialSections NOTIFY materialSectionsChanged)
Q_PROPERTY(QStringList customMaterialSections MEMBER m_customMaterialSections NOTIFY materialSectionsChanged)
public:
@@ -58,6 +59,7 @@ public:
int materialIndex(const ModelNode &material) const;
ModelNode materialAt(int idx) const;
bool loadPropertyGroups(const QString &path);
void unloadPropertyGroups();
void resetModel();
@@ -105,6 +107,7 @@ private:
QString m_searchText;
QList<ModelNode> m_materialList;
QStringList m_defaultMaterialSections;
QStringList m_specularGlossyMaterialSections;
QStringList m_principledMaterialSections;
QStringList m_customMaterialSections;
ModelNode m_copiedMaterial;

View File

@@ -22,6 +22,14 @@
#include <qmldesignerconstants.h>
#include <utils/algorithm.h>
#ifndef QMLDESIGNER_TEST
#include <projectexplorer/kit.h>
#include <projectexplorer/session.h>
#include <projectexplorer/target.h>
#include <qtsupport/baseqtversion.h>
#include <qtsupport/qtkitinformation.h>
#endif
#include <QQuickItem>
#include <QRegularExpression>
#include <QTimer>
@@ -100,7 +108,7 @@ WidgetInfo MaterialBrowserView::widgetInfo()
}
}
for (const PropertyName &propName : std::as_const(propNames)) {
if (propName != "objectName")
if (propName != "objectName" && propName != "data")
mat.removeProperty(propName);
}
}
@@ -267,11 +275,12 @@ void MaterialBrowserView::modelAttached(Model *model)
rootModelNode().metaInfo().isQtQuick3DMaterial());
m_hasQuick3DImport = model->hasImport("QtQuick3D");
updateBundleMaterialsQuick3DVersion();
updateBundleMaterialsImportedState();
// Project load is already very busy and may even trigger puppet reset, so let's wait a moment
// before refreshing the model
QTimer::singleShot(1000, this, [this]() {
QTimer::singleShot(1000, model, [this]() {
refreshModel(true);
loadPropertyGroups(); // Needs the delay because it uses metaInfo
});
@@ -279,7 +288,7 @@ void MaterialBrowserView::modelAttached(Model *model)
void MaterialBrowserView::refreshModel(bool updateImages)
{
if (!model() || !model()->nodeInstanceView())
if (!model())
return;
ModelNode matLib = modelNodeForId(Constants::MATERIAL_LIB_ID);
@@ -311,6 +320,11 @@ void MaterialBrowserView::modelAboutToBeDetached(Model *model)
{
m_widget->materialBrowserModel()->setMaterials({}, m_hasQuick3DImport);
if (m_propertyGroupsLoaded) {
m_propertyGroupsLoaded = false;
m_widget->materialBrowserModel()->unloadPropertyGroups();
}
AbstractView::modelAboutToBeDetached(model);
}
@@ -416,7 +430,7 @@ void MaterialBrowserView::nodeRemoved([[maybe_unused]] const ModelNode &removedN
void QmlDesigner::MaterialBrowserView::loadPropertyGroups()
{
if (!m_hasQuick3DImport || m_propertyGroupsLoaded)
if (!m_hasQuick3DImport || m_propertyGroupsLoaded || !model())
return;
QString matPropsPath = model()->metaInfo("QtQuick3D.Material").importDirectoryPath()
@@ -443,6 +457,41 @@ void MaterialBrowserView::updateBundleMaterialsImportedState()
m_widget->materialBrowserBundleModel()->updateImportedState(importedBundleMats);
}
void MaterialBrowserView::updateBundleMaterialsQuick3DVersion()
{
bool hasImport = false;
int major = -1;
int minor = -1;
const QString url {"QtQuick3D"};
const auto imports = model()->imports();
for (const auto &import : imports) {
if (import.url() == url) {
hasImport = true;
const int importMajor = import.majorVersion();
if (major < importMajor) {
minor = -1;
major = importMajor;
}
if (major == importMajor)
minor = qMax(minor, import.minorVersion());
}
}
#ifndef QMLDESIGNER_TEST
if (hasImport && major == -1) {
// Import without specifying version, so we take the kit version
auto target = ProjectExplorer::SessionManager::startupTarget();
if (target) {
QtSupport::QtVersion *qtVersion = QtSupport::QtKitAspect::qtVersion(target->kit());
if (qtVersion) {
major = qtVersion->qtVersion().majorVersion();
minor = qtVersion->qtVersion().minorVersion();
}
}
}
#endif
m_widget->materialBrowserBundleModel()->setQuick3DImportVersion(major, minor);
}
ModelNode MaterialBrowserView::getBundleMaterialDefaultInstance(const TypeName &type)
{
const QList<ModelNode> materials = m_widget->materialBrowserModel()->materials();
@@ -470,6 +519,8 @@ void MaterialBrowserView::importsChanged([[maybe_unused]] const QList<Import> &a
{
bool hasQuick3DImport = model()->hasImport("QtQuick3D");
updateBundleMaterialsQuick3DVersion();
if (hasQuick3DImport == m_hasQuick3DImport)
return;
@@ -494,7 +545,7 @@ void MaterialBrowserView::customNotification(const AbstractView *view,
if (idx != -1)
m_widget->materialBrowserModel()->selectMaterial(idx);
} else if (identifier == "refresh_material_browser") {
QTimer::singleShot(0, this, [this]() {
QTimer::singleShot(0, model(), [this]() {
refreshModel(true);
});
} else if (identifier == "delete_selected_material") {

View File

@@ -47,6 +47,7 @@ private:
bool isMaterial(const ModelNode &node) const;
void loadPropertyGroups();
void updateBundleMaterialsImportedState();
void updateBundleMaterialsQuick3DVersion();
void applyBundleMaterialToDropTarget(const ModelNode &bundleMat, const NodeMetaInfo &metaInfo = {});
ModelNode getBundleMaterialDefaultInstance(const TypeName &type);

View File

@@ -59,9 +59,7 @@ MaterialEditorView::MaterialEditorView()
m_ensureMatLibTimer.callOnTimeout([this] {
if (model() && model()->rewriterView() && !model()->rewriterView()->hasIncompleteTypeInformation()
&& model()->rewriterView()->errors().isEmpty()) {
executeInTransaction("MaterialEditorView::MaterialEditorView", [this] {
ensureMaterialLibraryNode();
});
m_ensureMatLibTimer.stop();
}
});
@@ -714,8 +712,8 @@ void MaterialEditorView::updatePossibleTypes()
return;
// Ensure basic types are always first
static const QStringList basicTypes {"DefaultMaterial", "PrincipledMaterial", "CustomMaterial"};
QStringList allTypes = basicTypes;
QStringList nonQuick3dTypes;
QStringList allTypes;
const QList<ItemLibraryEntry> itemLibEntries = m_itemLibraryInfo->entries();
for (const ItemLibraryEntry &entry : itemLibEntries) {
@@ -730,12 +728,22 @@ void MaterialEditorView::updatePossibleTypes()
addImport = model()->hasImport(import, true, true);
}
if (addImport) {
QString typeName = QString::fromLatin1(entry.typeName().split('.').last());
const QList<QByteArray> typeSplit = entry.typeName().split('.');
const QString typeName = QString::fromLatin1(typeSplit.last());
if (typeSplit.size() == 2 && typeSplit.first() == "QtQuick3D") {
if (!allTypes.contains(typeName))
allTypes.append(typeName);
} else if (!nonQuick3dTypes.contains(typeName)) {
nonQuick3dTypes.append(typeName);
}
}
}
}
allTypes.sort();
nonQuick3dTypes.sort();
allTypes.append(nonQuick3dTypes);
m_qmlBackEnd->contextObject()->setPossibleTypes(allTypes);
}
@@ -1006,6 +1014,8 @@ void MaterialEditorView::duplicateMaterial(const ModelNode &material)
TypeName matType = material.type();
QmlObjectNode sourceMat(material);
ModelNode duplicateMatNode;
QList<AbstractProperty> dynamicProps;
executeInTransaction(__FUNCTION__, [&] {
ModelNode matLib = materialLibraryNode();
@@ -1016,25 +1026,57 @@ void MaterialEditorView::duplicateMaterial(const ModelNode &material)
NodeMetaInfo metaInfo = model()->metaInfo(matType);
QmlObjectNode duplicateMat = createModelNode(matType, metaInfo.majorVersion(), metaInfo.minorVersion());
duplicateMatNode = duplicateMat.modelNode();
// set name and id
QString newName = sourceMat.modelNode().variantProperty("objectName").value().toString() + " copy";
duplicateMat.modelNode().variantProperty("objectName").setValue(newName);
duplicateMat.modelNode().setIdWithoutRefactoring(model()->generateIdFromName(newName, "material"));
duplicateMatNode.variantProperty("objectName").setValue(newName);
duplicateMatNode.setIdWithoutRefactoring(model()->generateIdFromName(newName, "material"));
// sync properties
// sync properties. Only the base state is duplicated.
const QList<AbstractProperty> props = material.properties();
for (const AbstractProperty &prop : props) {
if (prop.name() == "objectName")
if (prop.name() == "objectName" || prop.name() == "data")
continue;
if (prop.isVariantProperty())
duplicateMat.setVariantProperty(prop.name(), prop.toVariantProperty().value());
else if (prop.isBindingProperty())
duplicateMat.setBindingProperty(prop.name(), prop.toBindingProperty().expression());
if (prop.isVariantProperty()) {
if (prop.isDynamic()) {
dynamicProps.append(prop);
} else {
duplicateMatNode.variantProperty(prop.name())
.setValue(prop.toVariantProperty().value());
}
} else if (prop.isBindingProperty()) {
if (prop.isDynamic()) {
dynamicProps.append(prop);
} else {
duplicateMatNode.bindingProperty(prop.name())
.setExpression(prop.toBindingProperty().expression());
}
}
}
matLib.defaultNodeListProperty().reparentHere(duplicateMat);
});
// For some reason, creating dynamic properties in the same transaction doesn't work, so
// let's do it in separate transaction.
// TODO: Fix the issue and merge transactions (QDS-8094)
if (!dynamicProps.isEmpty()) {
executeInTransaction(__FUNCTION__, [&] {
for (const AbstractProperty &prop : std::as_const(dynamicProps)) {
if (prop.isVariantProperty()) {
duplicateMatNode.variantProperty(prop.name())
.setDynamicTypeNameAndValue(prop.dynamicTypeName(),
prop.toVariantProperty().value());
} else if (prop.isBindingProperty()) {
duplicateMatNode.bindingProperty(prop.name())
.setDynamicTypeNameAndExpression(prop.dynamicTypeName(),
prop.toBindingProperty().expression());
}
}
});
}
}
void MaterialEditorView::customNotification([[maybe_unused]] const AbstractView *view,

View File

@@ -18,6 +18,7 @@ ChooseFromPropertyListFilter::ChooseFromPropertyListFilter(const NodeMetaInfo &i
// Texture
// -> DefaultMaterial
// -> PrincipledMaterial
// -> SpecularGlossyMaterial
// -> SpriteParticle3D
// -> TextureInput
// -> SceneEnvironment
@@ -40,7 +41,8 @@ ChooseFromPropertyListFilter::ChooseFromPropertyListFilter(const NodeMetaInfo &i
// -> Model
if (insertInfo.isQtQuick3DTexture()) {
if (parentInfo.isQtQuick3DDefaultMaterial() || parentInfo.isQtQuick3DPrincipledMaterial()) {
if (parentInfo.isQtQuick3DDefaultMaterial() || parentInfo.isQtQuick3DPrincipledMaterial()
|| parentInfo.isQtQuick3DSpecularGlossyMaterial()) {
// All texture properties are valid targets
for (const auto &property : parentInfo.properties()) {
const auto &propType = property.propertyType();

View File

@@ -1024,7 +1024,8 @@ bool NavigatorTreeModel::dropAsImage3dTexture(const ModelNode &targetNode,
};
if (targetNode.metaInfo().isQtQuick3DDefaultMaterial()
|| targetNode.metaInfo().isQtQuick3DPrincipledMaterial()) {
|| targetNode.metaInfo().isQtQuick3DPrincipledMaterial()
|| targetNode.metaInfo().isQtQuick3DSpecularGlossyMaterial()) {
// if dropping an image on a material, create a texture instead of image
// Show texture property selection dialog
auto dialog = ChooseFromPropertyListDialog::createIfNeeded(targetNode,

View File

@@ -69,6 +69,8 @@ EasingCurveDialog::EasingCurveDialog(const QList<ModelNode> &frames, QWidget *pa
presetBar->setDrawBase(false);
presetBar->setSizePolicy(QSizePolicy::Fixed, QSizePolicy::Preferred);
m_presets->initialize(presetBar);
auto *durationLabel = new QLabel("Duration (ms)");
auto *durationEdit = new QSpinBox;
durationEdit->setMaximum(std::numeric_limits<int>::max());
@@ -85,6 +87,8 @@ EasingCurveDialog::EasingCurveDialog(const QList<ModelNode> &frames, QWidget *pa
m_durationLayout->insertSpacing(4, hSpacing);
m_durationLayout->addStretch(hSpacing);
m_splineEditor->setDuration(durationEdit->value());
m_buttons->setSizePolicy(QSizePolicy::Fixed, QSizePolicy::Preferred);
auto callButtonsClicked = [this](QAbstractButton *button) {
buttonsClicked(m_buttons->standardButton(button));
@@ -122,9 +126,6 @@ EasingCurveDialog::EasingCurveDialog(const QList<ModelNode> &frames, QWidget *pa
connect(durationEdit, &QSpinBox::valueChanged, m_splineEditor, &SplineEditor::setDuration);
connect(animateButton, &QPushButton::clicked, m_splineEditor, &SplineEditor::animate);
m_presets->initialize(presetBar);
m_splineEditor->setDuration(durationEdit->value());
resize(QSize(1421, 918));
}

View File

@@ -33,6 +33,19 @@ constexpr int spacingg = 5;
const QColor background = Qt::white;
QString makeNameUnique(const QString& name, const QStringList& currentNames)
{
QString n = name;
int idx = 0;
while (true) {
if (!currentNames.contains(n))
return n;
n = name + "_" + QString::number(idx++);
}
return {};
}
PresetItemDelegate::PresetItemDelegate(const QColor& background)
: QStyledItemDelegate()
, m_background(background)
@@ -366,7 +379,7 @@ void PresetList::createItem()
{
EasingCurve curve;
curve.makeDefault();
createItem(createUniqueName(), curve);
createItem(makeNameUnique("Default", allNames()), curve);
}
void PresetList::createItem(const QString &name, const EasingCurve &curve)
@@ -402,27 +415,6 @@ void PresetList::setItemData(const QModelIndex &index, const QVariant &curve, co
}
}
QString PresetList::createUniqueName() const
{
QStringList names = allNames();
auto nameIsUnique = [&](const QString &name) {
auto iter = std::find(names.begin(), names.end(), name);
if (iter == names.end())
return true;
else
return false;
};
int counter = 0;
QString tmp("Default");
QString name = tmp;
while (!nameIsUnique(name))
name = tmp + QString(" %1").arg(counter++);
return name;
}
QStringList PresetList::allNames() const
{
QStringList names;
@@ -529,7 +521,8 @@ bool PresetEditor::writePresets(const EasingCurve &curve)
if (ok && !name.isEmpty()) {
activate(m_customs->index());
m_customs->createItem(name, curve);
QString uname = makeNameUnique(name, m_customs->allNames());
m_customs->createItem(uname, curve);
}
}

View File

@@ -16,6 +16,8 @@ namespace QmlDesigner {
class EasingCurve;
class NamedEasingCurve;
QString makeNameUnique(const QString& name, const QStringList& currentNames);
class PresetItemDelegate : public QStyledItemDelegate
{
Q_OBJECT
@@ -65,6 +67,8 @@ public:
QColor curveColor() const;
QStringList allNames() const;
void initialize(int index);
void readPresets();
@@ -89,12 +93,8 @@ protected:
const QVector<int> &roles = QVector<int>()) override;
private:
QStringList allNames() const;
QList<NamedEasingCurve> storedCurves() const;
QString createUniqueName() const;
void removeSelectedItem();
private:

View File

@@ -39,7 +39,9 @@ public:
bool isSameModule(const Import &other) const;
int majorVersion() const;
int minorVersion() const;
static int majorFromVersion(const QString &version);
static int minorFromVersion(const QString &version);
private:
Import(const QString &url, const QString &file, const QString &version, const QString &alias, const QStringList &importPaths);

View File

@@ -135,6 +135,7 @@ public:
bool isQtQuick3DParticles3DSpriteParticle3D() const;
bool isQtQuick3DPass() const;
bool isQtQuick3DPrincipledMaterial() const;
bool isQtQuick3DSpecularGlossyMaterial() const;
bool isQtQuick3DSceneEnvironment() const;
bool isQtQuick3DShader() const;
bool isQtQuick3DTexture() const;

View File

@@ -60,7 +60,9 @@ public:
const QPointF &position,
NodeAbstractProperty parentproperty,
bool executeInTransaction = true);
static QmlItemNode createQmlItemNodeForEffect(AbstractView *view,
const QmlItemNode &parentNode,
const QString &effectName);
QList<QmlItemNode> children() const;
QList<QmlObjectNode> resources() const;
QList<QmlObjectNode> allDirectSubNodes() const;

View File

@@ -2734,6 +2734,16 @@ bool NodeMetaInfo::isQtQuick3DPrincipledMaterial() const
}
}
bool NodeMetaInfo::isQtQuick3DSpecularGlossyMaterial() const
{
if constexpr (useProjectStorage()) {
using namespace Storage::Info;
return isBasedOnCommonType<QtQuick3D, SpecularGlossyMaterial>(m_projectStorage, m_typeId);
} else {
return isValid() && isSubclassOf("QtQuick3D.SpecularGlossyMaterial");
}
}
bool NodeMetaInfo::isQtQuick3DParticles3DSpriteParticle3D() const
{
if constexpr (useProjectStorage()) {

View File

@@ -811,23 +811,26 @@ void AbstractView::changeRootNodeType(const TypeName &type, int majorVersion, in
m_model.data()->d->changeRootNodeType(type, majorVersion, minorVersion);
}
// Creates material library if it doesn't exist and moves any existing materials into it
// This function should be called only from inside a transaction, as it potentially does many
// changes to model, or undo stack should be cleared after the call.
// Creates material library if it doesn't exist and moves any existing materials into it.
void AbstractView::ensureMaterialLibraryNode()
{
ModelNode matLib = modelNodeForId(Constants::MATERIAL_LIB_ID);
if (matLib.isValid() || rootModelNode().metaInfo().isQtQuick3DMaterial())
return;
executeInTransaction(__FUNCTION__, [&] {
// Create material library node
auto nodeType = rootModelNode().metaInfo().isQtQuick3DNode() ? model()->qtQuick3DNodeMetaInfo()
auto nodeType = rootModelNode().metaInfo().isQtQuick3DNode()
? model()->qtQuick3DNodeMetaInfo()
: model()->qtQuickItemMetaInfo();
matLib = createModelNode(nodeType.typeName(), nodeType.majorVersion(), nodeType.minorVersion());
matLib.setIdWithoutRefactoring(Constants::MATERIAL_LIB_ID);
rootModelNode().defaultNodeListProperty().reparentHere(matLib);
});
// Do the material reparentings in different transaction to work around issue QDS-8094
executeInTransaction(__FUNCTION__, [&] {
const QList<ModelNode> materials = rootModelNode().subModelNodesOfType(
model()->qtQuick3DMaterialMetaInfo());
if (!materials.isEmpty()) {
@@ -843,15 +846,13 @@ void AbstractView::ensureMaterialLibraryNode()
matLib.defaultNodeListProperty().reparentHere(node);
}
}
});
}
// Returns ModelNode for project's material library.
// Since this calls ensureMaterialLibraryNode(), it should only be called within a transaction.
// Returns ModelNode for project's material library if it exists.
ModelNode AbstractView::materialLibraryNode()
{
ensureMaterialLibraryNode();
ModelNode matLib = modelNodeForId(Constants::MATERIAL_LIB_ID);
return matLib;
return modelNodeForId(Constants::MATERIAL_LIB_ID);
}
// Assigns given material to a 3D model.

View File

@@ -80,6 +80,11 @@ int Import::majorVersion() const
return majorFromVersion(m_version);
}
int Import::minorVersion() const
{
return minorFromVersion(m_version);
}
int Import::majorFromVersion(const QString &version)
{
if (version.isEmpty())
@@ -87,6 +92,16 @@ int Import::majorFromVersion(const QString &version)
return version.split('.').first().toInt();
}
int Import::minorFromVersion(const QString &version)
{
if (version.isEmpty())
return -1;
const QStringList parts = version.split('.');
if (parts.size() < 2)
return -1;
return parts[1].toInt();
}
size_t qHash(const Import &import)
{
return ::qHash(import.url()) ^ ::qHash(import.file()) ^ ::qHash(import.version()) ^ ::qHash(import.alias());

View File

@@ -197,7 +197,7 @@ public:
const AuxiliaryDataKeyView &key,
const QVariant &data);
void removeAuxiliaryData(const InternalNodePointer &node, const AuxiliaryDataKeyView &key);
[[noreturn]] void resetModelByRewriter(const QString &description);
void resetModelByRewriter(const QString &description);
// Imports:
const QList<Import> &imports() const { return m_imports; }

View File

@@ -159,6 +159,33 @@ QmlItemNode QmlItemNode::createQmlItemNodeFromFont(AbstractView *view,
return newQmlItemNode;
}
QmlItemNode QmlItemNode::createQmlItemNodeForEffect(AbstractView *view,
const QmlItemNode &parentNode,
const QString &effectName)
{
QmlItemNode newQmlItemNode;
QmlDesigner::Import import = Import::createLibraryImport("Effects." + effectName, "1.0");
try {
if (!view->model()->hasImport(import, true, true))
view->model()->changeImports({import}, {});
} catch (const Exception &e) {
QTC_ASSERT(false, return QmlItemNode());
}
TypeName type(effectName.toUtf8());
newQmlItemNode = QmlItemNode(view->createModelNode(type, 1, 0));
NodeAbstractProperty parentProperty = parentNode.defaultNodeAbstractProperty();
parentProperty.reparentHere(newQmlItemNode);
newQmlItemNode.modelNode().bindingProperty("source").setExpression("parent");
newQmlItemNode.modelNode().bindingProperty("anchors.fill").setExpression("parent");
QTC_ASSERT(newQmlItemNode.isValid(), return QmlItemNode());
return newQmlItemNode;
}
bool QmlItemNode::isValid() const
{
return isValidQmlItemNode(modelNode());

View File

@@ -70,7 +70,7 @@ QStringList supportedVersionsList()
{
static const QStringList list = {"2.0", "2.1", "2.2", "2.3", "2.4", "2.5", "2.6",
"2.7", "2.8", "2.9", "2.10", "2.11", "2.12", "2.13",
"2.14", "2.15", "6.0", "6.1", "6.2", "6.3"};
"2.14", "2.15", "6.0", "6.1", "6.2", "6.3", "6.4"};
return list;
}
@@ -509,10 +509,6 @@ public:
qDebug() << metaInfo.isValid() << metaInfo.typeName();
if (metaInfo.isValid())
qDebug() << metaInfo.superClasses().front().typeName();
if (!metaInfo.isFileComponent() && m_model == m_model->metaInfoProxyModel()
&& metaInfo.isValid())
throw RewritingException(__LINE__, __FUNCTION__, __FILE__, "test", "test");
}
typeName = QString::fromUtf8(metaInfo.typeName());

View File

@@ -66,6 +66,7 @@ inline constexpr char Picture[] = "Picture";
inline constexpr char Popup[] = "Popup";
inline constexpr char Positioner[] = "Positioner";
inline constexpr char PrincipledMaterial[] = "PrincipledMaterial";
inline constexpr char SpecularGlossyMaterial[] = "SpecularGlossyMaterial";
inline constexpr char PropertyAnimation[] = "PropertyAnimation";
inline constexpr char PropertyChanges[] = "PropertyChanges";
inline constexpr char QML[] = "QML";

View File

@@ -83,6 +83,7 @@ const char MIME_TYPE_ASSET_SOUND[] = "application/vnd.qtdesignstudio.asset
const char MIME_TYPE_ASSET_VIDEO[] = "application/vnd.qtdesignstudio.asset.video";
const char MIME_TYPE_ASSET_TEXTURE3D[] = "application/vnd.qtdesignstudio.asset.texture3d";
const char MIME_TYPE_MODELNODE_LIST[] = "application/vnd.qtdesignstudio.modelnode.list";
const char MIME_TYPE_ASSET_EFFECT[] = "application/vnd.qtdesignstudio.asset.effect";
// Menus
const char M_VIEW_WORKSPACES[] = "QmlDesigner.Menu.View.Workspaces";

View File

@@ -631,6 +631,11 @@ void QmlDesignerPlugin::emitCurrentTextEditorChanged(Core::IEditor *editor)
d->blockEditorChange = false;
}
void QmlDesignerPlugin::emitAssetChanged(const QString &assetPath)
{
emit assetChanged(assetPath);
}
double QmlDesignerPlugin::formEditorDevicePixelRatio()
{
if (QmlDesignerPlugin::settings().value(DesignerSettingsKey::IGNORE_DEVICE_PIXEL_RATIO).toBool())

View File

@@ -63,6 +63,8 @@ public:
void switchToTextModeDeferred();
void emitCurrentTextEditorChanged(Core::IEditor *editor);
void emitAssetChanged(const QString &assetPath);
static double formEditorDevicePixelRatio();
static void contextHelp(const Core::IContext::HelpCallback &callback, const QString &id);
@@ -81,7 +83,7 @@ public:
signals:
void usageStatisticsNotifier(const QString &identifier);
void usageStatisticsUsageTimer(const QString &identifier, int elapsed);
void assetChanged(const QString &assetPath);
private: // functions
void integrateIntoQtCreator(QWidget *modeWidget);

View File

@@ -66,6 +66,14 @@ static int preferedQtTarget(Target *target)
return 5;
}
static bool allowOnlySingleProject()
{
QSettings *settings = Core::ICore::settings();
const QString qdsAllowMultipleProjects = "QML/Designer/AllowMultipleProjects";
return !settings->value(qdsAllowMultipleProjects, false).toBool();
}
Utils::FilePaths QmlProject::getUiQmlFilesForFolder(const Utils::FilePath &folder)
{
const Utils::FilePaths uiFiles = files([&](const ProjectExplorer::Node *node) {
@@ -86,9 +94,10 @@ QmlProject::QmlProject(const Utils::FilePath &fileName)
setBuildSystemCreator([](Target *t) { return new QmlBuildSystem(t); });
if (QmlProject::isQtDesignStudio()) {
if (allowOnlySingleProject()) {
EditorManager::closeAllDocuments();
SessionManager::closeAllProjects();
}
m_openFileConnection
= connect(this,