Merge remote-tracking branch 'origin/8.0'

Conflicts:
	share/qtcreator/qmldesigner/propertyEditorQmlSources/imports/HelperWidgets/ColorEditor.qml
	share/qtcreator/qmldesigner/propertyEditorQmlSources/imports/StudioTheme/icons.ttf
	src/libs/utils/fileutils.cpp
	src/plugins/qmldesigner/components/edit3d/edit3dwidget.cpp
	src/plugins/qmldesigner/designercore/include/abstractview.h
	src/plugins/qmldesigner/designercore/include/nodemetainfo.h
	src/plugins/qmldesigner/designercore/metainfo/nodemetainfo.cpp
	src/plugins/qmldesigner/designercore/model/model_p.h
	src/plugins/remotelinux/linuxdevice.cpp
	tests/auto/utils/fileutils/tst_fileutils.cpp

Change-Id: I26a21e2523d3d725fdb8c548a531cdbdaeaeca20
This commit is contained in:
Eike Ziller
2022-09-19 09:54:06 +02:00
57 changed files with 761 additions and 279 deletions

View File

@@ -38,7 +38,7 @@
identifying potential bottlenecks, especially in the evaluation identifying potential bottlenecks, especially in the evaluation
of bindings. of bindings.
\li \l{Checking Code Coverage}{Squish Coco} \li \l{Checking Code Coverage}{Coco}
Analyze the way an application runs as part of a test suite, for Analyze the way an application runs as part of a test suite, for
example, and use the results to make the tests more efficient and example, and use the results to make the tests more efficient and

View File

