diff options
author | Qt Forward Merge Bot <qt_forward_merge_bot@qt-project.org> | 2019-02-23 01:00:50 +0100 |
---|---|---|
committer | Ulf Hermann <ulf.hermann@qt.io> | 2019-02-25 09:20:43 +0100 |
commit | a1aee495c8a69a076d3981ef005c627d74bb3660 (patch) | |
tree | 3fac2d8c217caf57f4faf0ead448126d44a28a51 | |
parent | b15654d77f7886ae23f06d760b90973983e12779 (diff) | |
parent | 3baa2d550512702dfc227aef0af3542ab189824f (diff) |
Merge remote-tracking branch 'origin/5.13' into dev
Conflicts:
src/qml/qml/qqmlmetatype.cpp
Change-Id: I517c001ea4eb0fdd8e469f9fffe5b7559a5b0795
35 files changed, 479 insertions, 177 deletions
diff --git a/src/qml/compiler/qqmlpropertycachecreator.cpp b/src/qml/compiler/qqmlpropertycachecreator.cpp index fd22cd58f1..fb54da5b73 100644 --- a/src/qml/compiler/qqmlpropertycachecreator.cpp +++ b/src/qml/compiler/qqmlpropertycachecreator.cpp @@ -74,7 +74,7 @@ QQmlRefPointer<QQmlPropertyCache> QQmlBindingInstantiationContext::instantiating if (instantiatingProperty->isQObject()) { return enginePrivate->rawPropertyCacheForType(instantiatingProperty->propType(), instantiatingProperty->typeMinorVersion()); } else if (const QMetaObject *vtmo = QQmlValueTypeFactory::metaObjectForMetaType(instantiatingProperty->propType())) { - return enginePrivate->cache(vtmo); + return enginePrivate->cache(vtmo, instantiatingProperty->typeMinorVersion()); } } return QQmlRefPointer<QQmlPropertyCache>(); diff --git a/src/qml/compiler/qqmlpropertyvalidator.cpp b/src/qml/compiler/qqmlpropertyvalidator.cpp index a6b57841a8..1beaac8095 100644 --- a/src/qml/compiler/qqmlpropertyvalidator.cpp +++ b/src/qml/compiler/qqmlpropertyvalidator.cpp @@ -160,10 +160,12 @@ QVector<QQmlCompileError> QQmlPropertyValidator::validateObject(int objectIndex, QQmlPropertyData *pd = nullptr; if (!name.isEmpty()) { if (binding->flags & QV4::CompiledData::Binding::IsSignalHandlerExpression - || binding->flags & QV4::CompiledData::Binding::IsSignalHandlerObject) + || binding->flags & QV4::CompiledData::Binding::IsSignalHandlerObject) { pd = propertyResolver.signal(name, ¬InRevision); - else - pd = propertyResolver.property(name, ¬InRevision, isGroupProperty ? QmlIR::PropertyResolver::IgnoreRevision : QmlIR::PropertyResolver::CheckRevision); + } else { + pd = propertyResolver.property(name, ¬InRevision, + QmlIR::PropertyResolver::CheckRevision); + } if (notInRevision) { QString typeName = stringAt(obj->inheritedTypeNameIndex); @@ -350,30 +352,45 @@ QQmlCompileError QQmlPropertyValidator::validateLiteralBinding(QQmlPropertyCache return noError; } + auto warnOrError = [&](const QString &error) { + if (binding->type == QV4::CompiledData::Binding::Type_Null) { + QQmlError warning; + warning.setUrl(compilationUnit->url()); + warning.setLine(binding->valueLocation.line); + warning.setColumn(binding->valueLocation.column); + warning.setDescription(error + tr(" - Assigning null to incompatible properties in QML " + "is deprecated. This will become a compile error in " + "future versions of Qt.")); + enginePrivate->warning(warning); + return noError; + } + return QQmlCompileError(binding->valueLocation, error); + }; + switch (property->propType()) { case QMetaType::QVariant: break; case QVariant::String: { if (!binding->evaluatesToString()) { - return QQmlCompileError(binding->valueLocation, tr("Invalid property assignment: string expected")); + return warnOrError(tr("Invalid property assignment: string expected")); } } break; case QVariant::StringList: { if (!binding->evaluatesToString()) { - return QQmlCompileError(binding->valueLocation, tr("Invalid property assignment: string or string list expected")); + return warnOrError(tr("Invalid property assignment: string or string list expected")); } } break; case QVariant::ByteArray: { if (binding->type != QV4::CompiledData::Binding::Type_String) { - return QQmlCompileError(binding->valueLocation, tr("Invalid property assignment: byte array expected")); + return warnOrError(tr("Invalid property assignment: byte array expected")); } } break; case QVariant::Url: { if (binding->type != QV4::CompiledData::Binding::Type_String) { - return QQmlCompileError(binding->valueLocation, tr("Invalid property assignment: url expected")); + return warnOrError(tr("Invalid property assignment: url expected")); } } break; @@ -383,7 +400,7 @@ QQmlCompileError QQmlPropertyValidator::validateLiteralBinding(QQmlPropertyCache if (double(uint(d)) == d) return noError; } - return QQmlCompileError(binding->valueLocation, tr("Invalid property assignment: unsigned int expected")); + return warnOrError(tr("Invalid property assignment: unsigned int expected")); } break; case QVariant::Int: { @@ -392,18 +409,18 @@ QQmlCompileError QQmlPropertyValidator::validateLiteralBinding(QQmlPropertyCache if (double(int(d)) == d) return noError; } - return QQmlCompileError(binding->valueLocation, tr("Invalid property assignment: int expected")); + return warnOrError(tr("Invalid property assignment: int expected")); } break; case QMetaType::Float: { if (binding->type != QV4::CompiledData::Binding::Type_Number) { - return QQmlCompileError(binding->valueLocation, tr("Invalid property assignment: number expected")); + return warnOrError(tr("Invalid property assignment: number expected")); } } break; case QVariant::Double: { if (binding->type != QV4::CompiledData::Binding::Type_Number) { - return QQmlCompileError(binding->valueLocation, tr("Invalid property assignment: number expected")); + return warnOrError(tr("Invalid property assignment: number expected")); } } break; @@ -411,7 +428,7 @@ QQmlCompileError QQmlPropertyValidator::validateLiteralBinding(QQmlPropertyCache bool ok = false; QQmlStringConverters::rgbaFromString(binding->valueAsString(compilationUnit.data()), &ok); if (!ok) { - return QQmlCompileError(binding->valueLocation, tr("Invalid property assignment: color expected")); + return warnOrError(tr("Invalid property assignment: color expected")); } } break; @@ -420,7 +437,7 @@ QQmlCompileError QQmlPropertyValidator::validateLiteralBinding(QQmlPropertyCache bool ok = false; QQmlStringConverters::dateFromString(binding->valueAsString(compilationUnit.data()), &ok); if (!ok) { - return QQmlCompileError(binding->valueLocation, tr("Invalid property assignment: date expected")); + return warnOrError(tr("Invalid property assignment: date expected")); } } break; @@ -428,7 +445,7 @@ QQmlCompileError QQmlPropertyValidator::validateLiteralBinding(QQmlPropertyCache bool ok = false; QQmlStringConverters::timeFromString(binding->valueAsString(compilationUnit.data()), &ok); if (!ok) { - return QQmlCompileError(binding->valueLocation, tr("Invalid property assignment: time expected")); + return warnOrError(tr("Invalid property assignment: time expected")); } } break; @@ -436,7 +453,7 @@ QQmlCompileError QQmlPropertyValidator::validateLiteralBinding(QQmlPropertyCache bool ok = false; QQmlStringConverters::dateTimeFromString(binding->valueAsString(compilationUnit.data()), &ok); if (!ok) { - return QQmlCompileError(binding->valueLocation, tr("Invalid property assignment: datetime expected")); + return warnOrError(tr("Invalid property assignment: datetime expected")); } } break; @@ -445,7 +462,7 @@ QQmlCompileError QQmlPropertyValidator::validateLiteralBinding(QQmlPropertyCache bool ok = false; QQmlStringConverters::pointFFromString(binding->valueAsString(compilationUnit.data()), &ok); if (!ok) { - return QQmlCompileError(binding->valueLocation, tr("Invalid property assignment: point expected")); + return warnOrError(tr("Invalid property assignment: point expected")); } } break; @@ -453,7 +470,7 @@ QQmlCompileError QQmlPropertyValidator::validateLiteralBinding(QQmlPropertyCache bool ok = false; QQmlStringConverters::pointFFromString(binding->valueAsString(compilationUnit.data()), &ok); if (!ok) { - return QQmlCompileError(binding->valueLocation, tr("Invalid property assignment: point expected")); + return warnOrError(tr("Invalid property assignment: point expected")); } } break; @@ -461,7 +478,7 @@ QQmlCompileError QQmlPropertyValidator::validateLiteralBinding(QQmlPropertyCache bool ok = false; QQmlStringConverters::sizeFFromString(binding->valueAsString(compilationUnit.data()), &ok); if (!ok) { - return QQmlCompileError(binding->valueLocation, tr("Invalid property assignment: size expected")); + return warnOrError(tr("Invalid property assignment: size expected")); } } break; @@ -469,7 +486,7 @@ QQmlCompileError QQmlPropertyValidator::validateLiteralBinding(QQmlPropertyCache bool ok = false; QQmlStringConverters::sizeFFromString(binding->valueAsString(compilationUnit.data()), &ok); if (!ok) { - return QQmlCompileError(binding->valueLocation, tr("Invalid property assignment: size expected")); + return warnOrError(tr("Invalid property assignment: size expected")); } } break; @@ -477,7 +494,7 @@ QQmlCompileError QQmlPropertyValidator::validateLiteralBinding(QQmlPropertyCache bool ok = false; QQmlStringConverters::rectFFromString(binding->valueAsString(compilationUnit.data()), &ok); if (!ok) { - return QQmlCompileError(binding->valueLocation, tr("Invalid property assignment: rect expected")); + return warnOrError(tr("Invalid property assignment: rect expected")); } } break; @@ -485,13 +502,13 @@ QQmlCompileError QQmlPropertyValidator::validateLiteralBinding(QQmlPropertyCache bool ok = false; QQmlStringConverters::rectFFromString(binding->valueAsString(compilationUnit.data()), &ok); if (!ok) { - return QQmlCompileError(binding->valueLocation, tr("Invalid property assignment: point expected")); + return warnOrError(tr("Invalid property assignment: point expected")); } } break; case QVariant::Bool: { if (binding->type != QV4::CompiledData::Binding::Type_Boolean) { - return QQmlCompileError(binding->valueLocation, tr("Invalid property assignment: boolean expected")); + return warnOrError(tr("Invalid property assignment: boolean expected")); } } break; @@ -501,7 +518,7 @@ QQmlCompileError QQmlPropertyValidator::validateLiteralBinding(QQmlPropertyCache float yp; } vec; if (!QQmlStringConverters::createFromString(QMetaType::QVector2D, binding->valueAsString(compilationUnit.data()), &vec, sizeof(vec))) { - return QQmlCompileError(binding->valueLocation, tr("Invalid property assignment: 2D vector expected")); + return warnOrError(tr("Invalid property assignment: 2D vector expected")); } } break; @@ -512,7 +529,7 @@ QQmlCompileError QQmlPropertyValidator::validateLiteralBinding(QQmlPropertyCache float zy; } vec; if (!QQmlStringConverters::createFromString(QMetaType::QVector3D, binding->valueAsString(compilationUnit.data()), &vec, sizeof(vec))) { - return QQmlCompileError(binding->valueLocation, tr("Invalid property assignment: 3D vector expected")); + return warnOrError(tr("Invalid property assignment: 3D vector expected")); } } break; @@ -524,7 +541,7 @@ QQmlCompileError QQmlPropertyValidator::validateLiteralBinding(QQmlPropertyCache float wp; } vec; if (!QQmlStringConverters::createFromString(QMetaType::QVector4D, binding->valueAsString(compilationUnit.data()), &vec, sizeof(vec))) { - return QQmlCompileError(binding->valueLocation, tr("Invalid property assignment: 4D vector expected")); + return warnOrError(tr("Invalid property assignment: 4D vector expected")); } } break; @@ -536,17 +553,17 @@ QQmlCompileError QQmlPropertyValidator::validateLiteralBinding(QQmlPropertyCache float zp; } vec; if (!QQmlStringConverters::createFromString(QMetaType::QQuaternion, binding->valueAsString(compilationUnit.data()), &vec, sizeof(vec))) { - return QQmlCompileError(binding->valueLocation, tr("Invalid property assignment: quaternion expected")); + return warnOrError(tr("Invalid property assignment: quaternion expected")); } } break; case QVariant::RegExp: - return QQmlCompileError(binding->valueLocation, tr("Invalid property assignment: regular expression expected; use /pattern/ syntax")); + return warnOrError(tr("Invalid property assignment: regular expression expected; use /pattern/ syntax")); default: { // generate single literal value assignment to a list property if required if (property->propType() == qMetaTypeId<QList<qreal> >()) { if (binding->type != QV4::CompiledData::Binding::Type_Number) { - return QQmlCompileError(binding->valueLocation, tr("Invalid property assignment: number or array of numbers expected")); + return warnOrError(tr("Invalid property assignment: number or array of numbers expected")); } break; } else if (property->propType() == qMetaTypeId<QList<int> >()) { @@ -557,21 +574,21 @@ QQmlCompileError QQmlPropertyValidator::validateLiteralBinding(QQmlPropertyCache ok = false; } if (!ok) - return QQmlCompileError(binding->valueLocation, tr("Invalid property assignment: int or array of ints expected")); + return warnOrError(tr("Invalid property assignment: int or array of ints expected")); break; } else if (property->propType() == qMetaTypeId<QList<bool> >()) { if (binding->type != QV4::CompiledData::Binding::Type_Boolean) { - return QQmlCompileError(binding->valueLocation, tr("Invalid property assignment: bool or array of bools expected")); + return warnOrError(tr("Invalid property assignment: bool or array of bools expected")); } break; } else if (property->propType() == qMetaTypeId<QList<QUrl> >()) { if (binding->type != QV4::CompiledData::Binding::Type_String) { - return QQmlCompileError(binding->valueLocation, tr("Invalid property assignment: url or array of urls expected")); + return warnOrError(tr("Invalid property assignment: url or array of urls expected")); } break; } else if (property->propType() == qMetaTypeId<QList<QString> >()) { if (!binding->evaluatesToString()) { - return QQmlCompileError(binding->valueLocation, tr("Invalid property assignment: string or array of strings expected")); + return warnOrError(tr("Invalid property assignment: string or array of strings expected")); } break; } else if (property->propType() == qMetaTypeId<QJSValue>()) { @@ -586,7 +603,7 @@ QQmlCompileError QQmlPropertyValidator::validateLiteralBinding(QQmlPropertyCache // otherwise, try a custom type assignment QQmlMetaType::StringConverter converter = QQmlMetaType::customStringConverter(property->propType()); if (!converter) { - return QQmlCompileError(binding->valueLocation, tr("Invalid property assignment: unsupported type \"%1\"").arg(QString::fromLatin1(QMetaType::typeName(property->propType())))); + return warnOrError(tr("Invalid property assignment: unsupported type \"%1\"").arg(QString::fromLatin1(QMetaType::typeName(property->propType())))); } } break; diff --git a/src/qml/compiler/qv4compileddata.cpp b/src/qml/compiler/qv4compileddata.cpp index 0db35fbd9e..5dd6fca023 100644 --- a/src/qml/compiler/qv4compileddata.cpp +++ b/src/qml/compiler/qv4compileddata.cpp @@ -853,7 +853,7 @@ QQmlRefPointer<QQmlPropertyCache> ResolvedTypeReference::createPropertyCache(QQm if (typePropertyCache) { return typePropertyCache; } else if (type.isValid()) { - typePropertyCache = QQmlEnginePrivate::get(engine)->cache(type.metaObject()); + typePropertyCache = QQmlEnginePrivate::get(engine)->cache(type.metaObject(), minorVersion); return typePropertyCache; } else { return compilationUnit->rootPropertyCache(); diff --git a/src/qml/jsapi/qjsengine_p.h b/src/qml/jsapi/qjsengine_p.h index 360c9df075..a77d710cff 100644 --- a/src/qml/jsapi/qjsengine_p.h +++ b/src/qml/jsapi/qjsengine_p.h @@ -109,8 +109,8 @@ public: // These methods may be called from the QML loader thread - inline QQmlPropertyCache *cache(QObject *obj); - inline QQmlPropertyCache *cache(const QMetaObject *); + inline QQmlPropertyCache *cache(QObject *obj, int minorVersion = -1); + inline QQmlPropertyCache *cache(const QMetaObject *, int minorVersion = -1); }; QJSEnginePrivate::Locker::Locker(const QJSEngine *e) @@ -160,14 +160,14 @@ and deleted before the loader thread has a chance to use or reference it. This can't currently happen as the cache holds a reference to the QQmlPropertyCache until the QQmlEngine is destroyed. */ -QQmlPropertyCache *QJSEnginePrivate::cache(QObject *obj) +QQmlPropertyCache *QJSEnginePrivate::cache(QObject *obj, int minorVersion) { if (!obj || QObjectPrivate::get(obj)->metaObject || QObjectPrivate::get(obj)->wasDeleted) return nullptr; Locker locker(this); const QMetaObject *mo = obj->metaObject(); - return QQmlMetaType::propertyCache(mo); + return QQmlMetaType::propertyCache(mo, minorVersion); } /*! @@ -179,12 +179,12 @@ exist for the lifetime of the QQmlEngine. The returned cache is not referenced, so if it is to be stored, call addref(). */ -QQmlPropertyCache *QJSEnginePrivate::cache(const QMetaObject *metaObject) +QQmlPropertyCache *QJSEnginePrivate::cache(const QMetaObject *metaObject, int minorVersion) { Q_ASSERT(metaObject); Locker locker(this); - return QQmlMetaType::propertyCache(metaObject); + return QQmlMetaType::propertyCache(metaObject, minorVersion); } diff --git a/src/qml/jsruntime/qv4qobjectwrapper.cpp b/src/qml/jsruntime/qv4qobjectwrapper.cpp index 60dacff94f..355dcffaf7 100644 --- a/src/qml/jsruntime/qv4qobjectwrapper.cpp +++ b/src/qml/jsruntime/qv4qobjectwrapper.cpp @@ -1206,8 +1206,20 @@ static QV4::ReturnedValue CallMethod(const QQmlObjectOrGadget &object, int index args[0].initAsType(returnType); for (int ii = 0; ii < argCount; ++ii) { if (!args[ii + 1].fromValue(argTypes[ii], engine, callArgs->args[ii])) { - return engine->throwTypeError(QString::fromLatin1("Could not convert argument %1.") - .arg(ii)); + qWarning() << QString::fromLatin1("Could not convert argument %1 at").arg(ii); + const StackTrace stack = engine->stackTrace(); + for (const StackFrame &frame : stack) { + qWarning() << "\t" << frame.function + QLatin1Char('@') + frame.source + + (frame.line > 0 + ? (QLatin1Char(':') + QString::number(frame.line)) + : QString()); + + } + qWarning() << QLatin1String("Passing incompatible arguments to C++ functions from " + "JavaScript is dangerous and deprecated."); + qWarning() << QLatin1String("This will throw a JavaScript TypeError in future " + "releases of Qt!"); + } } QVarLengthArray<void *, 9> argData(args.count()); @@ -1724,6 +1736,7 @@ bool CallArgument::fromValue(int callType, QV4::ExecutionEngine *engine, const Q type = callType; } else if (callType == qMetaTypeId<QList<QObject*> >()) { qlistPtr = new (&allocData) QList<QObject *>(); + type = callType; QV4::ScopedArrayObject array(scope, value); if (array) { Scoped<QV4::QObjectWrapper> qobjectWrapper(scope); @@ -1737,14 +1750,14 @@ bool CallArgument::fromValue(int callType, QV4::ExecutionEngine *engine, const Q qlistPtr->append(o); } } else { - QObject *o = nullptr; - if (const QV4::QObjectWrapper *qobjectWrapper = value.as<QV4::QObjectWrapper>()) - o = qobjectWrapper->object(); - else if (!value.isNull() && !value.isUndefined()) - return false; - qlistPtr->append(o); + if (const QV4::QObjectWrapper *qobjectWrapper = value.as<QV4::QObjectWrapper>()) { + qlistPtr->append(qobjectWrapper->object()); + } else { + qlistPtr->append(nullptr); + if (!value.isNull() && !value.isUndefined()) + return false; + } } - type = callType; } else if (callType == qMetaTypeId<QQmlV4Handle>()) { handlePtr = new (&allocData) QQmlV4Handle(value.asReturnedValue()); type = callType; diff --git a/src/qml/qml/qqmlengine_p.h b/src/qml/qml/qqmlengine_p.h index f334f51298..20d451d607 100644 --- a/src/qml/qml/qqmlengine_p.h +++ b/src/qml/qml/qqmlengine_p.h @@ -377,7 +377,7 @@ QQmlPropertyCache *QQmlEnginePrivate::cache(const QQmlType &type, int minorVersi Q_ASSERT(type.isValid()); if (minorVersion == -1 || !type.containsRevisionedAttributes()) - return cache(type.metaObject()); + return cache(type.metaObject(), minorVersion); Locker locker(this); return QQmlMetaType::propertyCache(type, minorVersion); diff --git a/src/qml/qml/qqmlmetatype.cpp b/src/qml/qml/qqmlmetatype.cpp index 3764dbd07e..a034d72221 100644 --- a/src/qml/qml/qqmlmetatype.cpp +++ b/src/qml/qml/qqmlmetatype.cpp @@ -1183,10 +1183,10 @@ QQmlType QQmlMetaType::qmlType(const QUrl &unNormalizedUrl, bool includeNonFileI return QQmlType(); } -QQmlPropertyCache *QQmlMetaType::propertyCache(const QMetaObject *metaObject) +QQmlPropertyCache *QQmlMetaType::propertyCache(const QMetaObject *metaObject, int minorVersion) { QQmlMetaTypeDataPtr data; // not const: the cache is created on demand - return data->propertyCache(metaObject); + return data->propertyCache(metaObject, minorVersion); } QQmlPropertyCache *QQmlMetaType::propertyCache(const QQmlType &type, int minorVersion) diff --git a/src/qml/qml/qqmlmetatype_p.h b/src/qml/qml/qqmlmetatype_p.h index dbfa10d044..dde9cf68d7 100644 --- a/src/qml/qml/qqmlmetatype_p.h +++ b/src/qml/qml/qqmlmetatype_p.h @@ -108,7 +108,7 @@ public: static QQmlType qmlType(int typeId, TypeIdCategory category = TypeIdCategory::MetaType); static QQmlType qmlType(const QUrl &unNormalizedUrl, bool includeNonFileImports = false); - static QQmlPropertyCache *propertyCache(const QMetaObject *metaObject); + static QQmlPropertyCache *propertyCache(const QMetaObject *metaObject, int minorVersion = -1); static QQmlPropertyCache *propertyCache(const QQmlType &type, int minorVersion); static void freeUnusedTypesAndCaches(); diff --git a/src/qml/qml/qqmlmetatypedata.cpp b/src/qml/qml/qqmlmetatypedata.cpp index f4f127ab9a..da5b4ec075 100644 --- a/src/qml/qml/qqmlmetatypedata.cpp +++ b/src/qml/qml/qqmlmetatypedata.cpp @@ -77,7 +77,7 @@ void QQmlMetaTypeData::registerType(QQmlTypePrivate *priv) priv->refCount.deref(); } -QQmlPropertyCache *QQmlMetaTypeData::propertyCache(const QMetaObject *metaObject) +QQmlPropertyCache *QQmlMetaTypeData::propertyCache(const QMetaObject *metaObject, int minorVersion) { if (QQmlPropertyCache *rv = propertyCaches.value(metaObject)) return rv; @@ -87,8 +87,8 @@ QQmlPropertyCache *QQmlMetaTypeData::propertyCache(const QMetaObject *metaObject propertyCaches.insert(metaObject, rv); return rv; } - QQmlPropertyCache *super = propertyCache(metaObject->superClass()); - QQmlPropertyCache *rv = super->copyAndAppend(metaObject); + QQmlPropertyCache *super = propertyCache(metaObject->superClass(), minorVersion); + QQmlPropertyCache *rv = super->copyAndAppend(metaObject, minorVersion); propertyCaches.insert(metaObject, rv); return rv; } @@ -123,7 +123,7 @@ QQmlPropertyCache *QQmlMetaTypeData::propertyCache(const QQmlType &type, int min return pc; } - QQmlPropertyCache *raw = propertyCache(type.metaObject()); + QQmlPropertyCache *raw = propertyCache(type.metaObject(), minorVersion); bool hasCopied = false; diff --git a/src/qml/qml/qqmlmetatypedata_p.h b/src/qml/qml/qqmlmetatypedata_p.h index f61adada2c..2c5a32be1b 100644 --- a/src/qml/qml/qqmlmetatypedata_p.h +++ b/src/qml/qml/qqmlmetatypedata_p.h @@ -112,7 +112,7 @@ struct QQmlMetaTypeData QHash<int, int> qmlLists; QHash<const QMetaObject *, QQmlPropertyCache *> propertyCaches; - QQmlPropertyCache *propertyCache(const QMetaObject *metaObject); + QQmlPropertyCache *propertyCache(const QMetaObject *metaObject, int minorVersion); QQmlPropertyCache *propertyCache(const QQmlType &type, int minorVersion); void setTypeRegistrationFailures(QStringList *failures) diff --git a/src/qml/qml/qqmlobjectcreator.cpp b/src/qml/qml/qqmlobjectcreator.cpp index ca5498d06c..c36b3ed386 100644 --- a/src/qml/qml/qqmlobjectcreator.cpp +++ b/src/qml/qml/qqmlobjectcreator.cpp @@ -379,6 +379,18 @@ void QQmlObjectCreator::setPropertyValue(const QQmlPropertyData *property, const } } + auto assertOrNull = [&](bool ok) + { + Q_ASSERT(ok || binding->type == QV4::CompiledData::Binding::Type_Null); + Q_UNUSED(ok); + }; + + auto assertType = [&](QV4::CompiledData::Binding::ValueType type) + { + Q_ASSERT(binding->type == type || binding->type == QV4::CompiledData::Binding::Type_Null); + Q_UNUSED(type); + }; + if (property->isQObject()) { if (binding->type == QV4::CompiledData::Binding::Type_Null) { QObject *value = nullptr; @@ -436,25 +448,25 @@ void QQmlObjectCreator::setPropertyValue(const QQmlPropertyData *property, const } break; case QVariant::String: { - Q_ASSERT(binding->evaluatesToString()); + assertOrNull(binding->evaluatesToString()); QString value = binding->valueAsString(compilationUnit.data()); property->writeProperty(_qobject, &value, propertyWriteFlags); } break; case QVariant::StringList: { - Q_ASSERT(binding->evaluatesToString()); + assertOrNull(binding->evaluatesToString()); QStringList value(binding->valueAsString(compilationUnit.data())); property->writeProperty(_qobject, &value, propertyWriteFlags); } break; case QVariant::ByteArray: { - Q_ASSERT(binding->type == QV4::CompiledData::Binding::Type_String); + assertType(QV4::CompiledData::Binding::Type_String); QByteArray value(binding->valueAsString(compilationUnit.data()).toUtf8()); property->writeProperty(_qobject, &value, propertyWriteFlags); } break; case QVariant::Url: { - Q_ASSERT(binding->type == QV4::CompiledData::Binding::Type_String); + assertType(QV4::CompiledData::Binding::Type_String); QString string = binding->valueAsString(compilationUnit.data()); // Encoded dir-separators defeat QUrl processing - decode them first string.replace(QLatin1String("%2f"), QLatin1String("/"), Qt::CaseInsensitive); @@ -466,7 +478,7 @@ void QQmlObjectCreator::setPropertyValue(const QQmlPropertyData *property, const } break; case QVariant::UInt: { - Q_ASSERT(binding->type == QV4::CompiledData::Binding::Type_Number); + assertType(QV4::CompiledData::Binding::Type_Number); double d = binding->valueAsNumber(compilationUnit->constants); uint value = uint(d); property->writeProperty(_qobject, &value, propertyWriteFlags); @@ -474,7 +486,7 @@ void QQmlObjectCreator::setPropertyValue(const QQmlPropertyData *property, const } break; case QVariant::Int: { - Q_ASSERT(binding->type == QV4::CompiledData::Binding::Type_Number); + assertType(QV4::CompiledData::Binding::Type_Number); double d = binding->valueAsNumber(compilationUnit->constants); int value = int(d); property->writeProperty(_qobject, &value, propertyWriteFlags); @@ -482,13 +494,13 @@ void QQmlObjectCreator::setPropertyValue(const QQmlPropertyData *property, const } break; case QMetaType::Float: { - Q_ASSERT(binding->type == QV4::CompiledData::Binding::Type_Number); + assertType(QV4::CompiledData::Binding::Type_Number); float value = float(binding->valueAsNumber(compilationUnit->constants)); property->writeProperty(_qobject, &value, propertyWriteFlags); } break; case QVariant::Double: { - Q_ASSERT(binding->type == QV4::CompiledData::Binding::Type_Number); + assertType(QV4::CompiledData::Binding::Type_Number); double value = binding->valueAsNumber(compilationUnit->constants); property->writeProperty(_qobject, &value, propertyWriteFlags); } @@ -496,7 +508,7 @@ void QQmlObjectCreator::setPropertyValue(const QQmlPropertyData *property, const case QVariant::Color: { bool ok = false; uint colorValue = QQmlStringConverters::rgbaFromString(binding->valueAsString(compilationUnit.data()), &ok); - Q_ASSERT(ok); + assertOrNull(ok); struct { void *data[4]; } buffer; if (QQml_valueTypeProvider()->storeValueType(property->propType(), &colorValue, &buffer, sizeof(buffer))) { property->writeProperty(_qobject, &buffer, propertyWriteFlags); @@ -507,14 +519,14 @@ void QQmlObjectCreator::setPropertyValue(const QQmlPropertyData *property, const case QVariant::Date: { bool ok = false; QDate value = QQmlStringConverters::dateFromString(binding->valueAsString(compilationUnit.data()), &ok); - Q_ASSERT(ok); + assertOrNull(ok); property->writeProperty(_qobject, &value, propertyWriteFlags); } break; case QVariant::Time: { bool ok = false; QTime value = QQmlStringConverters::timeFromString(binding->valueAsString(compilationUnit.data()), &ok); - Q_ASSERT(ok); + assertOrNull(ok); property->writeProperty(_qobject, &value, propertyWriteFlags); } break; @@ -527,7 +539,7 @@ void QQmlObjectCreator::setPropertyValue(const QQmlPropertyData *property, const const int msecsSinceStartOfDay = value.time().msecsSinceStartOfDay(); value = QDateTime(QDate::fromJulianDay(date), QTime::fromMSecsSinceStartOfDay(msecsSinceStartOfDay)); } - Q_ASSERT(ok); + assertOrNull(ok); property->writeProperty(_qobject, &value, propertyWriteFlags); } break; @@ -535,47 +547,47 @@ void QQmlObjectCreator::setPropertyValue(const QQmlPropertyData *property, const case QVariant::Point: { bool ok = false; QPoint value = QQmlStringConverters::pointFFromString(binding->valueAsString(compilationUnit.data()), &ok).toPoint(); - Q_ASSERT(ok); + assertOrNull(ok); property->writeProperty(_qobject, &value, propertyWriteFlags); } break; case QVariant::PointF: { bool ok = false; QPointF value = QQmlStringConverters::pointFFromString(binding->valueAsString(compilationUnit.data()), &ok); - Q_ASSERT(ok); + assertOrNull(ok); property->writeProperty(_qobject, &value, propertyWriteFlags); } break; case QVariant::Size: { bool ok = false; QSize value = QQmlStringConverters::sizeFFromString(binding->valueAsString(compilationUnit.data()), &ok).toSize(); - Q_ASSERT(ok); + assertOrNull(ok); property->writeProperty(_qobject, &value, propertyWriteFlags); } break; case QVariant::SizeF: { bool ok = false; QSizeF value = QQmlStringConverters::sizeFFromString(binding->valueAsString(compilationUnit.data()), &ok); - Q_ASSERT(ok); + assertOrNull(ok); property->writeProperty(_qobject, &value, propertyWriteFlags); } break; case QVariant::Rect: { bool ok = false; QRect value = QQmlStringConverters::rectFFromString(binding->valueAsString(compilationUnit.data()), &ok).toRect(); - Q_ASSERT(ok); + assertOrNull(ok); property->writeProperty(_qobject, &value, propertyWriteFlags); } break; case QVariant::RectF: { bool ok = false; QRectF value = QQmlStringConverters::rectFFromString(binding->valueAsString(compilationUnit.data()), &ok); - Q_ASSERT(ok); + assertOrNull(ok); property->writeProperty(_qobject, &value, propertyWriteFlags); } break; case QVariant::Bool: { - Q_ASSERT(binding->type == QV4::CompiledData::Binding::Type_Boolean); + assertType(QV4::CompiledData::Binding::Type_Boolean); bool value = binding->valueAsBoolean(); property->writeProperty(_qobject, &value, propertyWriteFlags); } @@ -586,7 +598,7 @@ void QQmlObjectCreator::setPropertyValue(const QQmlPropertyData *property, const float yp; } vec; bool ok = QQmlStringConverters::createFromString(QMetaType::QVector2D, binding->valueAsString(compilationUnit.data()), &vec, sizeof(vec)); - Q_ASSERT(ok); + assertOrNull(ok); Q_UNUSED(ok); property->writeProperty(_qobject, &vec, propertyWriteFlags); } @@ -598,7 +610,7 @@ void QQmlObjectCreator::setPropertyValue(const QQmlPropertyData *property, const float zy; } vec; bool ok = QQmlStringConverters::createFromString(QMetaType::QVector3D, binding->valueAsString(compilationUnit.data()), &vec, sizeof(vec)); - Q_ASSERT(ok); + assertOrNull(ok); Q_UNUSED(ok); property->writeProperty(_qobject, &vec, propertyWriteFlags); } @@ -611,7 +623,7 @@ void QQmlObjectCreator::setPropertyValue(const QQmlPropertyData *property, const float wp; } vec; bool ok = QQmlStringConverters::createFromString(QMetaType::QVector4D, binding->valueAsString(compilationUnit.data()), &vec, sizeof(vec)); - Q_ASSERT(ok); + assertOrNull(ok); Q_UNUSED(ok); property->writeProperty(_qobject, &vec, propertyWriteFlags); } @@ -624,37 +636,37 @@ void QQmlObjectCreator::setPropertyValue(const QQmlPropertyData *property, const float zp; } vec; bool ok = QQmlStringConverters::createFromString(QMetaType::QQuaternion, binding->valueAsString(compilationUnit.data()), &vec, sizeof(vec)); - Q_ASSERT(ok); + assertOrNull(ok); Q_UNUSED(ok); property->writeProperty(_qobject, &vec, propertyWriteFlags); } break; case QVariant::RegExp: - Q_ASSERT(!"not possible"); + assertOrNull(!"not possible"); break; default: { // generate single literal value assignment to a list property if required if (property->propType() == qMetaTypeId<QList<qreal> >()) { - Q_ASSERT(binding->type == QV4::CompiledData::Binding::Type_Number); + assertType(QV4::CompiledData::Binding::Type_Number); QList<qreal> value; value.append(binding->valueAsNumber(compilationUnit->constants)); property->writeProperty(_qobject, &value, propertyWriteFlags); break; } else if (property->propType() == qMetaTypeId<QList<int> >()) { - Q_ASSERT(binding->type == QV4::CompiledData::Binding::Type_Number); + assertType(QV4::CompiledData::Binding::Type_Number); double n = binding->valueAsNumber(compilationUnit->constants); QList<int> value; value.append(int(n)); property->writeProperty(_qobject, &value, propertyWriteFlags); break; } else if (property->propType() == qMetaTypeId<QList<bool> >()) { - Q_ASSERT(binding->type == QV4::CompiledData::Binding::Type_Boolean); + assertType(QV4::CompiledData::Binding::Type_Boolean); QList<bool> value; value.append(binding->valueAsBoolean()); property->writeProperty(_qobject, &value, propertyWriteFlags); break; } else if (property->propType() == qMetaTypeId<QList<QUrl> >()) { - Q_ASSERT(binding->type == QV4::CompiledData::Binding::Type_String); + assertType(QV4::CompiledData::Binding::Type_String); QString urlString = binding->valueAsString(compilationUnit.data()); QUrl u = urlString.isEmpty() ? QUrl() : compilationUnit->finalUrl().resolved(QUrl(urlString)); @@ -663,7 +675,7 @@ void QQmlObjectCreator::setPropertyValue(const QQmlPropertyData *property, const property->writeProperty(_qobject, &value, propertyWriteFlags); break; } else if (property->propType() == qMetaTypeId<QList<QString> >()) { - Q_ASSERT(binding->evaluatesToString()); + assertOrNull(binding->evaluatesToString()); QList<QString> value; value.append(binding->valueAsString(compilationUnit.data())); property->writeProperty(_qobject, &value, propertyWriteFlags); diff --git a/src/qml/qml/qqmlpropertycache.cpp b/src/qml/qml/qqmlpropertycache.cpp index 8934827e5e..46457a8d76 100644 --- a/src/qml/qml/qqmlpropertycache.cpp +++ b/src/qml/qml/qqmlpropertycache.cpp @@ -238,12 +238,22 @@ QQmlPropertyCache::QQmlPropertyCache() /*! Creates a new QQmlPropertyCache of \a metaObject. */ -QQmlPropertyCache::QQmlPropertyCache(const QMetaObject *metaObject) +QQmlPropertyCache::QQmlPropertyCache(const QMetaObject *metaObject, int metaObjectRevision) : QQmlPropertyCache() { Q_ASSERT(metaObject); update(metaObject); + + if (metaObjectRevision > 0) { + // Set the revision of the meta object that this cache describes to be + // 'metaObjectRevision'. This is useful when constructing a property cache + // from a type that was created directly in C++, and not through QML. For such + // types, the revision for each recorded QMetaObject would normally be zero, which + // would exclude any revisioned properties. + for (int metaObjectOffset = 0; metaObjectOffset < allowedRevisionCache.size(); ++metaObjectOffset) + allowedRevisionCache[metaObjectOffset] = metaObjectRevision; + } } QQmlPropertyCache::~QQmlPropertyCache() @@ -440,7 +450,7 @@ QQmlPropertyCache::copyAndAppend(const QMetaObject *metaObject, QQmlPropertyCache * QQmlPropertyCache::copyAndAppend(const QMetaObject *metaObject, - int revision, + int typeMinorVersion, QQmlPropertyData::Flags propertyFlags, QQmlPropertyData::Flags methodFlags, QQmlPropertyData::Flags signalFlags) @@ -454,19 +464,17 @@ QQmlPropertyCache::copyAndAppend(const QMetaObject *metaObject, QMetaObjectPrivate::get(metaObject)->signalCount + QMetaObjectPrivate::get(metaObject)->propertyCount); - rv->append(metaObject, revision, propertyFlags, methodFlags, signalFlags); + rv->append(metaObject, typeMinorVersion, propertyFlags, methodFlags, signalFlags); return rv; } void QQmlPropertyCache::append(const QMetaObject *metaObject, - int revision, + int typeMinorVersion, QQmlPropertyData::Flags propertyFlags, QQmlPropertyData::Flags methodFlags, QQmlPropertyData::Flags signalFlags) { - Q_UNUSED(revision); - _metaObject = metaObject; bool dynamicMetaObject = isDynamicMetaObject(metaObject); @@ -616,6 +624,7 @@ void QQmlPropertyCache::append(const QMetaObject *metaObject, data->setFlags(propertyFlags); data->lazyLoad(p); + data->setTypeMinorVersion(typeMinorVersion); data->_flags.isDirect = !dynamicMetaObject; diff --git a/src/qml/qml/qqmlpropertycache_p.h b/src/qml/qml/qqmlpropertycache_p.h index 68f086e191..4f47e5d351 100644 --- a/src/qml/qml/qqmlpropertycache_p.h +++ b/src/qml/qml/qqmlpropertycache_p.h @@ -80,7 +80,7 @@ class Q_QML_PRIVATE_EXPORT QQmlPropertyCache : public QQmlRefCount { public: QQmlPropertyCache(); - QQmlPropertyCache(const QMetaObject *); + QQmlPropertyCache(const QMetaObject *, int metaObjectRevision = 0); ~QQmlPropertyCache() override; void update(const QMetaObject *); @@ -92,7 +92,7 @@ public: QQmlPropertyRawData::Flags propertyFlags = QQmlPropertyData::Flags(), QQmlPropertyRawData::Flags methodFlags = QQmlPropertyData::Flags(), QQmlPropertyRawData::Flags signalFlags = QQmlPropertyData::Flags()); - QQmlPropertyCache *copyAndAppend(const QMetaObject *, int revision, + QQmlPropertyCache *copyAndAppend(const QMetaObject *, int typeMinorVersion, QQmlPropertyRawData::Flags propertyFlags = QQmlPropertyData::Flags(), QQmlPropertyRawData::Flags methodFlags = QQmlPropertyData::Flags(), QQmlPropertyRawData::Flags signalFlags = QQmlPropertyData::Flags()); @@ -186,7 +186,7 @@ private: inline QQmlPropertyCache *copy(int reserve); - void append(const QMetaObject *, int revision, + void append(const QMetaObject *, int typeMinorVersion, QQmlPropertyRawData::Flags propertyFlags = QQmlPropertyRawData::Flags(), QQmlPropertyRawData::Flags methodFlags = QQmlPropertyData::Flags(), QQmlPropertyRawData::Flags signalFlags = QQmlPropertyData::Flags()); diff --git a/src/qml/types/qqmldelegatemodel.cpp b/src/qml/types/qqmldelegatemodel.cpp index 48cc77bc3d..53e3f65553 100644 --- a/src/qml/types/qqmldelegatemodel.cpp +++ b/src/qml/types/qqmldelegatemodel.cpp @@ -2036,7 +2036,9 @@ void QV4::Heap::QQmlDelegateModelItemObject::destroy() } -QQmlDelegateModelItem::QQmlDelegateModelItem(QQmlDelegateModelItemMetaType *metaType, int modelIndex, int row, int column) +QQmlDelegateModelItem::QQmlDelegateModelItem(QQmlDelegateModelItemMetaType *metaType, + QQmlAdaptorModel::Accessors *accessor, + int modelIndex, int row, int column) : v4(metaType->v4Engine) , metaType(metaType) , contextData(nullptr) @@ -2053,6 +2055,21 @@ QQmlDelegateModelItem::QQmlDelegateModelItem(QQmlDelegateModelItemMetaType *meta , column(column) { metaType->addref(); + + if (accessor->propertyCache) { + // The property cache in the accessor is common for all the model + // items in the model it wraps. It describes available model roles, + // together with revisioned properties like row, column and index, all + // which should be available in the delegate. We assign this cache to the + // model item so that the QML engine can use the revision information + // when resolving the properties (rather than falling back to just + // inspecting the QObject in the model item directly). + QQmlData *qmldata = QQmlData::get(this, true); + if (qmldata->propertyCache) + qmldata->propertyCache->release(); + qmldata->propertyCache = accessor->propertyCache.data(); + qmldata->propertyCache->addref(); + } } QQmlDelegateModelItem::~QQmlDelegateModelItem() diff --git a/src/qml/types/qqmldelegatemodel_p_p.h b/src/qml/types/qqmldelegatemodel_p_p.h index 5e480f4df6..0028849828 100644 --- a/src/qml/types/qqmldelegatemodel_p_p.h +++ b/src/qml/types/qqmldelegatemodel_p_p.h @@ -96,11 +96,13 @@ class QQmlDelegateModelItem : public QObject { Q_OBJECT Q_PROPERTY(int index READ modelIndex NOTIFY modelIndexChanged) - Q_PROPERTY(int row MEMBER row NOTIFY rowChanged) - Q_PROPERTY(int column MEMBER column NOTIFY columnChanged) + Q_PROPERTY(int row READ modelRow NOTIFY rowChanged REVISION 12) + Q_PROPERTY(int column READ modelColumn NOTIFY columnChanged REVISION 12) Q_PROPERTY(QObject *model READ modelObject CONSTANT) public: - QQmlDelegateModelItem(QQmlDelegateModelItemMetaType *metaType, int modelIndex, int row, int column); + QQmlDelegateModelItem(QQmlDelegateModelItemMetaType *metaType, + QQmlAdaptorModel::Accessors *accessor, int modelIndex, + int row, int column); ~QQmlDelegateModelItem(); void referenceObject() { ++objectRef; } @@ -124,6 +126,8 @@ public: int groupIndex(Compositor::Group group); + int modelRow() const { return row; } + int modelColumn() const { return column; } int modelIndex() const { return index; } virtual void setModelIndex(int idx, int newRow, int newColumn); @@ -154,8 +158,8 @@ public: Q_SIGNALS: void modelIndexChanged(); - void rowChanged(); - void columnChanged(); + Q_REVISION(12) void rowChanged(); + Q_REVISION(12) void columnChanged(); protected: void objectDestroyed(QObject *); diff --git a/src/qml/types/qqmltableinstancemodel.cpp b/src/qml/types/qqmltableinstancemodel.cpp index 1054158dc8..2170e2daec 100644 --- a/src/qml/types/qqmltableinstancemodel.cpp +++ b/src/qml/types/qqmltableinstancemodel.cpp @@ -82,6 +82,11 @@ QQmlTableInstanceModel::QQmlTableInstanceModel(QQmlContext *qmlContext, QObject { } +void QQmlTableInstanceModel::useImportVersion(int minorVersion) +{ + m_adaptorModel.useImportVersion(minorVersion); +} + QQmlTableInstanceModel::~QQmlTableInstanceModel() { for (const auto modelItem : m_modelItems) { diff --git a/src/qml/types/qqmltableinstancemodel_p.h b/src/qml/types/qqmltableinstancemodel_p.h index 03761af326..3dd5c4e4ce 100644 --- a/src/qml/types/qqmltableinstancemodel_p.h +++ b/src/qml/types/qqmltableinstancemodel_p.h @@ -93,6 +93,8 @@ public: QQmlTableInstanceModel(QQmlContext *qmlContext, QObject *parent = nullptr); ~QQmlTableInstanceModel() override; + void useImportVersion(int minorVersion); + int count() const override { return m_adaptorModel.count(); } int rows() const { return m_adaptorModel.rowCount(); } int columns() const { return m_adaptorModel.columnCount(); } diff --git a/src/qml/util/qqmladaptormodel.cpp b/src/qml/util/qqmladaptormodel.cpp index 831663fb7b..d9cb6506b8 100644 --- a/src/qml/util/qqmladaptormodel.cpp +++ b/src/qml/util/qqmladaptormodel.cpp @@ -121,21 +121,12 @@ class VDMModelDelegateDataType public: VDMModelDelegateDataType(QQmlAdaptorModel *model) : model(model) - , metaObject(nullptr) - , propertyCache(nullptr) , propertyOffset(0) , signalOffset(0) , hasModelData(false) { } - ~VDMModelDelegateDataType() - { - if (propertyCache) - propertyCache->release(); - free(metaObject); - } - bool notify( const QQmlAdaptorModel &, const QList<QQmlDelegateModelItem *> &items, @@ -255,15 +246,13 @@ public: QList<QByteArray> watchedRoles; QHash<QByteArray, int> roleNames; QQmlAdaptorModel *model; - QMetaObject *metaObject; - QQmlPropertyCache *propertyCache; int propertyOffset; int signalOffset; bool hasModelData; }; QQmlDMCachedModelData::QQmlDMCachedModelData(QQmlDelegateModelItemMetaType *metaType, VDMModelDelegateDataType *dataType, int index, int row, int column) - : QQmlDelegateModelItem(metaType, index, row, column) + : QQmlDelegateModelItem(metaType, dataType, index, row, column) , type(dataType) { if (index == -1) @@ -272,10 +261,6 @@ QQmlDMCachedModelData::QQmlDMCachedModelData(QQmlDelegateModelItemMetaType *meta QObjectPrivate::get(this)->metaObject = type; type->addref(); - - QQmlData *qmldata = QQmlData::get(this, true); - qmldata->propertyCache = dataType->propertyCache; - qmldata->propertyCache->addref(); } int QQmlDMCachedModelData::metaCall(QMetaObject::Call call, int id, void **arguments) @@ -538,9 +523,9 @@ public: addProperty(&builder, 1, propertyName, propertyType); } - metaObject = builder.toMetaObject(); + metaObject.reset(builder.toMetaObject()); *static_cast<QMetaObject *>(this) = *metaObject; - propertyCache = new QQmlPropertyCache(metaObject); + propertyCache = new QQmlPropertyCache(metaObject.data(), model.modelItemRevision); } }; @@ -553,8 +538,10 @@ class QQmlDMListAccessorData : public QQmlDelegateModelItem Q_OBJECT Q_PROPERTY(QVariant modelData READ modelData WRITE setModelData NOTIFY modelDataChanged) public: - QQmlDMListAccessorData(QQmlDelegateModelItemMetaType *metaType, int index, int row, int column, const QVariant &value) - : QQmlDelegateModelItem(metaType, index, row, column) + QQmlDMListAccessorData(QQmlDelegateModelItemMetaType *metaType, + QQmlAdaptorModel::Accessors *accessor, + int index, int row, int column, const QVariant &value) + : QQmlDelegateModelItem(metaType, accessor, index, row, column) , cachedData(value) { } @@ -635,10 +622,18 @@ private: }; -class VDMListDelegateDataType : public QQmlAdaptorModel::Accessors +class VDMListDelegateDataType : public QQmlRefCount, public QQmlAdaptorModel::Accessors { public: - inline VDMListDelegateDataType() {} + VDMListDelegateDataType() + : QQmlRefCount() + , QQmlAdaptorModel::Accessors() + {} + + void cleanup(QQmlAdaptorModel &) const override + { + const_cast<VDMListDelegateDataType *>(this)->release(); + } int rowCount(const QQmlAdaptorModel &model) const override { @@ -662,8 +657,15 @@ public: QQmlDelegateModelItemMetaType *metaType, int index, int row, int column) const override { + VDMListDelegateDataType *dataType = const_cast<VDMListDelegateDataType *>(this); + if (!propertyCache) { + dataType->propertyCache = new QQmlPropertyCache( + &QQmlDMListAccessorData::staticMetaObject, model.modelItemRevision); + } + return new QQmlDMListAccessorData( metaType, + dataType, index, row, column, index >= 0 && index < model.list.count() ? model.list.at(index) : QVariant()); } @@ -721,15 +723,13 @@ Q_SIGNALS: class VDMObjectDelegateDataType : public QQmlRefCount, public QQmlAdaptorModel::Accessors { public: - QMetaObject *metaObject; int propertyOffset; int signalOffset; bool shared; QMetaObjectBuilder builder; VDMObjectDelegateDataType() - : metaObject(nullptr) - , propertyOffset(0) + : propertyOffset(0) , signalOffset(0) , shared(true) { @@ -738,11 +738,10 @@ public: VDMObjectDelegateDataType(const VDMObjectDelegateDataType &type) : QQmlRefCount() , QQmlAdaptorModel::Accessors() - , metaObject(nullptr) , propertyOffset(type.propertyOffset) , signalOffset(type.signalOffset) , shared(false) - , builder(type.metaObject, QMetaObjectBuilder::Properties + , builder(type.metaObject.data(), QMetaObjectBuilder::Properties | QMetaObjectBuilder::Signals | QMetaObjectBuilder::SuperClass | QMetaObjectBuilder::ClassName) @@ -750,11 +749,6 @@ public: builder.setFlags(QMetaObjectBuilder::DynamicMetaObject); } - ~VDMObjectDelegateDataType() - { - free(metaObject); - } - int rowCount(const QQmlAdaptorModel &model) const override { return model.list.count(); @@ -785,11 +779,18 @@ public: : nullptr; } - void initializeMetaType(QQmlAdaptorModel &) + void initializeMetaType(QQmlAdaptorModel &model) { + Q_UNUSED(model); setModelDataType<QQmlDMObjectData>(&builder, this); - metaObject = builder.toMetaObject(); + metaObject.reset(builder.toMetaObject()); + // Note: ATM we cannot create a shared property cache for this class, since each model + // object can have different properties. And to make those properties available to the + // delegate, QQmlDMObjectData makes use of a QAbstractDynamicMetaObject subclass + // (QQmlDMObjectDataMetaObject), which we cannot represent in a QQmlPropertyCache. + // By not having a shared property cache, revisioned properties in QQmlDelegateModelItem + // will always be available to the delegate, regardless of the import version. } void cleanup(QQmlAdaptorModel &) const override @@ -888,9 +889,7 @@ public: propertyBuilder.setConstant(property.isConstant()); } - if (m_type->metaObject) - free(m_type->metaObject); - m_type->metaObject = m_type->builder.toMetaObject(); + m_type->metaObject.reset(m_type->builder.toMetaObject()); *static_cast<QMetaObject *>(this) = *m_type->metaObject; notifierId = previousMethodCount; @@ -913,7 +912,7 @@ QQmlDMObjectData::QQmlDMObjectData(QQmlDelegateModelItemMetaType *metaType, VDMObjectDelegateDataType *dataType, int index, int row, int column, QObject *object) - : QQmlDelegateModelItem(metaType, index, row, column) + : QQmlDelegateModelItem(metaType, dataType, index, row, column) , object(object) { new QQmlDMObjectDataMetaObject(this, dataType); @@ -924,7 +923,6 @@ QQmlDMObjectData::QQmlDMObjectData(QQmlDelegateModelItemMetaType *metaType, //----------------------------------------------------------------- static const QQmlAdaptorModel::Accessors qt_vdm_null_accessors; -static const VDMListDelegateDataType qt_vdm_list_accessors; QQmlAdaptorModel::Accessors::~Accessors() { @@ -958,7 +956,7 @@ void QQmlAdaptorModel::setModel(const QVariant &variant, QObject *parent, QQmlEn } else if (list.type() != QQmlListAccessor::Invalid && list.type() != QQmlListAccessor::Instance) { // Null QObject setObject(nullptr, parent); - accessors = &qt_vdm_list_accessors; + accessors = new VDMListDelegateDataType; } else { setObject(nullptr, parent); accessors = &qt_vdm_null_accessors; @@ -1010,6 +1008,11 @@ int QQmlAdaptorModel::indexAt(int row, int column) const return column * rowCount() + row; } +void QQmlAdaptorModel::useImportVersion(int minorVersion) +{ + modelItemRevision = minorVersion; +} + void QQmlAdaptorModel::objectDestroyed(QObject *) { setModel(QVariant(), nullptr, nullptr); diff --git a/src/qml/util/qqmladaptormodel_p.h b/src/qml/util/qqmladaptormodel_p.h index b5e0881078..8c18466ab5 100644 --- a/src/qml/util/qqmladaptormodel_p.h +++ b/src/qml/util/qqmladaptormodel_p.h @@ -104,12 +104,17 @@ public: return QVariant(); } virtual bool canFetchMore(const QQmlAdaptorModel &) const { return false; } virtual void fetchMore(QQmlAdaptorModel &) const {} + + QScopedPointer<QMetaObject, QScopedPointerPodDeleter> metaObject; + QQmlRefPointer<QQmlPropertyCache> propertyCache; }; const Accessors *accessors; QPersistentModelIndex rootIndex; QQmlListAccessor list; + int modelItemRevision = 0; + QQmlAdaptorModel(); ~QQmlAdaptorModel(); @@ -125,6 +130,8 @@ public: int columnAt(int index) const; int indexAt(int row, int column) const; + void useImportVersion(int minorVersion); + inline bool adaptsAim() const { return qobject_cast<QAbstractItemModel *>(object()); } inline QAbstractItemModel *aim() { return static_cast<QAbstractItemModel *>(object()); } inline const QAbstractItemModel *aim() const { return static_cast<const QAbstractItemModel *>(object()); } diff --git a/src/qmldebug/qqmlinspectorclient_p.h b/src/qmldebug/qqmlinspectorclient_p.h index 3e502f4f45..d4ab136c9a 100644 --- a/src/qmldebug/qqmlinspectorclient_p.h +++ b/src/qmldebug/qqmlinspectorclient_p.h @@ -42,6 +42,17 @@ #include <private/qqmldebugclient_p.h> +// +// W A R N I N G +// ------------- +// +// This file is not part of the Qt API. It exists purely as an +// implementation detail. This header file may change from version to +// version without notice, or even be removed. +// +// We mean it. +// + QT_BEGIN_NAMESPACE class QQmlInspectorClientPrivate; diff --git a/src/quick/items/qquicktableview.cpp b/src/quick/items/qquicktableview.cpp index 28871e8068..675208d75c 100644 --- a/src/quick/items/qquicktableview.cpp +++ b/src/quick/items/qquicktableview.cpp @@ -1760,6 +1760,17 @@ void QQuickTableViewPrivate::fixup(QQuickFlickablePrivate::AxisData &data, qreal QQuickFlickablePrivate::fixup(data, minExtent, maxExtent); } +int QQuickTableViewPrivate::resolveImportVersion() +{ + const auto data = QQmlData::get(q_func()); + if (!data || !data->propertyCache) + return 0; + + const auto cppMetaObject = data->propertyCache->firstCppMetaObject(); + const auto qmlTypeView = QQmlMetaType::qmlType(cppMetaObject); + return qmlTypeView.minorVersion(); +} + void QQuickTableViewPrivate::createWrapperModel() { Q_Q(QQuickTableView); @@ -1769,6 +1780,7 @@ void QQuickTableViewPrivate::createWrapperModel() // common interface to any kind of model (js arrays, QAIM, number etc), and // help us create delegate instances. tableModel = new QQmlTableInstanceModel(qmlContext(q)); + tableModel->useImportVersion(resolveImportVersion()); model = tableModel; } diff --git a/src/quick/items/qquicktableview_p_p.h b/src/quick/items/qquicktableview_p_p.h index 9bea8040dc..f2fef0d774 100644 --- a/src/quick/items/qquicktableview_p_p.h +++ b/src/quick/items/qquicktableview_p_p.h @@ -359,6 +359,7 @@ public: void scheduleRebuildTable(QQuickTableViewPrivate::RebuildOptions options); void invalidateColumnRowPositions(); + int resolveImportVersion(); void createWrapperModel(); void initItemCallback(int modelIndex, QObject *item); diff --git a/tests/auto/qml/qqmlcomponent/data/createObjectWithScript.qml b/tests/auto/qml/qqmlcomponent/data/createObjectWithScript.qml index c5ebed612c..989b295cb5 100644 --- a/tests/auto/qml/qqmlcomponent/data/createObjectWithScript.qml +++ b/tests/auto/qml/qqmlcomponent/data/createObjectWithScript.qml @@ -18,7 +18,7 @@ Item{ id: b Item{ property bool testBool: false - property int testInt: { return null; } + property int testInt: null property QtObject testObject: null } } diff --git a/tests/auto/qml/qqmlecmascript/tst_qqmlecmascript.cpp b/tests/auto/qml/qqmlecmascript/tst_qqmlecmascript.cpp index e6d5ab7cae..63bca255c2 100644 --- a/tests/auto/qml/qqmlecmascript/tst_qqmlecmascript.cpp +++ b/tests/auto/qml/qqmlecmascript/tst_qqmlecmascript.cpp @@ -2762,28 +2762,32 @@ void tst_qqmlecmascript::callQtInvokables() QCOMPARE(o->actuals().at(0), QVariant(QString())); o->reset(); - QVERIFY(!EVALUATE_VALUE("object.method_QPointF(0)", QV4::Primitive::undefinedValue())); + QVERIFY(EVALUATE_VALUE("object.method_QPointF(0)", QV4::Primitive::undefinedValue())); QCOMPARE(o->error(), false); - QCOMPARE(o->invoked(), -1); - QCOMPARE(o->actuals().count(), 0); + QCOMPARE(o->invoked(), 12); + QCOMPARE(o->actuals().count(), 1); + QCOMPARE(o->actuals().at(0), QVariant(QPointF())); o->reset(); - QVERIFY(!EVALUATE_VALUE("object.method_QPointF(null)", QV4::Primitive::undefinedValue())); + QVERIFY(EVALUATE_VALUE("object.method_QPointF(null)", QV4::Primitive::undefinedValue())); QCOMPARE(o->error(), false); - QCOMPARE(o->invoked(), -1); - QCOMPARE(o->actuals().count(), 0); + QCOMPARE(o->invoked(), 12); + QCOMPARE(o->actuals().count(), 1); + QCOMPARE(o->actuals().at(0), QVariant(QPointF())); o->reset(); - QVERIFY(!EVALUATE_VALUE("object.method_QPointF(undefined)", QV4::Primitive::undefinedValue())); + QVERIFY(EVALUATE_VALUE("object.method_QPointF(undefined)", QV4::Primitive::undefinedValue())); QCOMPARE(o->error(), false); - QCOMPARE(o->invoked(), -1); - QCOMPARE(o->actuals().count(), 0); + QCOMPARE(o->invoked(), 12); + QCOMPARE(o->actuals().count(), 1); + QCOMPARE(o->actuals().at(0), QVariant(QPointF())); o->reset(); - QVERIFY(!EVALUATE_VALUE("object.method_QPointF(object)", QV4::Primitive::undefinedValue())); + QVERIFY(EVALUATE_VALUE("object.method_QPointF(object)", QV4::Primitive::undefinedValue())); QCOMPARE(o->error(), false); - QCOMPARE(o->invoked(), -1); - QCOMPARE(o->actuals().count(), 0); + QCOMPARE(o->invoked(), 12); + QCOMPARE(o->actuals().count(), 1); + QCOMPARE(o->actuals().at(0), QVariant(QPointF())); o->reset(); QVERIFY(EVALUATE_VALUE("object.method_QPointF(object.method_get_QPointF())", QV4::Primitive::undefinedValue())); @@ -2800,16 +2804,18 @@ void tst_qqmlecmascript::callQtInvokables() QCOMPARE(o->actuals().at(0), QVariant(QPointF(9, 12))); o->reset(); - QVERIFY(!EVALUATE_VALUE("object.method_QObject(0)", QV4::Primitive::undefinedValue())); + QVERIFY(EVALUATE_VALUE("object.method_QObject(0)", QV4::Primitive::undefinedValue())); QCOMPARE(o->error(), false); - QCOMPARE(o->invoked(), -1); - QCOMPARE(o->actuals().count(), 0); + QCOMPARE(o->invoked(), 13); + QCOMPARE(o->actuals().count(), 1); + QCOMPARE(o->actuals().at(0), qVariantFromValue((QObject *)nullptr)); o->reset(); - QVERIFY(!EVALUATE_VALUE("object.method_QObject(\"Hello world\")", QV4::Primitive::undefinedValue())); + QVERIFY(EVALUATE_VALUE("object.method_QObject(\"Hello world\")", QV4::Primitive::undefinedValue())); QCOMPARE(o->error(), false); - QCOMPARE(o->invoked(), -1); - QCOMPARE(o->actuals().count(), 0); + QCOMPARE(o->invoked(), 13); + QCOMPARE(o->actuals().count(), 1); + QCOMPARE(o->actuals().at(0), qVariantFromValue((QObject *)nullptr)); o->reset(); QVERIFY(EVALUATE_VALUE("object.method_QObject(null)", QV4::Primitive::undefinedValue())); diff --git a/tests/auto/qml/qqmllanguage/data/SignalEmitter.qml b/tests/auto/qml/qqmllanguage/data/SignalEmitter.qml index 31fe5e4a5e..259f45b7d2 100644 --- a/tests/auto/qml/qqmllanguage/data/SignalEmitter.qml +++ b/tests/auto/qml/qqmllanguage/data/SignalEmitter.qml @@ -10,18 +10,8 @@ QtObject { signal testSignal(SignalParam spp); function emitTestSignal() { - var caught = false; - try { - testObject.expectNull = true; - testSignal(op); - } catch(e) { - // good: We want a type error here - caught = true; - if (handleSignal) - testObject.determineSuccess(null); - } - if (!caught && handleSignal) - testObject.determineSuccess("fail"); + testObject.expectNull = true; + testSignal(op); testObject.expectNull = false; testSignal(p); diff --git a/tests/auto/qml/qqmllanguage/data/objectDeletionNotify.1.qml b/tests/auto/qml/qqmllanguage/data/objectDeletionNotify.1.qml index ac5622f9fb..acd5463a3c 100644 --- a/tests/auto/qml/qqmllanguage/data/objectDeletionNotify.1.qml +++ b/tests/auto/qml/qqmllanguage/data/objectDeletionNotify.1.qml @@ -10,7 +10,7 @@ Item { } } - property bool expectNull: { return null; } + property bool expectNull: null function setExpectNull(b) { success = false; diff --git a/tests/auto/qml/qqmllanguage/data/objectDeletionNotify.2.qml b/tests/auto/qml/qqmllanguage/data/objectDeletionNotify.2.qml index 3c18739c32..ed0e0d10f0 100644 --- a/tests/auto/qml/qqmllanguage/data/objectDeletionNotify.2.qml +++ b/tests/auto/qml/qqmllanguage/data/objectDeletionNotify.2.qml @@ -10,7 +10,7 @@ Item { } } - property bool expectNull: { return null; } + property bool expectNull: null function setExpectNull(b) { success = false; diff --git a/tests/auto/qml/qqmllanguage/data/objectDeletionNotify.3.qml b/tests/auto/qml/qqmllanguage/data/objectDeletionNotify.3.qml index e2e560199f..f5e94ba715 100644 --- a/tests/auto/qml/qqmllanguage/data/objectDeletionNotify.3.qml +++ b/tests/auto/qml/qqmllanguage/data/objectDeletionNotify.3.qml @@ -10,7 +10,7 @@ Item { } } - property bool expectNull: { return null; } + property bool expectNull: null function setExpectNull(b) { success = false; diff --git a/tests/auto/qml/qqmlmetatype/data/revisionedGroupedPropertiesInvalid.qml b/tests/auto/qml/qqmlmetatype/data/revisionedGroupedPropertiesInvalid.qml new file mode 100644 index 0000000000..df6d801cde --- /dev/null +++ b/tests/auto/qml/qqmlmetatype/data/revisionedGroupedPropertiesInvalid.qml @@ -0,0 +1,6 @@ +import QtQuick 2.0 +import GroupedTest 1.0 + +MyItem { + grouped.prop: 5 +} diff --git a/tests/auto/qml/qqmlmetatype/data/revisionedGroupedPropertiesValid.qml b/tests/auto/qml/qqmlmetatype/data/revisionedGroupedPropertiesValid.qml new file mode 100644 index 0000000000..b7ea017acf --- /dev/null +++ b/tests/auto/qml/qqmlmetatype/data/revisionedGroupedPropertiesValid.qml @@ -0,0 +1,6 @@ +import QtQuick 2.0 +import GroupedTest 1.1 + +MyItem { + grouped.prop: 5 +} diff --git a/tests/auto/qml/qqmlmetatype/tst_qqmlmetatype.cpp b/tests/auto/qml/qqmlmetatype/tst_qqmlmetatype.cpp index bce4c7d08c..ac75eeab26 100644 --- a/tests/auto/qml/qqmlmetatype/tst_qqmlmetatype.cpp +++ b/tests/auto/qml/qqmlmetatype/tst_qqmlmetatype.cpp @@ -65,6 +65,7 @@ private slots: void normalizeUrls(); void unregisterAttachedProperties(); + void revisionedGroupedProperties(); }; class TestType : public QObject @@ -571,6 +572,62 @@ void tst_qqmlmetatype::unregisterAttachedProperties() } } +class Grouped : public QObject +{ + Q_OBJECT + Q_PROPERTY(int prop READ prop WRITE setProp NOTIFY propChanged REVISION 1) +public: + int prop() const { return m_prop; } + void setProp(int prop) + { + if (prop != m_prop) { + m_prop = prop; + emit propChanged(prop); + } + } + +signals: + Q_REVISION(1) void propChanged(int prop); + +private: + int m_prop = 0; +}; + +class MyItem : public QObject +{ + Q_OBJECT + Q_PROPERTY(Grouped *grouped READ grouped CONSTANT) +public: + MyItem() : m_grouped(new Grouped) {} + Grouped *grouped() const { return m_grouped.data(); } + +private: + QScopedPointer<Grouped> m_grouped; +}; + +void tst_qqmlmetatype::revisionedGroupedProperties() +{ + qmlClearTypeRegistrations(); + qmlRegisterType<MyItem>("GroupedTest", 1, 0, "MyItem"); + qmlRegisterType<MyItem, 1>("GroupedTest", 1, 1, "MyItem"); + qmlRegisterUncreatableType<Grouped>("GroupedTest", 1, 0, "Grouped", "Grouped"); + qmlRegisterUncreatableType<Grouped, 1>("GroupedTest", 1, 1, "Grouped", "Grouped"); + + { + QQmlEngine engine; + QQmlComponent valid(&engine, testFileUrl("revisionedGroupedPropertiesValid.qml")); + QVERIFY(valid.isReady()); + QScopedPointer<QObject> obj(valid.create()); + QVERIFY(!obj.isNull()); + } + + { + QQmlEngine engine; + QQmlComponent invalid(&engine, testFileUrl("revisionedGroupedPropertiesInvalid.qml")); + QVERIFY(invalid.isError()); + } +} + QTEST_MAIN(tst_qqmlmetatype) #include "tst_qqmlmetatype.moc" diff --git a/tests/auto/qml/qqmlpropertycache/tst_qqmlpropertycache.cpp b/tests/auto/qml/qqmlpropertycache/tst_qqmlpropertycache.cpp index 07237c9157..02b5302a45 100644 --- a/tests/auto/qml/qqmlpropertycache/tst_qqmlpropertycache.cpp +++ b/tests/auto/qml/qqmlpropertycache/tst_qqmlpropertycache.cpp @@ -45,6 +45,7 @@ public: private slots: void properties(); void propertiesDerived(); + void revisionedProperties(); void methods(); void methodsDerived(); void signalHandlers(); @@ -84,11 +85,13 @@ class DerivedObject : public BaseObject Q_OBJECT Q_PROPERTY(int propertyC READ propertyC NOTIFY propertyCChanged) Q_PROPERTY(QString propertyD READ propertyD NOTIFY propertyDChanged) + Q_PROPERTY(int propertyE READ propertyE NOTIFY propertyEChanged REVISION 1) public: DerivedObject(QObject *parent = nullptr) : BaseObject(parent) {} int propertyC() const { return 0; } QString propertyD() const { return QString(); } + int propertyE() const { return 0; } public Q_SLOTS: void slotB() {} @@ -96,6 +99,7 @@ public Q_SLOTS: Q_SIGNALS: void propertyCChanged(); void propertyDChanged(); + Q_REVISION(1) void propertyEChanged(); void signalB(); }; @@ -149,6 +153,23 @@ void tst_qqmlpropertycache::propertiesDerived() QCOMPARE(data->coreIndex(), metaObject->indexOfProperty("propertyD")); } +void tst_qqmlpropertycache::revisionedProperties() +{ + // Check that if you create a QQmlPropertyCache from a QMetaObject together + // with an explicit revision, the cache will then, and only then, report a + // property with a matching revision as available. + DerivedObject object; + const QMetaObject *metaObject = object.metaObject(); + + QQmlRefPointer<QQmlPropertyCache> cacheWithoutVersion(new QQmlPropertyCache(metaObject)); + QQmlRefPointer<QQmlPropertyCache> cacheWithVersion(new QQmlPropertyCache(metaObject, 1)); + QQmlPropertyData *data; + + QVERIFY((data = cacheProperty(cacheWithoutVersion, "propertyE"))); + QCOMPARE(cacheWithoutVersion->isAllowedInRevision(data), false); + QCOMPARE(cacheWithVersion->isAllowedInRevision(data), true); +} + void tst_qqmlpropertycache::methods() { QQmlEngine engine; diff --git a/tests/auto/quick/pointerhandlers/flickableinterop/BLACKLIST b/tests/auto/quick/pointerhandlers/flickableinterop/BLACKLIST new file mode 100644 index 0000000000..62aa19a9ae --- /dev/null +++ b/tests/auto/quick/pointerhandlers/flickableinterop/BLACKLIST @@ -0,0 +1,4 @@ +[touchAndDragHandlerOnFlickable] +windows gcc +[touchDragFlickableBehindSlider] +windows gcc diff --git a/tests/auto/quick/qquicktableview/data/checkmodelpropertyrevision.qml b/tests/auto/quick/qquicktableview/data/checkmodelpropertyrevision.qml new file mode 100644 index 0000000000..0550f20bac --- /dev/null +++ b/tests/auto/quick/qquicktableview/data/checkmodelpropertyrevision.qml @@ -0,0 +1,87 @@ +/**************************************************************************** +** +** Copyright (C) 2018 The Qt Company Ltd. +** Contact: https://www.qt.io/licensing/ +** +** This file is part of the QtQuick module of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:LGPL$ +** Commercial License Usage +** Licensees holding valid commercial Qt licenses may use this file in +** accordance with the commercial license agreement provided with the +** Software or, alternatively, in accordance with the terms contained in +** a written agreement between you and The Qt Company. For licensing terms +** and conditions see https://www.qt.io/terms-conditions. For further +** information use the contact form at https://www.qt.io/contact-us. +** +** GNU Lesser General Public License Usage +** Alternatively, this file may be used under the terms of the GNU Lesser +** General Public License version 3 as published by the Free Software +** Foundation and appearing in the file LICENSE.LGPL3 included in the +** packaging of this file. Please review the following information to +** ensure the GNU Lesser General Public License version 3 requirements +** will be met: https://www.gnu.org/licenses/lgpl-3.0.html. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU +** General Public License version 2.0 or (at your option) the GNU General +** Public license version 3 or any later version approved by the KDE Free +** Qt Foundation. The licenses are as published by the Free Software +** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3 +** included in the packaging of this file. Please review the following +** information to ensure the GNU General Public License requirements will +** be met: https://www.gnu.org/licenses/gpl-2.0.html and +** https://www.gnu.org/licenses/gpl-3.0.html. +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +import QtQuick 2.12 +import QtQuick.Window 2.12 + +Item { + id: root + width: 640 + height: 480 + + property alias tableView: tableView + + property int row: 42 + property int column: 42 + + property int resolvedDelegateRow: 0 + property int resolvedDelegateColumn: 0 + + TableView { + id: tableView + // Dummy tableView, to let the auto test follow the + // same pattern for loading qml files as other tests. + } + + Item { + width: 100 + height: parent.height; + Repeater { + model: 1 + delegate: Component { + Rectangle { + color: "blue" + height: 100 + width: 100 + Component.onCompleted: { + // row and column should be resolved to be the ones + // found in the root item, and not in the delegate + // items context. The context properties are revisioned, + // and require that the QQmlDelegateModel has an import + // version set (which is not the case when using a + // Repeater, only when using a TableView). + resolvedDelegateRow = row + resolvedDelegateColumn = column + } + } + } + } + } +} + diff --git a/tests/auto/quick/qquicktableview/tst_qquicktableview.cpp b/tests/auto/quick/qquicktableview/tst_qquicktableview.cpp index e263427b59..60d48bb59f 100644 --- a/tests/auto/quick/qquicktableview/tst_qquicktableview.cpp +++ b/tests/auto/quick/qquicktableview/tst_qquicktableview.cpp @@ -161,6 +161,7 @@ private slots: void checkTableviewInsideAsyncLoader(); void hideRowsAndColumns_data(); void hideRowsAndColumns(); + void checkThatRevisionedPropertiesCannotBeUsedInOldImports(); }; tst_QQuickTableView::tst_QQuickTableView() @@ -2140,6 +2141,17 @@ void tst_QQuickTableView::hideRowsAndColumns() QVERIFY(!columnsToHideList.contains(column)); } +void tst_QQuickTableView::checkThatRevisionedPropertiesCannotBeUsedInOldImports() +{ + // Check that if you use a QQmlAdaptorModel together with a Repeater, the + // revisioned context properties 'row' and 'column' are not accessible. + LOAD_TABLEVIEW("checkmodelpropertyrevision.qml"); + const int resolvedRow = view->rootObject()->property("resolvedDelegateRow").toInt(); + const int resolvedColumn = view->rootObject()->property("resolvedDelegateColumn").toInt(); + QCOMPARE(resolvedRow, 42); + QCOMPARE(resolvedColumn, 42); +} + QTEST_MAIN(tst_QQuickTableView) #include "tst_qquicktableview.moc" |