From 00ee1ca7e030d59630925decdfd14d3ed57beb69 Mon Sep 17 00:00:00 2001 From: Thomas Hartmann Date: Tue, 19 Feb 2019 17:58:58 +0100 Subject: QmlDesigner: Fix crash The version number of 'GradientStop' was hardcoded, but does change with QtQuick 5.12. The issue is not consistently triggered. This is a backport from master. Task-number: QDS-472 Change-Id: I939659aa14ae1570fc5d833726f28894c043da02 Reviewed-by: Alessandro Portale Reviewed-by: Tim Jenssen --- .../components/propertyeditor/gradientmodel.cpp | 236 +++++++++++++++++---- .../components/propertyeditor/gradientmodel.h | 17 +- 2 files changed, 210 insertions(+), 43 deletions(-) diff --git a/src/plugins/qmldesigner/components/propertyeditor/gradientmodel.cpp b/src/plugins/qmldesigner/components/propertyeditor/gradientmodel.cpp index aa7cfe1bb0..b2e25fa6d6 100644 --- a/src/plugins/qmldesigner/components/propertyeditor/gradientmodel.cpp +++ b/src/plugins/qmldesigner/components/propertyeditor/gradientmodel.cpp @@ -28,6 +28,7 @@ #include "qmlanchorbindingproxy.h" #include "propertyeditorview.h" +#include #include #include #include @@ -35,8 +36,11 @@ #include #include +#include + GradientModel::GradientModel(QObject *parent) : QAbstractListModel(parent), m_locked(false) + ,m_gradientTypeName("Gradient") { } @@ -101,28 +105,29 @@ int GradientModel::addStop(qreal position, const QColor &color) return -1; if (m_itemNode.modelNode().hasNodeProperty(gradientPropertyName().toUtf8())) { - //QmlDesigner::RewriterTransaction transaction = m_itemNode.modelNode().view()->beginRewriterTransaction(); - //### TODO does not work + int properPos = 0; + try { - QmlDesigner::ModelNode gradientNode = m_itemNode.modelNode().nodeProperty(gradientPropertyName().toUtf8()).modelNode(); + QmlDesigner::ModelNode gradientNode = m_itemNode.modelNode().nodeProperty(gradientPropertyName().toUtf8()).modelNode(); - QmlDesigner::ModelNode gradientStopNode = - m_itemNode.modelNode().view()->createModelNode("QtQuick.GradientStop", - m_itemNode.modelNode().view()->majorQtQuickVersion(), 0); - gradientStopNode.variantProperty("position").setValue(position); - gradientStopNode.variantProperty("color").setValue(color); - gradientNode.nodeListProperty("stops").reparentHere(gradientStopNode); + QmlDesigner::ModelNode gradientStopNode = createGradientStopNode(); - const QList stopNodes = gradientNode.nodeListProperty("stops").toModelNodeList(); + gradientStopNode.variantProperty("position").setValue(position); + gradientStopNode.variantProperty("color").setValue(color); + gradientNode.nodeListProperty("stops").reparentHere(gradientStopNode); - int properPos = 0; - for (int i = 0; i < stopNodes.count(); i++) { - if (QmlDesigner::QmlObjectNode(stopNodes.at(i)).modelValue("position").toReal() < position) - properPos = i + 1; - } - gradientNode.nodeListProperty("stops").slide(stopNodes.count() - 1, properPos); + const QList stopNodes = gradientNode.nodeListProperty("stops").toModelNodeList(); - setupModel(); + for (int i = 0; i < stopNodes.count(); i++) { + if (QmlDesigner::QmlObjectNode(stopNodes.at(i)).modelValue("position").toReal() < position) + properPos = i + 1; + } + gradientNode.nodeListProperty("stops").slide(stopNodes.count() - 1, properPos); + + setupModel(); + } catch (const QmlDesigner::Exception &e) { + e.showException(); + } return properPos; } @@ -139,38 +144,38 @@ void GradientModel::addGradient() return; if (!m_itemNode.modelNode().hasNodeProperty(gradientPropertyName().toUtf8())) { + try { + + QColor color = m_itemNode.instanceValue("color").value(); - QColor color = m_itemNode.instanceValue("color").value(); + if (!color.isValid()) + color = QColor(Qt::white); - if (!color.isValid()) - color = QColor(Qt::white); + QmlDesigner::RewriterTransaction transaction = view()->beginRewriterTransaction(QByteArrayLiteral("GradientModel::addGradient")); - QmlDesigner::RewriterTransaction transaction = m_itemNode.modelNode().view()->beginRewriterTransaction(QByteArrayLiteral("GradientModel::addGradient")); + QmlDesigner::ModelNode gradientNode = createGradientNode(); - QmlDesigner::ModelNode gradientNode = - m_itemNode.modelNode().view()->createModelNode("QtQuick.Gradient", - m_itemNode.modelNode().view()->majorQtQuickVersion(), 0); - m_itemNode.modelNode().nodeProperty(gradientPropertyName().toUtf8()).reparentHere(gradientNode); + m_itemNode.modelNode().nodeProperty(gradientPropertyName().toUtf8()).reparentHere(gradientNode); + QmlDesigner::ModelNode gradientStopNode = createGradientStopNode(); + gradientStopNode.variantProperty("position").setValue(0.0); + gradientStopNode.variantProperty("color").setValue(color); + gradientNode.nodeListProperty("stops").reparentHere(gradientStopNode); - QmlDesigner::ModelNode gradientStopNode = - m_itemNode.modelNode().view()->createModelNode("QtQuick.GradientStop", - m_itemNode.modelNode().view()->majorQtQuickVersion(), 0); - gradientStopNode.variantProperty("position").setValue(0.0); - gradientStopNode.variantProperty("color").setValue(color); - gradientNode.nodeListProperty("stops").reparentHere(gradientStopNode); + gradientStopNode = createGradientStopNode(); + gradientStopNode.variantProperty("position").setValue(1.0); + gradientStopNode.variantProperty("color").setValue(QColor(Qt::black)); + gradientNode.nodeListProperty("stops").reparentHere(gradientStopNode); - gradientStopNode = m_itemNode.modelNode().view()->createModelNode( - "QtQuick.GradientStop", - m_itemNode.modelNode().view()->majorQtQuickVersion(), 0); - gradientStopNode.variantProperty("position").setValue(1.0); - gradientStopNode.variantProperty("color").setValue(QColor(Qt::black)); - gradientNode.nodeListProperty("stops").reparentHere(gradientStopNode); + } catch (const QmlDesigner::Exception &e) { + e.showException(); + } } setupModel(); emit hasGradientChanged(); + emit gradientTypeChanged(); } void GradientModel::setColor(int index, const QColor &color) @@ -231,7 +236,7 @@ qreal GradientModel::getPosition(int index) const void GradientModel::removeStop(int index) { if (index < rowCount() - 1 && index != 0) { - QmlDesigner::RewriterTransaction transaction = m_itemNode.modelNode().view()->beginRewriterTransaction(QByteArrayLiteral("GradientModel::removeStop")); + QmlDesigner::RewriterTransaction transaction = view()->beginRewriterTransaction(QByteArrayLiteral("GradientModel::removeStop")); QmlDesigner::ModelNode gradientNode = m_itemNode.modelNode().nodeProperty(gradientPropertyName().toUtf8()).modelNode(); QmlDesigner::QmlObjectNode stop = gradientNode.nodeListProperty("stops").at(index); if (stop.isValid()) { @@ -255,7 +260,7 @@ void GradientModel::deleteGradient() if (m_itemNode.isInBaseState()) { if (modelNode.hasProperty(gradientPropertyName().toUtf8())) { - QmlDesigner::RewriterTransaction transaction = m_itemNode.modelNode().view()->beginRewriterTransaction(QByteArrayLiteral("GradientModel::deleteGradient")); + QmlDesigner::RewriterTransaction transaction = view()->beginRewriterTransaction(QByteArrayLiteral("GradientModel::deleteGradient")); QmlDesigner::ModelNode gradientNode = modelNode.nodeProperty(gradientPropertyName().toUtf8()).modelNode(); if (QmlDesigner::QmlObjectNode(gradientNode).isValid()) QmlDesigner::QmlObjectNode(gradientNode).destroy(); @@ -263,6 +268,7 @@ void GradientModel::deleteGradient() } emit hasGradientChanged(); + emit gradientTypeChanged(); } void GradientModel::lock() @@ -280,6 +286,22 @@ void GradientModel::registerDeclarativeType() qmlRegisterType("HelperWidgets",2,0,"GradientModel"); } +qreal GradientModel::readGradientProperty(const QString &propertyName) const +{ + if (!m_itemNode.isValid()) + return 0; + + QmlDesigner::QmlObjectNode gradient; + + if (m_itemNode.modelNode().hasProperty(gradientPropertyName().toUtf8())) + gradient = m_itemNode.modelNode().nodeProperty(gradientPropertyName().toUtf8()).modelNode(); + + if (!gradient.isValid()) + return 0; + + return gradient.modelValue(propertyName.toUtf8()).toReal(); +} + void GradientModel::setupModel() { m_locked = true; @@ -299,12 +321,17 @@ void GradientModel::setAnchorBackend(const QVariant &anchorBackend) if (backendCasted) m_itemNode = backendCasted->getItemNode(); + if (m_itemNode.isValid() + && m_itemNode.modelNode().hasProperty(gradientPropertyName().toUtf8())) + m_gradientTypeName = m_itemNode.modelNode().nodeProperty(gradientPropertyName().toUtf8()).modelNode().simplifiedTypeName(); + setupModel(); m_locked = true; emit anchorBackendChanged(); emit hasGradientChanged(); + emit gradientTypeChanged(); m_locked = false; } @@ -319,6 +346,16 @@ void GradientModel::setGradientPropertyName(const QString &name) m_gradientPropertyName = name; } +QString GradientModel::gradientTypeName() const +{ + return m_gradientTypeName; +} + +void GradientModel::setGradientTypeName(const QString &name) +{ + m_gradientTypeName = name; +} + bool GradientModel::hasGradient() const { return m_itemNode.isValid() @@ -330,10 +367,125 @@ bool GradientModel::locked() const if (m_locked) return true; - auto view = qobject_cast(m_itemNode.view()); + auto editorView = qobject_cast(view()); - if (view && view->locked()) - return true; + return editorView && editorView->locked(); +} + +bool GradientModel::hasShapesImport() const +{ + if (m_itemNode.isValid()) { + QmlDesigner::Import import = QmlDesigner::Import::createLibraryImport("QtQuick.Shapes", "1.0"); + return model()->hasImport(import, true, true); + } return false; } + +void GradientModel::ensureShapesImport() +{ + if (!hasShapesImport()) { + QmlDesigner::Import timelineImport = QmlDesigner::Import::createLibraryImport("QtQuick.Shapes", "1.0"); + model()->changeImports({timelineImport}, {}); + } +} + +void GradientModel::setupGradientProperties(const QmlDesigner::ModelNode &gradient) +{ + QTC_ASSERT(m_itemNode.isValid(), return); + + QTC_ASSERT(gradient.isValid(), return); + + if (m_gradientTypeName == "Gradient") { + } else if (m_gradientTypeName == "LinearGradient") { + gradient.variantProperty("x1").setValue(0); + gradient.variantProperty("x2").setValue(m_itemNode.instanceValue("width")); + gradient.variantProperty("y1").setValue(0); + gradient.variantProperty("y2").setValue(m_itemNode.instanceValue("height")); + } else if (m_gradientTypeName == "RadialGradient") { + qreal width = m_itemNode.instanceValue("width").toReal(); + qreal height = m_itemNode.instanceValue("height").toReal(); + gradient.variantProperty("centerX").setValue(width / 2.0); + gradient.variantProperty("centerY").setValue(height / 2.0); + + gradient.variantProperty("focalX").setValue(width / 2.0); + gradient.variantProperty("focalY").setValue(height / 2.0); + + qreal radius = qMin(width, height) / 2; + + gradient.variantProperty("centerRadius").setValue(radius); + gradient.variantProperty("focalRadius").setValue(0); + + } else if (m_gradientTypeName == "ConicalGradient") { + qreal width = m_itemNode.instanceValue("width").toReal(); + qreal height = m_itemNode.instanceValue("height").toReal(); + gradient.variantProperty("centerX").setValue(width / 2.0); + gradient.variantProperty("centerY").setValue(height / 2.0); + + gradient.variantProperty("angle").setValue(0); + } +} + +QmlDesigner::Model *GradientModel::model() const +{ + QTC_ASSERT(m_itemNode.isValid(), return nullptr); + return m_itemNode.view()->model(); +} + +QmlDesigner::AbstractView *GradientModel::view() const +{ + QTC_ASSERT(m_itemNode.isValid(), return nullptr); + return m_itemNode.view(); +} + +QmlDesigner::ModelNode GradientModel::createGradientNode() +{ + QByteArray fullTypeName = m_gradientTypeName.toUtf8(); + + if (m_gradientTypeName == "Gradient") { + fullTypeName.prepend("QtQuick."); + } else { + fullTypeName.prepend("QtQuick.Shapes."); + ensureShapesImport(); + } + + auto metaInfo = model()->metaInfo(fullTypeName); + + int minorVersion = metaInfo.minorVersion(); + int majorVersion = metaInfo.majorVersion(); + + auto gradientNode = view()->createModelNode(fullTypeName, majorVersion, minorVersion); + + setupGradientProperties(gradientNode); + + return gradientNode; +} + +QmlDesigner::ModelNode GradientModel::createGradientStopNode() +{ + QByteArray fullTypeName = "QtQuick.GradientStop"; + auto metaInfo = model()->metaInfo(fullTypeName); + + int minorVersion = metaInfo.minorVersion(); + int majorVersion = metaInfo.majorVersion(); + + return view()->createModelNode(fullTypeName, majorVersion, minorVersion); +} + +void GradientModel::setGradientProperty(const QString &propertyName, qreal value) +{ + QTC_ASSERT(m_itemNode.isValid(), return); + + QmlDesigner::QmlObjectNode gradient; + + if (m_itemNode.modelNode().hasProperty(gradientPropertyName().toUtf8())) + gradient = m_itemNode.modelNode().nodeProperty(gradientPropertyName().toUtf8()).modelNode(); + + QTC_ASSERT(gradient.isValid(), return); + + try { + gradient.setVariantProperty(propertyName.toUtf8(), value); + } catch (const QmlDesigner::Exception &e) { + e.showException(); + } +} diff --git a/src/plugins/qmldesigner/components/propertyeditor/gradientmodel.h b/src/plugins/qmldesigner/components/propertyeditor/gradientmodel.h index 2ca8b93c42..48514ae688 100644 --- a/src/plugins/qmldesigner/components/propertyeditor/gradientmodel.h +++ b/src/plugins/qmldesigner/components/propertyeditor/gradientmodel.h @@ -37,6 +37,7 @@ class GradientModel : public QAbstractListModel Q_PROPERTY(QVariant anchorBackendProperty READ anchorBackend WRITE setAnchorBackend NOTIFY anchorBackendChanged) Q_PROPERTY(QString gradientPropertyName READ gradientPropertyName WRITE setGradientPropertyName) + Q_PROPERTY(QString gradientTypeName READ gradientTypeName WRITE setGradientTypeName NOTIFY gradientTypeChanged) Q_PROPERTY(int count READ rowCount) Q_PROPERTY(bool hasGradient READ hasGradient NOTIFY hasGradientChanged) @@ -65,9 +66,14 @@ public: static void registerDeclarativeType(); + Q_INVOKABLE qreal readGradientProperty(const QString &property) const; + + Q_INVOKABLE void setGradientProperty(const QString &propertyName, qreal value); + signals: void anchorBackendChanged(); void hasGradientChanged(); + void gradientTypeChanged(); private: void setupModel(); @@ -75,14 +81,23 @@ private: QVariant anchorBackend() const {return QVariant(); } QString gradientPropertyName() const; void setGradientPropertyName(const QString &name); + QString gradientTypeName() const; + void setGradientTypeName(const QString &name); bool hasGradient() const; bool locked() const; + QmlDesigner::ModelNode createGradientNode(); + QmlDesigner::ModelNode createGradientStopNode(); private: QmlDesigner::QmlItemNode m_itemNode; QString m_gradientPropertyName; + QString m_gradientTypeName; bool m_locked; - + bool hasShapesImport() const; + void ensureShapesImport(); + void setupGradientProperties(const QmlDesigner::ModelNode &gradient); + QmlDesigner::Model *model() const; + QmlDesigner::AbstractView *view() const; }; QML_DECLARE_TYPE(GradientModel) -- cgit v1.2.3