forked from qt-creator/qt-creator
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:
@@ -38,7 +38,7 @@
|
||||
identifying potential bottlenecks, especially in the evaluation
|
||||
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
|
||||
example, and use the results to make the tests more efficient and
|
||||
|
@@ -8,11 +8,10 @@
|
||||
|
||||
\title Checking Code Coverage
|
||||
|
||||
\l{https://doc.froglogic.com/squish-coco/latest/}{Squish Coco} is a complete
|
||||
code coverage tool chain for Tcl, QML, C# and C/C++ programs that runs on
|
||||
\macOS, Linux, and Windows.
|
||||
\l{https://doc.qt.io/coco/}{Coco} is a complete code coverage tool chain for
|
||||
Tcl, QML, C# and C/C++ programs that runs on \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
|
||||
complete.
|
||||
|
||||
@@ -20,7 +19,7 @@
|
||||
|
||||
\list
|
||||
\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
|
||||
can detect whether a new test covers lines in the source code that
|
||||
the existing tests do not cover.
|
||||
@@ -38,10 +37,10 @@
|
||||
The experimental Coco plugin integrates Coco CoverageBrowser into \QC.
|
||||
It enables you to analyze the test coverage by loading an instrumentation
|
||||
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.
|
||||
|
||||
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
|
||||
|
||||
|
BIN
doc/qtdesignstudio/images/material-copy-properties.png
Normal file
BIN
doc/qtdesignstudio/images/material-copy-properties.png
Normal file
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 |
@@ -39,8 +39,12 @@
|
||||
|
||||
\section1 Assigning a Material to an Object
|
||||
|
||||
To assign a material to a 3D object in your project, first select the object
|
||||
in \uicontrol Navigator or the \uicontrol{3D} view. Then, do one of the
|
||||
To assign a material to a 3D object in your project, drag the material from
|
||||
\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:
|
||||
|
||||
\list
|
||||
@@ -64,6 +68,26 @@
|
||||
\image materials-remove-material.png
|
||||
\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
|
||||
|
||||
In \QDS you can add many different texture maps to your material.
|
||||
|
@@ -59,23 +59,10 @@ public:
|
||||
QQuick3DNode *pickNode() const;
|
||||
MouseArea3D *dragHelper() const;
|
||||
|
||||
QVector3D getMousePosInPlane(const MouseArea3D *helper, const QPointF &mousePosInView) const;
|
||||
|
||||
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,
|
||||
const QVector3D &rayPos1,
|
||||
const QVector3D &planePos,
|
||||
@@ -98,6 +85,21 @@ public slots:
|
||||
Q_INVOKABLE void forceMoveEvent(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:
|
||||
void view3DChanged();
|
||||
|
||||
@@ -131,7 +133,6 @@ private:
|
||||
void setHovering(bool enable);
|
||||
QVector3D getNormal() const;
|
||||
QVector3D getCameraToNodeDir(QQuick3DNode *node) const;
|
||||
QVector3D getMousePosInPlane(const MouseArea3D *helper, const QPointF &mousePosInView) const;
|
||||
|
||||
Q_DISABLE_COPY(MouseArea3D)
|
||||
QQuick3DViewport *m_view3D = nullptr;
|
||||
|
@@ -73,9 +73,7 @@ void QmlStateNodeInstance::setPropertyVariant(const PropertyName &name, const QV
|
||||
|
||||
void QmlStateNodeInstance::setPropertyBinding(const PropertyName &name, const QString &expression)
|
||||
{
|
||||
bool isStateOfTheRootModelNode = parentInstance() && parentInstance()->isRootNodeInstance();
|
||||
|
||||
if (name == "when" && (isStateOfTheRootModelNode))
|
||||
if (name == "when")
|
||||
return;
|
||||
|
||||
ObjectNodeInstance::setPropertyBinding(name, expression);
|
||||
|
@@ -405,18 +405,33 @@ void Qt5InformationNodeInstanceServer::getNodeAtPos(const QPointF &pos)
|
||||
Q_ARG(QVariant, pos.x()),
|
||||
Q_ARG(QVariant, pos.y()));
|
||||
QObject *gizmoObj = qvariant_cast<QObject *>(gizmoVar);
|
||||
QVariant instance = -1;
|
||||
qint32 instanceId = -1;
|
||||
|
||||
if (gizmoObj && hasInstanceForObject(gizmoObj)) {
|
||||
instance = instanceForObject(gizmoObj).instanceId();
|
||||
instanceId = instanceForObject(gizmoObj).instanceId();
|
||||
} else {
|
||||
QQuick3DModel *hitModel = helper->pickViewAt(editView, pos.x(), pos.y()).objectHit();
|
||||
QObject *resolvedPick = helper->resolvePick(hitModel);
|
||||
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
|
||||
Q_UNUSED(pos)
|
||||
#endif
|
||||
|
@@ -1,5 +1,3 @@
|
||||
|
||||
|
||||
// Copyright (C) 2021 The Qt Company Ltd.
|
||||
// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0 WITH Qt-GPL-exception-1.0
|
||||
import QtQuick 2.15
|
||||
@@ -29,7 +27,7 @@ SecondColumnLayout {
|
||||
else
|
||||
return colorEditor.backendValue.value
|
||||
}
|
||||
property alias gradientPropertyName: cePopup.gradientPropertyName
|
||||
property alias gradientPropertyName: popupLoader.gradientPropertyName
|
||||
|
||||
property alias gradientThumbnail: gradientThumbnail
|
||||
property alias shapeGradientThumbnail: shapeGradientThumbnail
|
||||
@@ -45,7 +43,7 @@ SecondColumnLayout {
|
||||
}
|
||||
|
||||
function initEditor() {
|
||||
cePopup.initEditor()
|
||||
colorEditor.color = colorEditor.value
|
||||
}
|
||||
|
||||
Connections {
|
||||
@@ -53,12 +51,12 @@ SecondColumnLayout {
|
||||
target: colorEditor
|
||||
|
||||
function onValueChanged() {
|
||||
if (cePopup.isNotInGradientMode())
|
||||
if (popupLoader.isNotInGradientMode())
|
||||
colorEditor.color = colorEditor.value
|
||||
}
|
||||
|
||||
function onBackendValueChanged() {
|
||||
if (cePopup.isNotInGradientMode())
|
||||
if (popupLoader.isNotInGradientMode())
|
||||
colorEditor.color = colorEditor.value
|
||||
}
|
||||
}
|
||||
@@ -85,17 +83,13 @@ SecondColumnLayout {
|
||||
}
|
||||
|
||||
onColorChanged: {
|
||||
if (!cePopup.isInValidState)
|
||||
if (!popupLoader.isInValidState)
|
||||
return
|
||||
|
||||
if (colorEditor.supportGradient && cePopup.gradientModel.hasGradient) {
|
||||
var hexColor = convertColorToString(colorEditor.color)
|
||||
hexTextField.text = hexColor
|
||||
cePopup.commitGradientColor()
|
||||
}
|
||||
popupLoader.commitToGradient()
|
||||
|
||||
// Delay setting the color to keep ui responsive
|
||||
if (cePopup.isNotInGradientMode())
|
||||
if (popupLoader.isNotInGradientMode())
|
||||
colorEditorTimer.restart()
|
||||
}
|
||||
|
||||
@@ -115,16 +109,16 @@ SecondColumnLayout {
|
||||
id: gradientThumbnail
|
||||
anchors.fill: parent
|
||||
anchors.margins: StudioTheme.Values.border
|
||||
visible: !cePopup.isNotInGradientMode()
|
||||
visible: !popupLoader.isNotInGradientMode()
|
||||
&& !colorEditor.shapeGradients
|
||||
&& cePopup.hasLinearGradient()
|
||||
&& popupLoader.hasLinearGradient()
|
||||
}
|
||||
|
||||
Shape {
|
||||
id: shape
|
||||
anchors.fill: parent
|
||||
anchors.margins: StudioTheme.Values.border
|
||||
visible: !cePopup.isNotInGradientMode()
|
||||
visible: !popupLoader.isNotInGradientMode()
|
||||
&& colorEditor.shapeGradients
|
||||
|
||||
ShapePath {
|
||||
@@ -159,16 +153,81 @@ SecondColumnLayout {
|
||||
MouseArea {
|
||||
anchors.fill: parent
|
||||
onClicked: {
|
||||
cePopup.opened ? cePopup.close() : cePopup.open()
|
||||
popupLoader.opened ? popupLoader.close() : popupLoader.open()
|
||||
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
|
||||
x: cePopup.__defaultX
|
||||
y: cePopup.__defaultY
|
||||
}
|
||||
onLoaded: {
|
||||
popupLoader.dialog.initEditor()
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Spacer {
|
||||
@@ -180,7 +239,7 @@ SecondColumnLayout {
|
||||
implicitWidth: StudioTheme.Values.twoControlColumnWidth
|
||||
+ StudioTheme.Values.actionIndicatorWidth
|
||||
width: implicitWidth
|
||||
enabled: cePopup.isNotInGradientMode()
|
||||
enabled: popupLoader.isNotInGradientMode()
|
||||
writeValueManually: true
|
||||
validator: RegExpValidator {
|
||||
regExp: /#[0-9A-Fa-f]{6}([0-9A-Fa-f]{2})?/g
|
||||
@@ -191,7 +250,7 @@ SecondColumnLayout {
|
||||
onAccepted: colorEditor.color = colorFromString(hexTextField.text)
|
||||
onCommitData: {
|
||||
colorEditor.color = colorFromString(hexTextField.text)
|
||||
if (cePopup.isNotInGradientMode()) {
|
||||
if (popupLoader.isNotInGradientMode()) {
|
||||
if (colorEditor.isVector3D) {
|
||||
backendValue.value = Qt.vector3d(colorEditor.color.r,
|
||||
colorEditor.color.g,
|
||||
@@ -216,9 +275,9 @@ SecondColumnLayout {
|
||||
}
|
||||
}
|
||||
|
||||
Component.onCompleted: cePopup.determineActiveColorMode()
|
||||
Component.onCompleted: popupLoader.determineActiveColorMode()
|
||||
|
||||
onBackendValueChanged: {
|
||||
cePopup.determineActiveColorMode()
|
||||
popupLoader.determineActiveColorMode()
|
||||
}
|
||||
}
|
||||
|
@@ -53,11 +53,10 @@ Section {
|
||||
Spacer { implicitWidth: StudioTheme.Values.twoControlColumnGap }
|
||||
|
||||
IconIndicator {
|
||||
Layout.alignment: Qt.AlignLeft
|
||||
|
||||
icon: StudioTheme.Constants.closeCross
|
||||
onClicked: colorEditorControl.remove()
|
||||
}
|
||||
|
||||
ExpandingSpacer {}
|
||||
}
|
||||
}
|
||||
@@ -79,24 +78,17 @@ Section {
|
||||
+ StudioTheme.Values.actionIndicatorWidth
|
||||
}
|
||||
|
||||
Spacer {
|
||||
implicitWidth: StudioTheme.Values.twoControlColumnGap
|
||||
}
|
||||
Spacer { implicitWidth: StudioTheme.Values.twoControlColumnGap }
|
||||
|
||||
Item {
|
||||
height: 10
|
||||
implicitWidth: {
|
||||
return StudioTheme.Values.twoControlColumnWidth
|
||||
implicitWidth: StudioTheme.Values.twoControlColumnWidth
|
||||
+ StudioTheme.Values.actionIndicatorWidth
|
||||
}
|
||||
}
|
||||
|
||||
Spacer {
|
||||
implicitWidth: StudioTheme.Values.twoControlColumnGap
|
||||
}
|
||||
Spacer { implicitWidth: StudioTheme.Values.twoControlColumnGap }
|
||||
|
||||
IconIndicator {
|
||||
Layout.alignment: Qt.AlignLeft
|
||||
icon: StudioTheme.Constants.closeCross
|
||||
onClicked: layoutInt.remove()
|
||||
}
|
||||
@@ -124,24 +116,17 @@ Section {
|
||||
+ StudioTheme.Values.actionIndicatorWidth
|
||||
}
|
||||
|
||||
Spacer {
|
||||
implicitWidth: StudioTheme.Values.twoControlColumnGap
|
||||
}
|
||||
Spacer { implicitWidth: StudioTheme.Values.twoControlColumnGap }
|
||||
|
||||
Item {
|
||||
height: 10
|
||||
implicitWidth: {
|
||||
return StudioTheme.Values.twoControlColumnWidth
|
||||
implicitWidth: StudioTheme.Values.twoControlColumnWidth
|
||||
+ StudioTheme.Values.actionIndicatorWidth
|
||||
}
|
||||
}
|
||||
|
||||
Spacer {
|
||||
implicitWidth: StudioTheme.Values.twoControlColumnGap
|
||||
}
|
||||
Spacer { implicitWidth: StudioTheme.Values.twoControlColumnGap }
|
||||
|
||||
IconIndicator {
|
||||
Layout.alignment: Qt.AlignLeft
|
||||
icon: StudioTheme.Constants.closeCross
|
||||
onClicked: layoutReal.remove()
|
||||
}
|
||||
@@ -165,12 +150,9 @@ Section {
|
||||
+ StudioTheme.Values.actionIndicatorWidth
|
||||
}
|
||||
|
||||
Spacer {
|
||||
implicitWidth: StudioTheme.Values.twoControlColumnGap
|
||||
}
|
||||
Spacer { implicitWidth: StudioTheme.Values.twoControlColumnGap }
|
||||
|
||||
IconIndicator {
|
||||
Layout.alignment: Qt.AlignLeft
|
||||
icon: StudioTheme.Constants.closeCross
|
||||
onClicked: layoutString.remove()
|
||||
}
|
||||
@@ -195,24 +177,17 @@ Section {
|
||||
backendValue: layoutBool.backendValue
|
||||
}
|
||||
|
||||
Spacer {
|
||||
implicitWidth: StudioTheme.Values.twoControlColumnGap
|
||||
}
|
||||
Spacer { implicitWidth: StudioTheme.Values.twoControlColumnGap }
|
||||
|
||||
Item {
|
||||
height: 10
|
||||
implicitWidth: {
|
||||
return StudioTheme.Values.twoControlColumnWidth
|
||||
implicitWidth: StudioTheme.Values.twoControlColumnWidth
|
||||
+ StudioTheme.Values.actionIndicatorWidth
|
||||
}
|
||||
}
|
||||
|
||||
Spacer {
|
||||
implicitWidth: StudioTheme.Values.twoControlColumnGap
|
||||
}
|
||||
Spacer { implicitWidth: StudioTheme.Values.twoControlColumnGap }
|
||||
|
||||
IconIndicator {
|
||||
Layout.alignment: Qt.AlignLeft
|
||||
icon: StudioTheme.Constants.closeCross
|
||||
onClicked: layoutBool.remove()
|
||||
}
|
||||
@@ -238,7 +213,6 @@ Section {
|
||||
}
|
||||
|
||||
IconIndicator {
|
||||
Layout.alignment: Qt.AlignLeft
|
||||
icon: StudioTheme.Constants.closeCross
|
||||
onClicked: layoutUrl.remove()
|
||||
}
|
||||
@@ -270,12 +244,9 @@ Section {
|
||||
showTranslateCheckBox: false
|
||||
}
|
||||
|
||||
Spacer {
|
||||
implicitWidth: StudioTheme.Values.twoControlColumnGap
|
||||
}
|
||||
Spacer { implicitWidth: StudioTheme.Values.twoControlColumnGap }
|
||||
|
||||
IconIndicator {
|
||||
Layout.alignment: Qt.AlignLeft
|
||||
icon: StudioTheme.Constants.closeCross
|
||||
onClicked: layoutAlias.remove()
|
||||
}
|
||||
@@ -301,12 +272,9 @@ Section {
|
||||
+ StudioTheme.Values.actionIndicatorWidth
|
||||
}
|
||||
|
||||
Spacer {
|
||||
implicitWidth: StudioTheme.Values.twoControlColumnGap
|
||||
}
|
||||
Spacer { implicitWidth: StudioTheme.Values.twoControlColumnGap }
|
||||
|
||||
IconIndicator {
|
||||
Layout.alignment: Qt.AlignLeft
|
||||
icon: StudioTheme.Constants.closeCross
|
||||
onClicked: layoutTextureInput.remove()
|
||||
}
|
||||
@@ -411,7 +379,6 @@ Section {
|
||||
Spacer { implicitWidth: StudioTheme.Values.controlGap }
|
||||
|
||||
IconIndicator {
|
||||
Layout.alignment: Qt.AlignLeft
|
||||
icon: StudioTheme.Constants.closeCross
|
||||
onClicked: layoutVector.remove()
|
||||
}
|
||||
@@ -462,16 +429,12 @@ Section {
|
||||
|
||||
Item {
|
||||
height: 10
|
||||
implicitWidth: {
|
||||
return StudioTheme.Values.twoControlColumnWidth
|
||||
implicitWidth: StudioTheme.Values.twoControlColumnWidth
|
||||
+ StudioTheme.Values.actionIndicatorWidth
|
||||
}
|
||||
visible: vecSize === 2 // Placeholder for last spinbox
|
||||
}
|
||||
|
||||
Spacer {
|
||||
implicitWidth: StudioTheme.Values.twoControlColumnGap
|
||||
}
|
||||
Spacer { implicitWidth: StudioTheme.Values.twoControlColumnGap }
|
||||
|
||||
ExpandingSpacer {}
|
||||
}
|
||||
@@ -497,11 +460,9 @@ Section {
|
||||
+ StudioTheme.Values.actionIndicatorWidth
|
||||
}
|
||||
|
||||
Spacer {
|
||||
implicitWidth: StudioTheme.Values.twoControlColumnGap
|
||||
}
|
||||
Spacer { implicitWidth: StudioTheme.Values.twoControlColumnGap }
|
||||
|
||||
IconIndicator {
|
||||
Layout.alignment: Qt.AlignLeft
|
||||
icon: StudioTheme.Constants.closeCross
|
||||
onClicked: layoutReadonly.remove()
|
||||
}
|
||||
@@ -541,6 +502,7 @@ Section {
|
||||
active: repeater.loadActive
|
||||
width: loader.item ? loader.item.width : 0
|
||||
height: loader.item ? loader.item.height : 0
|
||||
Layout.fillWidth: true
|
||||
|
||||
sourceComponent: {
|
||||
if (propertyType == "color")
|
||||
@@ -615,7 +577,6 @@ Section {
|
||||
Spacer { implicitWidth: StudioTheme.Values.actionIndicatorWidth }
|
||||
|
||||
StudioControls.AbstractButton {
|
||||
|
||||
id: plusButton
|
||||
buttonIcon: StudioTheme.Constants.plus
|
||||
onClicked: {
|
||||
@@ -691,7 +652,7 @@ Section {
|
||||
RowLayout {
|
||||
width: cePopup.width - 8
|
||||
PropertyLabel {
|
||||
text: "Add New Property"
|
||||
text: qsTr("Add New Property")
|
||||
horizontalAlignment: Text.AlignLeft
|
||||
leftPadding: 8
|
||||
width: cePopup.width - closeIndicator.width - 24
|
||||
@@ -707,7 +668,7 @@ Section {
|
||||
RowLayout {
|
||||
PropertyLabel {
|
||||
id: textLabel
|
||||
text: "Name"
|
||||
text: qsTr("Name")
|
||||
width: cePopup.labelWidth
|
||||
}
|
||||
StudioControls.TextField {
|
||||
@@ -720,7 +681,7 @@ Section {
|
||||
}
|
||||
RowLayout {
|
||||
PropertyLabel {
|
||||
text: "Type"
|
||||
text: qsTr("Type")
|
||||
width: cePopup.labelWidth
|
||||
}
|
||||
StudioControls.ComboBox {
|
||||
|
@@ -54,6 +54,13 @@ Row {
|
||||
// when the combobox is closed by focusing on some other control.
|
||||
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 {
|
||||
id: dropArea
|
||||
|
||||
|
@@ -12,12 +12,11 @@ T.MenuSeparator {
|
||||
implicitContentWidth + leftPadding + rightPadding)
|
||||
implicitHeight: Math.max(implicitBackgroundHeight + topInset + bottomInset,
|
||||
implicitContentHeight + topPadding + bottomPadding)
|
||||
|
||||
padding: 0
|
||||
|
||||
contentItem: Rectangle {
|
||||
width: control.parent.width
|
||||
height: StudioTheme.Values.border
|
||||
implicitWidth: control.parent.width
|
||||
implicitHeight: StudioTheme.Values.border
|
||||
color: StudioTheme.Values.themeControlOutline
|
||||
}
|
||||
}
|
||||
|
Binary file not shown.
@@ -951,7 +951,7 @@ void Check::visitQmlObject(Node *ast, UiQualifiedId *typeId,
|
||||
if (checkTypeForQmlUiSupport(typeId))
|
||||
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(ErrStatesOnlyInRootItemInQmlUi, typeErrorLocation);
|
||||
}
|
||||
|
@@ -422,7 +422,10 @@ int TimelineModel::insert(qint64 startTime, qint64 duration, int selectionId)
|
||||
int index = d->insertStart(TimelineModelPrivate::Range(startTime, duration, selectionId));
|
||||
if (index < d->ranges.size() - 1)
|
||||
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;
|
||||
}
|
||||
|
||||
@@ -446,7 +449,10 @@ int TimelineModel::insertStart(qint64 startTime, int selectionId)
|
||||
void TimelineModel::insertEnd(int index, qint64 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
|
||||
|
@@ -30,13 +30,14 @@ public:
|
||||
};
|
||||
|
||||
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) :
|
||||
start(start), duration(duration), selectionId(selectionId), parent(-1) {}
|
||||
start(start), duration(duration), selectionId(selectionId), parent(-1), endIndex(-1) {}
|
||||
qint64 start;
|
||||
qint64 duration;
|
||||
int selectionId;
|
||||
int parent;
|
||||
int endIndex;
|
||||
inline qint64 timestamp() const {return start;}
|
||||
};
|
||||
|
||||
@@ -55,11 +56,21 @@ public:
|
||||
|
||||
void incrementStartIndices(int index)
|
||||
{
|
||||
for (RangeEnd &endTime : endTimes) {
|
||||
if (endTime.startIndex >= index)
|
||||
++(endTime.startIndex);
|
||||
for (index = index + 1; index < ranges.count(); index++) {
|
||||
if (ranges[index].endIndex >= 0)
|
||||
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)
|
||||
{
|
||||
|
@@ -1,6 +1,8 @@
|
||||
// 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
|
||||
|
||||
#pragma once
|
||||
|
||||
#include "utils_global.h"
|
||||
|
||||
#include <QMap>
|
||||
|
@@ -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
|
||||
|
@@ -82,6 +82,8 @@ public:
|
||||
const FileFilter &filter,
|
||||
const std::function<bool(const FilePath &)> &callBack);
|
||||
|
||||
static qint64 bytesAvailableFromDFOutput(const QByteArray &dfOutput);
|
||||
|
||||
#ifdef QT_WIDGETS_LIB
|
||||
static void setDialogParentGetter(const std::function<QWidget *()> &getter);
|
||||
|
||||
|
@@ -61,7 +61,7 @@ QStringList GTestConfiguration::argumentsForTestRunner(QStringList *omitted) con
|
||||
|
||||
const QStringList &testSets = testCases();
|
||||
if (!testSets.isEmpty())
|
||||
arguments << "--gtest_filter=" + testSets.join(':');
|
||||
arguments << "--gtest_filter=\"" + testSets.join(':') + '"';
|
||||
|
||||
auto gSettings = static_cast<GTestSettings *>(framework()->testSettings());
|
||||
if (!gSettings)
|
||||
|
@@ -329,7 +329,7 @@ void CompilerOptionsBuilder::insertWrappedHeaders(const QStringList &relPaths)
|
||||
static const QString baseDir = creatorResourcePath() + "/cplusplus";
|
||||
const QString fullPath = baseDir + '/' + relPath;
|
||||
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"));
|
||||
@@ -686,7 +686,7 @@ void CompilerOptionsBuilder::addIncludeDirOptionForPath(const HeaderPath &path)
|
||||
return;
|
||||
}
|
||||
|
||||
add({includeUserPathOption, QDir::toNativeSeparators(path.path)});
|
||||
add(includeUserPathOption + QDir::toNativeSeparators(path.path));
|
||||
}
|
||||
|
||||
bool CompilerOptionsBuilder::excludeDefineDirective(const Macro ¯o) const
|
||||
|
@@ -191,8 +191,8 @@ void CompilerOptionsBuilderTest::testHeaderPathOptionsOrder()
|
||||
compilerOptionsBuilder.addHeaderPathOptions();
|
||||
|
||||
QCOMPARE(compilerOptionsBuilder.options(),
|
||||
(QStringList{"-nostdinc", "-nostdinc++", "-I", t.toNative("/tmp/path"),
|
||||
"-I", t.toNative("/tmp/system_path"), "-isystem", t.toNative("/dummy"),
|
||||
(QStringList{"-nostdinc", "-nostdinc++", "-I" + t.toNative("/tmp/path"),
|
||||
"-I" + t.toNative("/tmp/system_path"), "-isystem", t.toNative("/dummy"),
|
||||
"-isystem", t.toNative("/tmp/builtin_path")}));
|
||||
}
|
||||
|
||||
@@ -207,8 +207,8 @@ void CompilerOptionsBuilderTest::testHeaderPathOptionsOrderMsvc()
|
||||
compilerOptionsBuilder.addHeaderPathOptions();
|
||||
|
||||
QCOMPARE(compilerOptionsBuilder.options(),
|
||||
(QStringList{"-nostdinc", "-nostdinc++", "-I", t.toNative("/tmp/path"),
|
||||
"-I", t.toNative("/tmp/system_path"), "/clang:-isystem",
|
||||
(QStringList{"-nostdinc", "-nostdinc++", "-I" + t.toNative("/tmp/path"),
|
||||
"-I" + t.toNative("/tmp/system_path"), "/clang:-isystem",
|
||||
"/clang:" + t.toNative("/dummy"), "/clang:-isystem",
|
||||
"/clang:" + t.toNative("/tmp/builtin_path")}));
|
||||
}
|
||||
@@ -222,7 +222,7 @@ void CompilerOptionsBuilderTest::testUseSystemHeader()
|
||||
compilerOptionsBuilder.addHeaderPathOptions();
|
||||
|
||||
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("/dummy"),
|
||||
"-isystem", t.toNative("/tmp/builtin_path")}));
|
||||
@@ -235,7 +235,7 @@ void CompilerOptionsBuilderTest::testNoClangHeadersPath()
|
||||
t.compilerOptionsBuilder->addHeaderPathOptions();
|
||||
|
||||
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()
|
||||
@@ -255,8 +255,8 @@ void CompilerOptionsBuilderTest::testClangHeadersAndCppIncludePathsOrderMacOs()
|
||||
compilerOptionsBuilder.addHeaderPathOptions();
|
||||
|
||||
QCOMPARE(compilerOptionsBuilder.options(),
|
||||
(QStringList{"-nostdinc", "-nostdinc++", "-I", t.toNative("/tmp/path"),
|
||||
"-I", t.toNative("/tmp/system_path"),
|
||||
(QStringList{"-nostdinc", "-nostdinc++", "-I" + t.toNative("/tmp/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/backward"),
|
||||
"-isystem", t.toNative("/usr/local/include"),
|
||||
@@ -588,10 +588,11 @@ void CompilerOptionsBuilderTest::testBuildAllOptions()
|
||||
QCOMPARE(compilerOptionsBuilder.options(),
|
||||
(QStringList{"-nostdinc", "-nostdinc++", "-arch", "x86_64", "-fsyntax-only", "-m64",
|
||||
"--target=x86_64-apple-darwin10", "-x", "c++", "-std=c++17",
|
||||
"-DprojectFoo=projectBar", "-I", wrappedQtHeadersPath,
|
||||
"-I", wrappedQtCoreHeadersPath,
|
||||
"-I", t.toNative("/tmp/path"),
|
||||
"-I", t.toNative("/tmp/system_path"),
|
||||
"-DprojectFoo=projectBar",
|
||||
wrappedQtHeadersPath, // contains -I already
|
||||
wrappedQtCoreHeadersPath, // contains -I already
|
||||
"-I" + t.toNative("/tmp/path"),
|
||||
"-I" + t.toNative("/tmp/system_path"),
|
||||
"-isystem", t.toNative("/dummy"),
|
||||
"-isystem", t.toNative("/tmp/builtin_path")}));
|
||||
}
|
||||
@@ -616,10 +617,10 @@ void CompilerOptionsBuilderTest::testBuildAllOptionsMsvc()
|
||||
"-D__FUNCSIG__=\"void __cdecl someLegalAndLongishFunctionNameThatWorksAroundQTCREATORBUG-24580(void)\"",
|
||||
"-D__FUNCTION__=\"someLegalAndLongishFunctionNameThatWorksAroundQTCREATORBUG-24580\"",
|
||||
"-D__FUNCDNAME__=\"?someLegalAndLongishFunctionNameThatWorksAroundQTCREATORBUG-24580@@YAXXZ\"",
|
||||
"-I", wrappedQtHeadersPath,
|
||||
"-I", wrappedQtCoreHeadersPath,
|
||||
"-I", t.toNative("/tmp/path"),
|
||||
"-I", t.toNative("/tmp/system_path"),
|
||||
wrappedQtHeadersPath, // contains -I already
|
||||
wrappedQtCoreHeadersPath, // contains -I already
|
||||
"-I" + t.toNative("/tmp/path"),
|
||||
"-I" + t.toNative("/tmp/system_path"),
|
||||
"/clang:-isystem", "/clang:" + t.toNative("/dummy"),
|
||||
"/clang:-isystem", "/clang:" + t.toNative("/tmp/builtin_path")}));
|
||||
}
|
||||
@@ -646,10 +647,10 @@ void CompilerOptionsBuilderTest::testBuildAllOptionsMsvcWithExceptions()
|
||||
"-D__FUNCSIG__=\"void __cdecl someLegalAndLongishFunctionNameThatWorksAroundQTCREATORBUG-24580(void)\"",
|
||||
"-D__FUNCTION__=\"someLegalAndLongishFunctionNameThatWorksAroundQTCREATORBUG-24580\"",
|
||||
"-D__FUNCDNAME__=\"?someLegalAndLongishFunctionNameThatWorksAroundQTCREATORBUG-24580@@YAXXZ\"",
|
||||
"-I", wrappedQtHeadersPath,
|
||||
"-I", wrappedQtCoreHeadersPath,
|
||||
"-I", t.toNative("/tmp/path"),
|
||||
"-I", t.toNative("/tmp/system_path"),
|
||||
wrappedQtHeadersPath, // contains -I already
|
||||
wrappedQtCoreHeadersPath, // contains -I already
|
||||
"-I" + t.toNative("/tmp/path"),
|
||||
"-I" + t.toNative("/tmp/system_path"),
|
||||
"/clang:-isystem", "/clang:" + t.toNative("/dummy"),
|
||||
"/clang:-isystem", "/clang:" + t.toNative("/tmp/builtin_path")}));
|
||||
}
|
||||
|
@@ -70,6 +70,7 @@ const char removeGroupItemCommandId[] = "RemoveToGroupItem";
|
||||
const char fitRootToScreenCommandId[] = "FitRootToScreen";
|
||||
const char fitSelectionToScreenCommandId[] = "FitSelectionToScreen";
|
||||
const char editAnnotationCommandId[] = "EditAnnotation";
|
||||
const char addMouseAreaFillCommandId[] = "AddMouseAreaFill";
|
||||
|
||||
const char openSignalDialogCommandId[] = "OpenSignalDialog";
|
||||
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 editMaterialDisplayName[] = QT_TRANSLATE_NOOP("QmlDesignerContextMenu", "Edit Material");
|
||||
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 update3DAssetDisplayName[] = QT_TRANSLATE_NOOP("QmlDesignerContextMenu", "Update 3D Asset");
|
||||
|
@@ -1449,6 +1449,17 @@ void DesignerActionManager::createDefaultDesignerActions()
|
||||
&singleSelection,
|
||||
&singleSelection));
|
||||
|
||||
addDesignerAction(new ModelNodeContextMenuAction(
|
||||
addMouseAreaFillCommandId,
|
||||
addMouseAreaFillDisplayName,
|
||||
{},
|
||||
rootCategory,
|
||||
QKeySequence(),
|
||||
(priorityLast+7),
|
||||
&addMouseAreaFill,
|
||||
&addMouseAreaFillCheck,
|
||||
&singleSelection));
|
||||
|
||||
const bool standaloneMode = QmlProjectManager::QmlProject::isQtDesignStudio();
|
||||
|
||||
if (!standaloneMode) {
|
||||
|
@@ -42,6 +42,18 @@ inline bool singleSelection(const SelectionContext &selectionState)
|
||||
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)
|
||||
{
|
||||
ModelNode node = selectionState.currentSingleSelectedNode();
|
||||
|
@@ -1616,6 +1616,34 @@ void editAnnotation(const SelectionContext &selectionContext)
|
||||
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)
|
||||
{
|
||||
if (modelNode.isValid())
|
||||
|
@@ -71,6 +71,7 @@ void selectFlowEffect(const SelectionContext &selectionContext);
|
||||
void mergeWithTemplate(const SelectionContext &selectionContext);
|
||||
void removeGroup(const SelectionContext &selectionContext);
|
||||
void editAnnotation(const SelectionContext &selectionContext);
|
||||
void addMouseAreaFill(const SelectionContext &selectionContext);
|
||||
|
||||
void openSignalDialog(const SelectionContext &selectionContext);
|
||||
void updateImported3DAsset(const SelectionContext &selectionContext);
|
||||
|
@@ -89,6 +89,8 @@ void ConnectionView::propertiesRemoved(const QList<AbstractProperty> &propertyLi
|
||||
for (const AbstractProperty &property : propertyList) {
|
||||
if (property.isDefaultProperty())
|
||||
connectionModel()->resetModel();
|
||||
|
||||
dynamicPropertiesModel()->dispatchPropertyChanges(property);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -116,8 +118,9 @@ void ConnectionView::variantPropertiesChanged(const QList<VariantProperty> &prop
|
||||
backendModel()->resetModel();
|
||||
|
||||
connectionModel()->variantPropertyChanged(variantProperty);
|
||||
}
|
||||
|
||||
dynamicPropertiesModel()->dispatchPropertyChanges(variantProperty);
|
||||
}
|
||||
}
|
||||
|
||||
void ConnectionView::bindingPropertiesChanged(const QList<BindingProperty> &propertyList,
|
||||
@@ -131,6 +134,8 @@ void ConnectionView::bindingPropertiesChanged(const QList<BindingProperty> &prop
|
||||
backendModel()->resetModel();
|
||||
|
||||
connectionModel()->bindingPropertyChanged(bindingProperty);
|
||||
|
||||
dynamicPropertiesModel()->dispatchPropertyChanges(bindingProperty);
|
||||
}
|
||||
}
|
||||
|
||||
|
@@ -5,14 +5,14 @@
|
||||
|
||||
#include "connectionview.h"
|
||||
|
||||
#include <bindingproperty.h>
|
||||
#include <nodemetainfo.h>
|
||||
#include <nodeproperty.h>
|
||||
#include <variantproperty.h>
|
||||
#include <bindingproperty.h>
|
||||
#include <rewritingexception.h>
|
||||
#include <rewritertransaction.h>
|
||||
#include <qmldesignerplugin.h>
|
||||
#include <rewritingexception.h>
|
||||
#include <variantproperty.h>
|
||||
#include <qmldesignerconstants.h>
|
||||
#include <qmldesignerplugin.h>
|
||||
|
||||
#include <utils/algorithm.h>
|
||||
#include <utils/fileutils.h>
|
||||
@@ -117,6 +117,44 @@ bool DynamicPropertiesModel::isValueType(const TypeName &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)
|
||||
: QStandardItemModel(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)
|
||||
{
|
||||
if (!bindingProperty.isDynamic())
|
||||
@@ -240,6 +292,27 @@ void DynamicPropertiesModel::bindingPropertyChanged(const BindingProperty &bindi
|
||||
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)
|
||||
{
|
||||
if (!variantProperty.isDynamic())
|
||||
@@ -312,7 +385,8 @@ void DynamicPropertiesModel::setSelectedNode(const ModelNode &node)
|
||||
AbstractProperty DynamicPropertiesModel::abstractPropertyForRow(int rowNumber) const
|
||||
{
|
||||
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())
|
||||
return AbstractProperty();
|
||||
@@ -383,7 +457,7 @@ void DynamicPropertiesModel::addDynamicPropertyForCurrentNode()
|
||||
const ModelNode modelNode = selectedNodes().constFirst();
|
||||
if (modelNode.isValid()) {
|
||||
try {
|
||||
modelNode.variantProperty(unusedProperty(modelNode)).setDynamicTypeNameAndValue("string", QLatin1String("none.none"));
|
||||
modelNode.variantProperty(unusedProperty(modelNode)).setDynamicTypeNameAndValue("string", "This is a string");
|
||||
} catch (RewritingException &e) {
|
||||
m_exceptionError = e.description();
|
||||
QTimer::singleShot(200, this, &DynamicPropertiesModel::handleException);
|
||||
@@ -434,7 +508,10 @@ QStringList DynamicPropertiesModel::possibleSourceProperties(const BindingProper
|
||||
|
||||
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);
|
||||
if (bindingProperty.isValid()) {
|
||||
bindingProperty.parentModelNode().removeProperty(bindingProperty.name());
|
||||
@@ -443,6 +520,22 @@ void DynamicPropertiesModel::deleteDynamicPropertyByRow(int rowNumber)
|
||||
if (variantProperty.isValid())
|
||||
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();
|
||||
@@ -502,6 +595,12 @@ void DynamicPropertiesModel::updateBindingProperty(int rowNumber)
|
||||
QString type = QString::fromUtf8(bindingProperty.dynamicTypeName());
|
||||
updateDisplayRole(rowNumber, PropertyTypeRow, type);
|
||||
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();
|
||||
QString type = QString::fromUtf8(variantProperty.dynamicTypeName());
|
||||
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);
|
||||
}
|
||||
@@ -525,16 +628,21 @@ void DynamicPropertiesModel::addModelNode(const ModelNode &modelNode)
|
||||
if (!modelNode.isValid())
|
||||
return;
|
||||
|
||||
const QList<BindingProperty> bindingProperties = modelNode.bindingProperties();
|
||||
for (const BindingProperty &bindingProperty : bindingProperties) {
|
||||
if (bindingProperty.isDynamic())
|
||||
addBindingProperty(bindingProperty);
|
||||
}
|
||||
auto properties = modelNode.properties();
|
||||
|
||||
const QList<VariantProperty> variantProperties = modelNode.variantProperties();
|
||||
for (const VariantProperty &variantProperty : variantProperties) {
|
||||
if (variantProperty.isDynamic())
|
||||
addVariantProperty(variantProperty);
|
||||
auto dynamicProperties = Utils::filtered(properties, [](const AbstractProperty &p) {
|
||||
return p.isDynamic();
|
||||
});
|
||||
|
||||
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;
|
||||
}
|
||||
|
||||
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)
|
||||
{
|
||||
//### todo we assume no expressions yet
|
||||
|
@@ -28,6 +28,7 @@ public:
|
||||
};
|
||||
DynamicPropertiesModel(bool explicitSelection, AbstractView *parent);
|
||||
void bindingPropertyChanged(const BindingProperty &bindingProperty);
|
||||
void abstractPropertyChanged(const AbstractProperty &bindingProperty);
|
||||
void variantPropertyChanged(const VariantProperty &variantProperty);
|
||||
void bindingRemoved(const BindingProperty &bindingProperty);
|
||||
void variantRemoved(const VariantProperty &variantProperty);
|
||||
@@ -51,9 +52,13 @@ public:
|
||||
BindingProperty replaceVariantWithBinding(const PropertyName &name, bool copyValue = false);
|
||||
void resetProperty(const PropertyName &name);
|
||||
|
||||
void dispatchPropertyChanges(const AbstractProperty &abstractProperty);
|
||||
|
||||
QmlDesigner::PropertyName unusedProperty(const QmlDesigner::ModelNode &modelNode);
|
||||
|
||||
static bool isValueType(const TypeName &type);
|
||||
static QVariant defaultValueForType(const TypeName &type);
|
||||
static QString defaultExpressionForType(const TypeName &type);
|
||||
|
||||
protected:
|
||||
void addProperty(const QVariant &propertyValue,
|
||||
@@ -72,6 +77,7 @@ protected:
|
||||
void updateCustomData(int row, const AbstractProperty &property);
|
||||
int findRowForBindingProperty(const BindingProperty &bindingProperty) const;
|
||||
int findRowForVariantProperty(const VariantProperty &variantProperty) const;
|
||||
int findRowForProperty(const AbstractProperty &abstractProperty) const;
|
||||
|
||||
bool getExpressionStrings(const BindingProperty &bindingProperty, QString *sourceNode, QString *sourceProperty);
|
||||
|
||||
|
@@ -268,15 +268,16 @@ void Edit3DView::customNotification([[maybe_unused]] const AbstractView *view,
|
||||
* 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 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) {
|
||||
// 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.
|
||||
if (modelNode.isValid() && !modelNode.isSelected())
|
||||
setSelectedModelNode(modelNode);
|
||||
m_edit3DWidget->showContextMenu(m_contextMenuPos, modelNode);
|
||||
m_edit3DWidget->showContextMenu(m_contextMenuPos, modelNode, pos3d);
|
||||
} else if (m_nodeAtPosReqType == NodeAtPosReqType::MaterialDrop) {
|
||||
// TODO: this is from 8.0 branch that doesn't apply anymore:
|
||||
// const bool isModel = modelNode.isSubclassOf("QtQuick3D.Model");
|
||||
|
@@ -41,7 +41,7 @@ public:
|
||||
void modelAboutToBeDetached(Model *model) 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 nodeAtPosReady(const ModelNode &modelNode) override;
|
||||
void nodeAtPosReady(const ModelNode &modelNode, const QVector3D &pos3d) override;
|
||||
|
||||
void sendInputEvent(QInputEvent *e) const;
|
||||
void edit3DViewResized(const QSize &size) const;
|
||||
|
@@ -215,7 +215,7 @@ void Edit3DWidget::onCreateAction()
|
||||
// int activeScene = m_view->rootModelNode().auxiliaryData("active3dScene@Internal").toInt();
|
||||
|
||||
// auto modelNode = QmlVisualNode::createQml3DNode(m_view, m_nameToEntry.value(action->data().toString()),
|
||||
// activeScene).modelNode();
|
||||
// activeScene, m_contextMenuPos3d).modelNode();
|
||||
// QTC_ASSERT(modelNode.isValid(), return);
|
||||
// m_view->setSelectedModelNode(modelNode);
|
||||
|
||||
@@ -273,9 +273,10 @@ void Edit3DWidget::showBackgroundColorMenu(bool show, const QPoint &pos)
|
||||
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_contextMenuPos3d = pos3d;
|
||||
|
||||
const bool isValid = modelNode.isValid();
|
||||
// TODO: this is from 8.0 branch that doesn't apply anymore:
|
||||
|
@@ -5,6 +5,7 @@
|
||||
#include <QLabel>
|
||||
#include <QMenu>
|
||||
#include <QPointer>
|
||||
#include <QVector3D>
|
||||
#include <QWidget>
|
||||
|
||||
#include <coreplugin/icontext.h>
|
||||
@@ -35,7 +36,7 @@ public:
|
||||
QMenu *backgroundColorMenu() const;
|
||||
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,
|
||||
const QHash<QString, QList<ItemLibraryEntry>> &entriesMap);
|
||||
|
||||
@@ -63,6 +64,7 @@ private:
|
||||
QPointer<QAction> m_deleteAction;
|
||||
QPointer<QMenu> m_createSubMenu;
|
||||
ModelNode m_contextMenuTarget;
|
||||
QVector3D m_contextMenuPos3d;
|
||||
QHash<QString, ItemLibraryEntry> m_nameToEntry;
|
||||
};
|
||||
|
||||
|
@@ -799,6 +799,8 @@ void MaterialEditorView::propertiesRemoved(const QList<AbstractProperty> &proper
|
||||
setValue(m_selectedMaterial, property.name(), QmlObjectNode(m_selectedMaterial).instanceValue(property.name()));
|
||||
changed = true;
|
||||
}
|
||||
|
||||
dynamicPropertiesModel()->dispatchPropertyChanges(property);
|
||||
}
|
||||
if (changed)
|
||||
requestPreviewRender();
|
||||
@@ -822,6 +824,8 @@ void MaterialEditorView::variantPropertiesChanged(const QList<VariantProperty> &
|
||||
|
||||
changed = true;
|
||||
}
|
||||
|
||||
dynamicPropertiesModel()->dispatchPropertyChanges(property);
|
||||
}
|
||||
if (changed)
|
||||
requestPreviewRender();
|
||||
@@ -849,6 +853,8 @@ void MaterialEditorView::bindingPropertiesChanged(const QList<BindingProperty> &
|
||||
|
||||
changed = true;
|
||||
}
|
||||
|
||||
dynamicPropertiesModel()->dispatchPropertyChanges(property);
|
||||
}
|
||||
if (changed)
|
||||
requestPreviewRender();
|
||||
|
@@ -106,8 +106,10 @@ QVariant DynamicPropertiesProxyModel::data(const QModelIndex &index, int role) c
|
||||
QmlObjectNode objectNode = property.parentQmlObjectNode();
|
||||
return objectNode.modelValue(property.name());
|
||||
} else if (role == propertyBindingRole) {
|
||||
if (property.isBindingProperty())
|
||||
return property.toBindingProperty().expression();
|
||||
if (property.isBindingProperty()) {
|
||||
QmlObjectNode objectNode = property.parentQmlObjectNode();
|
||||
return objectNode.expression(property.name());
|
||||
}
|
||||
return QVariant();
|
||||
}
|
||||
qWarning() << Q_FUNC_INFO << "invalid role";
|
||||
@@ -142,45 +144,23 @@ void DynamicPropertiesProxyModel::createProperty(const QString &name, const QStr
|
||||
{
|
||||
QmlDesignerPlugin::emitUsageStatistics(Constants::EVENT_PROPERTY_ADDED);
|
||||
|
||||
TypeName typeName = type.toUtf8();
|
||||
|
||||
const auto selectedNodes = dynamicPropertiesModel()->selectedNodes();
|
||||
if (selectedNodes.count() == 1) {
|
||||
const ModelNode modelNode = selectedNodes.constFirst();
|
||||
if (modelNode.isValid()) {
|
||||
try {
|
||||
if (Internal::DynamicPropertiesModel::isValueType(type.toUtf8())) {
|
||||
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 = "";
|
||||
else if (type == "bool")
|
||||
value = false;
|
||||
else if (type == "url")
|
||||
value = "";
|
||||
else if (type == "variant")
|
||||
value = "";
|
||||
|
||||
if (Internal::DynamicPropertiesModel::isValueType(typeName)) {
|
||||
QVariant value = Internal::DynamicPropertiesModel::defaultValueForType(typeName);
|
||||
modelNode.variantProperty(name.toUtf8())
|
||||
.setDynamicTypeNameAndValue(type.toUtf8(), value);
|
||||
.setDynamicTypeNameAndValue(typeName, value);
|
||||
} else {
|
||||
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)";
|
||||
QString expression = Internal::DynamicPropertiesModel::defaultExpressionForType(
|
||||
typeName);
|
||||
|
||||
modelNode.bindingProperty(name.toUtf8())
|
||||
.setDynamicTypeNameAndExpression(type.toUtf8(), expression);
|
||||
.setDynamicTypeNameAndExpression(typeName, expression);
|
||||
}
|
||||
} catch (Exception &e) {
|
||||
e.showException();
|
||||
@@ -203,7 +183,12 @@ DynamicPropertyRow::DynamicPropertyRow()
|
||||
QObject::connect(m_backendValue,
|
||||
&PropertyEditorValue::expressionChanged,
|
||||
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()
|
||||
@@ -301,13 +286,16 @@ void DynamicPropertyRow::setupBackendValue()
|
||||
m_backendValue->setModelNode(node);
|
||||
|
||||
QVariant modelValue = property.parentQmlObjectNode().modelValue(property.name());
|
||||
|
||||
const bool isBound = property.parentQmlObjectNode().hasBindingProperty(property.name());
|
||||
|
||||
if (modelValue != m_backendValue->value()) {
|
||||
m_backendValue->setValue({});
|
||||
m_backendValue->setValue(modelValue);
|
||||
}
|
||||
|
||||
if (property.isBindingProperty()) {
|
||||
QString expression = property.toBindingProperty().expression();
|
||||
if (isBound) {
|
||||
QString expression = property.parentQmlObjectNode().expression(property.name());
|
||||
if (m_backendValue->expression() != expression)
|
||||
m_backendValue->setExpression(expression);
|
||||
}
|
||||
@@ -323,6 +311,9 @@ void DynamicPropertyRow::commitValue(const QVariant &value)
|
||||
if (m_row < 0)
|
||||
return;
|
||||
|
||||
if (!value.isValid())
|
||||
return;
|
||||
|
||||
auto propertiesModel = m_model->dynamicPropertiesModel();
|
||||
VariantProperty variantProperty = propertiesModel->variantPropertyForRow(m_row);
|
||||
|
||||
@@ -336,11 +327,11 @@ void DynamicPropertyRow::commitValue(const QVariant &value)
|
||||
RewriterTransaction transaction = view->beginRewriterTransaction(
|
||||
QByteArrayLiteral("DynamicPropertiesModel::commitValue"));
|
||||
try {
|
||||
if (view->currentState().isBaseState()) {
|
||||
QmlObjectNode objectNode = variantProperty.parentQmlObjectNode();
|
||||
if (view->currentState().isBaseState() && !objectNode.timelineIsActive()) {
|
||||
if (variantProperty.value() != value)
|
||||
variantProperty.setDynamicTypeNameAndValue(variantProperty.dynamicTypeName(), value);
|
||||
} else {
|
||||
QmlObjectNode objectNode = variantProperty.parentQmlObjectNode();
|
||||
QTC_CHECK(objectNode.isValid());
|
||||
PropertyName name = variantProperty.name();
|
||||
if (objectNode.isValid() && objectNode.modelValue(name) != value)
|
||||
@@ -360,24 +351,43 @@ void DynamicPropertyRow::commitExpression(const QString &expression)
|
||||
if (m_row < 0)
|
||||
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;
|
||||
auto unlock = qScopeGuard([this] { m_lock = false; });
|
||||
|
||||
auto propertiesModel = m_model->dynamicPropertiesModel();
|
||||
BindingProperty bindingProperty = propertiesModel->bindingPropertyForRow(m_row);
|
||||
|
||||
auto view = propertiesModel->view();
|
||||
RewriterTransaction transaction = view->beginRewriterTransaction(
|
||||
QByteArrayLiteral("DynamicPropertiesModel::commitExpression"));
|
||||
QByteArrayLiteral("DynamicPropertyRow::commitExpression"));
|
||||
try {
|
||||
QString theExpression = expression;
|
||||
if (theExpression.isEmpty())
|
||||
theExpression = "null";
|
||||
|
||||
if (view->currentState().isBaseState()) {
|
||||
if (bindingProperty.expression() != theExpression) {
|
||||
bindingProperty.setDynamicTypeNameAndExpression(bindingProperty.dynamicTypeName(),
|
||||
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
|
||||
} catch (Exception &e) {
|
||||
e.showException();
|
||||
@@ -390,3 +400,46 @@ void DynamicPropertyRow::handleDataChanged(const QModelIndex &topLeft, const QMo
|
||||
if (topLeft.row() == m_row)
|
||||
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();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@@ -100,6 +100,7 @@ private:
|
||||
void commitValue(const QVariant &value);
|
||||
void commitExpression(const QString &expression);
|
||||
void handleDataChanged(const QModelIndex &topLeft, const QModelIndex &, const QList<int> &);
|
||||
void resetValue();
|
||||
|
||||
int m_row = -1;
|
||||
PropertyEditorValue *m_backendValue = nullptr;
|
||||
|
@@ -181,7 +181,7 @@ void PropertyEditorValue::setExpressionWithEmit(const QString &expression)
|
||||
if ( m_expression != expression) {
|
||||
setExpression(expression);
|
||||
m_value.clear();
|
||||
emit expressionChanged(nameAsQString());
|
||||
emit expressionChanged(nameAsQString()); //Note that we set the name in this case
|
||||
}
|
||||
}
|
||||
|
||||
|
@@ -135,7 +135,11 @@ signals:
|
||||
void valueChanged(const QString &name, const QVariant&);
|
||||
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 removeAliasExportRequested(const QString &name);
|
||||
|
||||
|
@@ -16,6 +16,7 @@
|
||||
|
||||
#include <QObject>
|
||||
#include <QPointer>
|
||||
#include <QVector3D>
|
||||
|
||||
#include <functional>
|
||||
#include <memory>
|
||||
@@ -145,7 +146,7 @@ public:
|
||||
void emitUpdateActiveScene3D(const QVariantMap &sceneState);
|
||||
void emitModelNodelPreviewPixmapChanged(const ModelNode &node, const QPixmap &pixmap);
|
||||
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 sendTokenToInstances(const QString &token, int number, const QVector<ModelNode> &nodeVector);
|
||||
@@ -214,7 +215,7 @@ public:
|
||||
virtual void renderImage3DChanged(const QImage &image);
|
||||
virtual void updateActiveScene3D(const QVariantMap &sceneState);
|
||||
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 view3DAction(View3DActionType type, const QVariant &value);
|
||||
|
@@ -37,6 +37,7 @@ public:
|
||||
bool isAlias() const;
|
||||
bool isAliasExport() const;
|
||||
|
||||
static QVariant convertToLiteral(const TypeName &typeName, const QString &expression);
|
||||
|
||||
protected:
|
||||
BindingProperty(const PropertyName &propertyName, const Internal::InternalNodePointer &internalNode, Model* model, AbstractView *view);
|
||||
|
@@ -87,6 +87,7 @@ public:
|
||||
bool isFlowViewFlowWildcard() const;
|
||||
bool isFlowViewItem() const;
|
||||
bool isFont() const;
|
||||
bool isSuitableForMouseAreaFill() const;
|
||||
bool isGraphicalItem() const;
|
||||
bool isInteger() const;
|
||||
bool isLayoutable() const;
|
||||
|
@@ -119,6 +119,8 @@ public:
|
||||
|
||||
QmlModelStateGroup states() const;
|
||||
|
||||
QList<ModelNode> allTimelines() const;
|
||||
|
||||
protected:
|
||||
NodeInstance nodeInstance() const;
|
||||
QmlObjectNode nodeForInstance(const NodeInstance &instance) const;
|
||||
|
@@ -44,6 +44,10 @@ public:
|
||||
QList<ModelNode> allTargets() const;
|
||||
QList<QmlTimelineKeyframeGroup> keyframeGroupsForTarget(const ModelNode &target) const;
|
||||
void destroyKeyframesForTarget(const ModelNode &target);
|
||||
|
||||
void removeKeyframesForTargetAndProperty(const ModelNode &target,
|
||||
const PropertyName &propertyName);
|
||||
|
||||
static bool hasActiveTimeline(AbstractView *view);
|
||||
|
||||
bool isRecording() const;
|
||||
|
@@ -1737,8 +1737,12 @@ void NodeInstanceView::handlePuppetToCreatorCommand(const PuppetToCreatorCommand
|
||||
const QVariantMap supportMap = qvariant_cast<QVariantMap>(command.data());
|
||||
emitImport3DSupportChanged(supportMap);
|
||||
} else if (command.type() == PuppetToCreatorCommand::NodeAtPos) {
|
||||
ModelNode modelNode = modelNodeForInternalId(command.data().toUInt());
|
||||
emitNodeAtPosResult(modelNode);
|
||||
auto data = qvariant_cast<QVariantList>(command.data());
|
||||
if (data.size() == 2) {
|
||||
ModelNode modelNode = modelNodeForInternalId(data[0].toInt());
|
||||
QVector3D pos3d = data[1].value<QVector3D>();
|
||||
emitNodeAtPosResult(modelNode, pos3d);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
@@ -1689,6 +1689,12 @@ bool NodeMetaInfo::isSubclassOf(const TypeName &type, int majorVersion, int mino
|
||||
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
|
||||
{
|
||||
if constexpr (useProjectStorage()) {
|
||||
|
@@ -388,8 +388,9 @@ void AbstractView::updateImport3DSupport(const QVariantMap & /*supportMap*/)
|
||||
{
|
||||
}
|
||||
|
||||
// a Quick3DModel that is picked at the requested position in the 3D Editor
|
||||
void AbstractView::nodeAtPosReady(const ModelNode & /*modelNode*/) {}
|
||||
// a Quick3DNode that is picked at the requested view position in the 3D Editor and the 3D scene
|
||||
// position of the requested view position.
|
||||
void AbstractView::nodeAtPosReady(const ModelNode & /*modelNode*/, const QVector3D &/*pos3d*/) {}
|
||||
|
||||
void AbstractView::modelNodePreviewPixmapChanged(const ModelNode & /*node*/, const QPixmap & /*pixmap*/)
|
||||
{
|
||||
@@ -783,10 +784,10 @@ void AbstractView::emitImport3DSupportChanged(const QVariantMap &supportMap)
|
||||
model()->d->notifyImport3DSupportChanged(supportMap);
|
||||
}
|
||||
|
||||
void AbstractView::emitNodeAtPosResult(const ModelNode &modelNode)
|
||||
void AbstractView::emitNodeAtPosResult(const ModelNode &modelNode, const QVector3D &pos3d)
|
||||
{
|
||||
if (model())
|
||||
model()->d->notifyNodeAtPosResult(modelNode);
|
||||
model()->d->notifyNodeAtPosResult(modelNode, pos3d);
|
||||
}
|
||||
|
||||
void AbstractView::emitView3DAction(View3DActionType type, const QVariant &value)
|
||||
|
@@ -269,6 +269,52 @@ bool BindingProperty::isAliasExport() const
|
||||
&& 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)
|
||||
{
|
||||
Internal::WriteLocker locker(model());
|
||||
|
@@ -571,9 +571,9 @@ void ModelPrivate::notifyImport3DSupportChanged(const QVariantMap &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)
|
||||
|
@@ -7,6 +7,7 @@
|
||||
#include <QPointer>
|
||||
#include <QSet>
|
||||
#include <QUrl>
|
||||
#include <QVector3D>
|
||||
|
||||
#include "modelnode.h"
|
||||
#include "abstractview.h"
|
||||
@@ -170,7 +171,7 @@ public:
|
||||
void notifyUpdateActiveScene3D(const QVariantMap &sceneState);
|
||||
void notifyModelNodePreviewPixmapChanged(const ModelNode &node, const QPixmap &pixmap);
|
||||
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 notifyDragStarted(QMimeData *mimeData);
|
||||
|
@@ -554,6 +554,12 @@ QList<QmlModelState> QmlObjectNode::allDefinedStates() const
|
||||
for (const QmlVisualNode &node : qAsConst(allVisualNodes))
|
||||
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;
|
||||
}
|
||||
|
||||
@@ -575,6 +581,18 @@ QmlModelStateGroup QmlObjectNode::states() const
|
||||
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
|
||||
model.
|
||||
|
@@ -185,6 +185,15 @@ void QmlTimeline::destroyKeyframesForTarget(const ModelNode &target)
|
||||
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)
|
||||
{
|
||||
if (view && view->isAttached()) {
|
||||
|
@@ -268,7 +268,7 @@ QmlObjectNode QmlVisualNode::createQmlObjectNode(AbstractView *view,
|
||||
QList<PropertyBindingEntry> propertyBindingList;
|
||||
QList<PropertyBindingEntry> propertyEnumList;
|
||||
if (itemLibraryEntry.qmlSource().isEmpty()) {
|
||||
QList<QPair<PropertyName, QVariant> > propertyPairList = position.propertyPairList();
|
||||
QList<QPair<PropertyName, QVariant> > propertyPairList;
|
||||
|
||||
for (const auto &property : itemLibraryEntry.properties()) {
|
||||
if (property.type() == "binding") {
|
||||
@@ -282,6 +282,8 @@ QmlObjectNode QmlVisualNode::createQmlObjectNode(AbstractView *view,
|
||||
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;
|
||||
if (itemLibraryEntry.typeName() == "QtQml.Component")
|
||||
|
@@ -219,7 +219,7 @@ void FileSystemAccessTest::testFileTransfer()
|
||||
QVERIFY2(dirForFilesToDownload.isValid(), qPrintable(dirForFilesToDownload.errorString()));
|
||||
QVERIFY2(dir2ForFilesToDownload.isValid(), qPrintable(dirForFilesToDownload.errorString()));
|
||||
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;
|
||||
std::srand(QDateTime::currentDateTime().toSecsSinceEpoch());
|
||||
@@ -255,11 +255,11 @@ void FileSystemAccessTest::testFileTransfer()
|
||||
getRemoteFilePath(bigFileName)};
|
||||
fileTransfer.setFilesToTransfer(filesToUpload);
|
||||
|
||||
QString jobError;
|
||||
ProcessResultData result;
|
||||
QEventLoop loop;
|
||||
connect(&fileTransfer, &FileTransfer::done, [&jobError, &loop]
|
||||
connect(&fileTransfer, &FileTransfer::done, [&result, &loop]
|
||||
(const ProcessResultData &resultData) {
|
||||
jobError = resultData.m_errorString;
|
||||
result = resultData;
|
||||
loop.quit();
|
||||
});
|
||||
QTimer timer;
|
||||
@@ -271,7 +271,15 @@ void FileSystemAccessTest::testFileTransfer()
|
||||
loop.exec();
|
||||
QVERIFY(timer.isActive());
|
||||
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
|
||||
|
@@ -1269,13 +1269,9 @@ qint64 LinuxDevice::bytesAvailable(const FilePath &filePath) const
|
||||
QTC_ASSERT(handlesFile(filePath), return -1);
|
||||
CommandLine cmd("df", {"-k"});
|
||||
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());
|
||||
bool ok = false;
|
||||
const qint64 size = output.toLongLong(&ok);
|
||||
if (ok)
|
||||
return size * 1024;
|
||||
return -1;
|
||||
|
||||
return FileUtils::bytesAvailableFromDFOutput(output);
|
||||
}
|
||||
|
||||
QFileDevice::Permissions LinuxDevice::permissions(const FilePath &filePath) const
|
||||
@@ -1499,18 +1495,12 @@ private:
|
||||
return;
|
||||
}
|
||||
|
||||
m_batchFile.reset(new QTemporaryFile(this));
|
||||
if (!m_batchFile->isOpen() && !m_batchFile->open()) {
|
||||
startFailed(Tr::tr("Could not create temporary file: %1")
|
||||
.arg(m_batchFile->errorString()));
|
||||
return;
|
||||
}
|
||||
QByteArray batchData;
|
||||
|
||||
const FilePaths dirs = dirsToCreate(m_setup.m_files);
|
||||
for (const FilePath &dir : dirs) {
|
||||
if (direction() == FileTransferDirection::Upload) {
|
||||
m_batchFile->write("-mkdir " + ProcessArgs::quoteArgUnix(dir.path()).toLocal8Bit()
|
||||
+ '\n');
|
||||
batchData += "-mkdir " + ProcessArgs::quoteArgUnix(dir.path()).toLocal8Bit() + '\n';
|
||||
} else if (direction() == FileTransferDirection::Download) {
|
||||
if (!QDir::root().mkpath(dir.path())) {
|
||||
startFailed(Tr::tr("Failed to create local directory \"%1\".")
|
||||
@@ -1527,26 +1517,23 @@ private:
|
||||
const QFileInfo fi(file.m_source.toFileInfo());
|
||||
if (fi.isSymLink()) {
|
||||
link = true;
|
||||
m_batchFile->write("-rm " + ProcessArgs::quoteArgUnix(
|
||||
file.m_target.path()).toLocal8Bit() + '\n');
|
||||
batchData += "-rm " + ProcessArgs::quoteArgUnix(
|
||||
file.m_target.path()).toLocal8Bit() + '\n';
|
||||
// see QTBUG-5817.
|
||||
sourceFileOrLinkTarget =
|
||||
sourceFileOrLinkTarget.withNewPath(fi.dir().relativeFilePath(fi.symLinkTarget()));
|
||||
}
|
||||
}
|
||||
m_batchFile->write(transferCommand(direction(), link) + ' '
|
||||
batchData += transferCommand(direction(), link) + ' '
|
||||
+ 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(CommandLine(sftpBinary, fullConnectionOptions()
|
||||
<< "-b" << m_batchFile->fileName() << host()));
|
||||
process().setCommand({sftpBinary, fullConnectionOptions() << "-b" << "-" << host()});
|
||||
process().setWriteData(batchData);
|
||||
process().start();
|
||||
}
|
||||
|
||||
void doneImpl() final { handleDone(); }
|
||||
|
||||
std::unique_ptr<QTemporaryFile> m_batchFile;
|
||||
};
|
||||
|
||||
class RsyncTransferImpl : public SshTransferInterface
|
||||
|
@@ -60,6 +60,9 @@ private slots:
|
||||
void resolvePath();
|
||||
void relativeChildPath_data();
|
||||
void relativeChildPath();
|
||||
void bytesAvailableFromDF_data();
|
||||
void bytesAvailableFromDF();
|
||||
|
||||
void asyncLocalCopy();
|
||||
void startsWithDriveLetter();
|
||||
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");
|
||||
}
|
||||
|
||||
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)
|
||||
#include "tst_fileutils.moc"
|
||||
|
@@ -152,6 +152,8 @@ def doSimpleDebugging(currentKit, currentConfigName, expectedBPOrder=[], enableQ
|
||||
|
||||
# param currentKit specifies the ID of the kit to use (see class Targets)
|
||||
def isMsvcConfig(currentKit):
|
||||
if platform.system() not in ('Microsoft' 'Windows'):
|
||||
return False
|
||||
switchViewTo(ViewConstants.PROJECTS)
|
||||
switchToBuildOrRunSettingsFor(currentKit, ProjectSettings.BUILD)
|
||||
|
||||
@@ -164,7 +166,8 @@ def isMsvcConfig(currentKit):
|
||||
raise Exception("Kit '%s' is not activated in the project." % wantedKitName)
|
||||
index = waitForObject(wantedKitIndexString)
|
||||
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)
|
||||
if match is None:
|
||||
test.warning("UI seems to have changed - failed to check for compiler.")
|
||||
|
Reference in New Issue
Block a user