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
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

View File

@@ -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

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
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.

View File

@@ -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;

View File

@@ -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);

View File

@@ -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

View File

@@ -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,15 +153,80 @@ SecondColumnLayout {
MouseArea {
anchors.fill: parent
onClicked: {
cePopup.opened ? cePopup.close() : cePopup.open()
popupLoader.opened ? popupLoader.close() : popupLoader.open()
forceActiveFocus()
}
}
ColorEditorPopup {
id: cePopup
x: cePopup.__defaultX
y: cePopup.__defaultY
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()
}
}
}
}
@@ -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()
}
}

View File

@@ -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
+ StudioTheme.Values.actionIndicatorWidth
}
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
+ StudioTheme.Values.actionIndicatorWidth
}
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()
}
@@ -192,27 +174,20 @@ Section {
implicitWidth: StudioTheme.Values.twoControlColumnWidth
+ StudioTheme.Values.actionIndicatorWidth
text: layoutBool.backendValue.value
backendValue: layoutBool.backendValue
backendValue: layoutBool.backendValue
}
Spacer {
implicitWidth: StudioTheme.Values.twoControlColumnGap
}
Spacer { implicitWidth: StudioTheme.Values.twoControlColumnGap }
Item {
height: 10
implicitWidth: {
return StudioTheme.Values.twoControlColumnWidth
+ StudioTheme.Values.actionIndicatorWidth
}
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
+ StudioTheme.Values.actionIndicatorWidth
}
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,8 +502,9 @@ Section {
active: repeater.loadActive
width: loader.item ? loader.item.width : 0
height: loader.item ? loader.item.height : 0
Layout.fillWidth: true
sourceComponent: {
sourceComponent: {
if (propertyType == "color")
return colorEditor
if (propertyType == "int")
@@ -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 {

View File

@@ -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

View File

@@ -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
}
}

View File

@@ -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);
}

View File

@@ -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

View File

@@ -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)
{

View File

@@ -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>

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

View File

@@ -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);

View File

@@ -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)

View File

@@ -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 &macro) const

View File

@@ -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")}));
}

View File

@@ -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");

View File

@@ -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) {

View File

@@ -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();

View File

@@ -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())

View File

@@ -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);

View File

@@ -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);
}
}

View File

@@ -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,12 +385,13 @@ 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();
ModelNode modelNode = m_view->modelNodeForInternalId(internalId);
ModelNode modelNode = m_view->modelNodeForInternalId(internalId);
if (modelNode.isValid())
return modelNode.property(targetPropertyName.toUtf8());
@@ -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,16 +508,35 @@ QStringList DynamicPropertiesModel::possibleSourceProperties(const BindingProper
void DynamicPropertiesModel::deleteDynamicPropertyByRow(int rowNumber)
{
m_view->executeInTransaction("DynamicPropertiesModel::deleteDynamicPropertyByRow", [this, rowNumber]() {
BindingProperty bindingProperty = bindingPropertyForRow(rowNumber);
if (bindingProperty.isValid()) {
bindingProperty.parentModelNode().removeProperty(bindingProperty.name());
} else {
VariantProperty variantProperty = variantPropertyForRow(rowNumber);
if (variantProperty.isValid())
variantProperty.parentModelNode().removeProperty(variantProperty.name());
}
});
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());
} else {
VariantProperty variantProperty = variantPropertyForRow(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

View File

@@ -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);

View File

@@ -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");

View File

@@ -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;

View File

@@ -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:

View File

@@ -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;
};

View File

@@ -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();

View File

@@ -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 (bindingProperty.expression() != theExpression) {
bindingProperty.setDynamicTypeNameAndExpression(bindingProperty.dynamicTypeName(),
theExpression);
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();
}
}
}

View File

@@ -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;

View File

@@ -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
}
}

View File

@@ -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);

View File

@@ -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);

View File

@@ -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);

View File

@@ -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;

View File

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

View File

@@ -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;

View File

@@ -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);
}
}
}

View File

@@ -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()) {

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
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)

View File

@@ -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());

View File

@@ -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)

View File

@@ -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);

View File

@@ -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.

View File

@@ -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()) {

View File

@@ -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")

View File

@@ -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

View File

@@ -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) + ' '
+ ProcessArgs::quoteArgUnix(sourceFileOrLinkTarget.path()).toLocal8Bit() + ' '
+ ProcessArgs::quoteArgUnix(file.m_target.path()).toLocal8Bit() + '\n');
batchData += transferCommand(direction(), link) + ' '
+ ProcessArgs::quoteArgUnix(sourceFileOrLinkTarget.path()).toLocal8Bit() + ' '
+ 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

View File

@@ -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"

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)
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.")