@@ -8,11 +8,10 @@
\title Checking Code Coverage \title Checking Code Coverage
\l{https://doc.froglogic.com/squish-coco/latest/}{Squish Coco} is a complete \l{https://doc.qt.io/coco/}{Coco} is a complete code coverage tool chain for
code coverage tool chain for Tcl, QML, C# and C/C++ programs that runs on Tcl, QML, C# and C/C++ programs that runs on \macOS, Linux, and Windows.
\macOS, Linux, and Windows.
Squish Coco analyzes the way an application runs, as part of a test suite, Coco analyzes the way an application runs, as part of a test suite,
for example. The results enable you to make the tests more efficient and for example. The results enable you to make the tests more efficient and
complete. complete.
@@ -20,7 +19,7 @@
\list \list
\li Find untested code sections. \li Find untested code sections.
\li Find redundant tests which can then be eliminated. Squish Coco can \li Find redundant tests which can then be eliminated. Coco can
identify portions of the source code that are covered by a test. It identify portions of the source code that are covered by a test. It
can detect whether a new test covers lines in the source code that can detect whether a new test covers lines in the source code that
the existing tests do not cover. the existing tests do not cover.
@@ -38,10 +37,10 @@
The experimental Coco plugin integrates Coco CoverageBrowser into \QC. The experimental Coco plugin integrates Coco CoverageBrowser into \QC.
It enables you to analyze the test coverage by loading an instrumentation It enables you to analyze the test coverage by loading an instrumentation
database (a .csmes file) that was generated by Coco CoverageScanner. database (a .csmes file) that was generated by Coco CoverageScanner.
It is currently supported only on Windows, with Squish Coco version 6.0, It is currently supported only on Windows, with Coco version 6.0,
or later. or later.
To use the plugin, you must download and install Squish Coco. To use the plugin, you must download and install Coco.
\section1 Enabling the Coco Plugin \section1 Enabling the Coco Plugin

Binary file not shown.

After

Width:  |  Height:  |  Size: 34 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 49 KiB

After

Width:  |  Height:  |  Size: 47 KiB

View File

@@ -39,8 +39,12 @@
\section1 Assigning a Material to an Object \section1 Assigning a Material to an Object
To assign a material to a 3D object in your project, first select the object To assign a material to a 3D object in your project, drag the material from
in \uicontrol Navigator or the \uicontrol{3D} view. Then, do one of the \uicontrol {Material Browser} to the object in the \uicontrol Navigator or
\uicontrol 3D view.
Additionally, you can also first select the object
in the \uicontrol Navigator or \uicontrol{3D} view, and then do one of the
following: following:
\list \list
@@ -64,6 +68,26 @@
\image materials-remove-material.png \image materials-remove-material.png
\endlist \endlist
\section1 Copying and Pasting Material Properties
You can copy properties from one material to another. You can choose if you
want to copy all properties or certain property groups.
To copy material properties from one material to another:
\list
\li In \uicontrol {Material Browser}, right-click the material that you
want to copy properties from.
\li Select \uicontrol {Copy properties} and then
\uicontrol All or a property group.
\image material-copy-properties.png
\li Right-click the material that you want to copy the properties to.
\li Select \uicontrol {Paste properties}.
\endlist
\note You can't copy material properties between materials of different
material types.
\section1 Using Texture Maps \section1 Using Texture Maps
In \QDS you can add many different texture maps to your material. In \QDS you can add many different texture maps to your material.

View File

@@ -59,23 +59,10 @@ public:
QQuick3DNode *pickNode() const; QQuick3DNode *pickNode() const;
MouseArea3D *dragHelper() const; MouseArea3D *dragHelper() const;
QVector3D getMousePosInPlane(const MouseArea3D *helper, const QPointF &mousePosInView) const;
static qreal mouseDragMultiplier() { return .02; } static qreal mouseDragMultiplier() { return .02; }
public slots:
void setView3D(QQuick3DViewport *view3D);
void setGrabsMouse(bool grabsMouse);
void setActive(bool active);
void setCirclePickArea(const QPointF &pickArea);
void setMinAngle(qreal angle);
void setPickNode(QQuick3DNode *node);
void setDragHelper(MouseArea3D *dragHelper);
void setX(qreal x);
void setY(qreal y);
void setWidth(qreal width);
void setHeight(qreal height);
void setPriority(int level);
Q_INVOKABLE QVector3D rayIntersectsPlane(const QVector3D &rayPos0, Q_INVOKABLE QVector3D rayIntersectsPlane(const QVector3D &rayPos0,
const QVector3D &rayPos1, const QVector3D &rayPos1,
const QVector3D &planePos, const QVector3D &planePos,
@@ -98,6 +85,21 @@ public slots:
Q_INVOKABLE void forceMoveEvent(double x, double y); Q_INVOKABLE void forceMoveEvent(double x, double y);
Q_INVOKABLE void forceReleaseEvent(double x, double y); Q_INVOKABLE void forceReleaseEvent(double x, double y);
public slots:
void setView3D(QQuick3DViewport *view3D);
void setGrabsMouse(bool grabsMouse);
void setActive(bool active);
void setCirclePickArea(const QPointF &pickArea);
void setMinAngle(qreal angle);
void setPickNode(QQuick3DNode *node);
void setDragHelper(MouseArea3D *dragHelper);
void setX(qreal x);
void setY(qreal y);
void setWidth(qreal width);
void setHeight(qreal height);
void setPriority(int level);
signals: signals:
void view3DChanged(); void view3DChanged();
@@ -131,7 +133,6 @@ private:
void setHovering(bool enable); void setHovering(bool enable);
QVector3D getNormal() const; QVector3D getNormal() const;
QVector3D getCameraToNodeDir(QQuick3DNode *node) const; QVector3D getCameraToNodeDir(QQuick3DNode *node) const;
QVector3D getMousePosInPlane(const MouseArea3D *helper, const QPointF &mousePosInView) const;
Q_DISABLE_COPY(MouseArea3D) Q_DISABLE_COPY(MouseArea3D)
QQuick3DViewport *m_view3D = nullptr; QQuick3DViewport *m_view3D = nullptr;

View File

@@ -73,9 +73,7 @@ void QmlStateNodeInstance::setPropertyVariant(const PropertyName &name, const QV
void QmlStateNodeInstance::setPropertyBinding(const PropertyName &name, const QString &expression) void QmlStateNodeInstance::setPropertyBinding(const PropertyName &name, const QString &expression)
{ {
bool isStateOfTheRootModelNode = parentInstance() && parentInstance()->isRootNodeInstance(); if (name == "when")
if (name == "when" && (isStateOfTheRootModelNode))
return; return;
ObjectNodeInstance::setPropertyBinding(name, expression); ObjectNodeInstance::setPropertyBinding(name, expression);

View File

@@ -405,18 +405,33 @@ void Qt5InformationNodeInstanceServer::getNodeAtPos(const QPointF &pos)
Q_ARG(QVariant, pos.x()), Q_ARG(QVariant, pos.x()),
Q_ARG(QVariant, pos.y())); Q_ARG(QVariant, pos.y()));
QObject *gizmoObj = qvariant_cast<QObject *>(gizmoVar); QObject *gizmoObj = qvariant_cast<QObject *>(gizmoVar);
QVariant instance = -1; qint32 instanceId = -1;
if (gizmoObj && hasInstanceForObject(gizmoObj)) { if (gizmoObj && hasInstanceForObject(gizmoObj)) {
instance = instanceForObject(gizmoObj).instanceId(); instanceId = instanceForObject(gizmoObj).instanceId();
} else { } else {
QQuick3DModel *hitModel = helper->pickViewAt(editView, pos.x(), pos.y()).objectHit(); QQuick3DModel *hitModel = helper->pickViewAt(editView, pos.x(), pos.y()).objectHit();
QObject *resolvedPick = helper->resolvePick(hitModel); QObject *resolvedPick = helper->resolvePick(hitModel);
if (hasInstanceForObject(resolvedPick)) if (hasInstanceForObject(resolvedPick))
instance = instanceForObject(resolvedPick).instanceId(); instanceId = instanceForObject(resolvedPick).instanceId();
} }
nodeInstanceClient()->handlePuppetToCreatorCommand({PuppetToCreatorCommand::NodeAtPos, instance}); // Also get the intersection with an axis plane of the scene.
QVector3D pos3d;
if (editView) {
Internal::MouseArea3D ma;
ma.setView3D(editView);
ma.setEulerRotation({90, 0, 0}); // Default grid plane (XZ plane)
QVector3D planePos = ma.getMousePosInPlane(nullptr, pos);
const float limit = 10000000; // Remove extremes on nearly parallel plane
if (!qFuzzyCompare(planePos.z(), -1.f) && qAbs(planePos.x()) < limit && qAbs(planePos.y()) < limit)
pos3d = {planePos.x(), 0, planePos.y()};
}
QVariantList data;
data.append(instanceId);
data.append(pos3d);
nodeInstanceClient()->handlePuppetToCreatorCommand({PuppetToCreatorCommand::NodeAtPos,
QVariant::fromValue(data)});
#else #else
Q_UNUSED(pos) Q_UNUSED(pos)
#endif #endif

View File

@@ -1,5 +1,3 @@
// Copyright (C) 2021 The Qt Company Ltd. // Copyright (C) 2021 The Qt Company Ltd.
// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0 WITH Qt-GPL-exception-1.0 // SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0 WITH Qt-GPL-exception-1.0
import QtQuick 2.15 import QtQuick 2.15
@@ -29,7 +27,7 @@ SecondColumnLayout {
else else
return colorEditor.backendValue.value return colorEditor.backendValue.value
} }
property alias gradientPropertyName: cePopup.gradientPropertyName property alias gradientPropertyName: popupLoader.gradientPropertyName
property alias gradientThumbnail: gradientThumbnail property alias gradientThumbnail: gradientThumbnail
property alias shapeGradientThumbnail: shapeGradientThumbnail property alias shapeGradientThumbnail: shapeGradientThumbnail
@@ -45,7 +43,7 @@ SecondColumnLayout {
} }
function initEditor() { function initEditor() {
cePopup.initEditor() colorEditor.color = colorEditor.value
} }
Connections { Connections {
@@ -53,12 +51,12 @@ SecondColumnLayout {
target: colorEditor target: colorEditor
function onValueChanged() { function onValueChanged() {
if (cePopup.isNotInGradientMode()) if (popupLoader.isNotInGradientMode())
colorEditor.color = colorEditor.value colorEditor.color = colorEditor.value
} }
function onBackendValueChanged() { function onBackendValueChanged() {
if (cePopup.isNotInGradientMode()) if (popupLoader.isNotInGradientMode())
colorEditor.color = colorEditor.value colorEditor.color = colorEditor.value
} }
} }
@@ -85,17 +83,13 @@ SecondColumnLayout {
} }
onColorChanged: { onColorChanged: {
if (!cePopup.isInValidState) if (!popupLoader.isInValidState)
return return
if (colorEditor.supportGradient && cePopup.gradientModel.hasGradient) { popupLoader.commitToGradient()
var hexColor = convertColorToString(colorEditor.color)
hexTextField.text = hexColor
cePopup.commitGradientColor()
}
// Delay setting the color to keep ui responsive // Delay setting the color to keep ui responsive
if (cePopup.isNotInGradientMode()) if (popupLoader.isNotInGradientMode())
colorEditorTimer.restart() colorEditorTimer.restart()
} }
@@ -115,16 +109,16 @@ SecondColumnLayout {
id: gradientThumbnail id: gradientThumbnail
anchors.fill: parent anchors.fill: parent
anchors.margins: StudioTheme.Values.border anchors.margins: StudioTheme.Values.border
visible: !cePopup.isNotInGradientMode() visible: !popupLoader.isNotInGradientMode()
&& !colorEditor.shapeGradients && !colorEditor.shapeGradients
&& cePopup.hasLinearGradient() && popupLoader.hasLinearGradient()
} }
Shape { Shape {
id: shape id: shape
anchors.fill: parent anchors.fill: parent
anchors.margins: StudioTheme.Values.border anchors.margins: StudioTheme.Values.border
visible: !cePopup.isNotInGradientMode() visible: !popupLoader.isNotInGradientMode()
&& colorEditor.shapeGradients && colorEditor.shapeGradients
ShapePath { ShapePath {
@@ -159,16 +153,81 @@ SecondColumnLayout {
MouseArea { MouseArea {
anchors.fill: parent anchors.fill: parent
onClicked: { onClicked: {
cePopup.opened ? cePopup.close() : cePopup.open() popupLoader.opened ? popupLoader.close() : popupLoader.open()
forceActiveFocus() forceActiveFocus()
} }
} }
ColorEditorPopup { QtObject {
id: popupLoader
property bool isInValidState: popupLoader.active ? popupLoader.dialog.isInValidState : true
property QtObject dialog: popupLoader.loader.item
property bool opened: popupLoader.active ? popupLoader.dialog.opened : false
property string gradientPropertyName
function commitToGradient() {
if (!popupLoader.active)
return
if (colorEditor.supportGradient && popupLoader.dialog.gradientModel.hasGradient) {
var hexColor = convertColorToString(colorEditor.color)
hexTextField.text = hexColor
popupLoader.dialog.commitGradientColor()
}
}
function isNotInGradientMode() {
if (!popupLoader.active)
return true
return popupLoader.dialog.isNotInGradientMode()
}
function hasLinearGradient(){
if (!popupLoader.active)
return false
return popupLoader.dialog.hasLinearGradient()
}
function ensureLoader() {
if (!popupLoader.active)
popupLoader.active = true
}
function open() {
popupLoader.ensureLoader()
popupLoader.dialog.open()
}
function close() {
popupLoader.ensureLoader()
popupLoader.dialog.close()
}
function determineActiveColorMode() {
if (popupLoader.active && popupLoader.dialog)
popupLoader.dialog.determineActiveColorMode()
else
colorEditor.color = colorEditor.value
}
property alias active: popupLoader.loader.active
property Loader loader: Loader {
parent: colorEditor
active: colorEditor.supportGradient
sourceComponent: ColorEditorPopup {
id: cePopup id: cePopup
x: cePopup.__defaultX x: cePopup.__defaultX
y: cePopup.__defaultY y: cePopup.__defaultY
} }
onLoaded: {
popupLoader.dialog.initEditor()
}
}
}
} }
Spacer { Spacer {
@@ -180,7 +239,7 @@ SecondColumnLayout {
implicitWidth: StudioTheme.Values.twoControlColumnWidth implicitWidth: StudioTheme.Values.twoControlColumnWidth
+ StudioTheme.Values.actionIndicatorWidth + StudioTheme.Values.actionIndicatorWidth
width: implicitWidth width: implicitWidth
enabled: cePopup.isNotInGradientMode() enabled: popupLoader.isNotInGradientMode()
writeValueManually: true writeValueManually: true
validator: RegExpValidator { validator: RegExpValidator {
regExp: /#[0-9A-Fa-f]{6}([0-9A-Fa-f]{2})?/g regExp: /#[0-9A-Fa-f]{6}([0-9A-Fa-f]{2})?/g
@@ -191,7 +250,7 @@ SecondColumnLayout {
onAccepted: colorEditor.color = colorFromString(hexTextField.text) onAccepted: colorEditor.color = colorFromString(hexTextField.text)
onCommitData: { onCommitData: {
colorEditor.color = colorFromString(hexTextField.text) colorEditor.color = colorFromString(hexTextField.text)
if (cePopup.isNotInGradientMode()) { if (popupLoader.isNotInGradientMode()) {
if (colorEditor.isVector3D) { if (colorEditor.isVector3D) {
backendValue.value = Qt.vector3d(colorEditor.color.r, backendValue.value = Qt.vector3d(colorEditor.color.r,
colorEditor.color.g, colorEditor.color.g,
@@ -216,9 +275,9 @@ SecondColumnLayout {
} }
} }
Component.onCompleted: cePopup.determineActiveColorMode() Component.onCompleted: popupLoader.determineActiveColorMode()
onBackendValueChanged: { onBackendValueChanged: {
cePopup.determineActiveColorMode() popupLoader.determineActiveColorMode()
} }
} }

View File

@@ -53,11 +53,10 @@ Section {
Spacer { implicitWidth: StudioTheme.Values.twoControlColumnGap } Spacer { implicitWidth: StudioTheme.Values.twoControlColumnGap }
IconIndicator { IconIndicator {
Layout.alignment: Qt.AlignLeft
icon: StudioTheme.Constants.closeCross icon: StudioTheme.Constants.closeCross
onClicked: colorEditorControl.remove() onClicked: colorEditorControl.remove()
} }
ExpandingSpacer {} ExpandingSpacer {}
} }
} }
@@ -79,24 +78,17 @@ Section {
+ StudioTheme.Values.actionIndicatorWidth + StudioTheme.Values.actionIndicatorWidth
} }
Spacer { Spacer { implicitWidth: StudioTheme.Values.twoControlColumnGap }
implicitWidth: StudioTheme.Values.twoControlColumnGap
}
Item { Item {
height: 10 height: 10
implicitWidth: { implicitWidth: StudioTheme.Values.twoControlColumnWidth
return StudioTheme.Values.twoControlColumnWidth
+ StudioTheme.Values.actionIndicatorWidth + StudioTheme.Values.actionIndicatorWidth
} }
}
Spacer { Spacer { implicitWidth: StudioTheme.Values.twoControlColumnGap }
implicitWidth: StudioTheme.Values.twoControlColumnGap
}
IconIndicator { IconIndicator {
Layout.alignment: Qt.AlignLeft
icon: StudioTheme.Constants.closeCross icon: StudioTheme.Constants.closeCross
onClicked: layoutInt.remove() onClicked: layoutInt.remove()
} }
@@ -124,24 +116,17 @@ Section {
+ StudioTheme.Values.actionIndicatorWidth + StudioTheme.Values.actionIndicatorWidth
} }
Spacer { Spacer { implicitWidth: StudioTheme.Values.twoControlColumnGap }
implicitWidth: StudioTheme.Values.twoControlColumnGap
}
Item { Item {
height: 10 height: 10
implicitWidth: { implicitWidth: StudioTheme.Values.twoControlColumnWidth
return StudioTheme.Values.twoControlColumnWidth
+ StudioTheme.Values.actionIndicatorWidth + StudioTheme.Values.actionIndicatorWidth
} }
}
Spacer { Spacer { implicitWidth: StudioTheme.Values.twoControlColumnGap }
implicitWidth: StudioTheme.Values.twoControlColumnGap
}
IconIndicator { IconIndicator {
Layout.alignment: Qt.AlignLeft
icon: StudioTheme.Constants.closeCross icon: StudioTheme.Constants.closeCross
onClicked: layoutReal.remove() onClicked: layoutReal.remove()
} }
@@ -165,12 +150,9 @@ Section {
+ StudioTheme.Values.actionIndicatorWidth + StudioTheme.Values.actionIndicatorWidth
} }
Spacer { Spacer { implicitWidth: StudioTheme.Values.twoControlColumnGap }
implicitWidth: StudioTheme.Values.twoControlColumnGap
}
IconIndicator { IconIndicator {
Layout.alignment: Qt.AlignLeft
icon: StudioTheme.Constants.closeCross icon: StudioTheme.Constants.closeCross
onClicked: layoutString.remove() onClicked: layoutString.remove()
} }
@@ -195,24 +177,17 @@ Section {
backendValue: layoutBool.backendValue backendValue: layoutBool.backendValue
} }
Spacer { Spacer { implicitWidth: StudioTheme.Values.twoControlColumnGap }
implicitWidth: StudioTheme.Values.twoControlColumnGap
}
Item { Item {
height: 10 height: 10
implicitWidth: { implicitWidth: StudioTheme.Values.twoControlColumnWidth
return StudioTheme.Values.twoControlColumnWidth
+ StudioTheme.Values.actionIndicatorWidth + StudioTheme.Values.actionIndicatorWidth
} }
}
Spacer { Spacer { implicitWidth: StudioTheme.Values.twoControlColumnGap }
implicitWidth: StudioTheme.Values.twoControlColumnGap
}
IconIndicator { IconIndicator {
Layout.alignment: Qt.AlignLeft
icon: StudioTheme.Constants.closeCross icon: StudioTheme.Constants.closeCross
onClicked: layoutBool.remove() onClicked: layoutBool.remove()
} }
@@ -238,7 +213,6 @@ Section {
} }
IconIndicator { IconIndicator {
Layout.alignment: Qt.AlignLeft
icon: StudioTheme.Constants.closeCross icon: StudioTheme.Constants.closeCross
onClicked: layoutUrl.remove() onClicked: layoutUrl.remove()
} }
@@ -270,12 +244,9 @@ Section {
showTranslateCheckBox: false showTranslateCheckBox: false
} }
Spacer { Spacer { implicitWidth: StudioTheme.Values.twoControlColumnGap }
implicitWidth: StudioTheme.Values.twoControlColumnGap
}
IconIndicator { IconIndicator {
Layout.alignment: Qt.AlignLeft
icon: StudioTheme.Constants.closeCross icon: StudioTheme.Constants.closeCross
onClicked: layoutAlias.remove() onClicked: layoutAlias.remove()
} }
@@ -301,12 +272,9 @@ Section {
+ StudioTheme.Values.actionIndicatorWidth + StudioTheme.Values.actionIndicatorWidth
} }
Spacer { Spacer { implicitWidth: StudioTheme.Values.twoControlColumnGap }
implicitWidth: StudioTheme.Values.twoControlColumnGap
}
IconIndicator { IconIndicator {
Layout.alignment: Qt.AlignLeft
icon: StudioTheme.Constants.closeCross icon: StudioTheme.Constants.closeCross
onClicked: layoutTextureInput.remove() onClicked: layoutTextureInput.remove()
} }
@@ -411,7 +379,6 @@ Section {
Spacer { implicitWidth: StudioTheme.Values.controlGap } Spacer { implicitWidth: StudioTheme.Values.controlGap }
IconIndicator { IconIndicator {
Layout.alignment: Qt.AlignLeft
icon: StudioTheme.Constants.closeCross icon: StudioTheme.Constants.closeCross
onClicked: layoutVector.remove() onClicked: layoutVector.remove()
} }
@@ -462,16 +429,12 @@ Section {
Item { Item {
height: 10 height: 10
implicitWidth: { implicitWidth: StudioTheme.Values.twoControlColumnWidth
return StudioTheme.Values.twoControlColumnWidth
+ StudioTheme.Values.actionIndicatorWidth + StudioTheme.Values.actionIndicatorWidth
}
visible: vecSize === 2 // Placeholder for last spinbox visible: vecSize === 2 // Placeholder for last spinbox
} }
Spacer { Spacer { implicitWidth: StudioTheme.Values.twoControlColumnGap }
implicitWidth: StudioTheme.Values.twoControlColumnGap
}
ExpandingSpacer {} ExpandingSpacer {}
} }
@@ -497,11 +460,9 @@ Section {
+ StudioTheme.Values.actionIndicatorWidth + StudioTheme.Values.actionIndicatorWidth
} }
Spacer { Spacer { implicitWidth: StudioTheme.Values.twoControlColumnGap }
implicitWidth: StudioTheme.Values.twoControlColumnGap
}
IconIndicator { IconIndicator {
Layout.alignment: Qt.AlignLeft
icon: StudioTheme.Constants.closeCross icon: StudioTheme.Constants.closeCross
onClicked: layoutReadonly.remove() onClicked: layoutReadonly.remove()
} }
@@ -541,6 +502,7 @@ Section {
active: repeater.loadActive active: repeater.loadActive
width: loader.item ? loader.item.width : 0 width: loader.item ? loader.item.width : 0
height: loader.item ? loader.item.height : 0 height: loader.item ? loader.item.height : 0
Layout.fillWidth: true
sourceComponent: { sourceComponent: {
if (propertyType == "color") if (propertyType == "color")
@@ -615,7 +577,6 @@ Section {
Spacer { implicitWidth: StudioTheme.Values.actionIndicatorWidth } Spacer { implicitWidth: StudioTheme.Values.actionIndicatorWidth }
StudioControls.AbstractButton { StudioControls.AbstractButton {
id: plusButton id: plusButton
buttonIcon: StudioTheme.Constants.plus buttonIcon: StudioTheme.Constants.plus
onClicked: { onClicked: {
@@ -691,7 +652,7 @@ Section {
RowLayout { RowLayout {
width: cePopup.width - 8 width: cePopup.width - 8
PropertyLabel { PropertyLabel {
text: "Add New Property" text: qsTr("Add New Property")
horizontalAlignment: Text.AlignLeft horizontalAlignment: Text.AlignLeft
leftPadding: 8 leftPadding: 8
width: cePopup.width - closeIndicator.width - 24 width: cePopup.width - closeIndicator.width - 24
@@ -707,7 +668,7 @@ Section {
RowLayout { RowLayout {
PropertyLabel { PropertyLabel {
id: textLabel id: textLabel
text: "Name" text: qsTr("Name")
width: cePopup.labelWidth width: cePopup.labelWidth
} }
StudioControls.TextField { StudioControls.TextField {
@@ -720,7 +681,7 @@ Section {
} }
RowLayout { RowLayout {
PropertyLabel { PropertyLabel {
text: "Type" text: qsTr("Type")
width: cePopup.labelWidth width: cePopup.labelWidth
} }
StudioControls.ComboBox { StudioControls.ComboBox {

View File

@@ -54,6 +54,13 @@ Row {
// when the combobox is closed by focusing on some other control. // when the combobox is closed by focusing on some other control.
property int hoverIndex: -1 property int hoverIndex: -1
onCurrentIndexChanged: {
// This is needed to correctly update root.absoluteFilePath in cases where selection
// changes between two nodes of same type.
if (currentIndex !== -1 && !root.backendValue.isBound)
root.absoluteFilePath = fileModel.resolve(root.backendValue.value)
}
DropArea { DropArea {
id: dropArea id: dropArea

View File

@@ -12,12 +12,11 @@ T.MenuSeparator {
implicitContentWidth + leftPadding + rightPadding) implicitContentWidth + leftPadding + rightPadding)
implicitHeight: Math.max(implicitBackgroundHeight + topInset + bottomInset, implicitHeight: Math.max(implicitBackgroundHeight + topInset + bottomInset,
implicitContentHeight + topPadding + bottomPadding) implicitContentHeight + topPadding + bottomPadding)
padding: 0 padding: 0
contentItem: Rectangle { contentItem: Rectangle {
width: control.parent.width implicitWidth: control.parent.width
height: StudioTheme.Values.border implicitHeight: StudioTheme.Values.border
color: StudioTheme.Values.themeControlOutline color: StudioTheme.Values.themeControlOutline
} }
} }

View File

@@ -951,7 +951,7 @@ void Check::visitQmlObject(Node *ast, UiQualifiedId *typeId,
if (checkTypeForQmlUiSupport(typeId)) if (checkTypeForQmlUiSupport(typeId))
addMessage(ErrUnsupportedTypeInQmlUi, typeErrorLocation, typeName); addMessage(ErrUnsupportedTypeInQmlUi, typeErrorLocation, typeName);
if (m_typeStack.count() > 1 && typeName == "State") { if (m_typeStack.count() > 1 && typeName == "State" && m_typeStack.last() != "StateGroup") {
addMessage(WarnStatesOnlyInRootItemForVisualDesigner, typeErrorLocation); addMessage(WarnStatesOnlyInRootItemForVisualDesigner, typeErrorLocation);
addMessage(ErrStatesOnlyInRootItemInQmlUi, typeErrorLocation); addMessage(ErrStatesOnlyInRootItemInQmlUi, typeErrorLocation);
} }

View File

@@ -422,7 +422,10 @@ int TimelineModel::insert(qint64 startTime, qint64 duration, int selectionId)
int index = d->insertStart(TimelineModelPrivate::Range(startTime, duration, selectionId)); int index = d->insertStart(TimelineModelPrivate::Range(startTime, duration, selectionId));
if (index < d->ranges.size() - 1) if (index < d->ranges.size() - 1)
d->incrementStartIndices(index); d->incrementStartIndices(index);
d->insertEnd(TimelineModelPrivate::RangeEnd(index, startTime + duration)); int endIndex = d->insertEnd(TimelineModelPrivate::RangeEnd(index, startTime + duration));
d->setEndIndex(index, endIndex);
if (endIndex < d->endTimes.size() - 1)
d->incrementEndIndices(endIndex);
return index; return index;
} }
@@ -446,7 +449,10 @@ int TimelineModel::insertStart(qint64 startTime, int selectionId)
void TimelineModel::insertEnd(int index, qint64 duration) void TimelineModel::insertEnd(int index, qint64 duration)
{ {
d->ranges[index].duration = duration; d->ranges[index].duration = duration;
d->insertEnd(TimelineModelPrivate::RangeEnd(index, d->ranges[index].start + duration)); int endIndex = d->insertEnd(TimelineModelPrivate::RangeEnd(index, d->ranges[index].start + duration));
d->setEndIndex(index, endIndex);
if (endIndex < d->endTimes.size() - 1)
d->incrementEndIndices(endIndex);
} }
bool TimelineModel::expanded() const bool TimelineModel::expanded() const

View File

@@ -30,13 +30,14 @@ public:
}; };
struct Range { struct Range {
Range() : start(-1), duration(-1), selectionId(-1), parent(-1) {} Range() : start(-1), duration(-1), selectionId(-1), parent(-1), endIndex(-1) {}
Range(qint64 start, qint64 duration, int selectionId) : Range(qint64 start, qint64 duration, int selectionId) :
start(start), duration(duration), selectionId(selectionId), parent(-1) {} start(start), duration(duration), selectionId(selectionId), parent(-1), endIndex(-1) {}
qint64 start; qint64 start;
qint64 duration; qint64 duration;
int selectionId; int selectionId;
int parent; int parent;
int endIndex;
inline qint64 timestamp() const {return start;} inline qint64 timestamp() const {return start;}
}; };
@@ -55,11 +56,21 @@ public:
void incrementStartIndices(int index) void incrementStartIndices(int index)
{ {
for (RangeEnd &endTime : endTimes) { for (index = index + 1; index < ranges.count(); index++) {
if (endTime.startIndex >= index) if (ranges[index].endIndex >= 0)
++(endTime.startIndex); endTimes[ranges[index].endIndex].startIndex++;
} }
} }
void incrementEndIndices(int index)
{
for (index = index + 1; index < endTimes.count(); index++)
ranges[endTimes[index].startIndex].endIndex++;
}
inline void setEndIndex(int index, int endIndex)
{
ranges[index].endIndex = endIndex;
}
inline int insertStart(const Range &start) inline int insertStart(const Range &start)
{ {

View File

@@ -1,6 +1,8 @@
// Copyright (C) 2022 The Qt Company Ltd. // Copyright (C) 2022 The Qt Company Ltd.
// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0+ OR GPL-3.0 WITH Qt-GPL-exception-1.0 // SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0+ OR GPL-3.0 WITH Qt-GPL-exception-1.0
#pragma once
#include "utils_global.h" #include "utils_global.h"
#include <QMap> #include <QMap>

View File

@@ -800,4 +800,26 @@ FilePaths FileUtils::toFilePathList(const QStringList &paths) {
} }
qint64 FileUtils::bytesAvailableFromDFOutput(const QByteArray &dfOutput)
{
const auto lines = filtered(dfOutput.split('\n'),
[](const QByteArray &line) { return line.size() > 0; });
QTC_ASSERT(lines.size() == 2, return -1);
const auto headers = filtered(lines[0].split(' '),
[](const QByteArray &field) { return field.size() > 0; });
QTC_ASSERT(headers.size() >= 4, return -1);
QTC_ASSERT(headers[3] == QByteArray("Available"), return -1);
const auto fields = filtered(lines[1].split(' '),
[](const QByteArray &field) { return field.size() > 0; });
QTC_ASSERT(fields.size() >= 4, return -1);
bool ok = false;
const quint64 result = QString::fromUtf8(fields[3]).toULongLong(&ok);
if (ok)
return result;
return -1;
}
} // namespace Utils } // namespace Utils

View File

@@ -82,6 +82,8 @@ public:
const FileFilter &filter, const FileFilter &filter,
const std::function<bool(const FilePath &)> &callBack); const std::function<bool(const FilePath &)> &callBack);
static qint64 bytesAvailableFromDFOutput(const QByteArray &dfOutput);
#ifdef QT_WIDGETS_LIB #ifdef QT_WIDGETS_LIB
static void setDialogParentGetter(const std::function<QWidget *()> &getter); static void setDialogParentGetter(const std::function<QWidget *()> &getter);

View File

@@ -61,7 +61,7 @@ QStringList GTestConfiguration::argumentsForTestRunner(QStringList *omitted) con
const QStringList &testSets = testCases(); const QStringList &testSets = testCases();
if (!testSets.isEmpty()) if (!testSets.isEmpty())
arguments << "--gtest_filter=" + testSets.join(':'); arguments << "--gtest_filter=\"" + testSets.join(':') + '"';
auto gSettings = static_cast<GTestSettings *>(framework()->testSettings()); auto gSettings = static_cast<GTestSettings *>(framework()->testSettings());
if (!gSettings) if (!gSettings)

View File

@@ -329,7 +329,7 @@ void CompilerOptionsBuilder::insertWrappedHeaders(const QStringList &relPaths)
static const QString baseDir = creatorResourcePath() + "/cplusplus"; static const QString baseDir = creatorResourcePath() + "/cplusplus";
const QString fullPath = baseDir + '/' + relPath; const QString fullPath = baseDir + '/' + relPath;
QTC_ASSERT(QDir(fullPath).exists(), continue); QTC_ASSERT(QDir(fullPath).exists(), continue);
args << includeUserPathOption << QDir::toNativeSeparators(fullPath); args << (includeUserPathOption + QDir::toNativeSeparators(fullPath));
} }
const int index = m_options.indexOf(QRegularExpression("\\A-I.*\\z")); const int index = m_options.indexOf(QRegularExpression("\\A-I.*\\z"));
@@ -686,7 +686,7 @@ void CompilerOptionsBuilder::addIncludeDirOptionForPath(const HeaderPath &path)
return; return;
} }
add({includeUserPathOption, QDir::toNativeSeparators(path.path)}); add(includeUserPathOption + QDir::toNativeSeparators(path.path));
} }
bool CompilerOptionsBuilder::excludeDefineDirective(const Macro &macro) const bool CompilerOptionsBuilder::excludeDefineDirective(const Macro &macro) const

View File

@@ -191,8 +191,8 @@ void CompilerOptionsBuilderTest::testHeaderPathOptionsOrder()
compilerOptionsBuilder.addHeaderPathOptions(); compilerOptionsBuilder.addHeaderPathOptions();
QCOMPARE(compilerOptionsBuilder.options(), QCOMPARE(compilerOptionsBuilder.options(),
(QStringList{"-nostdinc", "-nostdinc++", "-I", t.toNative("/tmp/path"), (QStringList{"-nostdinc", "-nostdinc++", "-I" + t.toNative("/tmp/path"),
"-I", t.toNative("/tmp/system_path"), "-isystem", t.toNative("/dummy"), "-I" + t.toNative("/tmp/system_path"), "-isystem", t.toNative("/dummy"),
"-isystem", t.toNative("/tmp/builtin_path")})); "-isystem", t.toNative("/tmp/builtin_path")}));
} }
@@ -207,8 +207,8 @@ void CompilerOptionsBuilderTest::testHeaderPathOptionsOrderMsvc()
compilerOptionsBuilder.addHeaderPathOptions(); compilerOptionsBuilder.addHeaderPathOptions();
QCOMPARE(compilerOptionsBuilder.options(), QCOMPARE(compilerOptionsBuilder.options(),
(QStringList{"-nostdinc", "-nostdinc++", "-I", t.toNative("/tmp/path"), (QStringList{"-nostdinc", "-nostdinc++", "-I" + t.toNative("/tmp/path"),
"-I", t.toNative("/tmp/system_path"), "/clang:-isystem", "-I" + t.toNative("/tmp/system_path"), "/clang:-isystem",
"/clang:" + t.toNative("/dummy"), "/clang:-isystem", "/clang:" + t.toNative("/dummy"), "/clang:-isystem",
"/clang:" + t.toNative("/tmp/builtin_path")})); "/clang:" + t.toNative("/tmp/builtin_path")}));
} }
@@ -222,7 +222,7 @@ void CompilerOptionsBuilderTest::testUseSystemHeader()
compilerOptionsBuilder.addHeaderPathOptions(); compilerOptionsBuilder.addHeaderPathOptions();
QCOMPARE(compilerOptionsBuilder.options(), QCOMPARE(compilerOptionsBuilder.options(),
(QStringList{"-nostdinc", "-nostdinc++", "-I", t.toNative("/tmp/path"), (QStringList{"-nostdinc", "-nostdinc++", "-I" + t.toNative("/tmp/path"),
"-isystem", t.toNative("/tmp/system_path"), "-isystem", t.toNative("/tmp/system_path"),
"-isystem", t.toNative("/dummy"), "-isystem", t.toNative("/dummy"),
"-isystem", t.toNative("/tmp/builtin_path")})); "-isystem", t.toNative("/tmp/builtin_path")}));
@@ -235,7 +235,7 @@ void CompilerOptionsBuilderTest::testNoClangHeadersPath()
t.compilerOptionsBuilder->addHeaderPathOptions(); t.compilerOptionsBuilder->addHeaderPathOptions();
QCOMPARE(t.compilerOptionsBuilder->options(), QCOMPARE(t.compilerOptionsBuilder->options(),
(QStringList{"-I", t.toNative("/tmp/path"), "-I", t.toNative("/tmp/system_path")})); (QStringList{"-I" + t.toNative("/tmp/path"), "-I" + t.toNative("/tmp/system_path")}));
} }
void CompilerOptionsBuilderTest::testClangHeadersAndCppIncludePathsOrderMacOs() void CompilerOptionsBuilderTest::testClangHeadersAndCppIncludePathsOrderMacOs()
@@ -255,8 +255,8 @@ void CompilerOptionsBuilderTest::testClangHeadersAndCppIncludePathsOrderMacOs()
compilerOptionsBuilder.addHeaderPathOptions(); compilerOptionsBuilder.addHeaderPathOptions();
QCOMPARE(compilerOptionsBuilder.options(), QCOMPARE(compilerOptionsBuilder.options(),
(QStringList{"-nostdinc", "-nostdinc++", "-I", t.toNative("/tmp/path"), (QStringList{"-nostdinc", "-nostdinc++", "-I" + t.toNative("/tmp/path"),
"-I", t.toNative("/tmp/system_path"), "-I" + t.toNative("/tmp/system_path"),
"-isystem", t.toNative("/usr/include/c++/4.2.1"), "-isystem", t.toNative("/usr/include/c++/4.2.1"),
"-isystem", t.toNative("/usr/include/c++/4.2.1/backward"), "-isystem", t.toNative("/usr/include/c++/4.2.1/backward"),
"-isystem", t.toNative("/usr/local/include"), "-isystem", t.toNative("/usr/local/include"),
@@ -588,10 +588,11 @@ void CompilerOptionsBuilderTest::testBuildAllOptions()
QCOMPARE(compilerOptionsBuilder.options(), QCOMPARE(compilerOptionsBuilder.options(),
(QStringList{"-nostdinc", "-nostdinc++", "-arch", "x86_64", "-fsyntax-only", "-m64", (QStringList{"-nostdinc", "-nostdinc++", "-arch", "x86_64", "-fsyntax-only", "-m64",
"--target=x86_64-apple-darwin10", "-x", "c++", "-std=c++17", "--target=x86_64-apple-darwin10", "-x", "c++", "-std=c++17",
"-DprojectFoo=projectBar", "-I", wrappedQtHeadersPath, "-DprojectFoo=projectBar",
"-I", wrappedQtCoreHeadersPath, wrappedQtHeadersPath, // contains -I already
"-I", t.toNative("/tmp/path"), wrappedQtCoreHeadersPath, // contains -I already
"-I", t.toNative("/tmp/system_path"), "-I" + t.toNative("/tmp/path"),
"-I" + t.toNative("/tmp/system_path"),
"-isystem", t.toNative("/dummy"), "-isystem", t.toNative("/dummy"),
"-isystem", t.toNative("/tmp/builtin_path")})); "-isystem", t.toNative("/tmp/builtin_path")}));
} }
@@ -616,10 +617,10 @@ void CompilerOptionsBuilderTest::testBuildAllOptionsMsvc()
"-D__FUNCSIG__=\"void __cdecl someLegalAndLongishFunctionNameThatWorksAroundQTCREATORBUG-24580(void)\"", "-D__FUNCSIG__=\"void __cdecl someLegalAndLongishFunctionNameThatWorksAroundQTCREATORBUG-24580(void)\"",
"-D__FUNCTION__=\"someLegalAndLongishFunctionNameThatWorksAroundQTCREATORBUG-24580\"", "-D__FUNCTION__=\"someLegalAndLongishFunctionNameThatWorksAroundQTCREATORBUG-24580\"",
"-D__FUNCDNAME__=\"?someLegalAndLongishFunctionNameThatWorksAroundQTCREATORBUG-24580@@YAXXZ\"", "-D__FUNCDNAME__=\"?someLegalAndLongishFunctionNameThatWorksAroundQTCREATORBUG-24580@@YAXXZ\"",
"-I", wrappedQtHeadersPath, wrappedQtHeadersPath, // contains -I already
"-I", wrappedQtCoreHeadersPath, wrappedQtCoreHeadersPath, // contains -I already
"-I", t.toNative("/tmp/path"), "-I" + t.toNative("/tmp/path"),
"-I", t.toNative("/tmp/system_path"), "-I" + t.toNative("/tmp/system_path"),
"/clang:-isystem", "/clang:" + t.toNative("/dummy"), "/clang:-isystem", "/clang:" + t.toNative("/dummy"),
"/clang:-isystem", "/clang:" + t.toNative("/tmp/builtin_path")})); "/clang:-isystem", "/clang:" + t.toNative("/tmp/builtin_path")}));
} }
@@ -646,10 +647,10 @@ void CompilerOptionsBuilderTest::testBuildAllOptionsMsvcWithExceptions()
"-D__FUNCSIG__=\"void __cdecl someLegalAndLongishFunctionNameThatWorksAroundQTCREATORBUG-24580(void)\"", "-D__FUNCSIG__=\"void __cdecl someLegalAndLongishFunctionNameThatWorksAroundQTCREATORBUG-24580(void)\"",
"-D__FUNCTION__=\"someLegalAndLongishFunctionNameThatWorksAroundQTCREATORBUG-24580\"", "-D__FUNCTION__=\"someLegalAndLongishFunctionNameThatWorksAroundQTCREATORBUG-24580\"",
"-D__FUNCDNAME__=\"?someLegalAndLongishFunctionNameThatWorksAroundQTCREATORBUG-24580@@YAXXZ\"", "-D__FUNCDNAME__=\"?someLegalAndLongishFunctionNameThatWorksAroundQTCREATORBUG-24580@@YAXXZ\"",
"-I", wrappedQtHeadersPath, wrappedQtHeadersPath, // contains -I already
"-I", wrappedQtCoreHeadersPath, wrappedQtCoreHeadersPath, // contains -I already
"-I", t.toNative("/tmp/path"), "-I" + t.toNative("/tmp/path"),
"-I", t.toNative("/tmp/system_path"), "-I" + t.toNative("/tmp/system_path"),
"/clang:-isystem", "/clang:" + t.toNative("/dummy"), "/clang:-isystem", "/clang:" + t.toNative("/dummy"),
"/clang:-isystem", "/clang:" + t.toNative("/tmp/builtin_path")})); "/clang:-isystem", "/clang:" + t.toNative("/tmp/builtin_path")}));
} }

