diff --git a/src/plugins/qmldesigner/designercore/filemanager/addpropertyvisitor.cpp b/src/plugins/qmldesigner/designercore/filemanager/addpropertyvisitor.cpp index 47a7af5fc3b..baa6dcdcf2b 100644 --- a/src/plugins/qmldesigner/designercore/filemanager/addpropertyvisitor.cpp +++ b/src/plugins/qmldesigner/designercore/filemanager/addpropertyvisitor.cpp @@ -155,8 +155,14 @@ void AddPropertyVisitor::addInMembers(QmlJS::AST::UiObjectInitializer *initializ Q_ASSERT(!"unknown property type"); } - if (!m_dynamicTypeName.isEmpty()) - newPropertyTemplate.prepend(QStringLiteral("property %1 ").arg(QString::fromUtf8(m_dynamicTypeName))); + if (!m_dynamicTypeName.isEmpty()) { + if (m_dynamicTypeName == "signal") { + newPropertyTemplate = "signal %1%2"; + } else { + newPropertyTemplate.prepend( + QStringLiteral("property %1 ").arg(QString::fromUtf8(m_dynamicTypeName))); + } + } if (isOneLiner) { if (needsPreceedingSemicolon) diff --git a/src/plugins/qmldesigner/designercore/filemanager/changepropertyvisitor.cpp b/src/plugins/qmldesigner/designercore/filemanager/changepropertyvisitor.cpp index c76b67dceb9..caaab23e654 100644 --- a/src/plugins/qmldesigner/designercore/filemanager/changepropertyvisitor.cpp +++ b/src/plugins/qmldesigner/designercore/filemanager/changepropertyvisitor.cpp @@ -137,7 +137,14 @@ void ChangePropertyVisitor::replaceMemberValue(UiObjectMember *propertyMember, b startOffset = arrayBinding->lbracketToken.offset; endOffset = arrayBinding->rbracketToken.end(); } else if (auto publicMember = AST::cast(propertyMember)) { - if (publicMember->statement) { + if (publicMember->type == AST::UiPublicMember::Signal) { + startOffset = publicMember->firstSourceLocation().offset; + if (publicMember->semicolonToken.isValid()) + endOffset = publicMember->semicolonToken.end(); + else + endOffset = publicMember->lastSourceLocation().end(); + replacement.prepend(QStringLiteral("signal %1 ").arg(publicMember->name)); + } else if (publicMember->statement) { startOffset = publicMember->statement->firstSourceLocation().offset; if (publicMember->semicolonToken.isValid()) endOffset = publicMember->semicolonToken.end(); diff --git a/src/plugins/qmldesigner/designercore/include/abstractproperty.h b/src/plugins/qmldesigner/designercore/include/abstractproperty.h index cb717664454..5eae8de3028 100644 --- a/src/plugins/qmldesigner/designercore/include/abstractproperty.h +++ b/src/plugins/qmldesigner/designercore/include/abstractproperty.h @@ -51,6 +51,7 @@ class QMLDESIGNERCORE_EXPORT NodeAbstractProperty; class QMLDESIGNERCORE_EXPORT BindingProperty; class QMLDESIGNERCORE_EXPORT NodeProperty; class QMLDESIGNERCORE_EXPORT SignalHandlerProperty; +class QMLDESIGNERCORE_EXPORT SignalDeclarationProperty; class QmlObjectNode; @@ -88,6 +89,7 @@ public: BindingProperty toBindingProperty() const; NodeProperty toNodeProperty() const; SignalHandlerProperty toSignalHandlerProperty() const; + SignalDeclarationProperty toSignalDeclarationProperty() const; bool isVariantProperty() const; bool isNodeListProperty() const; @@ -95,6 +97,7 @@ public: bool isBindingProperty() const; bool isNodeProperty() const; bool isSignalHandlerProperty() const; + bool isSignalDeclarationProperty() const; bool isDynamic() const; TypeName dynamicTypeName() const; diff --git a/src/plugins/qmldesigner/designercore/include/abstractview.h b/src/plugins/qmldesigner/designercore/include/abstractview.h index e41e93960c4..994caaa7ec4 100644 --- a/src/plugins/qmldesigner/designercore/include/abstractview.h +++ b/src/plugins/qmldesigner/designercore/include/abstractview.h @@ -185,6 +185,7 @@ public: virtual void bindingPropertiesAboutToBeChanged(const QList &propertyList); virtual void bindingPropertiesChanged(const QList& propertyList, PropertyChangeFlags propertyChange); virtual void signalHandlerPropertiesChanged(const QVector& propertyList, PropertyChangeFlags propertyChange); + virtual void signalDeclarationPropertiesChanged(const QVector& propertyList, PropertyChangeFlags propertyChange); virtual void rootNodeTypeChanged(const QString &type, int majorVersion, int minorVersion); virtual void nodeTypeChanged(const ModelNode& node, const TypeName &type, int majorVersion, int minorVersion); diff --git a/src/plugins/qmldesigner/designercore/include/modelnode.h b/src/plugins/qmldesigner/designercore/include/modelnode.h index d187332e614..003c732c80c 100644 --- a/src/plugins/qmldesigner/designercore/include/modelnode.h +++ b/src/plugins/qmldesigner/designercore/include/modelnode.h @@ -51,6 +51,7 @@ class AbstractProperty; class BindingProperty; class VariantProperty; class SignalHandlerProperty; +class SignalDeclarationProperty; class Model; class AbstractView; class NodeListProperty; @@ -128,6 +129,7 @@ public: VariantProperty variantProperty(const PropertyName &name) const; BindingProperty bindingProperty(const PropertyName &name) const; SignalHandlerProperty signalHandlerProperty(const PropertyName &name) const; + SignalDeclarationProperty signalDeclarationProperty(const PropertyName &name) const; NodeListProperty nodeListProperty(const PropertyName &name) const; NodeProperty nodeProperty(const PropertyName &name) const; NodeAbstractProperty nodeAbstractProperty(const PropertyName &name) const; diff --git a/src/plugins/qmldesigner/designercore/include/rewriterview.h b/src/plugins/qmldesigner/designercore/include/rewriterview.h index 4e099290cd0..c01bbcc499f 100644 --- a/src/plugins/qmldesigner/designercore/include/rewriterview.h +++ b/src/plugins/qmldesigner/designercore/include/rewriterview.h @@ -87,6 +87,7 @@ public: void variantPropertiesChanged(const QList& propertyList, PropertyChangeFlags propertyChange) override; void bindingPropertiesChanged(const QList& propertyList, PropertyChangeFlags propertyChange) override; void signalHandlerPropertiesChanged(const QVector& propertyList,PropertyChangeFlags propertyChange) override; + void signalDeclarationPropertiesChanged(const QVector& propertyList, PropertyChangeFlags propertyChange) override; void nodeReparented(const ModelNode &node, const NodeAbstractProperty &newPropertyParent, const NodeAbstractProperty &oldPropertyParent, AbstractView::PropertyChangeFlags propertyChange) override; diff --git a/src/plugins/qmldesigner/designercore/include/signalhandlerproperty.h b/src/plugins/qmldesigner/designercore/include/signalhandlerproperty.h index 07e48decadc..1f6656e4a70 100644 --- a/src/plugins/qmldesigner/designercore/include/signalhandlerproperty.h +++ b/src/plugins/qmldesigner/designercore/include/signalhandlerproperty.h @@ -30,7 +30,7 @@ namespace QmlDesigner { -class QMLDESIGNERCORE_EXPORT SignalHandlerProperty : public QmlDesigner::AbstractProperty +class QMLDESIGNERCORE_EXPORT SignalHandlerProperty : public AbstractProperty { friend ModelNode; friend Internal::ModelPrivate; @@ -50,4 +50,21 @@ protected: SignalHandlerProperty(const PropertyName &propertyName, const Internal::InternalNodePointer &internalNode, Model* model, AbstractView *view); }; +class QMLDESIGNERCORE_EXPORT SignalDeclarationProperty : public AbstractProperty +{ + friend ModelNode; + friend Internal::ModelPrivate; + friend AbstractProperty; + +public: + void setSignature(const QString &source); + QString signature() const; + + SignalDeclarationProperty(); + SignalDeclarationProperty(const SignalDeclarationProperty &property, AbstractView *view); + +protected: + SignalDeclarationProperty(const PropertyName &propertyName, const Internal::InternalNodePointer &internalNode, Model* model, AbstractView *view); +}; + } // namespace QmlDesigner diff --git a/src/plugins/qmldesigner/designercore/model/abstractproperty.cpp b/src/plugins/qmldesigner/designercore/model/abstractproperty.cpp index 4b2ff2f39cc..de1753e2590 100644 --- a/src/plugins/qmldesigner/designercore/model/abstractproperty.cpp +++ b/src/plugins/qmldesigner/designercore/model/abstractproperty.cpp @@ -203,6 +203,19 @@ SignalHandlerProperty AbstractProperty::toSignalHandlerProperty() const return SignalHandlerProperty(); } +SignalDeclarationProperty AbstractProperty::toSignalDeclarationProperty() const +{ + if (!isValid()) + throw InvalidPropertyException(__LINE__, __FUNCTION__, __FILE__, m_propertyName); + + SignalDeclarationProperty propertyNode(name(), internalNode(), model(), view()); + + if (propertyNode.isSignalDeclarationProperty()) + return propertyNode; + + return SignalDeclarationProperty(); +} + NodeListProperty AbstractProperty::toNodeListProperty() const { if (!isValid()) @@ -307,6 +320,18 @@ bool AbstractProperty::isSignalHandlerProperty() const return false; } +bool AbstractProperty::isSignalDeclarationProperty() const +{ + if (!isValid()) + throw InvalidPropertyException(__LINE__, __FUNCTION__, __FILE__, m_propertyName); + + if (internalNode()->hasProperty(name())) { + Q_ASSERT(internalNode()->property(name())); + return internalNode()->property(name())->isSignalDeclarationProperty(); + } + + return false; +} bool AbstractProperty::isBindingProperty() const { diff --git a/src/plugins/qmldesigner/designercore/model/abstractview.cpp b/src/plugins/qmldesigner/designercore/model/abstractview.cpp index f3c757e81db..3899d37d491 100644 --- a/src/plugins/qmldesigner/designercore/model/abstractview.cpp +++ b/src/plugins/qmldesigner/designercore/model/abstractview.cpp @@ -351,6 +351,10 @@ void AbstractView::signalHandlerPropertiesChanged(const QVector& /*propertyList*/, PropertyChangeFlags /*propertyChange*/) +{ +} + void AbstractView::rootNodeTypeChanged(const QString &/*type*/, int /*majorVersion*/, int /*minorVersion*/) { } diff --git a/src/plugins/qmldesigner/designercore/model/internalnode.cpp b/src/plugins/qmldesigner/designercore/model/internalnode.cpp index 37c1c21b406..3d29c24cb1f 100644 --- a/src/plugins/qmldesigner/designercore/model/internalnode.cpp +++ b/src/plugins/qmldesigner/designercore/model/internalnode.cpp @@ -215,6 +215,15 @@ InternalSignalHandlerProperty::Pointer InternalNode::signalHandlerProperty(const return InternalSignalHandlerProperty::Pointer(); } +InternalSignalDeclarationProperty::Pointer InternalNode::signalDeclarationProperty(const PropertyName &name) const +{ + InternalProperty::Pointer property = m_namePropertyHash.value(name); + if (property->isSignalDeclarationProperty()) + return property.staticCast(); + + return InternalSignalDeclarationProperty::Pointer(); +} + InternalVariantProperty::Pointer InternalNode::variantProperty(const PropertyName &name) const { InternalProperty::Pointer property = m_namePropertyHash.value(name); @@ -236,6 +245,12 @@ void InternalNode::addSignalHandlerProperty(const PropertyName &name) m_namePropertyHash.insert(name, newProperty); } +void InternalNode::addSignalDeclarationProperty(const PropertyName &name) +{ + InternalProperty::Pointer newProperty(InternalSignalDeclarationProperty::create(name, internalPointer())); + m_namePropertyHash.insert(name, newProperty); +} + InternalNodeListProperty::Pointer InternalNode::nodeListProperty(const PropertyName &name) const { InternalProperty::Pointer property = m_namePropertyHash.value(name); diff --git a/src/plugins/qmldesigner/designercore/model/internalnode_p.h b/src/plugins/qmldesigner/designercore/model/internalnode_p.h index d63fbed7445..04f0de41450 100644 --- a/src/plugins/qmldesigner/designercore/model/internalnode_p.h +++ b/src/plugins/qmldesigner/designercore/model/internalnode_p.h @@ -92,6 +92,7 @@ public: InternalProperty::Pointer property(const PropertyName &name) const; InternalBindingProperty::Pointer bindingProperty(const PropertyName &name) const; InternalSignalHandlerProperty::Pointer signalHandlerProperty(const PropertyName &name) const; + InternalSignalDeclarationProperty::Pointer signalDeclarationProperty(const PropertyName &name) const; InternalVariantProperty::Pointer variantProperty(const PropertyName &name) const; InternalNodeListProperty::Pointer nodeListProperty(const PropertyName &name) const; InternalNodeAbstractProperty::Pointer nodeAbstractProperty(const PropertyName &name) const; @@ -99,11 +100,11 @@ public: void addBindingProperty(const PropertyName &name); void addSignalHandlerProperty(const PropertyName &name); + void addSignalDeclarationProperty(const PropertyName &name); void addNodeListProperty(const PropertyName &name); void addVariantProperty(const PropertyName &name); void addNodeProperty(const PropertyName &name, const TypeName &dynamicTypeName); - PropertyNameList propertyNameList() const; bool hasProperties() const; diff --git a/src/plugins/qmldesigner/designercore/model/internalproperty.cpp b/src/plugins/qmldesigner/designercore/model/internalproperty.cpp index df2e2a22756..24730c74cc1 100644 --- a/src/plugins/qmldesigner/designercore/model/internalproperty.cpp +++ b/src/plugins/qmldesigner/designercore/model/internalproperty.cpp @@ -107,6 +107,11 @@ bool InternalProperty::isSignalHandlerProperty() const return false; } +bool InternalProperty::isSignalDeclarationProperty() const +{ + return false; +} + QSharedPointer InternalProperty::toVariantProperty() const { @@ -143,6 +148,12 @@ QSharedPointer InternalProperty::toSignalHandlerP return internalPointer().staticCast(); } +QSharedPointer InternalProperty::toSignalDeclarationProperty() const +{ + Q_ASSERT(internalPointer().dynamicCast()); + return internalPointer().staticCast(); +} + void InternalProperty::remove() { propertyOwner()->removeProperty(name()); diff --git a/src/plugins/qmldesigner/designercore/model/internalproperty.h b/src/plugins/qmldesigner/designercore/model/internalproperty.h index cf10f8ef7d9..97136d3c86e 100644 --- a/src/plugins/qmldesigner/designercore/model/internalproperty.h +++ b/src/plugins/qmldesigner/designercore/model/internalproperty.h @@ -36,6 +36,7 @@ namespace Internal { class InternalBindingProperty; class InternalSignalHandlerProperty; +class InternalSignalDeclarationProperty; class InternalVariantProperty; class InternalNodeListProperty; class InternalNodeProperty; @@ -62,6 +63,7 @@ public: virtual bool isNodeProperty() const; virtual bool isNodeAbstractProperty() const; virtual bool isSignalHandlerProperty() const; + virtual bool isSignalDeclarationProperty() const; QSharedPointer toBindingProperty() const; QSharedPointer toVariantProperty() const; @@ -69,6 +71,7 @@ public: QSharedPointer toNodeProperty() const; QSharedPointer toNodeAbstractProperty() const; QSharedPointer toSignalHandlerProperty() const; + QSharedPointer toSignalDeclarationProperty() const; InternalNodePointer propertyOwner() const; diff --git a/src/plugins/qmldesigner/designercore/model/internalsignalhandlerproperty.cpp b/src/plugins/qmldesigner/designercore/model/internalsignalhandlerproperty.cpp index 08ce26a4c83..e7905e8e864 100644 --- a/src/plugins/qmldesigner/designercore/model/internalsignalhandlerproperty.cpp +++ b/src/plugins/qmldesigner/designercore/model/internalsignalhandlerproperty.cpp @@ -63,5 +63,42 @@ bool InternalSignalHandlerProperty::isSignalHandlerProperty() const return true; } +InternalSignalDeclarationProperty::Pointer InternalSignalDeclarationProperty::create(const PropertyName &name, const InternalNodePointer &propertyOwner) +{ + auto newPointer(new InternalSignalDeclarationProperty(name, propertyOwner)); + InternalSignalDeclarationProperty::Pointer smartPointer(newPointer); + + newPointer->setInternalWeakPointer(smartPointer); + + newPointer->setDynamicTypeName("signal"); + + return smartPointer; +} + +bool InternalSignalDeclarationProperty::isValid() const +{ + return InternalProperty::isValid() && isSignalDeclarationProperty(); +} + +QString InternalSignalDeclarationProperty::signature() const +{ + return m_signature; +} + +void InternalSignalDeclarationProperty::setSignature(const QString &signature) +{ + m_signature = signature; +} + +bool InternalSignalDeclarationProperty::isSignalDeclarationProperty() const +{ + return true; +} + +InternalSignalDeclarationProperty::InternalSignalDeclarationProperty(const PropertyName &name, const InternalNodePointer &propertyOwner) + : InternalProperty(name, propertyOwner) +{ +} + } // namespace Internal } // namespace QmlDesigner diff --git a/src/plugins/qmldesigner/designercore/model/internalsignalhandlerproperty.h b/src/plugins/qmldesigner/designercore/model/internalsignalhandlerproperty.h index 9ecf424a544..c3f7f62e8ae 100644 --- a/src/plugins/qmldesigner/designercore/model/internalsignalhandlerproperty.h +++ b/src/plugins/qmldesigner/designercore/model/internalsignalhandlerproperty.h @@ -51,5 +51,26 @@ private: QString m_source; }; +class InternalSignalDeclarationProperty : public InternalProperty +{ +public: + using Pointer = QSharedPointer; + + static Pointer create(const PropertyName &name, const InternalNodePointer &propertyOwner); + + bool isValid() const override; + + QString signature() const; + void setSignature(const QString &source); + + bool isSignalDeclarationProperty() const override; + +protected: + InternalSignalDeclarationProperty(const PropertyName &name, const InternalNodePointer &propertyOwner); + +private: + QString m_signature; +}; + } // namespace Internal } // namespace QmlDesigner diff --git a/src/plugins/qmldesigner/designercore/model/model.cpp b/src/plugins/qmldesigner/designercore/model/model.cpp index 3dad31a40b6..5fd4dece8d4 100644 --- a/src/plugins/qmldesigner/designercore/model/model.cpp +++ b/src/plugins/qmldesigner/designercore/model/model.cpp @@ -843,6 +843,22 @@ void ModelPrivate::notifySignalHandlerPropertiesChanged( }); } +void ModelPrivate::notifySignalDeclarationPropertiesChanged( + const QVector &internalPropertyList, + AbstractView::PropertyChangeFlags propertyChange) +{ + notifyNodeInstanceViewLast([&](AbstractView *view) { + QVector propertyList; + for (const InternalSignalDeclarationPropertyPointer &signalHandlerProperty : internalPropertyList) { + propertyList.append(SignalDeclarationProperty(signalHandlerProperty->name(), + signalHandlerProperty->propertyOwner(), + m_model, + view)); + } + view->signalDeclarationPropertiesChanged(propertyList, propertyChange); + }); +} + void ModelPrivate::notifyScriptFunctionsChanged(const InternalNodePointer &node, const QStringList &scriptFunctionList) { @@ -1100,6 +1116,19 @@ void ModelPrivate::setSignalHandlerProperty(const InternalNodePointer &node, con notifySignalHandlerPropertiesChanged({signalHandlerProperty}, propertyChange); } +void ModelPrivate::setSignalDeclarationProperty(const InternalNodePointer &node, const PropertyName &name, const QString &signature) +{ + AbstractView::PropertyChangeFlags propertyChange = AbstractView::NoAdditionalChanges; + if (!node->hasProperty(name)) { + node->addSignalDeclarationProperty(name); + propertyChange = AbstractView::PropertiesAdded; + } + + InternalSignalDeclarationPropertyPointer signalDeclarationProperty = node->signalDeclarationProperty(name); + signalDeclarationProperty->setSignature(signature); + notifySignalDeclarationPropertiesChanged({signalDeclarationProperty}, propertyChange); +} + void ModelPrivate::setVariantProperty(const InternalNodePointer &node, const PropertyName &name, const QVariant &value) { AbstractView::PropertyChangeFlags propertyChange = AbstractView::NoAdditionalChanges; diff --git a/src/plugins/qmldesigner/designercore/model/model_p.h b/src/plugins/qmldesigner/designercore/model/model_p.h index 7e81ee3cd51..98be8a135fc 100644 --- a/src/plugins/qmldesigner/designercore/model/model_p.h +++ b/src/plugins/qmldesigner/designercore/model/model_p.h @@ -53,6 +53,7 @@ class InternalNode; class InternalProperty; class InternalBindingProperty; class InternalSignalHandlerProperty; +class InternalSignalDeclarationProperty; class InternalVariantProperty; class InternalNodeAbstractProperty; class InternalNodeListProperty; @@ -61,6 +62,7 @@ using InternalNodePointer = QSharedPointer; using InternalPropertyPointer = QSharedPointer; using InternalBindingPropertyPointer = QSharedPointer; using InternalSignalHandlerPropertyPointer = QSharedPointer; +using InternalSignalDeclarationPropertyPointer = QSharedPointer; using InternalVariantPropertyPointer = QSharedPointer; using InternalNodeAbstractPropertyPointer = QSharedPointer; using InternalNodeListPropertyPointer = QSharedPointer; @@ -154,6 +156,7 @@ public: const QList &internalPropertyList); void notifyBindingPropertiesChanged(const QList &internalPropertyList, AbstractView::PropertyChangeFlags propertyChange); void notifySignalHandlerPropertiesChanged(const QVector &propertyList, AbstractView::PropertyChangeFlags propertyChange); + void notifySignalDeclarationPropertiesChanged(const QVector &propertyList, AbstractView::PropertyChangeFlags propertyChange); void notifyVariantPropertiesChanged(const InternalNodePointer &node, const PropertyNameList &propertyNameList, AbstractView::PropertyChangeFlags propertyChange); void notifyScriptFunctionsChanged(const InternalNodePointer &node, const QStringList &scriptFunctionList); @@ -221,6 +224,7 @@ public: void setBindingProperty(const InternalNodePointer &node, const PropertyName &name, const QString &expression); void setSignalHandlerProperty(const InternalNodePointer &node, const PropertyName &name, const QString &source); + void setSignalDeclarationProperty(const InternalNodePointer &node, const PropertyName &name, const QString &signature); void setVariantProperty(const InternalNodePointer &node, const PropertyName &name, const QVariant &value); void setDynamicVariantProperty(const InternalNodePointer &node, const PropertyName &name, const TypeName &propertyType, const QVariant &value); void setDynamicBindingProperty(const InternalNodePointer &node, const PropertyName &name, const TypeName &dynamicPropertyType, const QString &expression); diff --git a/src/plugins/qmldesigner/designercore/model/modelnode.cpp b/src/plugins/qmldesigner/designercore/model/modelnode.cpp index 7d65d0495f6..b61aa9ecd63 100644 --- a/src/plugins/qmldesigner/designercore/model/modelnode.cpp +++ b/src/plugins/qmldesigner/designercore/model/modelnode.cpp @@ -487,6 +487,13 @@ SignalHandlerProperty ModelNode::signalHandlerProperty(const PropertyName &name) return SignalHandlerProperty(name, m_internalNode, model(), view()); } +SignalDeclarationProperty ModelNode::signalDeclarationProperty(const PropertyName &name) const +{ + if (!isValid()) + throw InvalidModelNodeException(__LINE__, __FUNCTION__, __FILE__); + + return SignalDeclarationProperty(name, m_internalNode, model(), view()); +} /*! \brief Returns a NodeProperty diff --git a/src/plugins/qmldesigner/designercore/model/modeltotextmerger.cpp b/src/plugins/qmldesigner/designercore/model/modeltotextmerger.cpp index d89765b5bf5..6469dd6a04a 100644 --- a/src/plugins/qmldesigner/designercore/model/modeltotextmerger.cpp +++ b/src/plugins/qmldesigner/designercore/model/modeltotextmerger.cpp @@ -356,6 +356,8 @@ QmlRefactoring::PropertyType ModelToTextMerger::propertyType(const AbstractPrope return QmlRefactoring::ObjectBinding; else if (property.isVariantProperty()) return QmlRefactoring::ScriptBinding; + else if (property.isSignalDeclarationProperty()) + return QmlRefactoring::ScriptBinding; Q_ASSERT(false); //Cannot convert property type return QmlRefactoring::Invalid; diff --git a/src/plugins/qmldesigner/designercore/model/qmltextgenerator.cpp b/src/plugins/qmldesigner/designercore/model/qmltextgenerator.cpp index 4c9311a4cf5..296b965548f 100644 --- a/src/plugins/qmldesigner/designercore/model/qmltextgenerator.cpp +++ b/src/plugins/qmldesigner/designercore/model/qmltextgenerator.cpp @@ -101,6 +101,8 @@ QString QmlTextGenerator::toQml(const AbstractProperty &property, int indentDept return property.toBindingProperty().expression(); } else if (property.isSignalHandlerProperty()) { return property.toSignalHandlerProperty().source(); + } else if (property.isSignalDeclarationProperty()) { + return property.toSignalDeclarationProperty().signature(); } else if (property.isNodeProperty()) { return toQml(property.toNodeProperty().modelNode(), indentDepth); } else if (property.isNodeListProperty()) { @@ -288,6 +290,10 @@ QString QmlTextGenerator::propertyToQml(const AbstractProperty &property, int in + QString::fromUtf8(property.name()) + QStringLiteral(": ") + toQml(property, indentDepth); + } + if (property.isSignalDeclarationProperty()) { + result = m_tabSettings.indentationString(0, indentDepth, 0) + "signal" + " " + + QString::fromUtf8(property.name()) + " " + toQml(property, indentDepth); } else { result = m_tabSettings.indentationString(0, indentDepth, 0) + QString::fromUtf8(property.name()) diff --git a/src/plugins/qmldesigner/designercore/model/rewriterview.cpp b/src/plugins/qmldesigner/designercore/model/rewriterview.cpp index a4b836fb74a..d3c65a1e239 100644 --- a/src/plugins/qmldesigner/designercore/model/rewriterview.cpp +++ b/src/plugins/qmldesigner/designercore/model/rewriterview.cpp @@ -261,6 +261,22 @@ void RewriterView::signalHandlerPropertiesChanged(const QVector &propertyList, PropertyChangeFlags propertyChange) +{ + Q_ASSERT(textModifier()); + if (textToModelMerger()->isActive()) + return; + + QList usefulPropertyList; + for (const SignalDeclarationProperty &property : propertyList) + usefulPropertyList.append(property); + + modelToTextMerger()->propertiesChanged(usefulPropertyList, propertyChange); + + if (!isModificationGroupActive()) + applyChanges(); +} + void RewriterView::nodeReparented(const ModelNode &node, const NodeAbstractProperty &newPropertyParent, const NodeAbstractProperty &oldPropertyParent, AbstractView::PropertyChangeFlags propertyChange) { Q_ASSERT(textModifier()); diff --git a/src/plugins/qmldesigner/designercore/model/signalhandlerproperty.cpp b/src/plugins/qmldesigner/designercore/model/signalhandlerproperty.cpp index d8d7e2c9359..d2e5e6dbc51 100644 --- a/src/plugins/qmldesigner/designercore/model/signalhandlerproperty.cpp +++ b/src/plugins/qmldesigner/designercore/model/signalhandlerproperty.cpp @@ -107,4 +107,57 @@ PropertyName SignalHandlerProperty::prefixRemoved(const PropertyName &propertyNa return nameAsString.toLatin1(); } +SignalDeclarationProperty::SignalDeclarationProperty() = default; + +SignalDeclarationProperty::SignalDeclarationProperty(const SignalDeclarationProperty &property, + AbstractView *view) + : AbstractProperty(property.name(), property.internalNode(), property.model(), view) +{} + +SignalDeclarationProperty::SignalDeclarationProperty( + const PropertyName &propertyName, + const Internal::InternalNodePointer &internalNode, + Model *model, + AbstractView *view) + : AbstractProperty(propertyName, internalNode, model, view) +{ +} + +void SignalDeclarationProperty::setSignature(const QString &signature) +{ + Internal::WriteLocker locker(model()); + if (!isValid()) + throw InvalidModelNodeException(__LINE__, __FUNCTION__, __FILE__); + + if (name() == "id") { // the ID for a node is independent of the state, so it has to be set with ModelNode::setId + throw InvalidPropertyException(__LINE__, __FUNCTION__, __FILE__, name()); + } + + if (signature.isEmpty()) + throw InvalidArgumentException(__LINE__, __FUNCTION__, __FILE__, name()); + + if (internalNode()->hasProperty(name())) { //check if oldValue != value + Internal::InternalProperty::Pointer internalProperty = internalNode()->property(name()); + if (internalProperty->isSignalDeclarationProperty() + && internalProperty->toSignalDeclarationProperty()->signature() == signature) + + return; + } + + if (internalNode()->hasProperty(name()) && !internalNode()->property(name())->isSignalDeclarationProperty()) + privateModel()->removeProperty(internalNode()->property(name())); + + privateModel()->setSignalDeclarationProperty(internalNode(), name(), signature); +} + +QString SignalDeclarationProperty::signature() const +{ + + if (internalNode()->hasProperty(name()) + && internalNode()->property(name())->isSignalDeclarationProperty()) + return internalNode()->signalDeclarationProperty(name())->signature(); + + return QString(); +} + } // namespace QmlDesigner diff --git a/src/plugins/qmldesigner/designercore/model/texttomodelmerger.cpp b/src/plugins/qmldesigner/designercore/model/texttomodelmerger.cpp index 49482cbdf3a..86996baf363 100644 --- a/src/plugins/qmldesigner/designercore/model/texttomodelmerger.cpp +++ b/src/plugins/qmldesigner/designercore/model/texttomodelmerger.cpp @@ -1357,8 +1357,21 @@ void TextToModelMerger::syncNode(ModelNode &modelNode, } else if (auto script = AST::cast(member)) { modelPropertyNames.remove(syncScriptBinding(modelNode, QString(), script, context, differenceHandler)); } else if (auto property = AST::cast(member)) { - if (property->type == AST::UiPublicMember::Signal) - continue; // QML designer doesn't support this yet. + if (property->type == AST::UiPublicMember::Signal) { + const QStringView astName = property->name; + AbstractProperty modelProperty = modelNode.property(astName.toUtf8()); + QString signature = "()"; + if (property->parameters) { + signature = "(" + + textAt(context->doc(), + property->parameters->firstSourceLocation(), + property->parameters->lastSourceLocation()) + + ")"; + } + + syncSignalDeclarationProperty(modelProperty, signature, differenceHandler); + continue; // Done + } const QStringView astName = property->name; QString astValue; @@ -1693,6 +1706,19 @@ void TextToModelMerger::syncVariantProperty(AbstractProperty &modelProperty, } } +void TextToModelMerger::syncSignalDeclarationProperty(AbstractProperty &modelProperty, + const QString &signature, + DifferenceHandler &differenceHandler) +{ + if (modelProperty.isSignalHandlerProperty()) { + SignalDeclarationProperty signalHandlerProperty = modelProperty.toSignalDeclarationProperty(); + if (signalHandlerProperty.signature() != signature) + differenceHandler.signalDeclarationSignatureDiffer(signalHandlerProperty, signature); + } else { + differenceHandler.shouldBeSignalDeclarationProperty(modelProperty, signature); + } +} + void TextToModelMerger::syncNodeListProperty(NodeListProperty &modelListProperty, const QList arrayMembers, ReadingContext *context, @@ -1834,6 +1860,13 @@ void ModelValidator::signalHandlerSourceDiffer(SignalHandlerProperty &modelPrope QTC_ASSERT(compareJavaScriptExpression(modelProperty.source(), javascript), return); } +void ModelValidator::signalDeclarationSignatureDiffer(SignalDeclarationProperty &modelProperty, const QString &signature) +{ + Q_UNUSED(modelProperty) + Q_UNUSED(signature) + QTC_ASSERT(compareJavaScriptExpression(modelProperty.signature(), signature), return); +} + void ModelValidator::shouldBeSignalHandlerProperty(AbstractProperty &modelProperty, const QString & /*javascript*/) { Q_UNUSED(modelProperty) @@ -1841,6 +1874,13 @@ void ModelValidator::shouldBeSignalHandlerProperty(AbstractProperty &modelProper Q_ASSERT(0); } +void ModelValidator::shouldBeSignalDeclarationProperty(AbstractProperty &modelProperty, const QString & /*javascript*/) +{ + Q_UNUSED(modelProperty) + Q_ASSERT(modelProperty.isSignalDeclarationProperty()); + Q_ASSERT(0); +} + void ModelValidator::shouldBeNodeListProperty(AbstractProperty &modelProperty, const QList /*arrayMembers*/, ReadingContext * /*context*/) @@ -1989,6 +2029,11 @@ void ModelAmender::signalHandlerSourceDiffer(SignalHandlerProperty &modelPropert modelProperty.setSource(javascript); } +void ModelAmender::signalDeclarationSignatureDiffer(SignalDeclarationProperty &modelProperty, const QString &signature) +{ + modelProperty.setSignature(signature); +} + void ModelAmender::shouldBeSignalHandlerProperty(AbstractProperty &modelProperty, const QString &javascript) { ModelNode theNode = modelProperty.parentModelNode(); @@ -1996,6 +2041,13 @@ void ModelAmender::shouldBeSignalHandlerProperty(AbstractProperty &modelProperty newModelProperty.setSource(javascript); } +void ModelAmender::shouldBeSignalDeclarationProperty(AbstractProperty &modelProperty, const QString &signature) +{ + ModelNode theNode = modelProperty.parentModelNode(); + SignalDeclarationProperty newModelProperty = theNode.signalDeclarationProperty(modelProperty.name()); + newModelProperty.setSignature(signature); +} + void ModelAmender::shouldBeNodeListProperty(AbstractProperty &modelProperty, const QList arrayMembers, ReadingContext *context) diff --git a/src/plugins/qmldesigner/designercore/model/texttomodelmerger.h b/src/plugins/qmldesigner/designercore/model/texttomodelmerger.h index ed48d4ebc8f..82fd8a16614 100644 --- a/src/plugins/qmldesigner/designercore/model/texttomodelmerger.h +++ b/src/plugins/qmldesigner/designercore/model/texttomodelmerger.h @@ -107,6 +107,9 @@ public: const QList &arrayMembers, ReadingContext *context, DifferenceHandler &differenceHandler); + void syncSignalDeclarationProperty(AbstractProperty &modelProperty, + const QString &signature, + DifferenceHandler &differenceHandler); void syncVariantProperty(AbstractProperty &modelProperty, const QVariant &astValue, const TypeName &astType, @@ -187,11 +190,15 @@ public: const TypeName &astType) = 0; virtual void signalHandlerSourceDiffer(SignalHandlerProperty &modelProperty, const QString &javascript) = 0; + virtual void signalDeclarationSignatureDiffer(SignalDeclarationProperty &modelProperty, + const QString &signature) = 0; virtual void shouldBeBindingProperty(AbstractProperty &modelProperty, const QString &javascript, const TypeName &astType) = 0; virtual void shouldBeSignalHandlerProperty(AbstractProperty &modelProperty, const QString &javascript) = 0; + virtual void shouldBeSignalDeclarationProperty(AbstractProperty &modelProperty, + const QString &signature) = 0; virtual void shouldBeNodeListProperty(AbstractProperty &modelProperty, const QList arrayMembers, ReadingContext *context) = 0; @@ -241,6 +248,10 @@ public: const TypeName &astType) override; void signalHandlerSourceDiffer(SignalHandlerProperty &modelProperty, const QString &javascript) override; + void signalDeclarationSignatureDiffer(SignalDeclarationProperty &modelProperty, + const QString &signature) override; + void shouldBeSignalDeclarationProperty(AbstractProperty &modelProperty, + const QString &signature) override; void shouldBeSignalHandlerProperty(AbstractProperty &modelProperty, const QString &javascript) override; void shouldBeNodeListProperty(AbstractProperty &modelProperty, @@ -290,6 +301,10 @@ public: const TypeName &astType) override; void signalHandlerSourceDiffer(SignalHandlerProperty &modelProperty, const QString &javascript) override; + void signalDeclarationSignatureDiffer(SignalDeclarationProperty &modelProperty, + const QString &signature) override; + void shouldBeSignalDeclarationProperty(AbstractProperty &modelProperty, + const QString &signature) override; void shouldBeSignalHandlerProperty(AbstractProperty &modelProperty, const QString &javascript) override; void shouldBeNodeListProperty(AbstractProperty &modelProperty, diff --git a/tests/auto/qml/qmldesigner/coretests/tst_testcore.cpp b/tests/auto/qml/qmldesigner/coretests/tst_testcore.cpp index 4813ac96f21..7c79a32dd18 100644 --- a/tests/auto/qml/qmldesigner/coretests/tst_testcore.cpp +++ b/tests/auto/qml/qmldesigner/coretests/tst_testcore.cpp @@ -170,7 +170,8 @@ tst_TestCore::tst_TestCore() : QObject() { QLoggingCategory::setFilterRules(QStringLiteral("qtc.qmljs.imports=false")); - QLoggingCategory::setFilterRules(QStringLiteral("*.info=false\n*.debug=false\n*.warning=false")); + //QLoggingCategory::setFilterRules(QStringLiteral("*.info=false\n*.debug=false\n*.warning=false")); + QLoggingCategory::setFilterRules(QStringLiteral("*.warning=false")); } void tst_TestCore::initTestCase() @@ -1273,6 +1274,7 @@ void tst_TestCore::testRewriterBehaivours() testRewriterView->setTextModifier(&modifier); model->attachView(testRewriterView.data()); + //qDebug() << testRewriterView->errors().first().toString(); QVERIFY(testRewriterView->errors().isEmpty()); ModelNode rootModelNode = testRewriterView->rootModelNode(); @@ -1345,6 +1347,119 @@ void tst_TestCore::testRewriterBehaivours() QVERIFY(!newBehavior.isValid()); } +void tst_TestCore::testRewriterSignalDefinition() +{ + const QLatin1String qmlString("\n" + "import QtQuick 2.1\n" + "\n" + "Rectangle {\n" + " id: root\n" + " x: 10;\n" + " y: 10;\n" + " signal testSignal()\n" + " signal testSignal2(float i)\n" + " Rectangle {\n" + " id: rectangle1\n" + " x: 10;\n" + " y: 10;\n" + " signal testSignal\n" + " }\n" + "}"); + + + QPlainTextEdit textEdit; + textEdit.setPlainText(qmlString); + NotIndentingTextEditModifier modifier(&textEdit); + + QScopedPointer model(Model::create("QtQuick.Text")); + + QScopedPointer testRewriterView(new TestRewriterView()); + testRewriterView->setTextModifier(&modifier); + model->attachView(testRewriterView.data()); + + QVERIFY(testRewriterView->errors().isEmpty()); + + ModelNode rootModelNode = testRewriterView->rootModelNode(); + QVERIFY(rootModelNode.isValid()); + + QVERIFY(rootModelNode.hasProperty("testSignal")); + QVERIFY(rootModelNode.hasProperty("testSignal2")); + + QVERIFY(rootModelNode.property("testSignal").isSignalDeclarationProperty()); + QVERIFY(rootModelNode.signalDeclarationProperty("testSignal").isValid()); + QCOMPARE(rootModelNode.signalDeclarationProperty("testSignal").signature(), "()"); + + QVERIFY(rootModelNode.property("testSignal2").isSignalDeclarationProperty()); + QVERIFY(rootModelNode.signalDeclarationProperty("testSignal2").isValid()); + QCOMPARE(rootModelNode.signalDeclarationProperty("testSignal2").signature(), "(float i)"); + + ModelNode rectangle = testRewriterView->modelNodeForId("rectangle1"); + QVERIFY(rectangle.isValid()); + + QVERIFY(rectangle.hasProperty("testSignal")); + + QVERIFY(rectangle.property("testSignal").isSignalDeclarationProperty()); + QVERIFY(rectangle.signalDeclarationProperty("testSignal").isValid()); + QCOMPARE(rectangle.signalDeclarationProperty("testSignal").signature(), "()"); + + rootModelNode.signalDeclarationProperty("addedSignal").setSignature("()"); + rootModelNode.signalDeclarationProperty("addedSignal").setSignature("(real i)"); + + const QLatin1String expectedQmlCode( + "\nimport QtQuick 2.1\n\n" + "Rectangle {\n" + " id: root\n" + " x: 10;\n" + " y: 10;\n" + " signal addedSignal (real i)\n" + " signal testSignal()\n" + " signal testSignal2(float i)\n" + " Rectangle {\n" + " id: rectangle1\n" + " x: 10;\n" + " y: 10;\n" + " signal testSignal\n" + " }\n}"); + + QCOMPARE(textEdit.toPlainText(), expectedQmlCode); + + rootModelNode.removeProperty("addedSignal"); + + const QLatin1String expectedQmlCode2( + "\nimport QtQuick 2.1\n\n" + "Rectangle {\n" + " id: root\n" + " x: 10;\n" + " y: 10;\n" + " signal testSignal()\n" + " signal testSignal2(float i)\n" + " Rectangle {\n" + " id: rectangle1\n" + " x: 10;\n" + " y: 10;\n" + " signal testSignal\n" + " }\n}"); + + QCOMPARE(textEdit.toPlainText(), expectedQmlCode2); + + testRewriterView->executeInTransaction("identifer", [rectangle](){ + ModelNode newRectangle = rectangle.view()->createModelNode(rectangle.type(), + rectangle.majorVersion(), + rectangle.minorVersion()); + + QVERIFY(newRectangle.isValid()); + newRectangle.signalDeclarationProperty("newSignal").setSignature("()"); + newRectangle.setIdWithoutRefactoring("newRect"); + newRectangle.view()->rootModelNode().defaultNodeListProperty().reparentHere(newRectangle); + }); + + const QString expectedQmlCode3 + = expectedQmlCode2.chopped(1) + + QLatin1String("\n Rectangle {\n id: newRect\n signal newSignal ()\n }\n}"); + + QCOMPARE(textEdit.toPlainText(), expectedQmlCode3); +} + void tst_TestCore::testRewriterForGradientMagic() { const QLatin1String qmlString("\n" @@ -6891,6 +7006,29 @@ void tst_TestCore::testModelChangeType() QCOMPARE(textEdit.toPlainText(), expectedQmlCode2); } +void tst_TestCore::testModelSignalDefinition() +{ + QScopedPointer model(createModel("QtQuick.Rectangle", 2, 0)); + QVERIFY(model.data()); + + QScopedPointer view(new TestView(model.data())); + QVERIFY(view.data()); + model->attachView(view.data()); + + ModelNode rootModelNode(view->rootModelNode()); + QVERIFY(rootModelNode.isValid()); + + QVERIFY(!rootModelNode.hasProperty("mySignal")); + + rootModelNode.signalDeclarationProperty("mySignal").setSignature("()"); + + QVERIFY(rootModelNode.hasProperty("mySignal")); + + QVERIFY(rootModelNode.signalDeclarationProperty("mySignal").isValid()); + QVERIFY(rootModelNode.property("mySignal").isSignalDeclarationProperty()); + QCOMPARE(rootModelNode.signalDeclarationProperty("mySignal").signature(), "()"); +} + void tst_TestCore::testModelDefaultProperties() { QScopedPointer model(createModel("QtQuick.Rectangle", 2, 0)); diff --git a/tests/auto/qml/qmldesigner/coretests/tst_testcore.h b/tests/auto/qml/qmldesigner/coretests/tst_testcore.h index d55bb2a1961..633731c7c28 100644 --- a/tests/auto/qml/qmldesigner/coretests/tst_testcore.h +++ b/tests/auto/qml/qmldesigner/coretests/tst_testcore.h @@ -90,6 +90,7 @@ private slots: void testModelNodeInHierarchy(); void testModelNodeIsAncestorOf(); void testModelChangeType(); + void testModelSignalDefinition(); // // unit tests Rewriter @@ -146,6 +147,7 @@ private slots: void testRewriterTransactionAddingAfterReparenting(); void testRewriterReparentToNewNode(); void testRewriterBehaivours(); + void testRewriterSignalDefinition(); // // unit tests QmlModelNodeFacade/QmlModelState