diff options
author | Christian Strømme <christian.stromme@qt.io> | 2018-08-20 15:29:41 +0200 |
---|---|---|
committer | Laszlo Agocs <laszlo.agocs@qt.io> | 2018-08-28 13:01:30 +0000 |
commit | 29f22c2e0444f00c62667437c64ccceb85d2951a (patch) | |
tree | dca463f124f68369dddc8c31338ae9e531bb9319 | |
parent | 7aed790d66a468dbd5c58813fafe1cef2630333b (diff) |
Add infrastructure to connect properties from Quick API to the Q3DS API
Removes the syncProperties() function, as it's strictly not needed
anymore. If there's a need to intercept one or more property change,
two different options are provided:
1. Add a property on the target object that is prefixed with "qq_" or
2. Re-implement the propertChanged() function.
Change-Id: If2ef181f09f17916b0d2d9606663175958e46e77
Reviewed-by: Laszlo Agocs <laszlo.agocs@qt.io>
-rw-r--r-- | src/runtime/aping/q3dsgroup3d.cpp | 9 | ||||
-rw-r--r-- | src/runtime/aping/q3dsgroup3d_p.h | 1 | ||||
-rw-r--r-- | src/runtime/aping/q3dslayer3d.cpp | 7 | ||||
-rw-r--r-- | src/runtime/aping/q3dslayer3d_p.h | 2 | ||||
-rw-r--r-- | src/runtime/aping/q3dsnode3d.cpp | 7 | ||||
-rw-r--r-- | src/runtime/aping/q3dsnode3d_p.h | 2 | ||||
-rw-r--r-- | src/runtime/aping/q3dsobject3d.cpp | 39 | ||||
-rw-r--r-- | src/runtime/aping/q3dsobject3d_p.h | 85 | ||||
-rw-r--r-- | src/runtime/q3dsuippresentation.cpp | 7 |
9 files changed, 129 insertions, 30 deletions
diff --git a/src/runtime/aping/q3dsgroup3d.cpp b/src/runtime/aping/q3dsgroup3d.cpp index 98f83fe..76d45a3 100644 --- a/src/runtime/aping/q3dsgroup3d.cpp +++ b/src/runtime/aping/q3dsgroup3d.cpp @@ -58,16 +58,7 @@ Q3DSGraphObject *Q3DSGroup3D::createObject(Q3DSUipPresentation *presentation) Q3DSGraphObject *obj = presentation->newObject<Q3DSGroupNode>(id); obj->setName(QString::fromLatin1(id)); - syncProperties(); - return obj; } -void Q3DSGroup3D::syncProperties() -{ - Q3DSNode3D::syncProperties(); - - // ### -} - QT_END_NAMESPACE diff --git a/src/runtime/aping/q3dsgroup3d_p.h b/src/runtime/aping/q3dsgroup3d_p.h index 506b08d..de8f3f4 100644 --- a/src/runtime/aping/q3dsgroup3d_p.h +++ b/src/runtime/aping/q3dsgroup3d_p.h @@ -56,7 +56,6 @@ public: Q3DSGroupNode *groupNode() const { return static_cast<Q3DSGroupNode *>(object()); } Q3DSGraphObject *createObject(Q3DSUipPresentation *presentation) override; - void syncProperties() override; }; QT_END_NAMESPACE diff --git a/src/runtime/aping/q3dslayer3d.cpp b/src/runtime/aping/q3dslayer3d.cpp index e783198..50f9eb4 100644 --- a/src/runtime/aping/q3dslayer3d.cpp +++ b/src/runtime/aping/q3dslayer3d.cpp @@ -243,8 +243,6 @@ void Q3DSLayer3D::sync() m_engine->handleViewGeometryChange(this, sz); } - syncProperties(); - // Notify the waiting Object3D, if there is one, to create its subtree // and parent it to our m_layer3DS. emit layerNodeCreated(); @@ -380,9 +378,4 @@ void Q3DSLayer3D::touchEvent(QTouchEvent *event) m_engine->engine()->handleTouchEvent(event, m_layer3DS); } -void Q3DSLayer3D::syncProperties() -{ - // ### -} - QT_END_NAMESPACE diff --git a/src/runtime/aping/q3dslayer3d_p.h b/src/runtime/aping/q3dslayer3d_p.h index 571a83e..f1f43bb 100644 --- a/src/runtime/aping/q3dslayer3d_p.h +++ b/src/runtime/aping/q3dslayer3d_p.h @@ -78,8 +78,6 @@ public: bool isLive() const { return layerNode() && presentation(); } - void syncProperties(); - signals: void engineChanged(); void layerNodeCreated(); diff --git a/src/runtime/aping/q3dsnode3d.cpp b/src/runtime/aping/q3dsnode3d.cpp index 58873c3..a885491 100644 --- a/src/runtime/aping/q3dsnode3d.cpp +++ b/src/runtime/aping/q3dsnode3d.cpp @@ -50,11 +50,4 @@ Q3DSNode3D::~Q3DSNode3D() { } -void Q3DSNode3D::syncProperties() -{ - Q3DSObject3D::syncProperties(); - - // ### -} - QT_END_NAMESPACE diff --git a/src/runtime/aping/q3dsnode3d_p.h b/src/runtime/aping/q3dsnode3d_p.h index 9ec5d77..88e61c8 100644 --- a/src/runtime/aping/q3dsnode3d_p.h +++ b/src/runtime/aping/q3dsnode3d_p.h @@ -54,8 +54,6 @@ public: ~Q3DSNode3D(); Q3DSNode *node() const { return static_cast<Q3DSNode *>(object()); } - - void syncProperties() override; }; QT_END_NAMESPACE diff --git a/src/runtime/aping/q3dsobject3d.cpp b/src/runtime/aping/q3dsobject3d.cpp index 54dfcd8..256845e 100644 --- a/src/runtime/aping/q3dsobject3d.cpp +++ b/src/runtime/aping/q3dsobject3d.cpp @@ -179,6 +179,17 @@ void Q3DSObject3D::activate() // Connect the object and its children to the Q3DSLayerNode. If that is // parented to a scene then the subtree becomes alive now. m_layer->layerNode()->appendChildNode(m_object); + + // Sync the properties and make sure they continue being updated. + syncProperties(); + Q3DSPropertyBinder *binder = nullptr; + const QVariant v = property(Q3DSPropertyBinder::binderName()); + if (v.isValid()) + binder = v.value<Q3DSPropertyBinder *>(); + + if (!binder) + binder = new Q3DSPropertyBinder(this); + binder->bind(this, m_object); } void Q3DSObject3D::setLayer_recursive(Q3DSLayer3D *layer) @@ -215,9 +226,35 @@ QByteArray Q3DSObject3D::makeIdAndName() const return id; } +void Q3DSObject3D::propertyChanged(const QMetaProperty &sp, + Q3DSGraphObject *target, + const QMetaProperty &tp) +{ + if (!target || !tp.isValid()) + return; + + const QVariant &v = sp.read(this); + if (!tp.writeOnGadget(target, v)) { + qWarning("Failed to write property %s on %s", sp.name(), target->id().constData()); + return; + } + const QString propName = QString::fromLatin1((!::strncmp(tp.name(), "qq_", 3)) ? tp.name() + 3 : tp.name()); + target->notifyPropertyChanges({propName, QString()}); +} + void Q3DSObject3D::syncProperties() { - // ### + Q_ASSERT(m_object); + // This is a bit crude, but it's only called once, so it's good enough for now. + const int propCount = metaObject()->propertyCount(); + for (int i = 0; i != propCount; ++i) { + const auto property = metaObject()->property(i); + const QByteArray name = QByteArrayLiteral("qq_") + property.name(); + int idx = m_object->metaObject()->indexOfProperty(name.constData()); + if (idx < 0) + idx = m_object->metaObject()->indexOfProperty(name.constData() + 3); + propertyChanged(property, m_object, (idx >= 0) ? m_object->metaObject()->property(idx) : QMetaProperty()); + } } QT_END_NAMESPACE diff --git a/src/runtime/aping/q3dsobject3d_p.h b/src/runtime/aping/q3dsobject3d_p.h index e588fdc..f055cef 100644 --- a/src/runtime/aping/q3dsobject3d_p.h +++ b/src/runtime/aping/q3dsobject3d_p.h @@ -58,7 +58,6 @@ public: ~Q3DSObject3D(); virtual Q3DSGraphObject *createObject(Q3DSUipPresentation *presentation) = 0; - virtual void syncProperties(); Q3DSGraphObject *object() const { return m_object; } Q3DSLayer3D *layer() const { return m_layer; } @@ -74,11 +73,15 @@ public: protected: void itemChange(ItemChange, const ItemChangeData &) override; QByteArray makeIdAndName() const; + virtual void propertyChanged(const QMetaProperty &sp, + Q3DSGraphObject *target, + const QMetaProperty &tp); private: void activate(); void activate_helper(Q3DSLayer3D *layer); void setLayer_recursive(Q3DSLayer3D *layer); + void syncProperties(); Q3DSGraphObject *m_object = nullptr; Q3DSLayer3D *m_layer = nullptr; @@ -87,10 +90,90 @@ private: QMetaObject::Connection m_layerConn; friend class Q3DSLayer3D; + friend class Q3DSPropertyBinder; }; Q_DECLARE_OPERATORS_FOR_FLAGS(Q3DSObject3D::InvalidateFlags) +class Q3DSPropertyBinder : public QObject +{ +public: + ~Q3DSPropertyBinder() { unbind(); } + static QByteArray binderName() { return QByteArrayLiteral("_q3dsbinding"); } + static QByteArray propertyPrefix() { return QByteArrayLiteral("qq_"); } + + Q3DSPropertyBinder(QObject *p = nullptr) : QObject(p) {} + int qt_metacall(QMetaObject::Call call, int methodId, void **args) override + { + methodId = QObject::qt_metacall(call, methodId, args); + if (methodId < 0) + return methodId; + + if (!m_dst || !m_src) + return methodId; + + if (call == QMetaObject::InvokeMetaMethod) { + QMetaProperty sp = m_src->metaObject()->property(methodId); + const int dstIdx = m_propMap[methodId]; + QMetaProperty tp = (dstIdx >= 0) ? m_dst->metaObject()->property(dstIdx) + : QMetaProperty(); + m_src->propertyChanged(sp, m_dst, tp); + return -1; + } + return methodId; + } + + void bind(Q3DSObject3D *src, Q3DSGraphObject *dst) + { + if (src == m_src && dst == m_dst) + return; + + unbind(); + + m_src = src; + m_src->setProperty(binderName(), QVariant::fromValue(this)); + m_dst = dst; + m_dst->setProperty(binderName(), QVariant::fromValue(this)); + const int propCount = src->metaObject()->propertyCount(); + for (int i = 0; i != propCount; ++i) { + const auto property = src->metaObject()->property(i); + if (!property.hasNotifySignal()) + continue; + const QByteArray name = propertyPrefix() + property.name(); + int idx = dst->metaObject()->indexOfProperty(name.constData()); + if (idx < 0) + idx = dst->metaObject()->indexOfProperty(name.constData() + 3); + m_propMap[i] = idx; + QMetaObject::connect(src, property.notifySignalIndex(), this, i + metaObject()->methodCount(), Qt::DirectConnection, nullptr); + } + } + + Q_INVOKABLE void unbind() + { + if (m_src) { + const QVariant h = m_src->property(binderName()); + Q_ASSERT(this == h.value<Q3DSPropertyBinder *>()); + m_src->setProperty(binderName(), QVariant()); + } + + if (m_dst) { + const QVariant h = m_dst->property(binderName()); + Q_ASSERT(this == h.value<Q3DSPropertyBinder *>()); + m_dst->setProperty(binderName(), QVariant()); + } + + disconnect(); + m_propMap.clear(); + m_src = nullptr; + m_dst = nullptr; + } + +private: + QMap<int, int> m_propMap; + Q3DSObject3D *m_src = nullptr; + Q3DSGraphObject *m_dst = nullptr; +}; + QT_END_NAMESPACE #endif // Q3DSOBJECT3D_P_H diff --git a/src/runtime/q3dsuippresentation.cpp b/src/runtime/q3dsuippresentation.cpp index 23836f0..11c2aa6 100644 --- a/src/runtime/q3dsuippresentation.cpp +++ b/src/runtime/q3dsuippresentation.cpp @@ -40,6 +40,7 @@ #include <QtMath> #include <QImage> +#include <QtCore/qobject.h> #include <QtCore/qmetaobject.h> QT_BEGIN_NAMESPACE @@ -411,6 +412,12 @@ Q3DSGraphObject::Q3DSGraphObject(Q3DSGraphObject::Type type) Q3DSGraphObject::~Q3DSGraphObject() { + const QVariant v = property(QByteArrayLiteral("_q3dsbinding")); + if (v.isValid()) { + QObject *src = v.value<QObject *>(); + QMetaObject::invokeMethod(src, "unbind", Qt::DirectConnection); + } + destroyGraph(); delete m_attached; } |