View File

@@ -70,6 +70,7 @@ const char removeGroupItemCommandId[] = "RemoveToGroupItem";
const char fitRootToScreenCommandId[] = "FitRootToScreen"; const char fitRootToScreenCommandId[] = "FitRootToScreen";
const char fitSelectionToScreenCommandId[] = "FitSelectionToScreen"; const char fitSelectionToScreenCommandId[] = "FitSelectionToScreen";
const char editAnnotationCommandId[] = "EditAnnotation"; const char editAnnotationCommandId[] = "EditAnnotation";
const char addMouseAreaFillCommandId[] = "AddMouseAreaFill";
const char openSignalDialogCommandId[] = "OpenSignalDialog"; const char openSignalDialogCommandId[] = "OpenSignalDialog";
const char update3DAssetCommandId[] = "Update3DAsset"; const char update3DAssetCommandId[] = "Update3DAsset";
@@ -115,6 +116,7 @@ const char addSignalHandlerDisplayName[] = QT_TRANSLATE_NOOP("QmlDesignerContext
const char moveToComponentDisplayName[] = QT_TRANSLATE_NOOP("QmlDesignerContextMenu", "Move Component into Separate File"); const char moveToComponentDisplayName[] = QT_TRANSLATE_NOOP("QmlDesignerContextMenu", "Move Component into Separate File");
const char editMaterialDisplayName[] = QT_TRANSLATE_NOOP("QmlDesignerContextMenu", "Edit Material"); const char editMaterialDisplayName[] = QT_TRANSLATE_NOOP("QmlDesignerContextMenu", "Edit Material");
const char editAnnotationDisplayName[] = QT_TRANSLATE_NOOP("QmlDesignerContextMenu", "Edit Annotation"); const char editAnnotationDisplayName[] = QT_TRANSLATE_NOOP("QmlDesignerContextMenu", "Edit Annotation");
const char addMouseAreaFillDisplayName[] = QT_TRANSLATE_NOOP("QmlDesignerContextMenu", "Add Mouse Area");
const char openSignalDialogDisplayName[] = QT_TRANSLATE_NOOP("QmlDesignerContextMenu", "Open Signal Dialog"); const char openSignalDialogDisplayName[] = QT_TRANSLATE_NOOP("QmlDesignerContextMenu", "Open Signal Dialog");
const char update3DAssetDisplayName[] = QT_TRANSLATE_NOOP("QmlDesignerContextMenu", "Update 3D Asset"); const char update3DAssetDisplayName[] = QT_TRANSLATE_NOOP("QmlDesignerContextMenu", "Update 3D Asset");

View File

@@ -1449,6 +1449,17 @@ void DesignerActionManager::createDefaultDesignerActions()
&singleSelection, &singleSelection,
&singleSelection)); &singleSelection));
addDesignerAction(new ModelNodeContextMenuAction(
addMouseAreaFillCommandId,
addMouseAreaFillDisplayName,
{},
rootCategory,
QKeySequence(),
(priorityLast+7),
&addMouseAreaFill,
&addMouseAreaFillCheck,
&singleSelection));
const bool standaloneMode = QmlProjectManager::QmlProject::isQtDesignStudio(); const bool standaloneMode = QmlProjectManager::QmlProject::isQtDesignStudio();
if (!standaloneMode) { if (!standaloneMode) {

View File

@@ -42,6 +42,18 @@ inline bool singleSelection(const SelectionContext &selectionState)
return selectionState.singleNodeIsSelected(); return selectionState.singleNodeIsSelected();
} }
inline bool addMouseAreaFillCheck(const SelectionContext &selectionContext)
{
if (selectionContext.isValid() && selectionContext.singleNodeIsSelected()) {
ModelNode node = selectionContext.currentSingleSelectedNode();
if (node.hasMetaInfo()) {
NodeMetaInfo nodeInfo = node.metaInfo();
return nodeInfo.isSuitableForMouseAreaFill();
}
}
return false;
}
inline bool isModel(const SelectionContext &selectionState) inline bool isModel(const SelectionContext &selectionState)
{ {
ModelNode node = selectionState.currentSingleSelectedNode(); ModelNode node = selectionState.currentSingleSelectedNode();

View File

@@ -1616,6 +1616,34 @@ void editAnnotation(const SelectionContext &selectionContext)
ModelNodeEditorProxy::fromModelNode<AnnotationEditor>(selectedNode); ModelNodeEditorProxy::fromModelNode<AnnotationEditor>(selectedNode);
} }
void addMouseAreaFill(const SelectionContext &selectionContext)
{
if (!selectionContext.isValid()) {
return;
}
if (!selectionContext.singleNodeIsSelected()) {
return;
}
selectionContext.view()->executeInTransaction("DesignerActionManager|addMouseAreaFill", [selectionContext]() {
ModelNode modelNode = selectionContext.currentSingleSelectedNode();
if (modelNode.isValid()) {
NodeMetaInfo itemMetaInfo = selectionContext.view()->model()->metaInfo("QtQuick.MouseArea", -1, -1);
QTC_ASSERT(itemMetaInfo.isValid(), return);
QmlDesigner::ModelNode mouseAreaNode =
selectionContext.view()->createModelNode("QtQuick.MouseArea", itemMetaInfo.majorVersion(), itemMetaInfo.minorVersion());
modelNode.defaultNodeListProperty().reparentHere(mouseAreaNode);
QmlItemNode mouseAreaItemNode(mouseAreaNode);
if (mouseAreaItemNode.isValid()) {
mouseAreaItemNode.anchors().fill();
}
}
});
}
QVariant previewImageDataForGenericNode(const ModelNode &modelNode) QVariant previewImageDataForGenericNode(const ModelNode &modelNode)
{ {
if (modelNode.isValid()) if (modelNode.isValid())

View File

@@ -71,6 +71,7 @@ void selectFlowEffect(const SelectionContext &selectionContext);
void mergeWithTemplate(const SelectionContext &selectionContext); void mergeWithTemplate(const SelectionContext &selectionContext);
void removeGroup(const SelectionContext &selectionContext); void removeGroup(const SelectionContext &selectionContext);
void editAnnotation(const SelectionContext &selectionContext); void editAnnotation(const SelectionContext &selectionContext);
void addMouseAreaFill(const SelectionContext &selectionContext);
void openSignalDialog(const SelectionContext &selectionContext); void openSignalDialog(const SelectionContext &selectionContext);
void updateImported3DAsset(const SelectionContext &selectionContext); void updateImported3DAsset(const SelectionContext &selectionContext);

View File

@@ -89,6 +89,8 @@ void ConnectionView::propertiesRemoved(const QList<AbstractProperty> &propertyLi
for (const AbstractProperty &property : propertyList) { for (const AbstractProperty &property : propertyList) {
if (property.isDefaultProperty()) if (property.isDefaultProperty())
connectionModel()->resetModel(); connectionModel()->resetModel();
dynamicPropertiesModel()->dispatchPropertyChanges(property);
} }
} }
@@ -116,8 +118,9 @@ void ConnectionView::variantPropertiesChanged(const QList<VariantProperty> &prop
backendModel()->resetModel(); backendModel()->resetModel();
connectionModel()->variantPropertyChanged(variantProperty); connectionModel()->variantPropertyChanged(variantProperty);
}
dynamicPropertiesModel()->dispatchPropertyChanges(variantProperty);
}
} }
void ConnectionView::bindingPropertiesChanged(const QList<BindingProperty> &propertyList, void ConnectionView::bindingPropertiesChanged(const QList<BindingProperty> &propertyList,
@@ -131,6 +134,8 @@ void ConnectionView::bindingPropertiesChanged(const QList<BindingProperty> &prop
backendModel()->resetModel(); backendModel()->resetModel();
connectionModel()->bindingPropertyChanged(bindingProperty); connectionModel()->bindingPropertyChanged(bindingProperty);
dynamicPropertiesModel()->dispatchPropertyChanges(bindingProperty);
} }
} }

