From f2e6fc95609de5ada890fa225c2a988cec066f94 Mon Sep 17 00:00:00 2001 From: Thomas Hartmann Date: Wed, 31 Jan 2018 17:10:26 +0100 Subject: [PATCH] QmlDesigner: Add keyframe support to property editor This patch allows to insert key frames if a timeline is present. Change-Id: I39c8281e5e559a838ad61939d3f2db7c6abcf76b Reviewed-by: Tim Jenssen --- .../HelperWidgets/ExtendedFunctionButton.qml | 6 ++++ .../propertyeditorcontextobject.cpp | 33 +++++++++++++++++++ .../propertyeditorcontextobject.h | 9 +++++ .../propertyeditorqmlbackend.cpp | 4 +++ .../propertyeditor/propertyeditorview.cpp | 9 +++++ .../propertyeditor/propertyeditorview.h | 2 ++ .../designercore/include/qmltimelinemutator.h | 1 + .../designercore/model/qmltimelinemutator.cpp | 17 ++++++++++ 8 files changed, 81 insertions(+) diff --git a/share/qtcreator/qmldesigner/propertyEditorQmlSources/imports/HelperWidgets/ExtendedFunctionButton.qml b/share/qtcreator/qmldesigner/propertyEditorQmlSources/imports/HelperWidgets/ExtendedFunctionButton.qml index 492cf2f6250..c0177032b77 100644 --- a/share/qtcreator/qmldesigner/propertyEditorQmlSources/imports/HelperWidgets/ExtendedFunctionButton.qml +++ b/share/qtcreator/qmldesigner/propertyEditorQmlSources/imports/HelperWidgets/ExtendedFunctionButton.qml @@ -155,6 +155,12 @@ Item { } checkable: true } + + Controls.MenuItem { + text: qsTr("Insert keyframe") + visible: hasActiveTimeline + onTriggered: insertKeyframe(backendValue.name) + } } } } diff --git a/src/plugins/qmldesigner/components/propertyeditor/propertyeditorcontextobject.cpp b/src/plugins/qmldesigner/components/propertyeditor/propertyeditorcontextobject.cpp index bda20ca52a5..1584d882559 100644 --- a/src/plugins/qmldesigner/components/propertyeditor/propertyeditorcontextobject.cpp +++ b/src/plugins/qmldesigner/components/propertyeditor/propertyeditorcontextobject.cpp @@ -208,6 +208,25 @@ void PropertyEditorContextObject::changeTypeName(const QString &typeName) } +void PropertyEditorContextObject::insertKeyframe(const QString &propertyName) +{ + if (!m_model || !m_model->rewriterView()) + return; + + /* Ideally we should not missuse the rewriterView + * If we add more code here we have to forward the property editor view */ + RewriterView *rewriterView = m_model->rewriterView(); + + if (rewriterView->selectedModelNodes().isEmpty()) + return; + + ModelNode selectedNode = rewriterView->selectedModelNodes().constFirst(); + + rewriterView->emitCustomNotification("INSERT_KEYFRAME", + { selectedNode }, + { propertyName }); +} + int PropertyEditorContextObject::majorVersion() const { return m_majorVersion; @@ -270,6 +289,20 @@ void PropertyEditorContextObject::setMinorVersion(int minorVersion) emit minorVersionChanged(); } +bool PropertyEditorContextObject::hasActiveTimeline() const +{ + return m_setHasActiveTimeline; +} + +void PropertyEditorContextObject::setHasActiveTimeline(bool b) +{ + if (b == m_setHasActiveTimeline) + return; + + m_setHasActiveTimeline = b; + emit hasActiveTimelineChanged(); +} + void PropertyEditorContextObject::insertInQmlContext(QQmlContext *context) { m_qmlContext = context; diff --git a/src/plugins/qmldesigner/components/propertyeditor/propertyeditorcontextobject.h b/src/plugins/qmldesigner/components/propertyeditor/propertyeditorcontextobject.h index f087bdaea1e..212f5742cdd 100644 --- a/src/plugins/qmldesigner/components/propertyeditor/propertyeditorcontextobject.h +++ b/src/plugins/qmldesigner/components/propertyeditor/propertyeditorcontextobject.h @@ -55,6 +55,8 @@ class PropertyEditorContextObject : public QObject Q_PROPERTY(bool hasAliasExport READ hasAliasExport NOTIFY hasAliasExportChanged) + Q_PROPERTY(bool hasActiveTimeline READ hasActiveTimeline NOTIFY hasActiveTimelineChanged) + Q_PROPERTY(QQmlPropertyMap* backendValues READ backendValues WRITE setBackendValues NOTIFY backendValuesChanged) Q_PROPERTY(QQmlComponent* specificQmlComponent READ specificQmlComponent NOTIFY specificQmlComponentChanged) @@ -81,6 +83,7 @@ public: Q_INVOKABLE void toogleExportAlias(); Q_INVOKABLE void changeTypeName(const QString &typeName); + Q_INVOKABLE void insertKeyframe(const QString &propertyName); int majorVersion() const; int majorQtQuickVersion() const; @@ -91,6 +94,9 @@ public: int minorVersion() const; void setMinorVersion(int minorVersion); + bool hasActiveTimeline() const; + void setHasActiveTimeline(bool b); + void insertInQmlContext(QQmlContext *context); QQmlComponent *specificQmlComponent(); @@ -110,6 +116,7 @@ signals: void minorQtQuickVersionChanged(); void specificQmlComponentChanged(); void hasAliasExportChanged(); + void hasActiveTimelineChanged(); public slots: void setGlobalBaseUrl(const QUrl &newBaseUrl); @@ -153,6 +160,8 @@ private: Model *m_model = nullptr; bool m_aliasExport = false; + + bool m_setHasActiveTimeline = false; }; } //QmlDesigner { diff --git a/src/plugins/qmldesigner/components/propertyeditor/propertyeditorqmlbackend.cpp b/src/plugins/qmldesigner/components/propertyeditor/propertyeditorqmlbackend.cpp index 7c6435a1b89..9a0cba3ca08 100644 --- a/src/plugins/qmldesigner/components/propertyeditor/propertyeditorqmlbackend.cpp +++ b/src/plugins/qmldesigner/components/propertyeditor/propertyeditorqmlbackend.cpp @@ -29,6 +29,7 @@ #include "propertyeditortransaction.h" #include #include +#include #include #include @@ -328,6 +329,9 @@ void PropertyEditorQmlBackend::setup(const QmlObjectNode &qmlObjectNode, const Q contextObject()->setIsBaseState(qmlObjectNode.isInBaseState()); contextObject()->setHasAliasExport(qmlObjectNode.isAliasExported()); + + contextObject()->setHasActiveTimeline(QmlTimelineMutator::hasActiveTimeline(qmlObjectNode.view())); + contextObject()->setSelectionChanged(false); contextObject()->setSelectionChanged(false); diff --git a/src/plugins/qmldesigner/components/propertyeditor/propertyeditorview.cpp b/src/plugins/qmldesigner/components/propertyeditor/propertyeditorview.cpp index 63e415f1b96..7ac69fb2ae4 100644 --- a/src/plugins/qmldesigner/components/propertyeditor/propertyeditorview.cpp +++ b/src/plugins/qmldesigner/components/propertyeditor/propertyeditorview.cpp @@ -30,6 +30,7 @@ #include "propertyeditortransaction.h" #include +#include #include #include @@ -368,6 +369,14 @@ bool PropertyEditorView::locked() const return m_locked; } +void PropertyEditorView::nodeCreated(const ModelNode &modelNode) +{ + if (!m_qmlBackEndForCurrentType->contextObject()->hasActiveTimeline() + && QmlTimelineMutator::isValidQmlTimelineMutator(modelNode)) { + m_qmlBackEndForCurrentType->contextObject()->setHasActiveTimeline(QmlTimelineMutator::hasActiveTimeline(this)); + } +} + void PropertyEditorView::updateSize() { if (!m_qmlBackEndForCurrentType) diff --git a/src/plugins/qmldesigner/components/propertyeditor/propertyeditorview.h b/src/plugins/qmldesigner/components/propertyeditor/propertyeditorview.h index 316164f4c29..0455a0d7f7f 100644 --- a/src/plugins/qmldesigner/components/propertyeditor/propertyeditorview.h +++ b/src/plugins/qmldesigner/components/propertyeditor/propertyeditorview.h @@ -93,6 +93,8 @@ public: bool locked() const; + void nodeCreated(const ModelNode &createdNode); + protected: void timerEvent(QTimerEvent *event) override; void setupPane(const TypeName &typeName); diff --git a/src/plugins/qmldesigner/designercore/include/qmltimelinemutator.h b/src/plugins/qmldesigner/designercore/include/qmltimelinemutator.h index 8cddecba803..0be3cc1d385 100644 --- a/src/plugins/qmldesigner/designercore/include/qmltimelinemutator.h +++ b/src/plugins/qmldesigner/designercore/include/qmltimelinemutator.h @@ -65,6 +65,7 @@ public: QList allTargets() const; QList framesForTarget(const ModelNode &target) const; void destroyFramesForTarget(const ModelNode &target); + static bool hasActiveTimeline(AbstractView *view); private: void addFramesIfNotExists(const ModelNode &node, const PropertyName &propertyName); diff --git a/src/plugins/qmldesigner/designercore/model/qmltimelinemutator.cpp b/src/plugins/qmldesigner/designercore/model/qmltimelinemutator.cpp index 82660513699..319a9a64215 100644 --- a/src/plugins/qmldesigner/designercore/model/qmltimelinemutator.cpp +++ b/src/plugins/qmldesigner/designercore/model/qmltimelinemutator.cpp @@ -210,6 +210,23 @@ void QmlTimelineMutator::destroyFramesForTarget(const ModelNode &target) frames.destroy(); } +bool QmlTimelineMutator::hasActiveTimeline(AbstractView *view) +{ + if (view && view->isAttached()) { + if (!view->model()->hasImport(Import::createLibraryImport("QtQuick.Timeline", "1.0"), true, true)) + return false; + + const ModelNode root = view->rootModelNode(); + if (root.isValid()) + for (const ModelNode &child : root.directSubModelNodes()) { + if (QmlTimelineMutator::isValidQmlTimelineMutator(child)) + return QmlTimelineMutator(child).isEnabled(); + } + } + + return false; +} + void QmlTimelineMutator::addFramesIfNotExists(const ModelNode &node, const PropertyName &propertyName) { if (!isValid())