Models: Straighten out model and modelData properties

If there is more than one role, just return the whole model item as
modelData. This makes sure we can always require modelData. That's a
basic precondition for writing delegates that work with any model.

The test shows that model and modelData behave quite erratically in the
different cases, but much of this cannot be changed anymore. At least
they are now both available in all cases.

Furthermore, provide modelData as anonymous property of model. This way,
if you have a model that can be singular, and a role that will be an
empty string if the model is singular, you can just write:

SomeDelegate {
    required property var model
    someData: model[role]
}

Task-number: QTBUG-111176
Task-number: QTBUG-110980
Task-number: QTBUG-104752
Change-Id: Ie200be467df2098d817b85b03d2409267722b596
Reviewed-by: Shawn Rutledge <shawn.rutledge@qt.io>
This commit is contained in:
Ulf Hermann 2023-02-17 13:36:00 +01:00
parent afa15792eb
commit e9f650cad8
10 changed files with 384 additions and 53 deletions

View File

@ -177,7 +177,7 @@ void Object::defineAccessorProperty(StringOrSymbol *name, VTable::Call getter, V
QV4::Scope scope(v4);
ScopedProperty p(scope);
QString n = name->toQString();
if (n.at(0) == QLatin1Char('@'))
if (!n.isEmpty() && n.at(0) == QLatin1Char('@'))
n = QChar::fromLatin1('[') + QStringView{n}.mid(1) + QChar::fromLatin1(']');
if (getter) {
ScopedString getName(scope, v4->newString(QString::fromLatin1("get ") + n));

View File

@ -12,7 +12,11 @@ QQmlAdaptorModelEngineData::QQmlAdaptorModelEngineData(QV4::ExecutionEngine *v4)
QV4::Scope scope(v4);
QV4::ScopedObject proto(scope, v4->newObject());
proto->defineAccessorProperty(QStringLiteral("index"), get_index, nullptr);
proto->defineAccessorProperty(QStringLiteral("modelData"),
proto->defineAccessorProperty(
QStringLiteral("modelData"),
QQmlDMListAccessorData::get_modelData, QQmlDMListAccessorData::set_modelData);
proto->defineAccessorProperty(
QString(),
QQmlDMListAccessorData::get_modelData, QQmlDMListAccessorData::set_modelData);
listItemProto.set(v4, proto);
}

View File

@ -12,7 +12,7 @@ QQmlDMAbstractItemModelData::QQmlDMAbstractItemModelData(
, m_type(dataType)
{
if (index == -1)
m_cachedData.resize(m_type->hasModelData ? 1 : m_type->propertyRoles.size());
m_cachedData.resize(m_type->propertyRoles.size());
QObjectPrivate::get(this)->metaObject = m_type;
@ -24,29 +24,28 @@ int QQmlDMAbstractItemModelData::metaCall(QMetaObject::Call call, int id, void *
if (call == QMetaObject::ReadProperty && id >= m_type->propertyOffset) {
const int propertyIndex = id - m_type->propertyOffset;
if (index == -1) {
if (!m_cachedData.isEmpty()) {
*static_cast<QVariant *>(arguments[0]) = m_cachedData.at(
m_type->hasModelData ? 0 : propertyIndex);
}
if (!m_cachedData.isEmpty())
*static_cast<QVariant *>(arguments[0]) = m_cachedData.at(propertyIndex);
} else if (*m_type->model) {
*static_cast<QVariant *>(arguments[0]) = value(m_type->propertyRoles.at(propertyIndex));
}
return -1;
} else if (call == QMetaObject::WriteProperty && id >= m_type->propertyOffset) {
const int propertyIndex = id - m_type->propertyOffset;
if (index == -1) {
const QMetaObject *meta = metaObject();
if (index == -1) {
if (m_cachedData.size() > 1) {
m_cachedData[propertyIndex] = *static_cast<QVariant *>(arguments[0]);
QMetaObject::activate(this, meta, propertyIndex, nullptr);
} else if (m_cachedData.size() == 1) {
m_cachedData[0] = *static_cast<QVariant *>(arguments[0]);
QMetaObject::activate(this, meta, 0, nullptr);
QMetaObject::activate(this, meta, 1, nullptr);
}
} else if (*m_type->model) {
setValue(m_type->propertyRoles.at(propertyIndex), *static_cast<QVariant *>(arguments[0]));
QMetaObject::activate(this, meta, propertyIndex, nullptr);
}
emit modelDataChanged();
return -1;
} else {
return qt_metacall(call, id, arguments);
@ -55,6 +54,15 @@ int QQmlDMAbstractItemModelData::metaCall(QMetaObject::Call call, int id, void *
void QQmlDMAbstractItemModelData::setValue(const QString &role, const QVariant &value)
{
// Used only for initialization of the cached data. Does not have to emit change signals.
if (m_type->propertyRoles.size() == 1
&& (role.isEmpty() || role == QLatin1String("modelData"))) {
// If the model has only a single role, the modelData is that role.
m_cachedData[0] = value;
return;
}
QHash<QByteArray, int>::iterator it = m_type->roleNames.find(role.toUtf8());
if (it != m_type->roleNames.end()) {
for (int i = 0; i < m_type->propertyRoles.size(); ++i) {
@ -76,6 +84,7 @@ bool QQmlDMAbstractItemModelData::resolveIndex(const QQmlAdaptorModel &adaptorMo
const int propertyCount = m_type->propertyRoles.size();
for (int i = 0; i < propertyCount; ++i)
QMetaObject::activate(this, meta, i, nullptr);
emit modelDataChanged();
return true;
} else {
return false;
@ -93,10 +102,8 @@ QV4::ReturnedValue QQmlDMAbstractItemModelData::get_property(const QV4::Function
QQmlDMAbstractItemModelData *modelData = static_cast<QQmlDMAbstractItemModelData *>(o->d()->item);
if (o->d()->item->index == -1) {
if (!modelData->m_cachedData.isEmpty()) {
return scope.engine->fromVariant(
modelData->m_cachedData.at(modelData->m_type->hasModelData ? 0 : propertyId));
}
if (!modelData->m_cachedData.isEmpty())
return scope.engine->fromVariant(modelData->m_cachedData.at(propertyId));
} else if (*modelData->m_type->model) {
return scope.engine->fromVariant(
modelData->value(modelData->m_type->propertyRoles.at(propertyId)));
@ -125,13 +132,82 @@ QV4::ReturnedValue QQmlDMAbstractItemModelData::set_property(const QV4::Function
} else if (modelData->m_cachedData.size() == 1) {
modelData->m_cachedData[0] = QV4::ExecutionEngine::toVariant(argv[0], QMetaType {});
QMetaObject::activate(o->d()->item, o->d()->item->metaObject(), 0, nullptr);
QMetaObject::activate(o->d()->item, o->d()->item->metaObject(), 1, nullptr);
}
emit modelData->modelDataChanged();
}
}
return QV4::Encode::undefined();
}
QV4::ReturnedValue QQmlDMAbstractItemModelData::get_modelData(
const QV4::FunctionObject *b, const QV4::Value *thisObject,
const QV4::Value *argv, int argc)
{
Q_UNUSED(argv)
Q_UNUSED(argc)
QV4::Scope scope(b);
QV4::Scoped<QQmlDelegateModelItemObject> o(
scope, thisObject->as<QQmlDelegateModelItemObject>());
if (!o)
return scope.engine->throwTypeError(QStringLiteral("Not a valid DelegateModel object"));
return scope.engine->fromVariant(
static_cast<QQmlDMAbstractItemModelData *>(o->d()->item)->modelData());
}
QV4::ReturnedValue QQmlDMAbstractItemModelData::set_modelData(
const QV4::FunctionObject *b, const QV4::Value *thisObject,
const QV4::Value *argv, int argc)
{
QV4::Scope scope(b);
QV4::Scoped<QQmlDelegateModelItemObject> o(scope, thisObject->as<QQmlDelegateModelItemObject>());
if (!o)
return scope.engine->throwTypeError(QStringLiteral("Not a valid DelegateModel object"));
if (!argc)
return scope.engine->throwTypeError();
static_cast<QQmlDMAbstractItemModelData *>(o->d()->item)->setModelData(
QV4::ExecutionEngine::toVariant(argv[0], QMetaType()));
return QV4::Encode::undefined();
}
QVariant QQmlDMAbstractItemModelData::modelData() const
{
if (m_type->propertyRoles.size() == 1) {
// If the model has only a single role, the modelData is that role.
return index == -1
? m_cachedData.isEmpty() ? QVariant() : m_cachedData[0]
: value(m_type->propertyRoles[0]);
}
// If there is no context object, we are using required properties.
// In that case, return the object itself as modelData.
return contextData->contextObject() ? QVariant() : QVariant::fromValue(this);
}
void QQmlDMAbstractItemModelData::setModelData(const QVariant &modelData)
{
if (m_type->propertyRoles.size() != 1) {
qWarning() << "Cannot overwrite model object";
return;
}
// If the model has only a single role, the modelData is that role.
if (index == -1) {
if (m_cachedData.isEmpty())
m_cachedData.append(modelData);
else
m_cachedData[0] = modelData;
} else {
setValue(m_type->propertyRoles[0], modelData);
}
QMetaObject::activate(this, metaObject(), 0, nullptr);
emit modelDataChanged();
}
bool QQmlDMAbstractItemModelData::hasModelChildren() const
{
if (index >= 0) {

View File

@ -17,6 +17,7 @@
#include <private/qqmladaptormodelenginedata_p.h>
#include <private/qqmldelegatemodel_p_p.h>
#include <private/qobject_p.h>
QT_BEGIN_NAMESPACE
@ -25,6 +26,8 @@ class QQmlDMAbstractItemModelData : public QQmlDelegateModelItem
{
Q_OBJECT
Q_PROPERTY(bool hasModelChildren READ hasModelChildren CONSTANT)
Q_PROPERTY(QVariant modelData READ modelData WRITE setModelData NOTIFY modelDataChanged)
QT_ANONYMOUS_PROPERTY(QVariant READ modelData NOTIFY modelDataChanged)
public:
QQmlDMAbstractItemModelData(
@ -39,11 +42,28 @@ public:
void setValue(const QString &role, const QVariant &value) override;
bool resolveIndex(const QQmlAdaptorModel &model, int idx) override;
static QV4::ReturnedValue get_property(const QV4::FunctionObject *, const QV4::Value *thisObject, const QV4::Value *argv, int argc);
static QV4::ReturnedValue set_property(const QV4::FunctionObject *, const QV4::Value *thisObject, const QV4::Value *argv, int argc);
static QV4::ReturnedValue get_property(
const QV4::FunctionObject *b, const QV4::Value *thisObject,
const QV4::Value *argv, int argc);
static QV4::ReturnedValue set_property(
const QV4::FunctionObject *b, const QV4::Value *thisObject,
const QV4::Value *argv, int argc);
static QV4::ReturnedValue get_modelData(
const QV4::FunctionObject *b, const QV4::Value *thisObject,
const QV4::Value *argv, int argc);
static QV4::ReturnedValue set_modelData(
const QV4::FunctionObject *b, const QV4::Value *thisObject,
const QV4::Value *argv, int argc);
QVariant modelData() const;
void setModelData(const QVariant &modelData);
const VDMAbstractItemModelDataType *type() const { return m_type; }
Q_SIGNALS:
void modelDataChanged();
private:
QVariant value(int role) const;
void setValue(int role, const QVariant &value);
@ -62,7 +82,6 @@ public:
: model(model)
, propertyOffset(0)
, signalOffset(0)
, hasModelData(false)
{
}
@ -101,9 +120,11 @@ public:
signalIndexes.append(propertyId + signalOffset);
}
QVarLengthArray<QQmlGuard<QQmlDelegateModelItem>> guardedItems;
for (const auto item : items)
guardedItems.append(item);
QVarLengthArray<QQmlGuard<QQmlDMAbstractItemModelData>> guardedItems;
for (const auto item : items) {
Q_ASSERT(qobject_cast<QQmlDMAbstractItemModelData *>(item) == item);
guardedItems.append(static_cast<QQmlDMAbstractItemModelData *>(item));
}
for (const auto &item : std::as_const(guardedItems)) {
if (item.isNull())
@ -113,6 +134,7 @@ public:
if (idx >= index && idx < index + count) {
for (int i = 0; i < signalIndexes.size(); ++i)
QMetaObject::activate(item, signalIndexes.at(i), nullptr);
emit item->modelDataChanged();
}
}
return changed;
@ -155,6 +177,9 @@ public:
QV4::ScopedObject proto(scope, v4->newObject());
proto->defineAccessorProperty(QStringLiteral("index"), QQmlAdaptorModelEngineData::get_index, nullptr);
proto->defineAccessorProperty(QStringLiteral("hasModelChildren"), get_hasModelChildren, nullptr);
proto->defineAccessorProperty(QStringLiteral("modelData"),
QQmlDMAbstractItemModelData::get_modelData,
QQmlDMAbstractItemModelData::set_modelData);
QV4::ScopedProperty p(scope);
typedef QHash<QByteArray, int>::const_iterator iterator;
@ -212,15 +237,25 @@ public:
}
if (const QAbstractItemModel *aim = model.aim()) {
QHash<QByteArray, int>::const_iterator it = roleNames.find(role.toUtf8());
if (it != roleNames.end()) {
return aim->index(model.rowAt(index), model.columnAt(index),
model.rootIndex).data(*it);
} else if (role == QLatin1String("hasModelChildren")) {
return QVariant(aim->hasChildren(aim->index(model.rowAt(index),
model.columnAt(index),
model.rootIndex)));
const QModelIndex modelIndex
= aim->index(model.rowAt(index), model.columnAt(index), model.rootIndex);
const auto it = roleNames.find(role.toUtf8()), end = roleNames.end();
if (it != roleNames.end())
return modelIndex.data(*it);
if (role.isEmpty() || role == QLatin1String("modelData")) {
if (roleNames.size() == 1)
return modelIndex.data(roleNames.begin().value());
QVariantMap modelData;
for (auto jt = roleNames.begin(); jt != end; ++jt)
modelData.insert(QString::fromUtf8(jt.key()), modelIndex.data(jt.value()));
return modelData;
}
if (role == QLatin1String("hasModelChildren"))
return QVariant(aim->hasChildren(modelIndex));
}
return QVariant();
}
@ -278,16 +313,6 @@ public:
QQmlAdaptorModelEngineData::addProperty(&builder, propertyId, it.value(), propertyType);
}
if (propertyRoles.size() == 1) {
hasModelData = true;
const int role = names.begin().key();
const QByteArray propertyName = QByteArrayLiteral("modelData");
propertyRoles.append(role);
roleNames.insert(propertyName, role);
QQmlAdaptorModelEngineData::addProperty(&builder, 1, propertyName, propertyType);
}
metaObject.reset(builder.toMetaObject());
*static_cast<QMetaObject *>(this) = *metaObject;
propertyCache = QQmlPropertyCache::createStandalone(
@ -302,7 +327,6 @@ public:
QQmlAdaptorModel *model;
int propertyOffset;
int signalOffset;
bool hasModelData;
};
QT_END_NAMESPACE

View File

@ -17,6 +17,7 @@
#include <private/qqmladaptormodelenginedata_p.h>
#include <private/qqmldelegatemodel_p_p.h>
#include <private/qobject_p.h>
QT_BEGIN_NAMESPACE
@ -24,6 +25,7 @@ class QQmlDMListAccessorData : public QQmlDelegateModelItem
{
Q_OBJECT
Q_PROPERTY(QVariant modelData READ modelData WRITE setModelData NOTIFY modelDataChanged)
QT_ANONYMOUS_PROPERTY(QVariant READ modelData WRITE setModelData NOTIFY modelDataChanged)
public:
QQmlDMListAccessorData(const QQmlRefPointer<QQmlDelegateModelItemMetaType> &metaType,
QQmlAdaptorModel::Accessors *accessor,
@ -84,7 +86,7 @@ public:
void setValue(const QString &role, const QVariant &value) override
{
if (role == QLatin1String("modelData"))
if (role == QLatin1String("modelData") || role.isEmpty())
cachedData = value;
}
@ -138,7 +140,7 @@ public:
QVariant value(const QQmlAdaptorModel &model, int index, const QString &role) const override
{
const QVariant entry = model.list.at(index);
if (role == QLatin1String("modelData"))
if (role == QLatin1String("modelData") || role.isEmpty())
return entry;
const QMetaType type = entry.metaType();

View File

@ -17,6 +17,7 @@
#include <private/qqmladaptormodelenginedata_p.h>
#include <private/qqmldelegatemodel_p_p.h>
#include <private/qobject_p.h>
QT_BEGIN_NAMESPACE
@ -25,6 +26,7 @@ class QQmlDMObjectData : public QQmlDelegateModelItem, public QQmlAdaptorModelPr
{
Q_OBJECT
Q_PROPERTY(QObject *modelData READ modelData NOTIFY modelDataChanged)
QT_ANONYMOUS_PROPERTY(QObject * READ modelData NOTIFY modelDataChanged)
Q_INTERFACES(QQmlAdaptorModelProxyInterface)
public:
QQmlDMObjectData(

View File

@ -188,12 +188,71 @@ To visualize data, bind the view's \c model property to a model and the
possible to delay delegate destruction in some views via a \c delayRemove
attached property.)
Models that do not have named roles (such as the ListModel shown
below) will have the data provided via the \e modelData role. The \e
modelData role is also provided for models that have only one role. In this
case the \e modelData role contains the same data as the named role.
Remember that you can use integers or arrays as model:
\note \e model, \e index, and \e modelData roles are not accessible
\qml
Repeater {
model: 5
Text {
required property int modelData
text: modelData
}
}
\endqml
\qml
Repeater {
model: ["one", "two", "three"]
Text {
required property string modelData
text: modelData
}
}
\endqml
Such models provide a singular, anonymous piece of data to each instance
of the delegate. Accessing this piece of data is the primary reason to
use \e modelData, but other models also provide \e modelData.
The object provided via the \e model role has a property with an empty name.
This anonymous property holds the \e modelData. Furthermore, the object
provided via the \e model role has another property called \e modelData.
This property is deprecated and also holds the \e modelData.
In addition to the \e model role, a \e modelData role is provided. The
\e modelData role holds the same data as the \e modelData property and the
anonymous property of the object provided via the \e model role.
The differences between the \e model role and the various means to access
\e modelData are as follows:
\list
\li Models that do not have named roles (such as integers or an array of
strings) have their data provided via the \e modelData role. The
\e modelData role does not necessarily contain an object in this case.
In the case of an integer model it would contain an integer (the index
of the current model item). In the case of an array of strings it would
contain a string. The \e model role still contains an object, but
without any properties for named roles. \e model still contains its
usual \e modelData and anonymous properties, though.
\li If the model has only one named role, the \e modelData role contains
the same data as the named role. It is not necessarily an object and it
does not contain the named role as a named property the way it usually
would. The \e model role still contains an object with the named role as
property, and the \e modelData and anonymous properties in this case.
\li For models with multiple roles, the \e modelData role is only provided as
a required property, not as a context property. This is due to backwards
compatibility with older versions of Qt.
\endlist
The anonymous property on \e model allows you to cleanly write delegates
that receive both their model data and the role name they should react
to as properties from the outside. You can provide a model without or
with only one named role, and an empty string as role. Then, a binding that
simply accesses \c{model[role]} will do what you expect. You don't have to
add special code for this case.
\note The \e model, \e index, and \e modelData roles are not accessible
if the delegate contains required properties, unless it has also required
properties with matching names.

View File

@ -0,0 +1,72 @@
import QtQml
DelegateModel {
id: root
// useful object as model, string as modelData
property ListModel singularModel: ListModel {
ListElement {
a: "a"
}
ListElement {
a: "b"
}
}
// same, useful, object as model and modelData
property ListModel listModel: ListModel {
ListElement {
a: "a"
b: "a"
}
ListElement {
a: "b"
b: "b"
}
}
// useful object as modelData
// useless object as model because the list accessor cannot deal with it yet.
property var array: [
{a: "a", b: "a"}, {a: "b", b: "a"}
]
// string as modelData
// object with anonymous string property as model.
property var stringList: ["a", "b"]
// useful but different objects as modelData and model
// This is how the object accessor works. We can live with it.
property QtObject object: QtObject {
property string a: "a"
property string b: "a"
}
// number as modelData
// object with anonymous number property as model
property int n: -1
model: {
switch (n) {
case 0: return singularModel
case 1: return listModel
case 2: return array
case 3: return stringList
case 4: return object
case 5: return n
}
return undefined;
}
delegate: QtObject {
required property var modelData
required property var model
property var modelA: model.a
property var modelDataA: modelData.a
property var modelSelf: model
property var modelDataSelf: modelData
property var modelModelData: model.modelData
property var modelAnonymous: model[""]
}
}

View File

@ -28,6 +28,7 @@ private slots:
void contextAccessedByHandler();
void redrawUponColumnChange();
void nestedDelegates();
void universalModelData();
};
class AbstractItemModel : public QAbstractItemModel
@ -264,6 +265,100 @@ void tst_QQmlDelegateModel::nestedDelegates()
QFAIL("Loader not found");
}
void tst_QQmlDelegateModel::universalModelData()
{
QQmlEngine engine;
QQmlComponent c(&engine, testFileUrl("universalModelData.qml"));
QVERIFY2(c.isReady(), qPrintable(c.errorString()));
QScopedPointer<QObject> o(c.create());
QQmlDelegateModel *delegateModel = qobject_cast<QQmlDelegateModel *>(o.data());
QVERIFY(delegateModel);
for (int i = 0; i < 6; ++i) {
delegateModel->setProperty("n", i);
QObject *delegate = delegateModel->object(0);
QObject *modelItem = delegate->property("modelSelf").value<QObject *>();
QVERIFY(modelItem != nullptr);
switch (i) {
case 0: {
// list model with 1 role
QCOMPARE(delegate->property("modelA"), QStringLiteral("a"));
QVERIFY(!delegate->property("modelDataA").isValid());
QCOMPARE(delegate->property("modelDataSelf"), QStringLiteral("a"));
QCOMPARE(delegate->property("modelModelData"), QStringLiteral("a"));
QCOMPARE(delegate->property("modelAnonymous"), QStringLiteral("a"));
break;
}
case 1: {
// list model with 2 roles
QCOMPARE(delegate->property("modelA"), QStringLiteral("a"));
QCOMPARE(delegate->property("modelDataA"), QStringLiteral("a"));
QCOMPARE(delegate->property("modelDataSelf"), QVariant::fromValue(modelItem));
QCOMPARE(delegate->property("modelModelData"), QVariant::fromValue(modelItem));
QCOMPARE(delegate->property("modelAnonymous"), QVariant::fromValue(modelItem));
break;
}
case 2: {
// JS array of objects
QEXPECT_FAIL("", "Model does not properly expose JS objects", Continue);
QCOMPARE(delegate->property("modelA"), QStringLiteral("a"));
QCOMPARE(delegate->property("modelDataA"), QStringLiteral("a"));
// Do the comparison in QVariantMap. The values get converted back and forth a
// few times, making any JavaScript equality comparison impossible.
// This is only due to test setup, though.
const QVariantMap modelData = delegate->property("modelDataSelf").value<QVariantMap>();
QVERIFY(!modelData.isEmpty());
QCOMPARE(delegate->property("modelModelData").value<QVariantMap>(), modelData);
QCOMPARE(delegate->property("modelAnonymous").value<QVariantMap>(), modelData);
break;
}
case 3: {
// string list
QVERIFY(!delegate->property("modelA").isValid());
QVERIFY(!delegate->property("modelDataA").isValid());
QCOMPARE(delegate->property("modelDataSelf"), QStringLiteral("a"));
QCOMPARE(delegate->property("modelModelData"), QStringLiteral("a"));
QCOMPARE(delegate->property("modelAnonymous"), QStringLiteral("a"));
break;
}
case 4: {
// single object
QCOMPARE(delegate->property("modelA"), QStringLiteral("a"));
QCOMPARE(delegate->property("modelDataA"), QStringLiteral("a"));
QObject *modelData = delegate->property("modelDataSelf").value<QObject *>();
QVERIFY(modelData != nullptr);
QCOMPARE(delegate->property("modelModelData"), QVariant::fromValue(modelData));
QCOMPARE(delegate->property("modelAnonymous"), QVariant::fromValue(modelData));
break;
}
case 5: {
// a number
QVERIFY(!delegate->property("modelA").isValid());
QVERIFY(!delegate->property("modelDataA").isValid());
const QVariant modelData = delegate->property("modelDataSelf");
// This is int on 32bit systems because qsizetype fits into int there.
// On 64bit systems it's double because qsizetype doesn't fit into int.
if (sizeof(qsizetype) > sizeof(int))
QCOMPARE(modelData.metaType(), QMetaType::fromType<double>());
else
QCOMPARE(modelData.metaType(), QMetaType::fromType<int>());
QCOMPARE(modelData.value<int>(), 0);
QCOMPARE(delegate->property("modelModelData"), modelData);
QCOMPARE(delegate->property("modelAnonymous"), modelData);
break;
}
default:
QFAIL("wrong model number");
break;
}
}
}
QTEST_MAIN(tst_QQmlDelegateModel)
#include "tst_qqmldelegatemodel.moc"

View File

@ -847,12 +847,9 @@ void tst_qquickvisualdatamodel::modelProperties()
QUrl source(testFileUrl("modelproperties2.qml"));
//3 items, 3 i each
QTest::ignoreMessage(QtWarningMsg, source.toString().toLatin1() + ":13: ReferenceError: modelData is not defined");
QTest::ignoreMessage(QtWarningMsg, source.toString().toLatin1() + ":13: ReferenceError: modelData is not defined");
QTest::ignoreMessage(QtWarningMsg, source.toString().toLatin1() + ":13: ReferenceError: modelData is not defined");
QTest::ignoreMessage(QtWarningMsg, source.toString().toLatin1() + ":11: ReferenceError: modelData is not defined");
QTest::ignoreMessage(QtWarningMsg, source.toString().toLatin1() + ":11: ReferenceError: modelData is not defined");
QTest::ignoreMessage(QtWarningMsg, source.toString().toLatin1() + ":11: ReferenceError: modelData is not defined");
QTest::ignoreMessage(QtWarningMsg, source.toString().toLatin1() + ":13: TypeError: Cannot read property 'display' of undefined");
QTest::ignoreMessage(QtWarningMsg, source.toString().toLatin1() + ":13: TypeError: Cannot read property 'display' of undefined");
QTest::ignoreMessage(QtWarningMsg, source.toString().toLatin1() + ":13: TypeError: Cannot read property 'display' of undefined");
QTest::ignoreMessage(QtWarningMsg, source.toString().toLatin1() + ":17: TypeError: Cannot read property 'display' of undefined");
QTest::ignoreMessage(QtWarningMsg, source.toString().toLatin1() + ":17: TypeError: Cannot read property 'display' of undefined");
QTest::ignoreMessage(QtWarningMsg, source.toString().toLatin1() + ":17: TypeError: Cannot read property 'display' of undefined");