View File

@@ -5,14 +5,14 @@
#include "connectionview.h" #include "connectionview.h"
#include <bindingproperty.h>
#include <nodemetainfo.h> #include <nodemetainfo.h>
#include <nodeproperty.h> #include <nodeproperty.h>
#include <variantproperty.h>
#include <bindingproperty.h>
#include <rewritingexception.h>
#include <rewritertransaction.h> #include <rewritertransaction.h>
#include <qmldesignerplugin.h> #include <rewritingexception.h>
#include <variantproperty.h>
#include <qmldesignerconstants.h> #include <qmldesignerconstants.h>
#include <qmldesignerplugin.h>
#include <utils/algorithm.h> #include <utils/algorithm.h>
#include <utils/fileutils.h> #include <utils/fileutils.h>
@@ -117,6 +117,44 @@ bool DynamicPropertiesModel::isValueType(const TypeName &type)
return valueTypes.contains(type); return valueTypes.contains(type);
} }
QVariant DynamicPropertiesModel::defaultValueForType(const TypeName &type)
{
QVariant value;
if (type == "int")
value = 0;
else if (type == "real")
value = 0.0;
else if (type == "color")
value = QColor(255, 255, 255);
else if (type == "string")
value = "This is a string";
else if (type == "bool")
value = false;
else if (type == "url")
value = "";
else if (type == "variant")
value = "";
return value;
}
QString DynamicPropertiesModel::defaultExpressionForType(const TypeName &type)
{
QString expression;
if (type == "alias")
expression = "null";
else if (type == "TextureInput")
expression = "null";
else if (type == "vector2d")
expression = "Qt.vector2d(0, 0)";
else if (type == "vector3d")
expression = "Qt.vector3d(0, 0, 0)";
else if (type == "vector4d")
expression = "Qt.vector4d(0, 0, 0 ,0)";
return expression;
}
DynamicPropertiesModel::DynamicPropertiesModel(bool explicitSelection, AbstractView *parent) DynamicPropertiesModel::DynamicPropertiesModel(bool explicitSelection, AbstractView *parent)
: QStandardItemModel(parent) : QStandardItemModel(parent)
, m_view(parent) , m_view(parent)
@@ -217,6 +255,20 @@ void DynamicPropertiesModel::resetProperty(const PropertyName &name)
} }
} }
void DynamicPropertiesModel::dispatchPropertyChanges(const AbstractProperty &abstractProperty)
{
if (abstractProperty.parentModelNode().simplifiedTypeName() == "PropertyChanges") {
QmlPropertyChanges changes(abstractProperty.parentModelNode());
if (changes.target().isValid()) {
const ModelNode target = changes.target();
const PropertyName propertyName = abstractProperty.name();
const AbstractProperty targetProperty = target.variantProperty(propertyName);
if (target.hasProperty(propertyName) && targetProperty.isDynamic())
abstractPropertyChanged(targetProperty);
}
}
}
void DynamicPropertiesModel::bindingPropertyChanged(const BindingProperty &bindingProperty) void DynamicPropertiesModel::bindingPropertyChanged(const BindingProperty &bindingProperty)
{ {
if (!bindingProperty.isDynamic()) if (!bindingProperty.isDynamic())
@@ -240,6 +292,27 @@ void DynamicPropertiesModel::bindingPropertyChanged(const BindingProperty &bindi
m_handleDataChanged = true; m_handleDataChanged = true;
} }
void DynamicPropertiesModel::abstractPropertyChanged(const AbstractProperty &property)
{
if (!property.isDynamic())
return;
m_handleDataChanged = false;
const QList<ModelNode> nodes = selectedNodes();
if (!nodes.contains(property.parentModelNode()))
return;
int rowNumber = findRowForProperty(property);
if (rowNumber > -1) {
if (property.isVariantProperty())
updateVariantProperty(rowNumber);
else
updateBindingProperty(rowNumber);
}
m_handleDataChanged = true;
}
void DynamicPropertiesModel::variantPropertyChanged(const VariantProperty &variantProperty) void DynamicPropertiesModel::variantPropertyChanged(const VariantProperty &variantProperty)
{ {
if (!variantProperty.isDynamic()) if (!variantProperty.isDynamic())
@@ -312,7 +385,8 @@ void DynamicPropertiesModel::setSelectedNode(const ModelNode &node)
AbstractProperty DynamicPropertiesModel::abstractPropertyForRow(int rowNumber) const AbstractProperty DynamicPropertiesModel::abstractPropertyForRow(int rowNumber) const
{ {
const int internalId = data(index(rowNumber, TargetModelNodeRow), Qt::UserRole + 1).toInt(); const int internalId = data(index(rowNumber, TargetModelNodeRow), Qt::UserRole + 1).toInt();
const QString targetPropertyName = data(index(rowNumber, TargetModelNodeRow), Qt::UserRole + 2).toString(); const QString targetPropertyName = data(index(rowNumber, TargetModelNodeRow), Qt::UserRole + 2)
.toString();
if (!m_view->isAttached()) if (!m_view->isAttached())
return AbstractProperty(); return AbstractProperty();
@@ -383,7 +457,7 @@ void DynamicPropertiesModel::addDynamicPropertyForCurrentNode()
const ModelNode modelNode = selectedNodes().constFirst(); const ModelNode modelNode = selectedNodes().constFirst();
if (modelNode.isValid()) { if (modelNode.isValid()) {
try { try {
modelNode.variantProperty(unusedProperty(modelNode)).setDynamicTypeNameAndValue("string", QLatin1String("none.none")); modelNode.variantProperty(unusedProperty(modelNode)).setDynamicTypeNameAndValue("string", "This is a string");
} catch (RewritingException &e) { } catch (RewritingException &e) {
m_exceptionError = e.description(); m_exceptionError = e.description();
QTimer::singleShot(200, this, &DynamicPropertiesModel::handleException); QTimer::singleShot(200, this, &DynamicPropertiesModel::handleException);
@@ -434,7 +508,10 @@ QStringList DynamicPropertiesModel::possibleSourceProperties(const BindingProper
void DynamicPropertiesModel::deleteDynamicPropertyByRow(int rowNumber) void DynamicPropertiesModel::deleteDynamicPropertyByRow(int rowNumber)
{ {
m_view->executeInTransaction("DynamicPropertiesModel::deleteDynamicPropertyByRow", [this, rowNumber]() { m_view->executeInTransaction(
"DynamicPropertiesModel::deleteDynamicPropertyByRow", [this, rowNumber]() {
const AbstractProperty property = abstractPropertyForRow(rowNumber);
const PropertyName propertyName = property.name();
BindingProperty bindingProperty = bindingPropertyForRow(rowNumber); BindingProperty bindingProperty = bindingPropertyForRow(rowNumber);
if (bindingProperty.isValid()) { if (bindingProperty.isValid()) {
bindingProperty.parentModelNode().removeProperty(bindingProperty.name()); bindingProperty.parentModelNode().removeProperty(bindingProperty.name());
@@ -443,6 +520,22 @@ void DynamicPropertiesModel::deleteDynamicPropertyByRow(int rowNumber)
if (variantProperty.isValid()) if (variantProperty.isValid())
variantProperty.parentModelNode().removeProperty(variantProperty.name()); variantProperty.parentModelNode().removeProperty(variantProperty.name());
} }
if (property.isValid()) {
QmlObjectNode objectNode = QmlObjectNode(property.parentModelNode());
const auto stateOperations = objectNode.allAffectingStatesOperations();
for (const QmlModelStateOperation &stateOperation : stateOperations) {
if (stateOperation.modelNode().hasProperty(propertyName))
stateOperation.modelNode().removeProperty(propertyName);
}
const auto timelineNodes = objectNode.allTimelines();
for (auto &timelineNode : timelineNodes) {
QmlTimeline timeline(timelineNode);
timeline.removeKeyframesForTargetAndProperty(objectNode.modelNode(),
propertyName);
}
}
}); });
resetModel(); resetModel();
@@ -502,6 +595,12 @@ void DynamicPropertiesModel::updateBindingProperty(int rowNumber)
QString type = QString::fromUtf8(bindingProperty.dynamicTypeName()); QString type = QString::fromUtf8(bindingProperty.dynamicTypeName());
updateDisplayRole(rowNumber, PropertyTypeRow, type); updateDisplayRole(rowNumber, PropertyTypeRow, type);
updateDisplayRole(rowNumber, PropertyValueRow, value); updateDisplayRole(rowNumber, PropertyValueRow, value);
const QmlObjectNode objectNode = QmlObjectNode(bindingProperty.parentModelNode());
if (objectNode.isValid() && !objectNode.view()->currentState().isBaseState())
value = objectNode.expression(bindingProperty.name());
updateDisplayRole(rowNumber, PropertyValueRow, value);
} }
} }
@@ -515,6 +614,10 @@ void DynamicPropertiesModel::updateVariantProperty(int rowNumber)
QVariant value = variantProperty.value(); QVariant value = variantProperty.value();
QString type = QString::fromUtf8(variantProperty.dynamicTypeName()); QString type = QString::fromUtf8(variantProperty.dynamicTypeName());
updateDisplayRole(rowNumber, PropertyTypeRow, type); updateDisplayRole(rowNumber, PropertyTypeRow, type);
const QmlObjectNode objectNode = QmlObjectNode(variantProperty.parentModelNode());
if (objectNode.isValid() && !objectNode.view()->currentState().isBaseState())
value = objectNode.modelValue(variantProperty.name());
updateDisplayRoleFromVariant(rowNumber, PropertyValueRow, value); updateDisplayRoleFromVariant(rowNumber, PropertyValueRow, value);
} }
@@ -525,16 +628,21 @@ void DynamicPropertiesModel::addModelNode(const ModelNode &modelNode)
if (!modelNode.isValid()) if (!modelNode.isValid())
return; return;
const QList<BindingProperty> bindingProperties = modelNode.bindingProperties(); auto properties = modelNode.properties();
for (const BindingProperty &bindingProperty : bindingProperties) {
if (bindingProperty.isDynamic())
addBindingProperty(bindingProperty);
}
const QList<VariantProperty> variantProperties = modelNode.variantProperties(); auto dynamicProperties = Utils::filtered(properties, [](const AbstractProperty &p) {
for (const VariantProperty &variantProperty : variantProperties) { return p.isDynamic();
if (variantProperty.isDynamic()) });
addVariantProperty(variantProperty);
Utils::sort(dynamicProperties, [](const AbstractProperty &a, const AbstractProperty &b) {
return a.name() < b.name();
});
for (const AbstractProperty &property : qAsConst(dynamicProperties)) {
if (property.isBindingProperty())
addBindingProperty(property.toBindingProperty());
else if (property.isVariantProperty())
addVariantProperty(property.toVariantProperty());
} }
} }
@@ -713,6 +821,16 @@ int DynamicPropertiesModel::findRowForVariantProperty(const VariantProperty &var
return -1; return -1;
} }
int DynamicPropertiesModel::findRowForProperty(const AbstractProperty &abstractProperty) const
{
for (int i = 0; i < rowCount(); i++) {
if ((abstractPropertyForRow(i).name() == abstractProperty.name()))
return i;
}
//not found
return -1;
}
bool DynamicPropertiesModel::getExpressionStrings(const BindingProperty &bindingProperty, QString *sourceNode, QString *sourceProperty) bool DynamicPropertiesModel::getExpressionStrings(const BindingProperty &bindingProperty, QString *sourceNode, QString *sourceProperty)
{ {
//### todo we assume no expressions yet //### todo we assume no expressions yet

View File

@@ -28,6 +28,7 @@ public:
}; };
DynamicPropertiesModel(bool explicitSelection, AbstractView *parent); DynamicPropertiesModel(bool explicitSelection, AbstractView *parent);
void bindingPropertyChanged(const BindingProperty &bindingProperty); void bindingPropertyChanged(const BindingProperty &bindingProperty);
void abstractPropertyChanged(const AbstractProperty &bindingProperty);
void variantPropertyChanged(const VariantProperty &variantProperty); void variantPropertyChanged(const VariantProperty &variantProperty);
void bindingRemoved(const BindingProperty &bindingProperty); void bindingRemoved(const BindingProperty &bindingProperty);
void variantRemoved(const VariantProperty &variantProperty); void variantRemoved(const VariantProperty &variantProperty);
@@ -51,9 +52,13 @@ public:
BindingProperty replaceVariantWithBinding(const PropertyName &name, bool copyValue = false); BindingProperty replaceVariantWithBinding(const PropertyName &name, bool copyValue = false);
void resetProperty(const PropertyName &name); void resetProperty(const PropertyName &name);
void dispatchPropertyChanges(const AbstractProperty &abstractProperty);
QmlDesigner::PropertyName unusedProperty(const QmlDesigner::ModelNode &modelNode); QmlDesigner::PropertyName unusedProperty(const QmlDesigner::ModelNode &modelNode);
static bool isValueType(const TypeName &type); static bool isValueType(const TypeName &type);
static QVariant defaultValueForType(const TypeName &type);
static QString defaultExpressionForType(const TypeName &type);
protected: protected:
void addProperty(const QVariant &propertyValue, void addProperty(const QVariant &propertyValue,
@@ -72,6 +77,7 @@ protected:
void updateCustomData(int row, const AbstractProperty &property); void updateCustomData(int row, const AbstractProperty &property);
int findRowForBindingProperty(const BindingProperty &bindingProperty) const; int findRowForBindingProperty(const BindingProperty &bindingProperty) const;
int findRowForVariantProperty(const VariantProperty &variantProperty) const; int findRowForVariantProperty(const VariantProperty &variantProperty) const;
int findRowForProperty(const AbstractProperty &abstractProperty) const;
bool getExpressionStrings(const BindingProperty &bindingProperty, QString *sourceNode, QString *sourceProperty); bool getExpressionStrings(const BindingProperty &bindingProperty, QString *sourceNode, QString *sourceProperty);

View File

@@ -268,15 +268,16 @@ void Edit3DView::customNotification([[maybe_unused]] const AbstractView *view,
* Response from puppet process for the model at requested position * Response from puppet process for the model at requested position
* *
* @param modelNode Node picked at the requested position or invalid node if nothing could be picked * @param modelNode Node picked at the requested position or invalid node if nothing could be picked
* @param pos3d 3D scene position of the requested view position
*/ */
void Edit3DView::nodeAtPosReady(const ModelNode &modelNode) void Edit3DView::nodeAtPosReady(const ModelNode &modelNode, const QVector3D &pos3d)
{ {
if (m_nodeAtPosReqType == NodeAtPosReqType::ContextMenu) { if (m_nodeAtPosReqType == NodeAtPosReqType::ContextMenu) {
// Make sure right-clicked item is selected. Due to a bug in puppet side right-clicking an item // Make sure right-clicked item is selected. Due to a bug in puppet side right-clicking an item
// while the context-menu is shown doesn't select the item. // while the context-menu is shown doesn't select the item.
if (modelNode.isValid() && !modelNode.isSelected()) if (modelNode.isValid() && !modelNode.isSelected())
setSelectedModelNode(modelNode); setSelectedModelNode(modelNode);
m_edit3DWidget->showContextMenu(m_contextMenuPos, modelNode); m_edit3DWidget->showContextMenu(m_contextMenuPos, modelNode, pos3d);
} else if (m_nodeAtPosReqType == NodeAtPosReqType::MaterialDrop) { } else if (m_nodeAtPosReqType == NodeAtPosReqType::MaterialDrop) {
// TODO: this is from 8.0 branch that doesn't apply anymore: // TODO: this is from 8.0 branch that doesn't apply anymore:
// const bool isModel = modelNode.isSubclassOf("QtQuick3D.Model"); // const bool isModel = modelNode.isSubclassOf("QtQuick3D.Model");

View File

@@ -41,7 +41,7 @@ public:
void modelAboutToBeDetached(Model *model) override; void modelAboutToBeDetached(Model *model) override;
void importsChanged(const QList<Import> &addedImports, const QList<Import> &removedImports) override; void importsChanged(const QList<Import> &addedImports, const QList<Import> &removedImports) override;
void customNotification(const AbstractView *view, const QString &identifier, const QList<ModelNode> &nodeList, const QList<QVariant> &data) override; void customNotification(const AbstractView *view, const QString &identifier, const QList<ModelNode> &nodeList, const QList<QVariant> &data) override;
void nodeAtPosReady(const ModelNode &modelNode) override; void nodeAtPosReady(const ModelNode &modelNode, const QVector3D &pos3d) override;
void sendInputEvent(QInputEvent *e) const; void sendInputEvent(QInputEvent *e) const;
void edit3DViewResized(const QSize &size) const; void edit3DViewResized(const QSize &size) const;

View File

@@ -215,7 +215,7 @@ void Edit3DWidget::onCreateAction()
// int activeScene = m_view->rootModelNode().auxiliaryData("active3dScene@Internal").toInt(); // int activeScene = m_view->rootModelNode().auxiliaryData("active3dScene@Internal").toInt();
// auto modelNode = QmlVisualNode::createQml3DNode(m_view, m_nameToEntry.value(action->data().toString()), // auto modelNode = QmlVisualNode::createQml3DNode(m_view, m_nameToEntry.value(action->data().toString()),
// activeScene).modelNode(); // activeScene, m_contextMenuPos3d).modelNode();
// QTC_ASSERT(modelNode.isValid(), return); // QTC_ASSERT(modelNode.isValid(), return);
// m_view->setSelectedModelNode(modelNode); // m_view->setSelectedModelNode(modelNode);
@@ -273,9 +273,10 @@ void Edit3DWidget::showBackgroundColorMenu(bool show, const QPoint &pos)
m_backgroundColorMenu->close(); m_backgroundColorMenu->close();
} }
void Edit3DWidget::showContextMenu(const QPoint &pos, const ModelNode &modelNode) void Edit3DWidget::showContextMenu(const QPoint &pos, const ModelNode &modelNode, const QVector3D &pos3d)
{ {
m_contextMenuTarget = modelNode; m_contextMenuTarget = modelNode;
m_contextMenuPos3d = pos3d;
const bool isValid = modelNode.isValid(); const bool isValid = modelNode.isValid();
// TODO: this is from 8.0 branch that doesn't apply anymore: // TODO: this is from 8.0 branch that doesn't apply anymore:

View File

@@ -5,6 +5,7 @@
#include <QLabel> #include <QLabel>
#include <QMenu> #include <QMenu>
#include <QPointer> #include <QPointer>
#include <QVector3D>
#include <QWidget> #include <QWidget>
#include <coreplugin/icontext.h> #include <coreplugin/icontext.h>
@@ -35,7 +36,7 @@ public:
QMenu *backgroundColorMenu() const; QMenu *backgroundColorMenu() const;
void showBackgroundColorMenu(bool show, const QPoint &pos); void showBackgroundColorMenu(bool show, const QPoint &pos);
void showContextMenu(const QPoint &pos, const ModelNode &modelNode); void showContextMenu(const QPoint &pos, const ModelNode &modelNode, const QVector3D &pos3d);
void updateCreateSubMenu(const QStringList &keys, void updateCreateSubMenu(const QStringList &keys,
const QHash<QString, QList<ItemLibraryEntry>> &entriesMap); const QHash<QString, QList<ItemLibraryEntry>> &entriesMap);
@@ -63,6 +64,7 @@ private:
QPointer<QAction> m_deleteAction; QPointer<QAction> m_deleteAction;
QPointer<QMenu> m_createSubMenu; QPointer<QMenu> m_createSubMenu;
ModelNode m_contextMenuTarget; ModelNode m_contextMenuTarget;
QVector3D m_contextMenuPos3d;
QHash<QString, ItemLibraryEntry> m_nameToEntry; QHash<QString, ItemLibraryEntry> m_nameToEntry;
}; };

View File

@@ -799,6 +799,8 @@ void MaterialEditorView::propertiesRemoved(const QList<AbstractProperty> &proper
setValue(m_selectedMaterial, property.name(), QmlObjectNode(m_selectedMaterial).instanceValue(property.name())); setValue(m_selectedMaterial, property.name(), QmlObjectNode(m_selectedMaterial).instanceValue(property.name()));
changed = true; changed = true;
} }
dynamicPropertiesModel()->dispatchPropertyChanges(property);
} }
if (changed) if (changed)
requestPreviewRender(); requestPreviewRender();
@@ -822,6 +824,8 @@ void MaterialEditorView::variantPropertiesChanged(const QList<VariantProperty> &
changed = true; changed = true;
} }
dynamicPropertiesModel()->dispatchPropertyChanges(property);
} }
if (changed) if (changed)
requestPreviewRender(); requestPreviewRender();
@@ -849,6 +853,8 @@ void MaterialEditorView::bindingPropertiesChanged(const QList<BindingProperty> &
changed = true; changed = true;
} }
dynamicPropertiesModel()->dispatchPropertyChanges(property);
} }
if (changed) if (changed)
requestPreviewRender(); requestPreviewRender();

