diff options
-rw-r--r-- | doc/src/declarative/extending.qdoc | 31 | ||||
-rw-r--r-- | src/declarative/graphicsitems/qmlgraphicsvisualitemmodel.cpp | 2 | ||||
-rw-r--r-- | src/declarative/qml/qmlmetaproperty.cpp | 34 | ||||
-rw-r--r-- | tests/auto/declarative/declarative.pro | 2 | ||||
-rw-r--r-- | tests/auto/declarative/qmllistreference/data/MyType.qml (renamed from tests/auto/declarative/qmllist/data/MyType.qml) | 0 | ||||
-rw-r--r-- | tests/auto/declarative/qmllistreference/data/engineTypes.qml (renamed from tests/auto/declarative/qmllist/data/engineTypes.qml) | 0 | ||||
-rw-r--r-- | tests/auto/declarative/qmllistreference/data/variantToList.qml (renamed from tests/auto/declarative/qmllist/data/variantToList.qml) | 0 | ||||
-rw-r--r-- | tests/auto/declarative/qmllistreference/qmllistreference.pro (renamed from tests/auto/declarative/qmllist/qmllist.pro) | 2 | ||||
-rw-r--r-- | tests/auto/declarative/qmllistreference/tst_qmllistreference.cpp (renamed from tests/auto/declarative/qmllist/tst_qmllist.cpp) | 42 | ||||
-rw-r--r-- | tests/auto/declarative/qmlmetaproperty/tst_qmlmetaproperty.cpp | 65 |
10 files changed, 127 insertions, 51 deletions
diff --git a/doc/src/declarative/extending.qdoc b/doc/src/declarative/extending.qdoc index 0456f3f..d3e6c14 100644 --- a/doc/src/declarative/extending.qdoc +++ b/doc/src/declarative/extending.qdoc @@ -375,6 +375,37 @@ object will only be returned if it has previously been created. \l {Extending QML - Attached Properties Example} shows the complete code used to implement the rsvp attached property. +\section1 Memory Management and QVariant types + +It is an elements responsibility to ensure that it does not access or return +pointers to invalid objects. QML makes the following guarentees: + +\list +\o An object assigned to an QObject (or QObject-derived) pointer property will be +valid at the time of assignment. + +Following assignment, it is the responsibility of the class to subsequently guard +this pointer, either through a class specific method or the generic QPointer class. + +\o An object assigned to a QVariant will be valid at the time of assignment. + +When assigning an object to a QVariant property, QML will always use a QMetaType::QObjectStar +typed QVariant. It is the responsibility of the class to guard the pointer. A +general rule when writing a class that uses QVariant properties is to check the +type of the QVariant when it is set and if the type is not handled by your class, +reset it to an invalid variant. + +\o An object assigned to a QObject (or QObject-derived) list property will be +valid at the time of assignment. + +Following assignment, it is the responsibility of the class to subsequently guard +this pointer, either through a class specific method or the generic QPointer class. +\endlist + +Elements should assume that any QML assigned object can be deleted at any time, and +respond accordingly. If documented as such an element need not continue to work in +this situation, but it must not crash. + \section1 Signal Support \snippet examples/declarative/extending/signal/example.qml 0 diff --git a/src/declarative/graphicsitems/qmlgraphicsvisualitemmodel.cpp b/src/declarative/graphicsitems/qmlgraphicsvisualitemmodel.cpp index b96f399..9216793 100644 --- a/src/declarative/graphicsitems/qmlgraphicsvisualitemmodel.cpp +++ b/src/declarative/graphicsitems/qmlgraphicsvisualitemmodel.cpp @@ -415,7 +415,7 @@ int QmlGraphicsVisualDataModelDataMetaObject::createProperty(const char *name, c if (model->m_listAccessor->type() == QmlListAccessor::ListProperty) { model->ensureRoles(); QObject *object = model->m_listAccessor->at(data->m_index).value<QObject*>(); - if (object && object->property(name).isValid()) + if (object && (object->property(name).isValid() || qstrcmp(name,"modelData")==0)) return QmlOpenMetaObject::createProperty(name, type); } } diff --git a/src/declarative/qml/qmlmetaproperty.cpp b/src/declarative/qml/qmlmetaproperty.cpp index 7c273dc..1742c43 100644 --- a/src/declarative/qml/qmlmetaproperty.cpp +++ b/src/declarative/qml/qmlmetaproperty.cpp @@ -378,7 +378,9 @@ QmlMetaProperty &QmlMetaProperty::operator=(const QmlMetaProperty &other) d->object = other.d->object; d->isDefaultProperty = other.d->isDefaultProperty; + d->isNameCached = other.d->isNameCached; d->core = other.d->core; + d->nameCache = other.d->nameCache; d->valueType = other.d->valueType; @@ -811,22 +813,22 @@ bool QmlMetaPropertyPrivate::write(QObject *object, const QmlPropertyCache::Data return writeEnumProperty(prop, coreIdx, object, v, flags); } - int t = property.propType; - int vt = value.userType(); + int propertyType = property.propType; + int variantType = value.userType(); QmlEnginePrivate *enginePriv = QmlEnginePrivate::get(context); - if (t == QVariant::Url) { + if (propertyType == QVariant::Url) { QUrl u; bool found = false; - if (vt == QVariant::Url) { + if (variantType == QVariant::Url) { u = value.toUrl(); found = true; - } else if (vt == QVariant::ByteArray) { + } else if (variantType == QVariant::ByteArray) { u = QUrl(QString::fromUtf8(value.toByteArray())); found = true; - } else if (vt == QVariant::String) { + } else if (variantType == QVariant::String) { u = QUrl(value.toString()); found = true; } @@ -840,12 +842,12 @@ bool QmlMetaPropertyPrivate::write(QObject *object, const QmlPropertyCache::Data void *argv[] = { &u, 0, &status, &flags }; QMetaObject::metacall(object, QMetaObject::WriteProperty, coreIdx, argv); - } else if (vt == t) { + } else if (variantType == propertyType) { void *a[] = { (void *)value.constData(), 0, &status, &flags }; QMetaObject::metacall(object, QMetaObject::WriteProperty, coreIdx, a); - } else if (qMetaTypeId<QVariant>() == t) { + } else if (qMetaTypeId<QVariant>() == propertyType) { void *a[] = { (void *)&value, 0, &status, &flags }; QMetaObject::metacall(object, QMetaObject::WriteProperty, coreIdx, a); @@ -858,7 +860,7 @@ bool QmlMetaPropertyPrivate::write(QObject *object, const QmlPropertyCache::Data return false; QObject *o = *(QObject **)value.constData(); - const QMetaObject *propMo = rawMetaObjectForType(enginePriv, t); + const QMetaObject *propMo = rawMetaObjectForType(enginePriv, propertyType); if (o) valMo = o->metaObject(); @@ -914,25 +916,25 @@ bool QmlMetaPropertyPrivate::write(QObject *object, const QmlPropertyCache::Data } } else { - Q_ASSERT(vt != t); + Q_ASSERT(variantType != propertyType); QVariant v = value; - if (v.convert((QVariant::Type)t)) { + if (v.convert((QVariant::Type)propertyType)) { void *a[] = { (void *)v.constData(), 0, &status, &flags}; QMetaObject::metacall(object, QMetaObject::WriteProperty, coreIdx, a); - } else if ((uint)t >= QVariant::UserType && vt == QVariant::String) { - QmlMetaType::StringConverter con = QmlMetaType::customStringConverter(t); + } else if ((uint)propertyType >= QVariant::UserType && variantType == QVariant::String) { + QmlMetaType::StringConverter con = QmlMetaType::customStringConverter(propertyType); if (!con) return false; QVariant v = con(value.toString()); - if (v.userType() == t) { + if (v.userType() == propertyType) { void *a[] = { (void *)v.constData(), 0, &status, &flags}; QMetaObject::metacall(object, QMetaObject::WriteProperty, coreIdx, a); } - } else if (vt == QVariant::String) { + } else if (variantType == QVariant::String) { bool ok = false; - QVariant v = QmlStringConverters::variantFromString(value.toString(), t, &ok); + QVariant v = QmlStringConverters::variantFromString(value.toString(), propertyType, &ok); if (!ok) return false; diff --git a/tests/auto/declarative/declarative.pro b/tests/auto/declarative/declarative.pro index 645f794..870c92b 100644 --- a/tests/auto/declarative/declarative.pro +++ b/tests/auto/declarative/declarative.pro @@ -39,7 +39,7 @@ SUBDIRS += \ qmlinfo \ # Cover qmlinstruction \ # Cover qmllanguage \ # Cover - qmllist \ # Cover + qmllistreference \ # Cover qmllistmodel \ # Cover qmlmetaproperty \ # Cover qmlmetatype \ # Cover diff --git a/tests/auto/declarative/qmllist/data/MyType.qml b/tests/auto/declarative/qmllistreference/data/MyType.qml index d08f35b..d08f35b 100644 --- a/tests/auto/declarative/qmllist/data/MyType.qml +++ b/tests/auto/declarative/qmllistreference/data/MyType.qml diff --git a/tests/auto/declarative/qmllist/data/engineTypes.qml b/tests/auto/declarative/qmllistreference/data/engineTypes.qml index 670aee4..670aee4 100644 --- a/tests/auto/declarative/qmllist/data/engineTypes.qml +++ b/tests/auto/declarative/qmllistreference/data/engineTypes.qml diff --git a/tests/auto/declarative/qmllist/data/variantToList.qml b/tests/auto/declarative/qmllistreference/data/variantToList.qml index 0c2d0aa..0c2d0aa 100644 --- a/tests/auto/declarative/qmllist/data/variantToList.qml +++ b/tests/auto/declarative/qmllistreference/data/variantToList.qml diff --git a/tests/auto/declarative/qmllist/qmllist.pro b/tests/auto/declarative/qmllistreference/qmllistreference.pro index b2145ed..fa49d5a 100644 --- a/tests/auto/declarative/qmllist/qmllist.pro +++ b/tests/auto/declarative/qmllistreference/qmllistreference.pro @@ -2,4 +2,4 @@ load(qttest_p4) contains(QT_CONFIG,declarative): QT += declarative macx:CONFIG -= app_bundle -SOURCES += tst_qmllist.cpp +SOURCES += tst_qmllistreference.cpp diff --git a/tests/auto/declarative/qmllist/tst_qmllist.cpp b/tests/auto/declarative/qmllistreference/tst_qmllistreference.cpp index 76def1c..6122f1e 100644 --- a/tests/auto/declarative/qmllist/tst_qmllist.cpp +++ b/tests/auto/declarative/qmllistreference/tst_qmllistreference.cpp @@ -60,11 +60,11 @@ inline QUrl TEST_FILE(const char *filename) return TEST_FILE(QLatin1String(filename)); } -class tst_QmlList : public QObject +class tst_qmllistreference : public QObject { Q_OBJECT public: - tst_QmlList() {} + tst_qmllistreference() {} private slots: void qmllistreference(); @@ -103,7 +103,7 @@ public: QML_DECLARE_TYPE(TestType); QML_DEFINE_NOCREATE_TYPE(TestType); -void tst_QmlList::qmllistreference() +void tst_qmllistreference::qmllistreference() { TestType tt; @@ -115,7 +115,7 @@ void tst_QmlList::qmllistreference() QCOMPARE(r.count(), 1); } -void tst_QmlList::qmllistreference_invalid() +void tst_qmllistreference::qmllistreference_invalid() { TestType tt; @@ -165,7 +165,7 @@ void tst_QmlList::qmllistreference_invalid() } } -void tst_QmlList::isValid() +void tst_qmllistreference::isValid() { TestType *tt = new TestType; @@ -187,7 +187,7 @@ void tst_QmlList::isValid() } } -void tst_QmlList::object() +void tst_qmllistreference::object() { TestType *tt = new TestType; @@ -209,7 +209,7 @@ void tst_QmlList::object() } } -void tst_QmlList::listElementType() +void tst_qmllistreference::listElementType() { TestType *tt = new TestType; @@ -231,7 +231,7 @@ void tst_QmlList::listElementType() } } -void tst_QmlList::canAppend() +void tst_qmllistreference::canAppend() { TestType *tt = new TestType; @@ -260,7 +260,7 @@ void tst_QmlList::canAppend() } } -void tst_QmlList::canAt() +void tst_qmllistreference::canAt() { TestType *tt = new TestType; @@ -289,7 +289,7 @@ void tst_QmlList::canAt() } } -void tst_QmlList::canClear() +void tst_qmllistreference::canClear() { TestType *tt = new TestType; @@ -318,7 +318,7 @@ void tst_QmlList::canClear() } } -void tst_QmlList::canCount() +void tst_qmllistreference::canCount() { TestType *tt = new TestType; @@ -347,7 +347,7 @@ void tst_QmlList::canCount() } } -void tst_QmlList::append() +void tst_qmllistreference::append() { TestType *tt = new TestType; QObject object; @@ -386,7 +386,7 @@ void tst_QmlList::append() } } -void tst_QmlList::at() +void tst_qmllistreference::at() { TestType *tt = new TestType; tt->data.append(tt); @@ -421,7 +421,7 @@ void tst_QmlList::at() } } -void tst_QmlList::clear() +void tst_qmllistreference::clear() { TestType *tt = new TestType; tt->data.append(tt); @@ -454,7 +454,7 @@ void tst_QmlList::clear() } } -void tst_QmlList::count() +void tst_qmllistreference::count() { TestType *tt = new TestType; tt->data.append(tt); @@ -489,7 +489,7 @@ void tst_QmlList::count() } } -void tst_QmlList::copy() +void tst_qmllistreference::copy() { TestType tt; tt.data.append(&tt); @@ -517,7 +517,7 @@ void tst_QmlList::copy() QVERIFY(r3.count() == 2); } -void tst_QmlList::qmlmetaproperty() +void tst_qmllistreference::qmlmetaproperty() { TestType tt; tt.data.append(&tt); @@ -532,7 +532,7 @@ void tst_QmlList::qmlmetaproperty() QVERIFY(ref.listElementType() == &TestType::staticMetaObject); } -void tst_QmlList::engineTypes() +void tst_qmllistreference::engineTypes() { QmlEngine engine; QmlComponent component(&engine, TEST_FILE("engineTypes.qml")); @@ -555,7 +555,7 @@ void tst_QmlList::engineTypes() delete o; } -void tst_QmlList::variantToList() +void tst_qmllistreference::variantToList() { QmlEngine engine; QmlComponent component(&engine, TEST_FILE("variantToList.qml")); @@ -569,6 +569,6 @@ void tst_QmlList::variantToList() delete o; } -QTEST_MAIN(tst_QmlList) +QTEST_MAIN(tst_qmllistreference) -#include "tst_qmllist.moc" +#include "tst_qmllistreference.moc" diff --git a/tests/auto/declarative/qmlmetaproperty/tst_qmlmetaproperty.cpp b/tests/auto/declarative/qmlmetaproperty/tst_qmlmetaproperty.cpp index 050cd3f..c289641 100644 --- a/tests/auto/declarative/qmlmetaproperty/tst_qmlmetaproperty.cpp +++ b/tests/auto/declarative/qmlmetaproperty/tst_qmlmetaproperty.cpp @@ -121,6 +121,7 @@ private slots: // Bugs void crashOnValueProperty(); + void copy(); private: QmlEngine engine; }; @@ -129,7 +130,7 @@ void tst_qmlmetaproperty::qmlmetaproperty() { QmlMetaProperty prop; - QGuard<QmlBinding> binding(new QmlBinding(QString(), 0, 0)); + QGuard<QmlBinding> binding(new QmlBinding(QLatin1String("null"), 0, engine.rootContext())); QVERIFY(binding != 0); QGuard<QmlExpression> expression(new QmlExpression()); QVERIFY(expression != 0); @@ -218,7 +219,7 @@ void tst_qmlmetaproperty::qmlmetaproperty_object() { QmlMetaProperty prop(&object); - QGuard<QmlBinding> binding(new QmlBinding(QString(), 0, 0)); + QGuard<QmlBinding> binding(new QmlBinding(QLatin1String("null"), 0, engine.rootContext())); QVERIFY(binding != 0); QGuard<QmlExpression> expression(new QmlExpression()); QVERIFY(expression != 0); @@ -264,7 +265,7 @@ void tst_qmlmetaproperty::qmlmetaproperty_object() { QmlMetaProperty prop(&dobject); - QGuard<QmlBinding> binding(new QmlBinding(QString(), 0, 0)); + QGuard<QmlBinding> binding(new QmlBinding(QLatin1String("null"), 0, engine.rootContext())); binding->setTarget(prop); QVERIFY(binding != 0); QGuard<QmlExpression> expression(new QmlExpression()); @@ -319,7 +320,7 @@ void tst_qmlmetaproperty::qmlmetaproperty_object_string() { QmlMetaProperty prop(&object, QString("defaultProperty")); - QGuard<QmlBinding> binding(new QmlBinding(QString(), 0, 0)); + QGuard<QmlBinding> binding(new QmlBinding(QLatin1String("null"), 0, engine.rootContext())); QVERIFY(binding != 0); QGuard<QmlExpression> expression(new QmlExpression()); QVERIFY(expression != 0); @@ -365,7 +366,7 @@ void tst_qmlmetaproperty::qmlmetaproperty_object_string() { QmlMetaProperty prop(&dobject, QString("defaultProperty")); - QGuard<QmlBinding> binding(new QmlBinding(QString(), 0, 0)); + QGuard<QmlBinding> binding(new QmlBinding(QLatin1String("null"), 0, engine.rootContext())); binding->setTarget(prop); QVERIFY(binding != 0); QGuard<QmlExpression> expression(new QmlExpression()); @@ -414,7 +415,7 @@ void tst_qmlmetaproperty::qmlmetaproperty_object_string() { QmlMetaProperty prop(&dobject, QString("onClicked")); - QGuard<QmlBinding> binding(new QmlBinding(QString(), 0, 0)); + QGuard<QmlBinding> binding(new QmlBinding(QLatin1String("null"), 0, engine.rootContext())); binding->setTarget(prop); QVERIFY(binding != 0); QGuard<QmlExpression> expression(new QmlExpression()); @@ -468,7 +469,7 @@ void tst_qmlmetaproperty::qmlmetaproperty_object_context() { QmlMetaProperty prop(&object, engine.rootContext()); - QGuard<QmlBinding> binding(new QmlBinding(QString(), 0, 0)); + QGuard<QmlBinding> binding(new QmlBinding(QLatin1String("null"), 0, engine.rootContext())); QVERIFY(binding != 0); QGuard<QmlExpression> expression(new QmlExpression()); QVERIFY(expression != 0); @@ -514,7 +515,7 @@ void tst_qmlmetaproperty::qmlmetaproperty_object_context() { QmlMetaProperty prop(&dobject, engine.rootContext()); - QGuard<QmlBinding> binding(new QmlBinding(QString(), 0, 0)); + QGuard<QmlBinding> binding(new QmlBinding(QLatin1String("null"), 0, engine.rootContext())); binding->setTarget(prop); QVERIFY(binding != 0); QGuard<QmlExpression> expression(new QmlExpression()); @@ -569,7 +570,7 @@ void tst_qmlmetaproperty::qmlmetaproperty_object_string_context() { QmlMetaProperty prop(&object, QString("defaultProperty"), engine.rootContext()); - QGuard<QmlBinding> binding(new QmlBinding(QString(), 0, 0)); + QGuard<QmlBinding> binding(new QmlBinding(QLatin1String("null"), 0, engine.rootContext())); QVERIFY(binding != 0); QGuard<QmlExpression> expression(new QmlExpression()); QVERIFY(expression != 0); @@ -615,7 +616,7 @@ void tst_qmlmetaproperty::qmlmetaproperty_object_string_context() { QmlMetaProperty prop(&dobject, QString("defaultProperty"), engine.rootContext()); - QGuard<QmlBinding> binding(new QmlBinding(QString(), 0, 0)); + QGuard<QmlBinding> binding(new QmlBinding(QLatin1String("null"), 0, engine.rootContext())); binding->setTarget(prop); QVERIFY(binding != 0); QGuard<QmlExpression> expression(new QmlExpression()); @@ -664,7 +665,7 @@ void tst_qmlmetaproperty::qmlmetaproperty_object_string_context() { QmlMetaProperty prop(&dobject, QString("onClicked"), engine.rootContext()); - QGuard<QmlBinding> binding(new QmlBinding(QString(), 0, 0)); + QGuard<QmlBinding> binding(new QmlBinding(QLatin1String("null"), 0, engine.rootContext())); binding->setTarget(prop); QVERIFY(binding != 0); QGuard<QmlExpression> expression(new QmlExpression()); @@ -1131,6 +1132,48 @@ void tst_qmlmetaproperty::crashOnValueProperty() QCOMPARE(p.read(), QVariant(20)); } +void tst_qmlmetaproperty::copy() +{ + PropertyObject object; + + QmlMetaProperty *property = new QmlMetaProperty(&object, QLatin1String("defaultProperty")); + QCOMPARE(property->name(), QString("defaultProperty")); + QCOMPARE(property->read(), QVariant(10)); + QCOMPARE(property->type(), QmlMetaProperty::Property); + QCOMPARE(property->propertyCategory(), QmlMetaProperty::Normal); + QCOMPARE(property->propertyType(), (int)QVariant::Int); + + QmlMetaProperty p1(*property); + QCOMPARE(p1.name(), QString("defaultProperty")); + QCOMPARE(p1.read(), QVariant(10)); + QCOMPARE(p1.type(), QmlMetaProperty::Property); + QCOMPARE(p1.propertyCategory(), QmlMetaProperty::Normal); + QCOMPARE(p1.propertyType(), (int)QVariant::Int); + + QmlMetaProperty p2(&object, QLatin1String("url")); + QCOMPARE(p2.name(), QString("url")); + p2 = *property; + QCOMPARE(p2.name(), QString("defaultProperty")); + QCOMPARE(p2.read(), QVariant(10)); + QCOMPARE(p2.type(), QmlMetaProperty::Property); + QCOMPARE(p2.propertyCategory(), QmlMetaProperty::Normal); + QCOMPARE(p2.propertyType(), (int)QVariant::Int); + + delete property; property = 0; + + QCOMPARE(p1.name(), QString("defaultProperty")); + QCOMPARE(p1.read(), QVariant(10)); + QCOMPARE(p1.type(), QmlMetaProperty::Property); + QCOMPARE(p1.propertyCategory(), QmlMetaProperty::Normal); + QCOMPARE(p1.propertyType(), (int)QVariant::Int); + + QCOMPARE(p2.name(), QString("defaultProperty")); + QCOMPARE(p2.read(), QVariant(10)); + QCOMPARE(p2.type(), QmlMetaProperty::Property); + QCOMPARE(p2.propertyCategory(), QmlMetaProperty::Normal); + QCOMPARE(p2.propertyType(), (int)QVariant::Int); +} + QTEST_MAIN(tst_qmlmetaproperty) #include "tst_qmlmetaproperty.moc" |