diff options
author | Liang Qi <liang.qi@qt.io> | 2019-02-22 14:26:13 +0100 |
---|---|---|
committer | Liang Qi <liang.qi@qt.io> | 2019-02-22 14:26:13 +0100 |
commit | 3baa2d550512702dfc227aef0af3542ab189824f (patch) | |
tree | fe2967757ce6abe70f3f819cd8f5691cc384288d | |
parent | 16aff415a44f5f10c5ac95da72559839305c8ae5 (diff) | |
parent | 3ad752e1c16a3d37a71c5a7527c7e67cc333cdd2 (diff) |
Merge remote-tracking branch 'origin/5.12' into 5.13
Conflicts:
tests/auto/quick/qquicktableview/tst_qquicktableview.cpp
Change-Id: If3bf1abc23a59c458be0bb862d92f2edcb16b79f
27 files changed, 378 insertions, 114 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 4e8f57c2cf..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); diff --git a/src/qml/compiler/qv4compileddata.cpp b/src/qml/compiler/qv4compileddata.cpp index c90bbf03e6..cb614f7d40 100644 --- a/src/qml/compiler/qv4compileddata.cpp +++ b/src/qml/compiler/qv4compileddata.cpp @@ -854,7 +854,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 6617dd5e89..40be6f41c8 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 70e188dc1c..d05c945ae4 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 032ee7d6fc..e4fd42932f 100644 --- a/src/qml/qml/qqmlmetatype.cpp +++ b/src/qml/qml/qqmlmetatype.cpp @@ -118,7 +118,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 startRecordingTypeRegFailures(QStringList *storage) @@ -2432,7 +2432,7 @@ QQmlType QQmlMetaType::qmlType(const QUrl &unNormalizedUrl, bool includeNonFileI return QQmlType(); } -QQmlPropertyCache *QQmlMetaTypeData::propertyCache(const QMetaObject *metaObject) +QQmlPropertyCache *QQmlMetaTypeData::propertyCache(const QMetaObject *metaObject, int minorVersion) { if (QQmlPropertyCache *rv = propertyCaches.value(metaObject)) return rv; @@ -2442,17 +2442,17 @@ 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; } -QQmlPropertyCache *QQmlMetaType::propertyCache(const QMetaObject *metaObject) +QQmlPropertyCache *QQmlMetaType::propertyCache(const QMetaObject *metaObject, int minorVersion) { QMutexLocker lock(metaTypeDataLock()); QQmlMetaTypeData *data = metaTypeData(); - return data->propertyCache(metaObject); + return data->propertyCache(metaObject, minorVersion); } QQmlPropertyCache *QQmlMetaTypeData::propertyCache(const QQmlType &type, int minorVersion) @@ -2485,7 +2485,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/qqmlmetatype_p.h b/src/qml/qml/qqmlmetatype_p.h index 2a45ddb4bb..3ad2de7bb3 100644 --- a/src/qml/qml/qqmlmetatype_p.h +++ b/src/qml/qml/qqmlmetatype_p.h @@ -103,7 +103,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/qqmlpropertycache.cpp b/src/qml/qml/qqmlpropertycache.cpp index d619730e28..73bfd7bbaa 100644 --- a/src/qml/qml/qqmlpropertycache.cpp +++ b/src/qml/qml/qqmlpropertycache.cpp @@ -252,12 +252,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() @@ -454,7 +464,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) @@ -468,19 +478,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); @@ -630,6 +638,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 0785910cec..c3c818eb77 100644 --- a/src/qml/qml/qqmlpropertycache_p.h +++ b/src/qml/qml/qqmlpropertycache_p.h @@ -394,7 +394,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 *); @@ -408,7 +408,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()); @@ -499,7 +499,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/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/qqmlecmascript/tst_qqmlecmascript.cpp b/tests/auto/qml/qqmlecmascript/tst_qqmlecmascript.cpp index 6bd19c2fcf..958bf847ce 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/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 7139a1c952..ce72f40dcc 100644 --- a/tests/auto/qml/qqmlmetatype/tst_qqmlmetatype.cpp +++ b/tests/auto/qml/qqmlmetatype/tst_qqmlmetatype.cpp @@ -66,6 +66,7 @@ private slots: void normalizeUrls(); void unregisterAttachedProperties(); + void revisionedGroupedProperties(); }; class TestType : public QObject @@ -572,6 +573,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" |