View File

@@ -106,8 +106,10 @@ QVariant DynamicPropertiesProxyModel::data(const QModelIndex &index, int role) c
QmlObjectNode objectNode = property.parentQmlObjectNode(); QmlObjectNode objectNode = property.parentQmlObjectNode();
return objectNode.modelValue(property.name()); return objectNode.modelValue(property.name());
} else if (role == propertyBindingRole) { } else if (role == propertyBindingRole) {
if (property.isBindingProperty()) if (property.isBindingProperty()) {
return property.toBindingProperty().expression(); QmlObjectNode objectNode = property.parentQmlObjectNode();
return objectNode.expression(property.name());
}
return QVariant(); return QVariant();
} }
qWarning() << Q_FUNC_INFO << "invalid role"; qWarning() << Q_FUNC_INFO << "invalid role";
@@ -142,45 +144,23 @@ void DynamicPropertiesProxyModel::createProperty(const QString &name, const QStr
{ {
QmlDesignerPlugin::emitUsageStatistics(Constants::EVENT_PROPERTY_ADDED); QmlDesignerPlugin::emitUsageStatistics(Constants::EVENT_PROPERTY_ADDED);
TypeName typeName = type.toUtf8();
const auto selectedNodes = dynamicPropertiesModel()->selectedNodes(); const auto selectedNodes = dynamicPropertiesModel()->selectedNodes();
if (selectedNodes.count() == 1) { if (selectedNodes.count() == 1) {
const ModelNode modelNode = selectedNodes.constFirst(); const ModelNode modelNode = selectedNodes.constFirst();
if (modelNode.isValid()) { if (modelNode.isValid()) {
try { try {
if (Internal::DynamicPropertiesModel::isValueType(type.toUtf8())) { if (Internal::DynamicPropertiesModel::isValueType(typeName)) {
QVariant value; QVariant value = Internal::DynamicPropertiesModel::defaultValueForType(typeName);
if (type == "int")
value = 0;
else if (type == "real")
value = 0.0;
else if (type == "color")
value = QColor(255, 255, 255);
else if (type == "string")
value = "";
else if (type == "bool")
value = false;
else if (type == "url")
value = "";
else if (type == "variant")
value = "";
modelNode.variantProperty(name.toUtf8()) modelNode.variantProperty(name.toUtf8())
.setDynamicTypeNameAndValue(type.toUtf8(), value); .setDynamicTypeNameAndValue(typeName, value);
} else { } else {
QString expression; QString expression = Internal::DynamicPropertiesModel::defaultExpressionForType(
if (type == "alias") typeName);
expression = "null";
else if (type == "TextureInput")
expression = "null";
else if (type == "vector2d")
expression = "Qt.vector2d(0, 0)";
else if (type == "vector3d")
expression = "Qt.vector3d(0, 0, 0)";
else if (type == "vector4d")
expression = "Qt.vector4d(0, 0, 0 ,0)";
modelNode.bindingProperty(name.toUtf8()) modelNode.bindingProperty(name.toUtf8())
.setDynamicTypeNameAndExpression(type.toUtf8(), expression); .setDynamicTypeNameAndExpression(typeName, expression);
} }
} catch (Exception &e) { } catch (Exception &e) {
e.showException(); e.showException();
@@ -203,7 +183,12 @@ DynamicPropertyRow::DynamicPropertyRow()
QObject::connect(m_backendValue, QObject::connect(m_backendValue,
&PropertyEditorValue::expressionChanged, &PropertyEditorValue::expressionChanged,
this, this,
[this](const QString &) { commitExpression(m_backendValue->expression()); }); [this](const QString &name) {
if (!name.isEmpty()) //If name is empty the notifer is only for QML
commitExpression(m_backendValue->expression());
else if (m_backendValue->expression().isEmpty())
resetValue();
});
} }
DynamicPropertyRow::~DynamicPropertyRow() DynamicPropertyRow::~DynamicPropertyRow()
@@ -301,13 +286,16 @@ void DynamicPropertyRow::setupBackendValue()
m_backendValue->setModelNode(node); m_backendValue->setModelNode(node);
QVariant modelValue = property.parentQmlObjectNode().modelValue(property.name()); QVariant modelValue = property.parentQmlObjectNode().modelValue(property.name());
const bool isBound = property.parentQmlObjectNode().hasBindingProperty(property.name());
if (modelValue != m_backendValue->value()) { if (modelValue != m_backendValue->value()) {
m_backendValue->setValue({}); m_backendValue->setValue({});
m_backendValue->setValue(modelValue); m_backendValue->setValue(modelValue);
} }
if (property.isBindingProperty()) { if (isBound) {
QString expression = property.toBindingProperty().expression(); QString expression = property.parentQmlObjectNode().expression(property.name());
if (m_backendValue->expression() != expression) if (m_backendValue->expression() != expression)
m_backendValue->setExpression(expression); m_backendValue->setExpression(expression);
} }
@@ -323,6 +311,9 @@ void DynamicPropertyRow::commitValue(const QVariant &value)
if (m_row < 0) if (m_row < 0)
return; return;
if (!value.isValid())
return;
auto propertiesModel = m_model->dynamicPropertiesModel(); auto propertiesModel = m_model->dynamicPropertiesModel();
VariantProperty variantProperty = propertiesModel->variantPropertyForRow(m_row); VariantProperty variantProperty = propertiesModel->variantPropertyForRow(m_row);
@@ -336,11 +327,11 @@ void DynamicPropertyRow::commitValue(const QVariant &value)
RewriterTransaction transaction = view->beginRewriterTransaction( RewriterTransaction transaction = view->beginRewriterTransaction(
QByteArrayLiteral("DynamicPropertiesModel::commitValue")); QByteArrayLiteral("DynamicPropertiesModel::commitValue"));
try { try {
if (view->currentState().isBaseState()) { QmlObjectNode objectNode = variantProperty.parentQmlObjectNode();
if (view->currentState().isBaseState() && !objectNode.timelineIsActive()) {
if (variantProperty.value() != value) if (variantProperty.value() != value)
variantProperty.setDynamicTypeNameAndValue(variantProperty.dynamicTypeName(), value); variantProperty.setDynamicTypeNameAndValue(variantProperty.dynamicTypeName(), value);
} else { } else {
QmlObjectNode objectNode = variantProperty.parentQmlObjectNode();
QTC_CHECK(objectNode.isValid()); QTC_CHECK(objectNode.isValid());
PropertyName name = variantProperty.name(); PropertyName name = variantProperty.name();
if (objectNode.isValid() && objectNode.modelValue(name) != value) if (objectNode.isValid() && objectNode.modelValue(name) != value)
@@ -360,24 +351,43 @@ void DynamicPropertyRow::commitExpression(const QString &expression)
if (m_row < 0) if (m_row < 0)
return; return;
auto propertiesModel = m_model->dynamicPropertiesModel();
AbstractProperty property = propertiesModel->abstractPropertyForRow(m_row);
BindingProperty bindingProperty = property.parentModelNode().bindingProperty(property.name());
const QVariant literal = BindingProperty::convertToLiteral(bindingProperty.dynamicTypeName(),
expression);
if (literal.isValid()) { //If the string can be converted to a literal we set it as a literal/value
commitValue(literal);
return;
}
m_lock = true; m_lock = true;
auto unlock = qScopeGuard([this] { m_lock = false; }); auto unlock = qScopeGuard([this] { m_lock = false; });
auto propertiesModel = m_model->dynamicPropertiesModel();
BindingProperty bindingProperty = propertiesModel->bindingPropertyForRow(m_row);
auto view = propertiesModel->view(); auto view = propertiesModel->view();
RewriterTransaction transaction = view->beginRewriterTransaction( RewriterTransaction transaction = view->beginRewriterTransaction(
QByteArrayLiteral("DynamicPropertiesModel::commitExpression")); QByteArrayLiteral("DynamicPropertyRow::commitExpression"));
try { try {
QString theExpression = expression; QString theExpression = expression;
if (theExpression.isEmpty()) if (theExpression.isEmpty())
theExpression = "null"; theExpression = "null";
if (view->currentState().isBaseState()) {
if (bindingProperty.expression() != theExpression) { if (bindingProperty.expression() != theExpression) {
bindingProperty.setDynamicTypeNameAndExpression(bindingProperty.dynamicTypeName(), bindingProperty.setDynamicTypeNameAndExpression(bindingProperty.dynamicTypeName(),
theExpression); theExpression);
} }
} else {
QmlObjectNode objectNode = bindingProperty.parentQmlObjectNode();
QTC_CHECK(objectNode.isValid());
PropertyName name = bindingProperty.name();
if (objectNode.isValid() && objectNode.expression(name) != theExpression)
objectNode.setBindingProperty(name, theExpression);
}
transaction.commit(); //committing in the try block transaction.commit(); //committing in the try block
} catch (Exception &e) { } catch (Exception &e) {
e.showException(); e.showException();
@@ -390,3 +400,46 @@ void DynamicPropertyRow::handleDataChanged(const QModelIndex &topLeft, const QMo
if (topLeft.row() == m_row) if (topLeft.row() == m_row)
setupBackendValue(); setupBackendValue();
} }
void DynamicPropertyRow::resetValue()
{
if (m_lock)
return;
if (m_row < 0)
return;
auto propertiesModel = m_model->dynamicPropertiesModel();
auto view = propertiesModel->view();
AbstractProperty property = propertiesModel->abstractPropertyForRow(m_row);
TypeName typeName = property.dynamicTypeName();
if (view->currentState().isBaseState()) {
if (Internal::DynamicPropertiesModel::isValueType(typeName)) {
QVariant value = Internal::DynamicPropertiesModel::defaultValueForType(typeName);
commitValue(value);
} else {
QString expression = Internal::DynamicPropertiesModel::defaultExpressionForType(
typeName);
commitExpression(expression);
}
} else {
m_lock = true;
auto unlock = qScopeGuard([this] { m_lock = false; });
RewriterTransaction transaction = view->beginRewriterTransaction(
QByteArrayLiteral("DynamicPropertyRow::resetValue"));
try {
QmlObjectNode objectNode = property.parentQmlObjectNode();
QTC_CHECK(objectNode.isValid());
PropertyName name = property.name();
if (objectNode.isValid() && objectNode.propertyAffectedByCurrentState(name))
objectNode.removeProperty(name);
transaction.commit(); //committing in the try block
} catch (Exception &e) {
e.showException();
}
}
}

View File

@@ -100,6 +100,7 @@ private:
void commitValue(const QVariant &value); void commitValue(const QVariant &value);
void commitExpression(const QString &expression); void commitExpression(const QString &expression);
void handleDataChanged(const QModelIndex &topLeft, const QModelIndex &, const QList<int> &); void handleDataChanged(const QModelIndex &topLeft, const QModelIndex &, const QList<int> &);
void resetValue();
int m_row = -1; int m_row = -1;
PropertyEditorValue *m_backendValue = nullptr; PropertyEditorValue *m_backendValue = nullptr;

View File

@@ -181,7 +181,7 @@ void PropertyEditorValue::setExpressionWithEmit(const QString &expression)
if ( m_expression != expression) { if ( m_expression != expression) {
setExpression(expression); setExpression(expression);
m_value.clear(); m_value.clear();
emit expressionChanged(nameAsQString()); emit expressionChanged(nameAsQString()); //Note that we set the name in this case
} }
} }

View File

@@ -135,7 +135,11 @@ signals:
void valueChanged(const QString &name, const QVariant&); void valueChanged(const QString &name, const QVariant&);
void valueChangedQml(); void valueChangedQml();
void expressionChanged(const QString &name); void expressionChanged(const QString &name); //HACK - We use the same notifer
//for the backend and frontend.
//If name is empty the signal is
//used for QML.
void exportPropertyAsAliasRequested(const QString &name); void exportPropertyAsAliasRequested(const QString &name);
void removeAliasExportRequested(const QString &name); void removeAliasExportRequested(const QString &name);

View File

@@ -16,6 +16,7 @@
#include <QObject> #include <QObject>
#include <QPointer> #include <QPointer>
#include <QVector3D>
#include <functional> #include <functional>
#include <memory> #include <memory>
@@ -145,7 +146,7 @@ public:
void emitUpdateActiveScene3D(const QVariantMap &sceneState); void emitUpdateActiveScene3D(const QVariantMap &sceneState);
void emitModelNodelPreviewPixmapChanged(const ModelNode &node, const QPixmap &pixmap); void emitModelNodelPreviewPixmapChanged(const ModelNode &node, const QPixmap &pixmap);
void emitImport3DSupportChanged(const QVariantMap &supportMap); void emitImport3DSupportChanged(const QVariantMap &supportMap);
void emitNodeAtPosResult(const ModelNode &modelNode); void emitNodeAtPosResult(const ModelNode &modelNode, const QVector3D &pos3d);
void emitView3DAction(View3DActionType type, const QVariant &value); void emitView3DAction(View3DActionType type, const QVariant &value);
void sendTokenToInstances(const QString &token, int number, const QVector<ModelNode> &nodeVector); void sendTokenToInstances(const QString &token, int number, const QVector<ModelNode> &nodeVector);
@@ -214,7 +215,7 @@ public:
virtual void renderImage3DChanged(const QImage &image); virtual void renderImage3DChanged(const QImage &image);
virtual void updateActiveScene3D(const QVariantMap &sceneState); virtual void updateActiveScene3D(const QVariantMap &sceneState);
virtual void updateImport3DSupport(const QVariantMap &supportMap); virtual void updateImport3DSupport(const QVariantMap &supportMap);
virtual void nodeAtPosReady(const ModelNode &modelNode); virtual void nodeAtPosReady(const ModelNode &modelNode, const QVector3D &pos3d);
virtual void modelNodePreviewPixmapChanged(const ModelNode &node, const QPixmap &pixmap); virtual void modelNodePreviewPixmapChanged(const ModelNode &node, const QPixmap &pixmap);
virtual void view3DAction(View3DActionType type, const QVariant &value); virtual void view3DAction(View3DActionType type, const QVariant &value);

View File

@@ -37,6 +37,7 @@ public:
bool isAlias() const; bool isAlias() const;
bool isAliasExport() const; bool isAliasExport() const;
static QVariant convertToLiteral(const TypeName &typeName, const QString &expression);
protected: protected:
BindingProperty(const PropertyName &propertyName, const Internal::InternalNodePointer &internalNode, Model* model, AbstractView *view); BindingProperty(const PropertyName &propertyName, const Internal::InternalNodePointer &internalNode, Model* model, AbstractView *view);

View File

@@ -87,6 +87,7 @@ public:
bool isFlowViewFlowWildcard() const; bool isFlowViewFlowWildcard() const;
bool isFlowViewItem() const; bool isFlowViewItem() const;
bool isFont() const; bool isFont() const;
bool isSuitableForMouseAreaFill() const;
bool isGraphicalItem() const; bool isGraphicalItem() const;
bool isInteger() const; bool isInteger() const;
bool isLayoutable() const; bool isLayoutable() const;

View File

@@ -119,6 +119,8 @@ public:
QmlModelStateGroup states() const; QmlModelStateGroup states() const;
QList<ModelNode> allTimelines() const;
protected: protected:
NodeInstance nodeInstance() const; NodeInstance nodeInstance() const;
QmlObjectNode nodeForInstance(const NodeInstance &instance) const; QmlObjectNode nodeForInstance(const NodeInstance &instance) const;

View File

@@ -44,6 +44,10 @@ public:
QList<ModelNode> allTargets() const; QList<ModelNode> allTargets() const;
QList<QmlTimelineKeyframeGroup> keyframeGroupsForTarget(const ModelNode &target) const; QList<QmlTimelineKeyframeGroup> keyframeGroupsForTarget(const ModelNode &target) const;
void destroyKeyframesForTarget(const ModelNode &target); void destroyKeyframesForTarget(const ModelNode &target);
void removeKeyframesForTargetAndProperty(const ModelNode &target,
const PropertyName &propertyName);
static bool hasActiveTimeline(AbstractView *view); static bool hasActiveTimeline(AbstractView *view);
bool isRecording() const; bool isRecording() const;

View File

@@ -1737,8 +1737,12 @@ void NodeInstanceView::handlePuppetToCreatorCommand(const PuppetToCreatorCommand
const QVariantMap supportMap = qvariant_cast<QVariantMap>(command.data()); const QVariantMap supportMap = qvariant_cast<QVariantMap>(command.data());
emitImport3DSupportChanged(supportMap); emitImport3DSupportChanged(supportMap);
} else if (command.type() == PuppetToCreatorCommand::NodeAtPos) { } else if (command.type() == PuppetToCreatorCommand::NodeAtPos) {
ModelNode modelNode = modelNodeForInternalId(command.data().toUInt()); auto data = qvariant_cast<QVariantList>(command.data());
emitNodeAtPosResult(modelNode); if (data.size() == 2) {
ModelNode modelNode = modelNodeForInternalId(data[0].toInt());
QVector3D pos3d = data[1].value<QVector3D>();
emitNodeAtPosResult(modelNode, pos3d);
}
} }
} }

View File

@@ -1689,6 +1689,12 @@ bool NodeMetaInfo::isSubclassOf(const TypeName &type, int majorVersion, int mino
return false; return false;
} }
bool NodeMetaInfo::isSuitableForMouseAreaFill() const
{
return isSubclassOf("QtQuick.Item") && !isSubclassOf("QtQuick.MouseArea")
&& !isSubclassOf("QtQuick.Controls.Control") && !isSubclassOf("QtQuick.Templates.Control");
}
bool NodeMetaInfo::isBasedOn(const NodeMetaInfo &metaInfo) const bool NodeMetaInfo::isBasedOn(const NodeMetaInfo &metaInfo) const
{ {
if constexpr (useProjectStorage()) { if constexpr (useProjectStorage()) {

View File

@@ -388,8 +388,9 @@ void AbstractView::updateImport3DSupport(const QVariantMap & /*supportMap*/)
{ {
} }
// a Quick3DModel that is picked at the requested position in the 3D Editor // a Quick3DNode that is picked at the requested view position in the 3D Editor and the 3D scene
void AbstractView::nodeAtPosReady(const ModelNode & /*modelNode*/) {} // position of the requested view position.
void AbstractView::nodeAtPosReady(const ModelNode & /*modelNode*/, const QVector3D &/*pos3d*/) {}
void AbstractView::modelNodePreviewPixmapChanged(const ModelNode & /*node*/, const QPixmap & /*pixmap*/) void AbstractView::modelNodePreviewPixmapChanged(const ModelNode & /*node*/, const QPixmap & /*pixmap*/)
{ {
@@ -783,10 +784,10 @@ void AbstractView::emitImport3DSupportChanged(const QVariantMap &supportMap)
model()->d->notifyImport3DSupportChanged(supportMap); model()->d->notifyImport3DSupportChanged(supportMap);
} }
void AbstractView::emitNodeAtPosResult(const ModelNode &modelNode) void AbstractView::emitNodeAtPosResult(const ModelNode &modelNode, const QVector3D &pos3d)
{ {
if (model()) if (model())
model()->d->notifyNodeAtPosResult(modelNode); model()->d->notifyNodeAtPosResult(modelNode, pos3d);
} }
void AbstractView::emitView3DAction(View3DActionType type, const QVariant &value) void AbstractView::emitView3DAction(View3DActionType type, const QVariant &value)

View File

@@ -269,6 +269,52 @@ bool BindingProperty::isAliasExport() const
&& parentModelNode().view()->modelNodeForId(expression()).isValid(); && parentModelNode().view()->modelNodeForId(expression()).isValid();
} }
static bool isTrueFalseLiteral(const QString &expression)
{
return (expression.compare("false", Qt::CaseInsensitive) == 0)
|| (expression.compare("true", Qt::CaseInsensitive) == 0);
}
QVariant BindingProperty::convertToLiteral(const TypeName &typeName, const QString &testExpression)
{
if ("QColor" == typeName || "color" == typeName) {
QString unquoted = testExpression;
unquoted.remove('"');
if (QColor(unquoted).isValid())
return QColor(unquoted);
} else if ("bool" == typeName) {
if (isTrueFalseLiteral(testExpression)) {
if (testExpression.compare("true", Qt::CaseInsensitive) == 0)
return true;
else
return false;
}
} else if ("int" == typeName) {
bool ok;
int intValue = testExpression.toInt(&ok);
if (ok)
return intValue;
} else if ("qreal" == typeName || "real" == typeName) {
bool ok;
qreal realValue = testExpression.toDouble(&ok);
if (ok)
return realValue;
} else if ("QVariant" == typeName || "variant" == typeName) {
bool ok;
qreal realValue = testExpression.toDouble(&ok);
if (ok) {
return realValue;
} else if (isTrueFalseLiteral(testExpression)) {
if (testExpression.compare("true", Qt::CaseInsensitive) == 0)
return true;
else
return false;
}
}
return {};
}
void BindingProperty::setDynamicTypeNameAndExpression(const TypeName &typeName, const QString &expression) void BindingProperty::setDynamicTypeNameAndExpression(const TypeName &typeName, const QString &expression)
{ {
Internal::WriteLocker locker(model()); Internal::WriteLocker locker(model());

View File

@@ -571,9 +571,9 @@ void ModelPrivate::notifyImport3DSupportChanged(const QVariantMap &supportMap)
notifyInstanceChanges([&](AbstractView *view) { view->updateImport3DSupport(supportMap); }); notifyInstanceChanges([&](AbstractView *view) { view->updateImport3DSupport(supportMap); });
} }
void ModelPrivate::notifyNodeAtPosResult(const ModelNode &modelNode) void ModelPrivate::notifyNodeAtPosResult(const ModelNode &modelNode, const QVector3D &pos3d)
{ {
notifyInstanceChanges([&](AbstractView *view) { view->nodeAtPosReady(modelNode); }); notifyInstanceChanges([&](AbstractView *view) { view->nodeAtPosReady(modelNode, pos3d); });
} }
void ModelPrivate::notifyView3DAction(View3DActionType type, const QVariant &value) void ModelPrivate::notifyView3DAction(View3DActionType type, const QVariant &value)

View File

@@ -7,6 +7,7 @@
#include <QPointer> #include <QPointer>
#include <QSet> #include <QSet>
#include <QUrl> #include <QUrl>
#include <QVector3D>
#include "modelnode.h" #include "modelnode.h"
#include "abstractview.h" #include "abstractview.h"
@@ -170,7 +171,7 @@ public:
void notifyUpdateActiveScene3D(const QVariantMap &sceneState); void notifyUpdateActiveScene3D(const QVariantMap &sceneState);
void notifyModelNodePreviewPixmapChanged(const ModelNode &node, const QPixmap &pixmap); void notifyModelNodePreviewPixmapChanged(const ModelNode &node, const QPixmap &pixmap);
void notifyImport3DSupportChanged(const QVariantMap &supportMap); void notifyImport3DSupportChanged(const QVariantMap &supportMap);
void notifyNodeAtPosResult(const ModelNode &modelNode); void notifyNodeAtPosResult(const ModelNode &modelNode, const QVector3D &pos3d);
void notifyView3DAction(View3DActionType type, const QVariant &value); void notifyView3DAction(View3DActionType type, const QVariant &value);
void notifyDragStarted(QMimeData *mimeData); void notifyDragStarted(QMimeData *mimeData);

View File

@@ -554,6 +554,12 @@ QList<QmlModelState> QmlObjectNode::allDefinedStates() const
for (const QmlVisualNode &node : qAsConst(allVisualNodes)) for (const QmlVisualNode &node : qAsConst(allVisualNodes))
returnList.append(node.states().allStates()); returnList.append(node.states().allStates());
const auto allNodes = view()->allModelNodes();
for (const ModelNode &node : allNodes) {
if (node.simplifiedTypeName() == "StateGroup")
returnList.append(QmlModelStateGroup(node).allStates());
}
return returnList; return returnList;
} }
@@ -575,6 +581,18 @@ QmlModelStateGroup QmlObjectNode::states() const
return QmlModelStateGroup(); return QmlModelStateGroup();
} }
QList<ModelNode> QmlObjectNode::allTimelines() const
{
QList<ModelNode> timelineNodes;
const auto allNodes = view()->allModelNodes();
for (const auto &timelineNode : allNodes) {
if (QmlTimeline::isValidQmlTimeline(timelineNode))
timelineNodes.append(timelineNode);
}
return timelineNodes;
}
/*! /*!
Removes a variant property of the object specified by \a name from the Removes a variant property of the object specified by \a name from the
model. model.

View File

@@ -185,6 +185,15 @@ void QmlTimeline::destroyKeyframesForTarget(const ModelNode &target)
frames.destroy(); frames.destroy();
} }
void QmlTimeline::removeKeyframesForTargetAndProperty(const ModelNode &target,
const PropertyName &propertyName)
{
for (QmlTimelineKeyframeGroup frames : keyframeGroupsForTarget(target)) {
if (frames.propertyName() == propertyName)
frames.destroy();
}
}
bool QmlTimeline::hasActiveTimeline(AbstractView *view) bool QmlTimeline::hasActiveTimeline(AbstractView *view)
{ {
if (view && view->isAttached()) { if (view && view->isAttached()) {

View File

@@ -268,7 +268,7 @@ QmlObjectNode QmlVisualNode::createQmlObjectNode(AbstractView *view,
QList<PropertyBindingEntry> propertyBindingList; QList<PropertyBindingEntry> propertyBindingList;
QList<PropertyBindingEntry> propertyEnumList; QList<PropertyBindingEntry> propertyEnumList;
if (itemLibraryEntry.qmlSource().isEmpty()) { if (itemLibraryEntry.qmlSource().isEmpty()) {
QList<QPair<PropertyName, QVariant> > propertyPairList = position.propertyPairList(); QList<QPair<PropertyName, QVariant> > propertyPairList;
for (const auto &property : itemLibraryEntry.properties()) { for (const auto &property : itemLibraryEntry.properties()) {
if (property.type() == "binding") { if (property.type() == "binding") {
@@ -282,6 +282,8 @@ QmlObjectNode QmlVisualNode::createQmlObjectNode(AbstractView *view,
propertyPairList.append({property.name(), property.value()}); propertyPairList.append({property.name(), property.value()});
} }
} }
// Add position last so it'll override any default position specified in the entry
propertyPairList.append(position.propertyPairList());
ModelNode::NodeSourceType nodeSourceType = ModelNode::NodeWithoutSource; ModelNode::NodeSourceType nodeSourceType = ModelNode::NodeWithoutSource;
if (itemLibraryEntry.typeName() == "QtQml.Component") if (itemLibraryEntry.typeName() == "QtQml.Component")

View File

@@ -219,7 +219,7 @@ void FileSystemAccessTest::testFileTransfer()
QVERIFY2(dirForFilesToDownload.isValid(), qPrintable(dirForFilesToDownload.errorString())); QVERIFY2(dirForFilesToDownload.isValid(), qPrintable(dirForFilesToDownload.errorString()));
QVERIFY2(dir2ForFilesToDownload.isValid(), qPrintable(dirForFilesToDownload.errorString())); QVERIFY2(dir2ForFilesToDownload.isValid(), qPrintable(dirForFilesToDownload.errorString()));
static const auto getRemoteFilePath = [this](const QString &localFileName) { static const auto getRemoteFilePath = [this](const QString &localFileName) {
return m_device->filePath(QString("/tmp/").append(localFileName).append(".upload")); return m_device->filePath(QString("/tmp/foo/bar/").append(localFileName).append(".upload"));
}; };
FilesToTransfer filesToUpload; FilesToTransfer filesToUpload;
std::srand(QDateTime::currentDateTime().toSecsSinceEpoch()); std::srand(QDateTime::currentDateTime().toSecsSinceEpoch());
@@ -255,11 +255,11 @@ void FileSystemAccessTest::testFileTransfer()
getRemoteFilePath(bigFileName)}; getRemoteFilePath(bigFileName)};
fileTransfer.setFilesToTransfer(filesToUpload); fileTransfer.setFilesToTransfer(filesToUpload);
QString jobError; ProcessResultData result;
QEventLoop loop; QEventLoop loop;
connect(&fileTransfer, &FileTransfer::done, [&jobError, &loop] connect(&fileTransfer, &FileTransfer::done, [&result, &loop]
(const ProcessResultData &resultData) { (const ProcessResultData &resultData) {
jobError = resultData.m_errorString; result = resultData;
loop.quit(); loop.quit();
}); });
QTimer timer; QTimer timer;
@@ -271,7 +271,15 @@ void FileSystemAccessTest::testFileTransfer()
loop.exec(); loop.exec();
QVERIFY(timer.isActive()); QVERIFY(timer.isActive());
timer.stop(); timer.stop();
QVERIFY2(jobError.isEmpty(), qPrintable(jobError)); QCOMPARE(result.m_exitStatus, QProcess::NormalExit);
QVERIFY2(result.m_errorString.isEmpty(), qPrintable(result.m_errorString));
QCOMPARE(result.m_exitCode, 0);
QCOMPARE(result.m_error, QProcess::UnknownError);
// Cleanup remote
const FilePath remoteDir = m_device->filePath(QString("/tmp/foo/"));
QString errorString;
QVERIFY2(remoteDir.removeRecursively(&errorString), qPrintable(errorString));
} }
} // Internal } // Internal

View File

@@ -1269,13 +1269,9 @@ qint64 LinuxDevice::bytesAvailable(const FilePath &filePath) const
QTC_ASSERT(handlesFile(filePath), return -1); QTC_ASSERT(handlesFile(filePath), return -1);
CommandLine cmd("df", {"-k"}); CommandLine cmd("df", {"-k"});
cmd.addArg(filePath.path()); cmd.addArg(filePath.path());
cmd.addArgs("|tail -n 1 |sed 's/ */ /g'|cut -d ' ' -f 4", CommandLine::Raw);
const QByteArray output = d->outputForRunInShell(cmd).value_or(QByteArray()); const QByteArray output = d->outputForRunInShell(cmd).value_or(QByteArray());
bool ok = false;
const qint64 size = output.toLongLong(&ok); return FileUtils::bytesAvailableFromDFOutput(output);
if (ok)
return size * 1024;
return -1;
} }
QFileDevice::Permissions LinuxDevice::permissions(const FilePath &filePath) const QFileDevice::Permissions LinuxDevice::permissions(const FilePath &filePath) const
@@ -1499,18 +1495,12 @@ private:
return; return;
} }
m_batchFile.reset(new QTemporaryFile(this)); QByteArray batchData;
if (!m_batchFile->isOpen() && !m_batchFile->open()) {
startFailed(Tr::tr("Could not create temporary file: %1")
.arg(m_batchFile->errorString()));
return;
}
const FilePaths dirs = dirsToCreate(m_setup.m_files); const FilePaths dirs = dirsToCreate(m_setup.m_files);
for (const FilePath &dir : dirs) { for (const FilePath &dir : dirs) {
if (direction() == FileTransferDirection::Upload) { if (direction() == FileTransferDirection::Upload) {
m_batchFile->write("-mkdir " + ProcessArgs::quoteArgUnix(dir.path()).toLocal8Bit() batchData += "-mkdir " + ProcessArgs::quoteArgUnix(dir.path()).toLocal8Bit() + '\n';
+ '\n');
} else if (direction() == FileTransferDirection::Download) { } else if (direction() == FileTransferDirection::Download) {
if (!QDir::root().mkpath(dir.path())) { if (!QDir::root().mkpath(dir.path())) {
startFailed(Tr::tr("Failed to create local directory \"%1\".") startFailed(Tr::tr("Failed to create local directory \"%1\".")
@@ -1527,26 +1517,23 @@ private:
const QFileInfo fi(file.m_source.toFileInfo()); const QFileInfo fi(file.m_source.toFileInfo());
if (fi.isSymLink()) { if (fi.isSymLink()) {
link = true; link = true;
m_batchFile->write("-rm " + ProcessArgs::quoteArgUnix( batchData += "-rm " + ProcessArgs::quoteArgUnix(
file.m_target.path()).toLocal8Bit() + '\n'); file.m_target.path()).toLocal8Bit() + '\n';
// see QTBUG-5817. // see QTBUG-5817.
sourceFileOrLinkTarget = sourceFileOrLinkTarget =
sourceFileOrLinkTarget.withNewPath(fi.dir().relativeFilePath(fi.symLinkTarget())); sourceFileOrLinkTarget.withNewPath(fi.dir().relativeFilePath(fi.symLinkTarget()));
} }
} }
m_batchFile->write(transferCommand(direction(), link) + ' ' batchData += transferCommand(direction(), link) + ' '
+ ProcessArgs::quoteArgUnix(sourceFileOrLinkTarget.path()).toLocal8Bit() + ' ' + ProcessArgs::quoteArgUnix(sourceFileOrLinkTarget.path()).toLocal8Bit() + ' '
+ ProcessArgs::quoteArgUnix(file.m_target.path()).toLocal8Bit() + '\n'); + ProcessArgs::quoteArgUnix(file.m_target.path()).toLocal8Bit() + '\n';
} }
m_batchFile->close(); process().setCommand({sftpBinary, fullConnectionOptions() << "-b" << "-" << host()});
process().setCommand(CommandLine(sftpBinary, fullConnectionOptions() process().setWriteData(batchData);
<< "-b" << m_batchFile->fileName() << host()));
process().start(); process().start();
} }
void doneImpl() final { handleDone(); } void doneImpl() final { handleDone(); }
std::unique_ptr<QTemporaryFile> m_batchFile;
}; };
class RsyncTransferImpl : public SshTransferInterface class RsyncTransferImpl : public SshTransferInterface

