diff options
author | Liang Qi <liang.qi@qt.io> | 2019-02-25 14:07:43 +0000 |
---|---|---|
committer | The Qt Project <gerrit-noreply@qt-project.org> | 2019-02-25 14:07:43 +0000 |
commit | f52b331e06136bf9d47ec2077626515c9008f97d (patch) | |
tree | d3aad6a685fb0caea6e5cad027d61c4e01b0c7b9 /src | |
parent | 5b3afe255c282479cfbd0e19071cf5fc249e4291 (diff) | |
parent | a1aee495c8a69a076d3981ef005c627d74bb3660 (diff) |
Merge "Merge remote-tracking branch 'origin/5.13' into dev" into refs/staging/dev
Diffstat (limited to 'src')
22 files changed, 256 insertions, 143 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); |