aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--src/qml/qml/qqmlpropertycache.cpp40
-rw-r--r--src/qml/qml/qqmlpropertycache_p.h4
-rw-r--r--src/qml/qml/qqmlvaluetype.cpp4
-rw-r--r--src/qml/qml/qqmlvaluetypewrapper.cpp10
-rw-r--r--tests/auto/qml/qqmlvaluetypes/data/customvaluetype.qml3
-rw-r--r--tests/auto/qml/qqmlvaluetypes/tst_qqmlvaluetypes.cpp54
6 files changed, 109 insertions, 6 deletions
diff --git a/src/qml/qml/qqmlpropertycache.cpp b/src/qml/qml/qqmlpropertycache.cpp
index b5bc29aaa6..182e6a7814 100644
--- a/src/qml/qml/qqmlpropertycache.cpp
+++ b/src/qml/qml/qqmlpropertycache.cpp
@@ -1510,6 +1510,39 @@ bool QQmlMetaObject::canConvert(const QQmlMetaObject &from, const QQmlMetaObject
return false;
}
+void QQmlMetaObject::resolveGadgetMethodOrPropertyIndex(QMetaObject::Call type, const QMetaObject **metaObject, int *index)
+{
+ int offset;
+
+ switch (type) {
+ case QMetaObject::ReadProperty:
+ case QMetaObject::WriteProperty:
+ case QMetaObject::ResetProperty:
+ case QMetaObject::QueryPropertyDesignable:
+ case QMetaObject::QueryPropertyEditable:
+ case QMetaObject::QueryPropertyScriptable:
+ case QMetaObject::QueryPropertyStored:
+ case QMetaObject::QueryPropertyUser:
+ offset = (*metaObject)->propertyOffset();
+ while (*index < offset) {
+ *metaObject = (*metaObject)->superClass();
+ offset = (*metaObject)->propertyOffset();
+ }
+ break;
+ case QMetaObject::InvokeMetaMethod:
+ offset = (*metaObject)->methodOffset();
+ while (*index < offset) {
+ *metaObject = (*metaObject)->superClass();
+ offset = (*metaObject)->methodOffset();
+ }
+ break;
+ default:
+ Q_UNIMPLEMENTED();
+ }
+
+ *index -= offset;
+}
+
QQmlPropertyCache *QQmlMetaObject::propertyCache(QQmlEnginePrivate *e) const
{
if (_m.isNull()) return 0;
@@ -1652,8 +1685,11 @@ void QQmlObjectOrGadget::metacall(QMetaObject::Call type, int index, void **argv
{
if (ptr.isT1())
QMetaObject::metacall(ptr.asT1(), type, index, argv);
- else
- _m.asT1()->metaObject()->d.static_metacall(reinterpret_cast<QObject*>(ptr.asT2()), type, index, argv);
+ else {
+ const QMetaObject *metaObject = _m.asT1()->metaObject();
+ QQmlMetaObject::resolveGadgetMethodOrPropertyIndex(type, &metaObject, &index);
+ metaObject->d.static_metacall(reinterpret_cast<QObject*>(ptr.asT2()), type, index, argv);
+ }
}
QT_END_NAMESPACE
diff --git a/src/qml/qml/qqmlpropertycache_p.h b/src/qml/qml/qqmlpropertycache_p.h
index 77bbd3dc14..033ff1de31 100644
--- a/src/qml/qml/qqmlpropertycache_p.h
+++ b/src/qml/qml/qqmlpropertycache_p.h
@@ -432,6 +432,10 @@ public:
static bool canConvert(const QQmlMetaObject &from, const QQmlMetaObject &to);
+ // static_metacall (on Gadgets) doesn't call the base implementation and therefore
+ // we need a helper to find the correct meta object and property/method index.
+ static void resolveGadgetMethodOrPropertyIndex(QMetaObject::Call type, const QMetaObject **metaObject, int *index);
+
protected:
QBiPointer<QQmlPropertyCache, const QMetaObject> _m;
};
diff --git a/src/qml/qml/qqmlvaluetype.cpp b/src/qml/qml/qqmlvaluetype.cpp
index e901a9c0d7..7f0e3a3a61 100644
--- a/src/qml/qml/qqmlvaluetype.cpp
+++ b/src/qml/qml/qqmlvaluetype.cpp
@@ -231,7 +231,9 @@ void QQmlValueType::objectDestroyed(QObject *)
int QQmlValueType::metaCall(QObject *, QMetaObject::Call type, int _id, void **argv)
{
- d.static_metacall(reinterpret_cast<QObject*>(gadgetPtr), type, _id, argv);
+ const QMetaObject *mo = _metaObject;
+ QQmlMetaObject::resolveGadgetMethodOrPropertyIndex(type, &mo, &_id);
+ mo->d.static_metacall(reinterpret_cast<QObject*>(gadgetPtr), type, _id, argv);
return _id;
}
diff --git a/src/qml/qml/qqmlvaluetypewrapper.cpp b/src/qml/qml/qqmlvaluetypewrapper.cpp
index 332cfefde9..85a391fd98 100644
--- a/src/qml/qml/qqmlvaluetypewrapper.cpp
+++ b/src/qml/qml/qqmlvaluetypewrapper.cpp
@@ -307,11 +307,15 @@ ReturnedValue QQmlValueTypeWrapper::get(Managed *m, String *name, bool *hasPrope
if (result->propType == metatype) { \
cpptype v; \
void *args[] = { &v, 0 }; \
- metaObject->d.static_metacall(reinterpret_cast<QObject*>(gadget), QMetaObject::ReadProperty, result->coreIndex, args); \
+ metaObject->d.static_metacall(reinterpret_cast<QObject*>(gadget), QMetaObject::ReadProperty, index, args); \
return QV4::Encode(constructor(v)); \
}
const QMetaObject *metaObject = r->d()->propertyCache->metaObject();
+
+ int index = result->coreIndex;
+ QQmlMetaObject::resolveGadgetMethodOrPropertyIndex(QMetaObject::ReadProperty, &metaObject, &index);
+
void *gadget = r->d()->gadget();
// These four types are the most common used by the value type wrappers
@@ -322,9 +326,9 @@ ReturnedValue QQmlValueTypeWrapper::get(Managed *m, String *name, bool *hasPrope
QVariant v(result->propType, (void *)0);
void *args[] = { v.data(), 0 };
- metaObject->d.static_metacall(reinterpret_cast<QObject*>(gadget), QMetaObject::ReadProperty, result->coreIndex, args);
+ metaObject->d.static_metacall(reinterpret_cast<QObject*>(gadget), QMetaObject::ReadProperty, index, args);
return QV8Engine::fromVariant(v4, v);
-#undef VALUE_TYPE_ACCESSOR
+#undef VALUE_TYPE_LOAD
}
void QQmlValueTypeWrapper::put(Managed *m, String *name, const ValueRef value)
diff --git a/tests/auto/qml/qqmlvaluetypes/data/customvaluetype.qml b/tests/auto/qml/qqmlvaluetypes/data/customvaluetype.qml
index 7ae73475c3..380eb55f54 100644
--- a/tests/auto/qml/qqmlvaluetypes/data/customvaluetype.qml
+++ b/tests/auto/qml/qqmlvaluetypes/data/customvaluetype.qml
@@ -5,4 +5,7 @@ TypeWithCustomValueType {
desk {
monitorCount: 3
}
+ derivedGadget {
+ baseProperty: 42
+ }
}
diff --git a/tests/auto/qml/qqmlvaluetypes/tst_qqmlvaluetypes.cpp b/tests/auto/qml/qqmlvaluetypes/tst_qqmlvaluetypes.cpp
index f07a34b2f2..45cbbebdc3 100644
--- a/tests/auto/qml/qqmlvaluetypes/tst_qqmlvaluetypes.cpp
+++ b/tests/auto/qml/qqmlvaluetypes/tst_qqmlvaluetypes.cpp
@@ -90,6 +90,7 @@ private slots:
void groupedInterceptors_data();
void customValueType();
void customValueTypeInQml();
+ void gadgetInheritance();
private:
QQmlEngine engine;
@@ -1484,13 +1485,48 @@ void tst_qqmlvaluetypes::customValueType()
QCOMPARE(cppOffice.desk().monitorCount, 2);
}
+struct BaseGadget
+{
+ Q_GADGET
+ Q_PROPERTY(int baseProperty READ baseProperty WRITE setBaseProperty)
+public:
+ BaseGadget() : m_baseProperty(0) {}
+
+ int baseProperty() const { return m_baseProperty; }
+ void setBaseProperty(int value) { m_baseProperty = value; }
+ int m_baseProperty;
+
+ Q_INVOKABLE void functionInBaseGadget(int value) { m_baseProperty = value; }
+};
+
+Q_DECLARE_METATYPE(BaseGadget)
+
+struct DerivedGadget : public BaseGadget
+{
+ Q_GADGET
+ Q_PROPERTY(int derivedProperty READ derivedProperty WRITE setDerivedProperty)
+public:
+ DerivedGadget() : m_derivedProperty(0) {}
+
+ int derivedProperty() const { return m_derivedProperty; }
+ void setDerivedProperty(int value) { m_derivedProperty = value; }
+ int m_derivedProperty;
+
+ Q_INVOKABLE void functionInDerivedGadget(int value) { m_derivedProperty = value; }
+};
+
class TypeWithCustomValueType : public QObject
{
Q_OBJECT
Q_PROPERTY(MyDesk desk MEMBER m_desk)
+ Q_PROPERTY(DerivedGadget derivedGadget READ derivedGadget WRITE setDerivedGadget)
public:
MyDesk m_desk;
+
+ DerivedGadget derivedGadget() const { return m_derivedGadget; }
+ void setDerivedGadget(const DerivedGadget &value) { m_derivedGadget = value; }
+ DerivedGadget m_derivedGadget;
};
void tst_qqmlvaluetypes::customValueTypeInQml()
@@ -1503,6 +1539,24 @@ void tst_qqmlvaluetypes::customValueTypeInQml()
TypeWithCustomValueType *t = qobject_cast<TypeWithCustomValueType*>(object.data());
Q_ASSERT(t);
QCOMPARE(t->m_desk.monitorCount, 3);
+ QCOMPARE(t->m_derivedGadget.baseProperty(), 42);
+}
+
+Q_DECLARE_METATYPE(DerivedGadget)
+
+void tst_qqmlvaluetypes::gadgetInheritance()
+{
+ QJSEngine engine;
+
+ QJSValue value = engine.toScriptValue(DerivedGadget());
+
+ QCOMPARE(value.property("baseProperty").toInt(), 0);
+ value.setProperty("baseProperty", 10);
+ QCOMPARE(value.property("baseProperty").toInt(), 10);
+
+ QJSValue method = value.property("functionInBaseGadget");
+ method.call(QJSValueList() << QJSValue(42));
+ QCOMPARE(value.property("baseProperty").toInt(), 42);
}
QTEST_MAIN(tst_qqmlvaluetypes)