View File

@@ -60,6 +60,9 @@ private slots:
void resolvePath(); void resolvePath();
void relativeChildPath_data(); void relativeChildPath_data();
void relativeChildPath(); void relativeChildPath();
void bytesAvailableFromDF_data();
void bytesAvailableFromDF();
void asyncLocalCopy(); void asyncLocalCopy();
void startsWithDriveLetter(); void startsWithDriveLetter();
void startsWithDriveLetter_data(); void startsWithDriveLetter_data();
@@ -888,5 +891,32 @@ void tst_fileutils::url_data()
QTest::newRow("http-qt.io-index.html") << QString("http://qt.io/index.html") << QString("http") << QString("qt.io") << QString("/index.html"); QTest::newRow("http-qt.io-index.html") << QString("http://qt.io/index.html") << QString("http") << QString("qt.io") << QString("/index.html");
} }
void tst_fileutils::bytesAvailableFromDF_data()
{
QTest::addColumn<QByteArray>("dfOutput");
QTest::addColumn<qint64>("expected");
QTest::newRow("empty") << QByteArray("") << qint64(-1);
QTest::newRow("mac") << QByteArray("Filesystem 1024-blocks Used Available Capacity iused ifree %iused Mounted on\n/dev/disk3s5 971350180 610014564 342672532 65% 4246780 3426725320 0% /System/Volumes/Data\n") << qint64(342672532);
QTest::newRow("alpine") << QByteArray("Filesystem 1K-blocks Used Available Use% Mounted on\noverlay 569466448 163526072 376983360 30% /\n") << qint64(376983360);
QTest::newRow("alpine-no-trailing-br") << QByteArray("Filesystem 1K-blocks Used Available Use% Mounted on\noverlay 569466448 163526072 376983360 30% /") << qint64(376983360);
QTest::newRow("alpine-missing-line") << QByteArray("Filesystem 1K-blocks Used Available Use% Mounted on\n") << qint64(-1);
QTest::newRow("wrong-header") << QByteArray("Filesystem 1K-blocks Used avail Use% Mounted on\noverlay 569466448 163526072 376983360 30% /\n") << qint64(-1);
QTest::newRow("not-enough-fields") << QByteArray("Filesystem 1K-blocks Used avail Use% Mounted on\noverlay 569466448\n") << qint64(-1);
QTest::newRow("not-enough-header-fields") << QByteArray("Filesystem 1K-blocks Used \noverlay 569466448 163526072 376983360 30% /\n") << qint64(-1);
}
void tst_fileutils::bytesAvailableFromDF()
{
if (HostOsInfo::isWindowsHost())
QSKIP("Test only valid on unix-ish systems");
QFETCH(QByteArray, dfOutput);
QFETCH(qint64, expected);
const auto result = FileUtils::bytesAvailableFromDFOutput(dfOutput);
QCOMPARE(result, expected);
}
QTEST_GUILESS_MAIN(tst_fileutils) QTEST_GUILESS_MAIN(tst_fileutils)
#include "tst_fileutils.moc" #include "tst_fileutils.moc"

