diff --git a/share/qtcreator/qml/qmlpuppet/qml2puppet/instances/nodeinstancemetaobject.cpp b/share/qtcreator/qml/qmlpuppet/qml2puppet/instances/nodeinstancemetaobject.cpp index a3d7483fa45..2cd639b700e 100644 --- a/share/qtcreator/qml/qmlpuppet/qml2puppet/instances/nodeinstancemetaobject.cpp +++ b/share/qtcreator/qml/qmlpuppet/qml2puppet/instances/nodeinstancemetaobject.cpp @@ -36,23 +36,167 @@ #include #include +#include +#include + namespace QmlDesigner { namespace Internal { -NodeInstanceMetaObject::NodeInstanceMetaObject(const ObjectNodeInstance::Pointer &nodeInstance, QQmlEngine *engine) - : QQmlOpenMetaObject(nodeInstance->object(), new QQmlOpenMetaObjectType(nodeInstance->object()->metaObject(), engine), true), - m_nodeInstance(nodeInstance), - m_context(nodeInstance->isRootNodeInstance() ? nodeInstance->context() : 0) +static QHash nodeInstanceMetaObjectList; + +struct MetaPropertyData { + inline QPair &getDataRef(int idx) { + while (m_data.count() <= idx) + m_data << QPair(QVariant(), false); + return m_data[idx]; + } + + inline QVariant &getData(int idx) { + QPair &prop = getDataRef(idx); + if (!prop.second) { + prop.first = QVariant(); + prop.second = true; + } + return prop.first; + } + + inline bool hasData(int idx) const { + if (idx >= m_data.count()) + return false; + return m_data[idx].second; + } + + inline int count() { return m_data.count(); } + + QList > m_data; +}; + +static bool constructedMetaData(const QQmlVMEMetaData* data) { - setCached(false); + return data->varPropertyCount == 0 + && data->propertyCount == 0 + && data->aliasCount == 0 + && data->signalCount == 0 + && data->methodCount == 0; +} + +static QQmlVMEMetaData* fakeMetaData() +{ + QQmlVMEMetaData* data = new QQmlVMEMetaData; + data->varPropertyCount = 0; + data->propertyCount = 0; + data->aliasCount = 0; + data->signalCount = 0; + data->methodCount = 0; + + return data; +} + +static const QQmlVMEMetaData* vMEMetaDataForObject(QObject *object) +{ + QQmlVMEMetaObject *metaObject = QQmlVMEMetaObject::get(object); + if (metaObject) + return metaObject->metaData; + + return fakeMetaData(); +} + +static QQmlPropertyCache *cacheForObject(QObject *object, QQmlEngine *engine) +{ + QQmlVMEMetaObject *metaObject = QQmlVMEMetaObject::get(object); + if (metaObject) + return metaObject->cache; + + return QQmlEnginePrivate::get(engine)->cache(object); +} + +static QAbstractDynamicMetaObject *abstractDynamicMetaObject(QObject *object) +{ + QObjectPrivate *op = QObjectPrivate::get(object); + if (op->metaObject) + return static_cast(op->metaObject); + return const_cast(static_cast(object->metaObject())); +} + + +NodeInstanceMetaObject *NodeInstanceMetaObject::createNodeInstanceMetaObject(const ObjectNodeInstancePointer &nodeInstance, QQmlEngine *engine) +{ + //Avoid setting up multiple NodeInstanceMetaObjects on the same QObject + QObjectPrivate *op = QObjectPrivate::get(nodeInstance->object()); + QDynamicMetaObjectData *parent = op->metaObject; + if (nodeInstanceMetaObjectList.contains(parent)) + return static_cast(parent); + + return new NodeInstanceMetaObject(nodeInstance, engine); +} + +NodeInstanceMetaObject *NodeInstanceMetaObject::createNodeInstanceMetaObject(const ObjectNodeInstancePointer &nodeInstance, QObject *object, const QString &prefix, QQmlEngine *engine) +{ + //Avoid setting up multiple NodeInstanceMetaObjects on the same QObject + QObjectPrivate *op = QObjectPrivate::get(nodeInstance->object()); + QDynamicMetaObjectData *parent = op->metaObject; + if (nodeInstanceMetaObjectList.contains(parent)) + return static_cast(parent); + + return new NodeInstanceMetaObject(nodeInstance, object, prefix, engine); +} + +void NodeInstanceMetaObject::init(QObject *object, QQmlEngine *engine) +{ + //Creating QQmlOpenMetaObjectType + m_type = new QQmlOpenMetaObjectType(metaObjectParent(), engine); + m_type->addref(); + //Assigning type to this + copyTypeMetaObject(); + + //Assign this to object + QObjectPrivate *op = QObjectPrivate::get(object); + op->metaObject = this; + + //create cache + cache = m_cache = QQmlEnginePrivate::get(engine)->cache(this); + + //If our parent is not a VMEMetaObject we just se the flag to false again + if (constructedMetaData(metaData)) + QQmlData::get(object)->hasVMEMetaObject = false; + + nodeInstanceMetaObjectList.insert(this, true); +} + +NodeInstanceMetaObject::NodeInstanceMetaObject(const ObjectNodeInstance::Pointer &nodeInstance, QQmlEngine *engine) + : QQmlVMEMetaObject(nodeInstance->object(), cacheForObject(nodeInstance->object(), engine), vMEMetaDataForObject(nodeInstance->object())), + m_nodeInstance(nodeInstance), + m_context(engine->contextForObject(nodeInstance->object())), + m_data(new MetaPropertyData), + m_cache(0) +{ + init(nodeInstance->object(), engine); + + QQmlData *ddata = QQmlData::get(nodeInstance->object(), false); + + //Assign cache to object + if (ddata && ddata->propertyCache) { + ddata->propertyCache = m_cache; + } } NodeInstanceMetaObject::NodeInstanceMetaObject(const ObjectNodeInstancePointer &nodeInstance, QObject *object, const QString &prefix, QQmlEngine *engine) - : QQmlOpenMetaObject(object, new QQmlOpenMetaObjectType(object->metaObject(), engine), true), - m_nodeInstance(nodeInstance), - m_prefix(prefix) + : QQmlVMEMetaObject(object, cacheForObject(object, engine), vMEMetaDataForObject(object)), + m_nodeInstance(nodeInstance), + m_context(engine->contextForObject(object)), + m_prefix(prefix), + + m_data(new MetaPropertyData), + m_cache(0) { - setCached(false); + init(object, engine); +} + +NodeInstanceMetaObject::~NodeInstanceMetaObject() +{ + m_type->release(); + + nodeInstanceMetaObjectList.remove(this); } void NodeInstanceMetaObject::createNewProperty(const QString &name) @@ -60,55 +204,114 @@ void NodeInstanceMetaObject::createNewProperty(const QString &name) int id = createProperty(name.toLatin1(), 0); setValue(id, QVariant()); Q_ASSERT(id >= 0); - Q_UNUSED(id) + Q_UNUSED(id); + + + //Updating cache + QQmlEnginePrivate::get(m_context->engine())->cache(this)->invalidate(m_context->engine(), this); + + QQmlProperty property(myObject(), name, m_context); + Q_ASSERT(property.isValid()); +} + +int NodeInstanceMetaObject::createProperty(const char *name, const char *) +{ + int id = m_type->createProperty(name); + copyTypeMetaObject(); + return id; +} + +void NodeInstanceMetaObject::setValue(int id, const QVariant &value) +{ + QPair &prop = m_data->getDataRef(id); + prop.first = propertyWriteValue(id, value); + prop.second = true; + QMetaObject::activate(myObject(), id + m_type->signalOffset(), 0); +} + +QVariant NodeInstanceMetaObject::propertyWriteValue(int, const QVariant &value) +{ + return value; +} + +int NodeInstanceMetaObject::openMetaCall(QMetaObject::Call call, int id, void **a) +{ + if ((call == QMetaObject::ReadProperty || call == QMetaObject::WriteProperty) + && id >= m_type->propertyOffset()) { + int propId = id - m_type->propertyOffset(); + if (call == QMetaObject::ReadProperty) { + //propertyRead(propId); + *reinterpret_cast(a[0]) = m_data->getData(propId); + } else if (call == QMetaObject::WriteProperty) { + if (propId <= m_data->count() || m_data->m_data[propId].first != *reinterpret_cast(a[0])) { + //propertyWrite(propId); + QPair &prop = m_data->getDataRef(propId); + prop.first = propertyWriteValue(propId, *reinterpret_cast(a[0])); + prop.second = true; + //propertyWritten(propId); + activate(myObject(), m_type->signalOffset() + propId, 0); + } + } + return -1; + } else { + QAbstractDynamicMetaObject *directParent = parent(); + if (directParent) + return directParent->metaCall(call, id, a); + else + return myObject()->qt_metacall(call, id, a); + } } int NodeInstanceMetaObject::metaCall(QMetaObject::Call call, int id, void **a) { int metaCallReturnValue = -1; + const QMetaProperty propertyById = QQmlVMEMetaObject::property(id); + if (call == QMetaObject::WriteProperty - && property(id).userType() == QMetaType::QVariant - && reinterpret_cast(a[0])->type() == QVariant::Double - && qIsNaN(reinterpret_cast(a[0])->toDouble())) { + && propertyById.userType() == QMetaType::QVariant + && reinterpret_cast(a[0])->type() == QVariant::Double + && qIsNaN(reinterpret_cast(a[0])->toDouble())) { return -1; } if (call == QMetaObject::WriteProperty - && property(id).userType() == QMetaType::Double - && qIsNaN(*reinterpret_cast(a[0]))) { + && propertyById.userType() == QMetaType::Double + && qIsNaN(*reinterpret_cast(a[0]))) { return -1; } if (call == QMetaObject::WriteProperty - && property(id).userType() == QMetaType::Float - && qIsNaN(*reinterpret_cast(a[0]))) { + && propertyById.userType() == QMetaType::Float + && qIsNaN(*reinterpret_cast(a[0]))) { return -1; } QVariant oldValue; - if (call == QMetaObject::WriteProperty && !property(id).hasNotifySignal()) + if (call == QMetaObject::WriteProperty && !propertyById.hasNotifySignal()) { - oldValue = property(id).read(object()); + oldValue = propertyById.read(myObject()); } ObjectNodeInstance::Pointer objectNodeInstance = m_nodeInstance.toStrongRef(); - if (parent() && id < parent()->propertyOffset()) { - metaCallReturnValue = parent()->metaCall(call, id, a); + QAbstractDynamicMetaObject *directParent = parent(); + if (directParent && id < directParent->propertyOffset()) { + metaCallReturnValue = directParent->metaCall(call, id, a); } else { - metaCallReturnValue = QQmlOpenMetaObject::metaCall(call, id, a); + openMetaCall(call, id, a); } if ((call == QMetaObject::WriteProperty || call == QMetaObject::ReadProperty) && metaCallReturnValue < 0) { if (objectNodeInstance && objectNodeInstance->nodeInstanceServer() && objectNodeInstance->nodeInstanceServer()->dummyContextObject() - && !(objectNodeInstance && !objectNodeInstance->isRootNodeInstance() && property(id).name() == QLatin1String("parent"))) { + && !(objectNodeInstance && !objectNodeInstance->isRootNodeInstance() + && property(id).name() == QLatin1String("parent"))) { QObject *contextDummyObject = objectNodeInstance->nodeInstanceServer()->dummyContextObject(); - int properyIndex = contextDummyObject->metaObject()->indexOfProperty(property(id).name()); + int properyIndex = contextDummyObject->metaObject()->indexOfProperty(propertyById.name()); if (properyIndex >= 0) metaCallReturnValue = contextDummyObject->qt_metacall(call, properyIndex, a); } @@ -116,8 +319,8 @@ int NodeInstanceMetaObject::metaCall(QMetaObject::Call call, int id, void **a) if (metaCallReturnValue >= 0 && call == QMetaObject::WriteProperty - && !property(id).hasNotifySignal() - && oldValue != property(id).read(object())) + && !propertyById.hasNotifySignal() + && oldValue != propertyById.read(myObject())) notifyPropertyChange(id); return metaCallReturnValue; @@ -126,15 +329,31 @@ int NodeInstanceMetaObject::metaCall(QMetaObject::Call call, int id, void **a) void NodeInstanceMetaObject::notifyPropertyChange(int id) { ObjectNodeInstance::Pointer objectNodeInstance = m_nodeInstance.toStrongRef(); + const QMetaProperty propertyById = property(id); if (objectNodeInstance && objectNodeInstance->nodeInstanceServer()) { - if (id < type()->propertyOffset()) { - objectNodeInstance->nodeInstanceServer()->notifyPropertyChange(objectNodeInstance->instanceId(), m_prefix + property(id).name()); + if (id < propertyOffset()) { + objectNodeInstance->nodeInstanceServer()->notifyPropertyChange(objectNodeInstance->instanceId(), m_prefix + propertyById.name()); } else { - objectNodeInstance->nodeInstanceServer()->notifyPropertyChange(objectNodeInstance->instanceId(), m_prefix + name(id - type()->propertyOffset())); + objectNodeInstance->nodeInstanceServer()->notifyPropertyChange(objectNodeInstance->instanceId(), m_prefix + name(id - propertyOffset())); } } } +int NodeInstanceMetaObject::count() const +{ + return m_type->propertyCount(); +} + +QByteArray NodeInstanceMetaObject::name(int idx) const +{ + return m_type->propertyName(idx); +} + +void NodeInstanceMetaObject::copyTypeMetaObject() +{ + *static_cast(this) = *m_type->metaObject(); +} + } // namespace Internal } // namespace QmlDesigner diff --git a/share/qtcreator/qml/qmlpuppet/qml2puppet/instances/nodeinstancemetaobject.h b/share/qtcreator/qml/qmlpuppet/qml2puppet/instances/nodeinstancemetaobject.h index db9a92fd355..5fa795b4553 100644 --- a/share/qtcreator/qml/qmlpuppet/qml2puppet/instances/nodeinstancemetaobject.h +++ b/share/qtcreator/qml/qmlpuppet/qml2puppet/instances/nodeinstancemetaobject.h @@ -32,7 +32,9 @@ #define NODEINSTANCEMETAOBJECT_H #include +#include #include +#include namespace QmlDesigner { namespace Internal { @@ -41,21 +43,63 @@ class ObjectNodeInstance; typedef QSharedPointer ObjectNodeInstancePointer; typedef QWeakPointer ObjectNodeInstanceWeakPointer; -class NodeInstanceMetaObject : public QQmlOpenMetaObject +struct MetaPropertyData; + +class NodeInstanceMetaObject : public QQmlVMEMetaObject { public: - NodeInstanceMetaObject(const ObjectNodeInstancePointer &nodeInstance, QQmlEngine *engine); - NodeInstanceMetaObject(const ObjectNodeInstancePointer &nodeInstance, QObject *object, const QString &prefix, QQmlEngine *engine); + static NodeInstanceMetaObject *createNodeInstanceMetaObject(const ObjectNodeInstancePointer &nodeInstance, QQmlEngine *engine); + static NodeInstanceMetaObject *createNodeInstanceMetaObject(const ObjectNodeInstancePointer &nodeInstance, QObject *object, const QString &prefix, QQmlEngine *engine); + ~NodeInstanceMetaObject(); void createNewProperty(const QString &name); protected: + NodeInstanceMetaObject(const ObjectNodeInstancePointer &nodeInstance, QQmlEngine *engine); + NodeInstanceMetaObject(const ObjectNodeInstancePointer &nodeInstance, QObject *object, const QString &prefix, QQmlEngine *engine); + + int openMetaCall(QMetaObject::Call _c, int _id, void **_a); int metaCall(QMetaObject::Call _c, int _id, void **_a); void notifyPropertyChange(int id); + void setValue(int id, const QVariant &value); + int createProperty(const char *, const char *); + QVariant propertyWriteValue(int, const QVariant &); + + QObject *myObject() const { return QQmlVMEMetaObject::object; } + QAbstractDynamicMetaObject *parent() const { return const_cast(dynamicMetaObjectParent()); } + + const QAbstractDynamicMetaObject *dynamicMetaObjectParent() const + { + if (QQmlVMEMetaObject::parent.isT1()) + return QQmlVMEMetaObject::parent.asT1()->toDynamicMetaObject(QQmlVMEMetaObject::object); + else + return 0; + } + + const QMetaObject *metaObjectParent() const + { + if (QQmlVMEMetaObject::parent.isT1()) + return QQmlVMEMetaObject::parent.asT1()->toDynamicMetaObject(QQmlVMEMetaObject::object); + + return QQmlVMEMetaObject::parent.asT2(); + } + + int propertyOffset() const { return cache->propertyOffset(); } + + int count() const; + QByteArray name(int) const; + + void copyTypeMetaObject(); private: + void init(QObject *, QQmlEngine *engine); + ObjectNodeInstanceWeakPointer m_nodeInstance; QString m_prefix; - QPointer m_context; + QPointer m_context; + QQmlOpenMetaObjectType *m_type; + QScopedPointer m_data; + //QAbstractDynamicMetaObject *m_parent; + QQmlPropertyCache *m_cache; }; } // namespace Internal diff --git a/share/qtcreator/qml/qmlpuppet/qml2puppet/instances/objectnodeinstance.cpp b/share/qtcreator/qml/qmlpuppet/qml2puppet/instances/objectnodeinstance.cpp index 1cfe4be8119..bb1ff8c0524 100644 --- a/share/qtcreator/qml/qmlpuppet/qml2puppet/instances/objectnodeinstance.cpp +++ b/share/qtcreator/qml/qmlpuppet/qml2puppet/instances/objectnodeinstance.cpp @@ -130,14 +130,15 @@ static bool hasPropertiesWitoutNotifications(const QMetaObject *metaObject) void ObjectNodeInstance::initializePropertyWatcher(const ObjectNodeInstance::Pointer &objectNodeInstance) { const QMetaObject *metaObject = objectNodeInstance->object()->metaObject(); - m_metaObject = new NodeInstanceMetaObject(objectNodeInstance, nodeInstanceServer()->engine()); - QQmlEnginePrivate::get(engine())->cache(m_metaObject); + m_metaObject = NodeInstanceMetaObject::createNodeInstanceMetaObject(objectNodeInstance, nodeInstanceServer()->engine()); for (int propertyIndex = QObject::staticMetaObject.propertyCount(); propertyIndex < metaObject->propertyCount(); propertyIndex++) { if (QQmlMetaType::isQObject(metaObject->property(propertyIndex).userType())) { QObject *propertyObject = QQmlMetaType::toQObject(metaObject->property(propertyIndex).read(objectNodeInstance->object())); if (propertyObject && hasPropertiesWitoutNotifications(propertyObject->metaObject())) { - QMetaObject *childMetaObject = new NodeInstanceMetaObject(objectNodeInstance, propertyObject, metaObject->property(propertyIndex).name(), nodeInstanceServer()->engine()); - QQmlEnginePrivate::get(engine())->cache(childMetaObject); + NodeInstanceMetaObject::createNodeInstanceMetaObject(objectNodeInstance, + propertyObject, + metaObject->property(propertyIndex).name(), + nodeInstanceServer()->engine()); } } }