View File

@@ -152,6 +152,8 @@ def doSimpleDebugging(currentKit, currentConfigName, expectedBPOrder=[], enableQ
# param currentKit specifies the ID of the kit to use (see class Targets) # param currentKit specifies the ID of the kit to use (see class Targets)
def isMsvcConfig(currentKit): def isMsvcConfig(currentKit):
if platform.system() not in ('Microsoft' 'Windows'):
return False
switchViewTo(ViewConstants.PROJECTS) switchViewTo(ViewConstants.PROJECTS)
switchToBuildOrRunSettingsFor(currentKit, ProjectSettings.BUILD) switchToBuildOrRunSettingsFor(currentKit, ProjectSettings.BUILD)
@@ -164,7 +166,8 @@ def isMsvcConfig(currentKit):
raise Exception("Kit '%s' is not activated in the project." % wantedKitName) raise Exception("Kit '%s' is not activated in the project." % wantedKitName)
index = waitForObject(wantedKitIndexString) index = waitForObject(wantedKitIndexString)
toolTip = str(index.data(Qt.ToolTipRole).toString()) toolTip = str(index.data(Qt.ToolTipRole).toString())
compilerPattern = re.compile("<tr><td><b>Compiler:</b></td><td>(?P<compiler>.+)</td></tr>") compilerPattern = re.compile('<dt style="font-weight:bold">Compiler:</dt><dd>(?P<compiler>.+)'
'</dd><dt style="font-weight:bold">Environment:')
match = compilerPattern.search(toolTip) match = compilerPattern.search(toolTip)
if match is None: if match is None:
test.warning("UI seems to have changed - failed to check for compiler.") test.warning("UI seems to have changed - failed to check for compiler.")