aboutsummaryrefslogtreecommitdiffstats
path: root/src/qmlmodels/qqmllistmodel.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'src/qmlmodels/qqmllistmodel.cpp')
-rw-r--r--src/qmlmodels/qqmllistmodel.cpp546
1 files changed, 333 insertions, 213 deletions
diff --git a/src/qmlmodels/qqmllistmodel.cpp b/src/qmlmodels/qqmllistmodel.cpp
index e0a66e7170..de7d97af2f 100644
--- a/src/qmlmodels/qqmllistmodel.cpp
+++ b/src/qmlmodels/qqmllistmodel.cpp
@@ -1,59 +1,27 @@
-/****************************************************************************
-**
-** Copyright (C) 2016 The Qt Company Ltd.
-** Contact: https://www.qt.io/licensing/
-**
-** This file is part of the QtQml 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$
-**
-****************************************************************************/
+// Copyright (C) 2016 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only
#include "qqmllistmodel_p_p.h"
#include "qqmllistmodelworkeragent_p.h"
-#include <private/qqmlopenmetaobject_p.h>
-#include <private/qqmljsast_p.h>
-#include <private/qqmljsengine_p.h>
+
#include <private/qjsvalue_p.h>
#include <private/qqmlcustomparser_p.h>
#include <private/qqmlengine_p.h>
+#include <private/qqmljsast_p.h>
+#include <private/qqmljsengine_p.h>
+#include <private/qqmllistwrapper_p.h>
#include <private/qqmlnotifier_p.h>
+#include <private/qqmlopenmetaobject_p.h>
-#include <private/qv4object_p.h>
-#include <private/qv4dateobject_p.h>
-#include <private/qv4objectiterator_p.h>
#include <private/qv4alloca_p.h>
+#include <private/qv4dateobject_p.h>
#include <private/qv4lookup_p.h>
+#include <private/qv4object_p.h>
+#include <private/qv4objectiterator_p.h>
#include <private/qv4qmlcontext_p.h>
+#include <private/qv4sequenceobject_p.h>
+#include <private/qv4urlobject_p.h>
#include <qqmlcontext.h>
#include <qqmlinfo.h>
@@ -89,7 +57,7 @@ static QString roleTypeName(ListLayout::Role::DataType t)
static const QString roleTypeNames[] = {
QStringLiteral("String"), QStringLiteral("Number"), QStringLiteral("Bool"),
QStringLiteral("List"), QStringLiteral("QObject"), QStringLiteral("VariantMap"),
- QStringLiteral("DateTime"), QStringLiteral("Function")
+ QStringLiteral("DateTime"), QStringLiteral("Url"), QStringLiteral("Function")
};
if (t > ListLayout::Role::Invalid && t < ListLayout::Role::MaxDataType)
@@ -128,8 +96,28 @@ const ListLayout::Role &ListLayout::getRoleOrCreate(QV4::String *key, Role::Data
const ListLayout::Role &ListLayout::createRole(const QString &key, ListLayout::Role::DataType type)
{
- const int dataSizes[] = { sizeof(StringOrTranslation), sizeof(double), sizeof(bool), sizeof(ListModel *), sizeof(QPointer<QObject>), sizeof(QVariantMap), sizeof(QDateTime), sizeof(QJSValue) };
- const int dataAlignments[] = { sizeof(StringOrTranslation), sizeof(double), sizeof(bool), sizeof(ListModel *), sizeof(QObject *), sizeof(QVariantMap), sizeof(QDateTime), sizeof(QJSValue) };
+ const int dataSizes[] = {
+ sizeof(StringOrTranslation),
+ sizeof(double),
+ sizeof(bool),
+ sizeof(ListModel *),
+ sizeof(QV4::PersistentValue),
+ sizeof(QVariantMap),
+ sizeof(QDateTime),
+ sizeof(QUrl),
+ sizeof(QJSValue)
+ };
+ const int dataAlignments[] = {
+ alignof(StringOrTranslation),
+ alignof(double),
+ alignof(bool),
+ alignof(ListModel *),
+ alignof(QV4::PersistentValue),
+ alignof(QVariantMap),
+ alignof(QDateTime),
+ alignof(QUrl),
+ alignof(QJSValue)
+ };
Role *r = new Role;
r->name = key;
@@ -155,7 +143,7 @@ const ListLayout::Role &ListLayout::createRole(const QString &key, ListLayout::R
currentBlockOffset = dataOffset + dataSize;
}
- int roleIndex = roles.count();
+ int roleIndex = roles.size();
r->index = roleIndex;
roles.append(r);
@@ -166,7 +154,7 @@ const ListLayout::Role &ListLayout::createRole(const QString &key, ListLayout::R
ListLayout::ListLayout(const ListLayout *other) : currentBlock(0), currentBlockOffset(0)
{
- const int otherRolesCount = other->roles.count();
+ const int otherRolesCount = other->roles.size();
roles.reserve(otherRolesCount);
for (int i=0 ; i < otherRolesCount; ++i) {
Role *role = new Role(other->roles[i]);
@@ -184,8 +172,8 @@ ListLayout::~ListLayout()
void ListLayout::sync(ListLayout *src, ListLayout *target)
{
- int roleOffset = target->roles.count();
- int newRoleCount = src->roles.count() - roleOffset;
+ int roleOffset = target->roles.size();
+ int newRoleCount = src->roles.size() - roleOffset;
for (int i=0 ; i < newRoleCount ; ++i) {
Role *role = new Role(src->roles[roleOffset + i]);
@@ -219,14 +207,15 @@ const ListLayout::Role *ListLayout::getRoleOrCreate(const QString &key, const QV
{
Role::DataType type;
- switch (data.type()) {
- case QVariant::Double: type = Role::Number; break;
- case QVariant::Int: type = Role::Number; break;
- case QVariant::Bool: type = Role::Bool; break;
- case QVariant::String: type = Role::String; break;
- case QVariant::Map: type = Role::VariantMap; break;
- case QVariant::DateTime: type = Role::DateTime; break;
- case QVariant::UserType: {
+ switch (data.userType()) {
+ case QMetaType::Double: type = Role::Number; break;
+ case QMetaType::Int: type = Role::Number; break;
+ case QMetaType::Bool: type = Role::Bool; break;
+ case QMetaType::QString: type = Role::String; break;
+ case QMetaType::QVariantMap: type = Role::VariantMap; break;
+ case QMetaType::QDateTime: type = Role::DateTime; break;
+ case QMetaType::QUrl: type = Role::Url; break;
+ default: {
if (data.userType() == qMetaTypeId<QJSValue>() &&
data.value<QJSValue>().isCallable()) {
type = Role::Function;
@@ -235,12 +224,14 @@ const ListLayout::Role *ListLayout::getRoleOrCreate(const QString &key, const QV
&& data.value<const QV4::CompiledData::Binding*>()->isTranslationBinding()) {
type = Role::String;
break;
- } else {
+ } else if (data.userType() >= QMetaType::User) {
type = Role::List;
break;
+ } else {
+ type = Role::Invalid;
+ break;
}
}
- default: type = Role::Invalid; break;
}
if (type == Role::Invalid) {
@@ -269,19 +260,6 @@ const ListLayout::Role *ListLayout::getExistingRole(QV4::String *key) const
return r;
}
-StringOrTranslation::StringOrTranslation(const QString &s)
-{
- d.setFlag();
- setString(s);
-}
-
-StringOrTranslation::StringOrTranslation(const QV4::CompiledData::Binding *binding)
-{
- d.setFlag();
- clear();
- d = binding;
-}
-
StringOrTranslation::~StringOrTranslation()
{
clear();
@@ -289,53 +267,52 @@ StringOrTranslation::~StringOrTranslation()
void StringOrTranslation::setString(const QString &s)
{
- d.setFlag();
clear();
- QStringData *stringData = const_cast<QString &>(s).data_ptr();
- d = stringData;
- if (stringData)
- stringData->ref.ref();
+ if (s.isEmpty())
+ return;
+ QString mutableString(s);
+ QString::DataPointer dataPointer = mutableString.data_ptr();
+ arrayData = dataPointer->d_ptr();
+ stringData = dataPointer->data();
+ stringSize = mutableString.size();
+ if (arrayData)
+ arrayData->ref();
}
void StringOrTranslation::setTranslation(const QV4::CompiledData::Binding *binding)
{
- d.setFlag();
clear();
- d = binding;
+ this->binding = binding;
}
QString StringOrTranslation::toString(const QQmlListModel *owner) const
{
- if (d.isNull())
- return QString();
- if (d.isT1()) {
- QStringDataPtr holder = { d.asT1() };
- holder.ptr->ref.ref();
- return QString(holder);
+ if (stringSize) {
+ if (arrayData)
+ arrayData->ref();
+ return QString(QStringPrivate(arrayData, stringData, stringSize));
}
if (!owner)
return QString();
- return owner->m_compilationUnit->bindingValueAsString(d.asT2());
+ return owner->m_compilationUnit->bindingValueAsString(binding);
}
QString StringOrTranslation::asString() const
{
- if (d.isNull())
+ if (!arrayData)
return QString();
- if (!d.isT1())
- return QString();
- QStringDataPtr holder = { d.asT1() };
- holder.ptr->ref.ref();
- return QString(holder);
+ arrayData->ref();
+ return QString(QStringPrivate(arrayData, stringData, stringSize));
}
void StringOrTranslation::clear()
{
- if (QStringData *strData = d.isT1() ? d.asT1() : nullptr) {
- if (!strData->ref.deref())
- QStringData::deallocate(strData);
- }
- d = static_cast<QStringData *>(nullptr);
+ if (arrayData && !arrayData->deref())
+ QTypedArrayData<ushort>::deallocate(arrayData);
+ arrayData = nullptr;
+ stringData = nullptr;
+ stringSize = 0;
+ binding = nullptr;
}
QObject *ListModel::getOrCreateModelObject(QQmlListModel *model, int elementIndex)
@@ -345,9 +322,12 @@ QObject *ListModel::getOrCreateModelObject(QQmlListModel *model, int elementInde
void *memory = operator new(sizeof(QObject) + sizeof(QQmlData));
void *ddataMemory = ((char *)memory) + sizeof(QObject);
e->m_objectCache = new (memory) QObject;
- QQmlData *ddata = new (ddataMemory) QQmlData;
- ddata->ownMemory = false;
- QObjectPrivate::get(e->m_objectCache)->declarativeData = ddata;
+
+ const QAbstractDeclarativeData *old = std::exchange(
+ QObjectPrivate::get(e->m_objectCache)->declarativeData,
+ new (ddataMemory) QQmlData(QQmlData::DoesNotOwnMemory));
+ Q_ASSERT(!old); // QObject should really not manipulate QQmlData
+
(void)new ModelNodeMetaObject(e->m_objectCache, model, elementIndex);
}
return e->m_objectCache;
@@ -444,7 +424,8 @@ bool ListModel::sync(ListModel *src, ListModel *target)
// to ensure things are kept in the correct order, emit inserts and moves first. This shouls ensure all persistent
// model indices are updated correctly
int rowsInserted = 0;
- for (int i = 0 ; i < target->elements.count() ; ++i) {
+ const int targetElementCount = target->elements.count();
+ for (int i = 0 ; i < targetElementCount ; ++i) {
ListElement *element = target->elements.at(i);
ElementSync &s = elementHash.find(element->getUid()).value();
Q_ASSERT(s.srcIndex >= 0);
@@ -454,13 +435,32 @@ bool ListModel::sync(ListModel *src, ListModel *target)
if (s.targetIndex == -1) {
targetModel->beginInsertRows(QModelIndex(), i, i);
targetModel->endInsertRows();
+ ++rowsInserted;
} else {
- targetModel->beginMoveRows(QModelIndex(), i, i, QModelIndex(), s.srcIndex);
+ bool validMove = targetModel->beginMoveRows(QModelIndex(), s.targetIndex, s.targetIndex, QModelIndex(), i);
+ Q_ASSERT(validMove);
targetModel->endMoveRows();
+ // fixup target indices of elements that still need to move
+ for (int j=i+1; j < targetElementCount; ++j) {
+ ListElement *eToFix = target->elements.at(j);
+ ElementSync &sToFix = elementHash.find(eToFix->getUid()).value();
+ if (i < s.targetIndex) {
+ // element was moved down
+ if (sToFix.targetIndex > s.targetIndex || sToFix.targetIndex < i)
+ continue; // unaffected by reordering
+ else
+ sToFix.targetIndex += 1;
+ } else {
+ // element was moved up
+ if (sToFix.targetIndex < s.targetIndex || sToFix.targetIndex > i)
+ continue; // unaffected by reordering
+ else
+ sToFix.targetIndex -= 1;
+ }
+ }
}
}
hasChanges = true;
- ++rowsInserted;
}
if (s.targetIndex != -1 && !s.changedRoles.isEmpty()) {
QModelIndex idx = targetModel->createIndex(i, 0);
@@ -557,6 +557,17 @@ ListModel *ListModel::getListProperty(int elementIndex, const ListLayout::Role &
return e->getListProperty(role);
}
+void ListModel::updateTranslations()
+{
+ for (int index = 0; index != elements.count(); ++index) {
+ ListElement *e = elements[index];
+ if (ModelNodeMetaObject *cache = e->objectCache()) {
+ // TODO: more fine grained tracking?
+ cache->updateValues();
+ }
+ }
+}
+
void ListModel::set(int elementIndex, QV4::Object *object, QVector<int> *roles)
{
ListElement *e = elements[elementIndex];
@@ -601,18 +612,27 @@ void ListModel::set(int elementIndex, QV4::Object *object, QVector<int> *roles)
const ListLayout::Role &r = m_layout->getRoleOrCreate(propertyName, ListLayout::Role::DateTime);
QDateTime dt = dd->toQDateTime();
roleIndex = e->setDateTimeProperty(r, dt);
+ } else if (QV4::UrlObject *url = propertyValue->as<QV4::UrlObject>()) {
+ const ListLayout::Role &r = m_layout->getRoleOrCreate(propertyName, ListLayout::Role::Url);
+ QUrl qurl = QUrl(url->href());
+ roleIndex = e->setUrlProperty(r, qurl);
} else if (QV4::FunctionObject *f = propertyValue->as<QV4::FunctionObject>()) {
const ListLayout::Role &r = m_layout->getRoleOrCreate(propertyName, ListLayout::Role::Function);
QV4::ScopedFunctionObject func(scope, f);
QJSValue jsv;
- QJSValuePrivate::setValue(&jsv, v4, func);
+ QJSValuePrivate::setValue(&jsv, func);
roleIndex = e->setFunctionProperty(r, jsv);
} else if (QV4::Object *o = propertyValue->as<QV4::Object>()) {
if (QV4::QObjectWrapper *wrapper = o->as<QV4::QObjectWrapper>()) {
- QObject *o = wrapper->object();
const ListLayout::Role &role = m_layout->getRoleOrCreate(propertyName, ListLayout::Role::QObject);
if (role.type == ListLayout::Role::QObject)
- roleIndex = e->setQObjectProperty(role, o);
+ roleIndex = e->setQObjectProperty(role, wrapper);
+ } else if (QVariant maybeUrl = QV4::ExecutionEngine::toVariant(
+ o->asReturnedValue(), QMetaType::fromType<QUrl>(), true);
+ maybeUrl.metaType() == QMetaType::fromType<QUrl>()) {
+ const ListLayout::Role &r = m_layout->getRoleOrCreate(propertyName, ListLayout::Role::Url);
+ QUrl qurl = maybeUrl.toUrl();
+ roleIndex = e->setUrlProperty(r, qurl);
} else {
const ListLayout::Role &role = m_layout->getRoleOrCreate(propertyName, ListLayout::Role::VariantMap);
if (role.type == ListLayout::Role::VariantMap) {
@@ -664,18 +684,11 @@ void ListModel::set(int elementIndex, QV4::Object *object, ListModel::SetElement
e->setDoublePropertyFast(r, propertyValue->asDouble());
}
} else if (QV4::ArrayObject *a = propertyValue->as<QV4::ArrayObject>()) {
- const ListLayout::Role &r = m_layout->getRoleOrCreate(propertyName, ListLayout::Role::List);
- if (r.type == ListLayout::Role::List) {
- ListModel *subModel = new ListModel(r.subLayout, nullptr);
-
- int arrayLength = a->getLength();
- for (int j=0 ; j < arrayLength ; ++j) {
- o = a->get(j);
- subModel->append(o);
- }
-
- e->setListPropertyFast(r, subModel);
- }
+ setArrayLike(&o, propertyName, e, a);
+ } else if (QV4::Sequence *s = propertyValue->as<QV4::Sequence>()) {
+ setArrayLike(&o, propertyName, e, s);
+ } else if (QV4::QmlListWrapper *l = propertyValue->as<QV4::QmlListWrapper>()) {
+ setArrayLike(&o, propertyName, e, l);
} else if (propertyValue->isBoolean()) {
const ListLayout::Role &r = m_layout->getRoleOrCreate(propertyName, ListLayout::Role::Bool);
if (r.type == ListLayout::Role::Bool) {
@@ -687,21 +700,35 @@ void ListModel::set(int elementIndex, QV4::Object *object, ListModel::SetElement
QDateTime dt = date->toQDateTime();
e->setDateTimePropertyFast(r, dt);
}
+ } else if (QV4::UrlObject *url = propertyValue->as<QV4::UrlObject>()){
+ const ListLayout::Role &r = m_layout->getRoleOrCreate(propertyName, ListLayout::Role::Url);
+ if (r.type == ListLayout::Role::Url) {
+ QUrl qurl = QUrl(url->href()); // does what the private UrlObject->toQUrl would do
+ e->setUrlPropertyFast(r, qurl);
+ }
} else if (QV4::Object *o = propertyValue->as<QV4::Object>()) {
if (QV4::QObjectWrapper *wrapper = o->as<QV4::QObjectWrapper>()) {
- QObject *o = wrapper->object();
const ListLayout::Role &r = m_layout->getRoleOrCreate(propertyName, ListLayout::Role::QObject);
if (r.type == ListLayout::Role::QObject)
- e->setQObjectPropertyFast(r, o);
+ e->setQObjectPropertyFast(r, wrapper);
} else {
- const ListLayout::Role &role = m_layout->getRoleOrCreate(propertyName, ListLayout::Role::VariantMap);
- if (role.type == ListLayout::Role::VariantMap)
- e->setVariantMapFast(role, o);
+ QVariant maybeUrl = QV4::ExecutionEngine::toVariant(
+ o->asReturnedValue(), QMetaType::fromType<QUrl>(), true);
+ if (maybeUrl.metaType() == QMetaType::fromType<QUrl>()) {
+ const QUrl qurl = maybeUrl.toUrl();
+ const ListLayout::Role &r = m_layout->getRoleOrCreate(propertyName, ListLayout::Role::Url);
+ if (r.type == ListLayout::Role::Url)
+ e->setUrlPropertyFast(r, qurl);
+ } else {
+ const ListLayout::Role &role = m_layout->getRoleOrCreate(propertyName, ListLayout::Role::VariantMap);
+ if (role.type == ListLayout::Role::VariantMap)
+ e->setVariantMapFast(role, o);
+ }
}
} else if (propertyValue->isNullOrUndefined()) {
if (reason == SetElement::WasJustInserted) {
QQmlError err;
- auto memberName = propertyName->toString(m_modelCache->engine())->toQString();
+ auto memberName = propertyName->toString(v4)->toQString();
err.setDescription(QString::fromLatin1("%1 is %2. Adding an object with a %2 member does not create a role for it.").arg(memberName, propertyValue->isNull() ? QLatin1String("null") : QLatin1String("undefined")));
qmlWarning(nullptr, err);
} else {
@@ -808,11 +835,11 @@ StringOrTranslation *ListElement::getStringProperty(const ListLayout::Role &role
return s;
}
-QObject *ListElement::getQObjectProperty(const ListLayout::Role &role)
+QV4::QObjectWrapper *ListElement::getQObjectProperty(const ListLayout::Role &role)
{
char *mem = getPropertyMemory(role);
- QPointer<QObject> *o = reinterpret_cast<QPointer<QObject> *>(mem);
- return o->data();
+ QV4::PersistentValue *g = reinterpret_cast<QV4::PersistentValue *>(mem);
+ return g->as<QV4::QObjectWrapper>();
}
QVariantMap *ListElement::getVariantMapProperty(const ListLayout::Role &role)
@@ -837,6 +864,17 @@ QDateTime *ListElement::getDateTimeProperty(const ListLayout::Role &role)
return dt;
}
+QUrl *ListElement::getUrlProperty(const ListLayout::Role &role)
+{
+ QUrl *url = nullptr;
+
+ char *mem = getPropertyMemory(role);
+ if (isMemoryUsed<QUrl>(mem))
+ url = reinterpret_cast<QUrl *>(mem);
+
+ return url;
+}
+
QJSValue *ListElement::getFunctionProperty(const ListLayout::Role &role)
{
QJSValue *f = nullptr;
@@ -848,24 +886,26 @@ QJSValue *ListElement::getFunctionProperty(const ListLayout::Role &role)
return f;
}
-QPointer<QObject> *ListElement::getGuardProperty(const ListLayout::Role &role)
+QV4::PersistentValue *
+ListElement::getGuardProperty(const ListLayout::Role &role)
{
char *mem = getPropertyMemory(role);
bool existingGuard = false;
- for (size_t i=0 ; i < sizeof(QPointer<QObject>) ; ++i) {
+ for (size_t i = 0; i < sizeof(QV4::PersistentValue);
+ ++i) {
if (mem[i] != 0) {
existingGuard = true;
break;
}
}
- QPointer<QObject> *o = nullptr;
+ QV4::PersistentValue *g = nullptr;
if (existingGuard)
- o = reinterpret_cast<QPointer<QObject> *>(mem);
+ g = reinterpret_cast<QV4::PersistentValue *>(mem);
- return o;
+ return g;
}
ListModel *ListElement::getListProperty(const ListLayout::Role &role)
@@ -893,6 +933,8 @@ QVariant ListElement::getProperty(const ListLayout::Role &role, const QQmlListMo
StringOrTranslation *value = reinterpret_cast<StringOrTranslation *>(mem);
if (value->isSet())
data = value->toString(owner);
+ else
+ data = QString();
}
break;
case ListLayout::Role::Bool:
@@ -919,10 +961,8 @@ QVariant ListElement::getProperty(const ListLayout::Role &role, const QQmlListMo
break;
case ListLayout::Role::QObject:
{
- QPointer<QObject> *guard = reinterpret_cast<QPointer<QObject> *>(mem);
- QObject *object = guard->data();
- if (object)
- data = QVariant::fromValue(object);
+ QV4::PersistentValue *guard = reinterpret_cast<QV4::PersistentValue *>(mem);
+ data = QVariant::fromValue(guard->as<QV4::QObjectWrapper>()->object());
}
break;
case ListLayout::Role::VariantMap:
@@ -941,6 +981,14 @@ QVariant ListElement::getProperty(const ListLayout::Role &role, const QQmlListMo
}
}
break;
+ case ListLayout::Role::Url:
+ {
+ if (isMemoryUsed<QUrl>(mem)) {
+ QUrl *url = reinterpret_cast<QUrl *>(mem);
+ data = *url;
+ }
+ }
+ break;
case ListLayout::Role::Function:
{
if (isMemoryUsed<QJSValue>(mem)) {
@@ -1026,30 +1074,17 @@ int ListElement::setListProperty(const ListLayout::Role &role, ListModel *m)
return roleIndex;
}
-int ListElement::setQObjectProperty(const ListLayout::Role &role, QObject *o)
+int ListElement::setQObjectProperty(const ListLayout::Role &role, QV4::QObjectWrapper *o)
{
int roleIndex = -1;
if (role.type == ListLayout::Role::QObject) {
char *mem = getPropertyMemory(role);
- QPointer<QObject> *g = reinterpret_cast<QPointer<QObject> *>(mem);
- bool existingGuard = false;
- for (size_t i=0 ; i < sizeof(QPointer<QObject>) ; ++i) {
- if (mem[i] != 0) {
- existingGuard = true;
- break;
- }
- }
- bool changed;
- if (existingGuard) {
- changed = g->data() != o;
- g->~QPointer();
- } else {
- changed = true;
- }
- new (mem) QPointer<QObject>(o);
- if (changed)
- roleIndex = role.index;
+ if (isMemoryUsed<QVariantMap>(mem))
+ reinterpret_cast<QV4::PersistentValue *>(mem)->set(o->engine(), *o);
+ else
+ new (mem) QV4::PersistentValue(o->engine(), o);
+ roleIndex = role.index;
}
return roleIndex;
@@ -1113,6 +1148,23 @@ int ListElement::setDateTimeProperty(const ListLayout::Role &role, const QDateTi
return roleIndex;
}
+int ListElement::setUrlProperty(const ListLayout::Role &role, const QUrl &url)
+{
+ int roleIndex = -1;
+
+ if (role.type == ListLayout::Role::Url) {
+ char *mem = getPropertyMemory(role);
+ if (isMemoryUsed<QUrl>(mem)) {
+ QUrl *qurl = reinterpret_cast<QUrl *>(mem);
+ qurl->~QUrl();
+ }
+ new (mem) QUrl(url);
+ roleIndex = role.index;
+ }
+
+ return roleIndex;
+}
+
int ListElement::setFunctionProperty(const ListLayout::Role &role, const QJSValue &f)
{
int roleIndex = -1;
@@ -1148,7 +1200,7 @@ int ListElement::setTranslationProperty(const ListLayout::Role &role, const QV4:
void ListElement::setStringPropertyFast(const ListLayout::Role &role, const QString &s)
{
char *mem = getPropertyMemory(role);
- new (mem) StringOrTranslation(s);
+ reinterpret_cast<StringOrTranslation *>(mem)->setString(s);
}
void ListElement::setDoublePropertyFast(const ListLayout::Role &role, double d)
@@ -1165,10 +1217,10 @@ void ListElement::setBoolPropertyFast(const ListLayout::Role &role, bool b)
*value = b;
}
-void ListElement::setQObjectPropertyFast(const ListLayout::Role &role, QObject *o)
+void ListElement::setQObjectPropertyFast(const ListLayout::Role &role, QV4::QObjectWrapper *o)
{
char *mem = getPropertyMemory(role);
- new (mem) QPointer<QObject>(o);
+ new (mem) QV4::PersistentValue(o->engine(), o);
}
void ListElement::setListPropertyFast(const ListLayout::Role &role, ListModel *m)
@@ -1191,6 +1243,12 @@ void ListElement::setDateTimePropertyFast(const ListLayout::Role &role, const QD
new (mem) QDateTime(dt);
}
+void ListElement::setUrlPropertyFast(const ListLayout::Role &role, const QUrl &url)
+{
+ char *mem = getPropertyMemory(role);
+ new (mem) QUrl(url);
+}
+
void ListElement::setFunctionPropertyFast(const ListLayout::Role &role, const QJSValue &f)
{
char *mem = getPropertyMemory(role);
@@ -1218,6 +1276,9 @@ void ListElement::clearProperty(const ListLayout::Role &role)
case ListLayout::Role::DateTime:
setDateTimeProperty(role, QDateTime());
break;
+ case ListLayout::Role::Url:
+ setUrlProperty(role, QUrl());
+ break;
case ListLayout::Role::VariantMap:
setVariantMapProperty(role, (QVariantMap *)nullptr);
break;
@@ -1276,7 +1337,7 @@ QVector<int> ListElement::sync(ListElement *src, ListLayout *srcLayout, ListElem
break;
case ListLayout::Role::QObject:
{
- QObject *object = src->getQObjectProperty(srcRole);
+ QV4::QObjectWrapper *object = src->getQObjectProperty(srcRole);
roleIndex = target->setQObjectProperty(targetRole, object);
}
break;
@@ -1331,9 +1392,8 @@ void ListElement::destroy(ListLayout *layout)
break;
case ListLayout::Role::QObject:
{
- QPointer<QObject> *guard = getGuardProperty(r);
- if (guard)
- guard->~QPointer();
+ if (QV4::PersistentValue *guard = getGuardProperty(r))
+ guard->~PersistentValue();
}
break;
case ListLayout::Role::VariantMap:
@@ -1350,6 +1410,13 @@ void ListElement::destroy(ListLayout *layout)
dt->~QDateTime();
}
break;
+ case ListLayout::Role::Url:
+ {
+ QUrl *url = getUrlProperty(r);
+ if (url)
+ url->~QUrl();
+ break;
+ }
case ListLayout::Role::Function:
{
QJSValue *f = getFunctionProperty(r);
@@ -1402,6 +1469,9 @@ int ListElement::setVariantProperty(const ListLayout::Role &role, const QVariant
case ListLayout::Role::DateTime:
roleIndex = setDateTimeProperty(role, d.toDateTime());
break;
+ case ListLayout::Role::Url:
+ roleIndex = setUrlProperty(role, d.toUrl());
+ break;
case ListLayout::Role::Function:
roleIndex = setFunctionProperty(role, d.value<QJSValue>());
break;
@@ -1447,19 +1517,28 @@ int ListElement::setJsProperty(const ListLayout::Role &role, const QV4::Value &d
QV4::Scoped<QV4::DateObject> dd(scope, d);
QDateTime dt = dd->toQDateTime();
roleIndex = setDateTimeProperty(role, dt);
+ } else if (d.as<QV4::UrlObject>()) {
+ QV4::Scoped<QV4::UrlObject> url(scope, d);
+ QUrl qurl = QUrl(url->href());
+ roleIndex = setUrlProperty(role, qurl);
} else if (d.as<QV4::FunctionObject>()) {
QV4::ScopedFunctionObject f(scope, d);
QJSValue jsv;
- QJSValuePrivate::setValue(&jsv, eng, f);
+ QJSValuePrivate::setValue(&jsv, f);
roleIndex = setFunctionProperty(role, jsv);
} else if (d.isObject()) {
QV4::ScopedObject o(scope, d);
QV4::QObjectWrapper *wrapper = o->as<QV4::QObjectWrapper>();
if (role.type == ListLayout::Role::QObject && wrapper) {
- QObject *o = wrapper->object();
- roleIndex = setQObjectProperty(role, o);
+ roleIndex = setQObjectProperty(role, wrapper);
} else if (role.type == ListLayout::Role::VariantMap) {
roleIndex = setVariantMapProperty(role, o);
+ } else if (role.type == ListLayout::Role::Url) {
+ QVariant maybeUrl = QV4::ExecutionEngine::toVariant(
+ o.asReturnedValue(), QMetaType::fromType<QUrl>(), true);
+ if (maybeUrl.metaType() == QMetaType::fromType<QUrl>()) {
+ roleIndex = setUrlProperty(role, maybeUrl.toUrl());
+ }
}
} else if (d.isNullOrUndefined()) {
clearProperty(role);
@@ -1491,7 +1570,7 @@ ModelNodeMetaObject::~ModelNodeMetaObject()
{
}
-QAbstractDynamicMetaObject *ModelNodeMetaObject::toDynamicMetaObject(QObject *object)
+QMetaObject *ModelNodeMetaObject::toDynamicMetaObject(QObject *object)
{
if (!m_initialized) {
m_initialized = true;
@@ -1529,10 +1608,10 @@ void ModelNodeMetaObject::updateValues()
void ModelNodeMetaObject::updateValues(const QVector<int> &roles)
{
if (!m_initialized) {
- emitDirectNotifies(roles.constData(), roles.count());
+ emitDirectNotifies(roles.constData(), roles.size());
return;
}
- int roleCount = roles.count();
+ int roleCount = roles.size();
for (int i=0 ; i < roleCount ; ++i) {
int roleIndex = roles.at(i);
const ListLayout::Role &role = m_model->m_listModel->getExistingRole(roleIndex);
@@ -1654,7 +1733,8 @@ PropertyKey ModelObjectOwnPropertyKeyIterator::next(const Object *o, Property *p
auto size = recursiveListModel->count();
auto array = ScopedArrayObject{scope, v4->newArrayObject(size)};
for (auto i = 0; i < size; i++) {
- array->arrayPut(i, QJSValuePrivate::convertedToValue(v4, recursiveListModel->get(i)));
+ array->arrayPut(i, QJSValuePrivate::convertToReturnedValue(
+ v4, recursiveListModel->get(i)));
}
pd->value = array;
} else {
@@ -1729,7 +1809,7 @@ void DynamicRoleModelNode::updateValues(const QVariantMap &object, QVector<int>
int roleIndex = m_owner->m_roles.indexOf(key);
if (roleIndex == -1) {
- roleIndex = m_owner->m_roles.count();
+ roleIndex = m_owner->m_roles.size();
m_owner->m_roles.append(key);
}
@@ -1740,7 +1820,7 @@ void DynamicRoleModelNode::updateValues(const QVariantMap &object, QVector<int>
if (value.userType() == qMetaTypeId<QJSValue>())
value = value.value<QJSValue>().toVariant();
- if (value.type() == QVariant::List) {
+ if (value.userType() == QMetaType::QVariantList) {
QQmlListModel *subModel = QQmlListModel::createWithOwner(m_owner);
QVariantList subArray = value.toList();
@@ -1803,7 +1883,7 @@ void DynamicRoleModelNodeMetaObject::propertyWritten(int index)
if (v.userType() == qMetaTypeId<QJSValue>())
v= v.value<QJSValue>().toVariant();
- if (v.type() == QVariant::List) {
+ if (v.userType() == QMetaType::QVariantList) {
QQmlListModel *subModel = QQmlListModel::createWithOwner(parentModel);
QVariantList subArray = v.toList();
@@ -1832,6 +1912,7 @@ void DynamicRoleModelNodeMetaObject::propertyWritten(int index)
/*!
\qmltype ListModel
\instantiates QQmlListModel
+ \inherits AbstractListModel
\inqmlmodule QtQml.Models
\ingroup qtquick-models
\brief Defines a free-form list data source.
@@ -1849,6 +1930,10 @@ void DynamicRoleModelNodeMetaObject::propertyWritten(int index)
Elements can be manipulated via the model using the setProperty() method, which
allows the roles of the specified element to be set and changed.
+ ListModel inherits from \l{QAbstractListModel} and provides its \l{Q_INVOKABLE}
+ methods. You can, for example use \l{QAbstractItemModel::index} to retrieve a
+ \l{QModelIndex} for a row and column.
+
\section1 Example Usage
The following example shows a ListModel containing three elements, with the roles
@@ -1897,7 +1982,7 @@ void DynamicRoleModelNodeMetaObject::propertyWritten(int index)
\section1 Using Threaded List Models with WorkerScript
- ListModel can be used together with WorkerScript access a list model
+ ListModel can be used together with WorkerScript to access a list model
from multiple threads. This is useful if list modifications are
synchronous and take some time: the list operations can be moved to a
different thread to avoid blocking of the main GUI thread.
@@ -1905,11 +1990,11 @@ void DynamicRoleModelNodeMetaObject::propertyWritten(int index)
Here is an example that uses WorkerScript to periodically append the
current time to a list model:
- \snippet ../quick/threading/threadedlistmodel/timedisplay.qml 0
+ \snippet qml/listmodel/WorkerScript.qml 0
The included file, \tt dataloader.mjs, looks like this:
- \snippet ../quick/threading/threadedlistmodel/dataloader.mjs 0
+ \snippet qml/listmodel/dataloader.mjs 0
The timer in the main example sends messages to the worker script by calling
\l WorkerScript::sendMessage(). When this message is received,
@@ -1920,7 +2005,7 @@ void DynamicRoleModelNodeMetaObject::propertyWritten(int index)
You must call sync() or else the changes made to the list from that
thread will not be reflected in the list model in the main thread.
- \sa {qml-data-models}{Data Models}, {Qt Quick Examples - Threading}, {Qt QML}
+ \sa {qml-data-models}{Data Models}, {Qt Qml}
*/
QQmlListModel::QQmlListModel(QObject *parent)
@@ -2029,7 +2114,7 @@ bool QQmlListModel::sync(QQmlListModel *src, QQmlListModel *target)
// Build hash of elements <-> uid for each of the lists
QHash<int, ElementSync> elementHash;
- for (int i = 0 ; i < target->m_modelObjects.count(); ++i) {
+ for (int i = 0 ; i < target->m_modelObjects.size(); ++i) {
DynamicRoleModelNode *e = target->m_modelObjects.at(i);
int uid = e->getUid();
ElementSync sync;
@@ -2037,7 +2122,7 @@ bool QQmlListModel::sync(QQmlListModel *src, QQmlListModel *target)
sync.targetIndex = i;
elementHash.insert(uid, sync);
}
- for (int i = 0 ; i < src->m_modelObjects.count(); ++i) {
+ for (int i = 0 ; i < src->m_modelObjects.size(); ++i) {
DynamicRoleModelNode *e = src->m_modelObjects.at(i);
int uid = e->getUid();
@@ -2056,7 +2141,7 @@ bool QQmlListModel::sync(QQmlListModel *src, QQmlListModel *target)
// Get list of elements that are in the target but no longer in the source. These get deleted first.
int rowsRemoved = 0;
- for (int i = 0 ; i < target->m_modelObjects.count() ; ++i) {
+ for (int i = 0 ; i < target->m_modelObjects.size() ; ++i) {
DynamicRoleModelNode *element = target->m_modelObjects.at(i);
ElementSync &s = elementHash.find(element->getUid()).value();
Q_ASSERT(s.targetIndex >= 0);
@@ -2077,7 +2162,7 @@ bool QQmlListModel::sync(QQmlListModel *src, QQmlListModel *target)
// Clear the target list, and append in correct order from the source
target->m_modelObjects.clear();
- for (int i = 0 ; i < src->m_modelObjects.count() ; ++i) {
+ for (int i = 0 ; i < src->m_modelObjects.size() ; ++i) {
DynamicRoleModelNode *element = src->m_modelObjects.at(i);
ElementSync &s = elementHash.find(element->getUid()).value();
Q_ASSERT(s.srcIndex >= 0);
@@ -2095,7 +2180,7 @@ bool QQmlListModel::sync(QQmlListModel *src, QQmlListModel *target)
// to ensure things are kept in the correct order, emit inserts and moves first. This shouls ensure all persistent
// model indices are updated correctly
int rowsInserted = 0;
- for (int i = 0 ; i < target->m_modelObjects.count() ; ++i) {
+ for (int i = 0 ; i < target->m_modelObjects.size() ; ++i) {
DynamicRoleModelNode *element = target->m_modelObjects.at(i);
ElementSync &s = elementHash.find(element->getUid()).value();
Q_ASSERT(s.srcIndex >= 0);
@@ -2214,7 +2299,7 @@ QHash<int, QByteArray> QQmlListModel::roleNames() const
QHash<int, QByteArray> roleNames;
if (m_dynamicRoles) {
- for (int i = 0 ; i < m_roles.count() ; ++i)
+ for (int i = 0 ; i < m_roles.size() ; ++i)
roleNames.insert(i, m_roles.at(i).toUtf8());
} else {
for (int i = 0 ; i < m_listModel->roleCount() ; ++i) {
@@ -2261,7 +2346,7 @@ void QQmlListModel::setDynamicRoles(bool enableDynamicRoles)
else
m_dynamicRoles = true;
} else {
- if (m_roles.count()) {
+ if (m_roles.size()) {
qmlWarning(this) << tr("unable to enable static roles as this model is not empty");
} else {
m_dynamicRoles = false;
@@ -2278,7 +2363,7 @@ void QQmlListModel::setDynamicRoles(bool enableDynamicRoles)
*/
int QQmlListModel::count() const
{
- return m_dynamicRoles ? m_modelObjects.count() : m_listModel->elementCount();
+ return m_dynamicRoles ? m_modelObjects.size() : m_listModel->elementCount();
}
/*!
@@ -2296,11 +2381,11 @@ void QQmlListModel::clear()
/*!
\qmlmethod ListModel::remove(int index, int count = 1)
- Deletes the content at \a index from the model.
+ Deletes \a count number of items at \a index from the model.
\sa clear()
*/
-void QQmlListModel::remove(QQmlV4Function *args)
+void QQmlListModel::remove(QQmlV4FunctionPtr args)
{
int argLength = args->length();
@@ -2351,6 +2436,27 @@ void QQmlListModel::removeElements(int index, int removeCount)
destroyer();
}
+void QQmlListModel::updateTranslations()
+{
+ // assumption: it is impossible to have retranslatable strings in a
+ // dynamic list model, as they would already have "decayed" to strings
+ // when they were inserted
+ if (m_dynamicRoles)
+ return;
+ Q_ASSERT(m_listModel);
+
+ QList<int> roles;
+ for (int i = 0, end = m_listModel->roleCount(); i != end; ++i) {
+ if (m_listModel->getExistingRole(i).type == ListLayout::Role::String)
+ roles.append(i);
+ }
+
+ if (!roles.isEmpty())
+ emitItemsChanged(0, rowCount(QModelIndex()), roles);
+
+ m_listModel->updateTranslations();
+}
+
/*!
\qmlmethod ListModel::insert(int index, jsobject dict)
@@ -2367,7 +2473,7 @@ void QQmlListModel::removeElements(int index, int removeCount)
\sa set(), append()
*/
-void QQmlListModel::insert(QQmlV4Function *args)
+void QQmlListModel::insert(QQmlV4FunctionPtr args)
{
if (args->length() == 2) {
QV4::Scope scope(args->v4engine());
@@ -2483,7 +2589,7 @@ void QQmlListModel::move(int from, int to, int n)
\sa set(), remove()
*/
-void QQmlListModel::append(QQmlV4Function *args)
+void QQmlListModel::append(QQmlV4FunctionPtr args)
{
if (args->length() == 1) {
QV4::Scope scope(args->v4engine());
@@ -2514,7 +2620,7 @@ void QQmlListModel::append(QQmlV4Function *args)
int index;
if (m_dynamicRoles) {
- index = m_modelObjects.count();
+ index = m_modelObjects.size();
emitItemsAboutToBeInserted(index, 1);
m_modelObjects.append(DynamicRoleModelNode::create(scope.engine->variantMapFromJS(argObject), this));
} else {
@@ -2586,7 +2692,7 @@ QJSValue QQmlListModel::get(int index) const
}
}
- return QJSValue(engine(), result->asReturnedValue());
+ return QJSValuePrivate::fromReturnedValue(result->asReturnedValue());
}
/*!
@@ -2608,7 +2714,7 @@ QJSValue QQmlListModel::get(int index) const
void QQmlListModel::set(int index, const QJSValue &value)
{
QV4::Scope scope(engine());
- QV4::ScopedObject object(scope, QJSValuePrivate::getValue(&value));
+ QV4::ScopedObject object(scope, QJSValuePrivate::asReturnedValue(&value));
if (!object) {
qmlWarning(this) << tr("set: value is not an object");
@@ -2640,7 +2746,7 @@ void QQmlListModel::set(int index, const QJSValue &value)
m_listModel->set(index, object, &roles);
}
- if (roles.count())
+ if (roles.size())
emitItemsChanged(index, 1, roles);
}
}
@@ -2668,7 +2774,7 @@ void QQmlListModel::setProperty(int index, const QString& property, const QVaria
if (m_dynamicRoles) {
int roleIndex = m_roles.indexOf(property);
if (roleIndex == -1) {
- roleIndex = m_roles.count();
+ roleIndex = m_roles.size();
m_roles.append(property);
}
if (m_modelObjects[index]->setValue(property.toUtf8(), value))
@@ -2696,7 +2802,7 @@ void QQmlListModel::sync()
bool QQmlListModelParser::verifyProperty(const QQmlRefPointer<QV4::ExecutableCompilationUnit> &compilationUnit, const QV4::CompiledData::Binding *binding)
{
- if (binding->type >= QV4::CompiledData::Binding::Type_Object) {
+ if (binding->type() >= QV4::CompiledData::Binding::Type_Object) {
const quint32 targetObjectIndex = binding->value.objectIndex;
const QV4::CompiledData::Object *target = compilationUnit->objectAt(targetObjectIndex);
QString objName = compilationUnit->stringAt(target->inheritedTypeNameIndex);
@@ -2724,12 +2830,11 @@ bool QQmlListModelParser::verifyProperty(const QQmlRefPointer<QV4::ExecutableCom
if (!verifyProperty(compilationUnit, binding))
return false;
}
- } else if (binding->type == QV4::CompiledData::Binding::Type_Script) {
+ } else if (binding->type() == QV4::CompiledData::Binding::Type_Script) {
QString scriptStr = compilationUnit->bindingValueAsScriptString(binding);
if (!binding->isFunctionExpression() && !definesEmptyList(scriptStr)) {
- QByteArray script = scriptStr.toUtf8();
bool ok;
- evaluateEnum(script, &ok);
+ evaluateEnum(scriptStr, &ok);
if (!ok) {
error(binding, QQmlListModel::tr("ListElement: cannot use script for property value"));
return false;
@@ -2747,7 +2852,8 @@ bool QQmlListModelParser::applyProperty(
const QString elementName = compilationUnit->stringAt(binding->propertyNameIndex);
bool roleSet = false;
- if (binding->type >= QV4::CompiledData::Binding::Type_Object) {
+ const QV4::CompiledData::Binding::Type bindingType = binding->type();
+ if (bindingType >= QV4::CompiledData::Binding::Type_Object) {
const quint32 targetObjectIndex = binding->value.objectIndex;
const QV4::CompiledData::Object *target = compilationUnit->objectAt(targetObjectIndex);
@@ -2776,17 +2882,18 @@ bool QQmlListModelParser::applyProperty(
} else {
QVariant value;
- if (binding->isTranslationBinding()) {
+ const bool isTranslationBinding = binding->isTranslationBinding();
+ if (isTranslationBinding) {
value = QVariant::fromValue<const QV4::CompiledData::Binding*>(binding);
} else if (binding->evaluatesToString()) {
value = compilationUnit->bindingValueAsString(binding);
- } else if (binding->type == QV4::CompiledData::Binding::Type_Number) {
+ } else if (bindingType == QV4::CompiledData::Binding::Type_Number) {
value = compilationUnit->bindingValueAsNumber(binding);
- } else if (binding->type == QV4::CompiledData::Binding::Type_Boolean) {
+ } else if (bindingType == QV4::CompiledData::Binding::Type_Boolean) {
value = binding->valueAsBoolean();
- } else if (binding->type == QV4::CompiledData::Binding::Type_Null) {
+ } else if (bindingType == QV4::CompiledData::Binding::Type_Null) {
value = QVariant::fromValue(nullptr);
- } else if (binding->type == QV4::CompiledData::Binding::Type_Script) {
+ } else if (bindingType == QV4::CompiledData::Binding::Type_Script) {
QString scriptStr = compilationUnit->bindingValueAsScriptString(binding);
if (definesEmptyList(scriptStr)) {
const ListLayout::Role &role = model->getOrCreateListRole(elementName);
@@ -2802,21 +2909,32 @@ bool QQmlListModelParser::applyProperty(
QV4::ScopedContext context(scope, QV4::QmlContext::create(v4->rootContext(), QQmlContextData::get(qmlContext(model->m_modelCache)), nullptr));
QV4::ScopedFunctionObject function(scope, QV4::FunctionObject::createScriptFunction(context, compilationUnit->runtimeFunctions[id]));
- QV4::ReturnedValue result = function->call(v4->globalObject, nullptr, 0);
-
QJSValue v;
- QJSValuePrivate::setValue(&v, v4, result);
- value.setValue<QJSValue>(v);
+ QV4::ScopedValue result(scope, function->call(v4->globalObject, nullptr, 0));
+ if (v4->hasException)
+ v4->catchException();
+ else
+ QJSValuePrivate::setValue(&v, result->asReturnedValue());
+ value.setValue(v);
} else {
- QByteArray script = scriptStr.toUtf8();
bool ok;
- value = evaluateEnum(script, &ok);
+ value = evaluateEnum(scriptStr, &ok);
}
} else {
Q_UNREACHABLE();
}
+ if (!model)
+ return roleSet;
model->setOrCreateProperty(outterElementIndex, elementName, value);
+ auto listModel = model->m_modelCache;
+ if (isTranslationBinding && listModel) {
+ if (!listModel->translationChangeHandler) {
+ auto ep = QQmlEnginePrivate::get(compilationUnit->engine);
+ model->m_modelCache->translationChangeHandler = std::make_unique<QPropertyNotifier>(
+ ep->translationLanguage.addNotifier([listModel](){ listModel->updateTranslations(); }));
+ }
+ }
roleSet = true;
}
return roleSet;
@@ -2847,7 +2965,7 @@ void QQmlListModelParser::applyBindings(QObject *obj, const QQmlRefPointer<QV4::
bool setRoles = false;
for (const QV4::CompiledData::Binding *binding : bindings) {
- if (binding->type != QV4::CompiledData::Binding::Type_Object)
+ if (binding->type() != QV4::CompiledData::Binding::Type_Object)
continue;
setRoles |= applyProperty(compilationUnit, binding, rv->m_listModel, /*outter element index*/-1);
}
@@ -2859,7 +2977,7 @@ void QQmlListModelParser::applyBindings(QObject *obj, const QQmlRefPointer<QV4::
bool QQmlListModelParser::definesEmptyList(const QString &s)
{
if (s.startsWith(QLatin1Char('[')) && s.endsWith(QLatin1Char(']'))) {
- for (int i=1; i<s.length()-1; i++) {
+ for (int i=1; i<s.size()-1; i++) {
if (!s[i].isSpace())
return false;
}
@@ -2917,4 +3035,6 @@ bool QQmlListModelParser::definesEmptyList(const QString &s)
QT_END_NAMESPACE
+#include "moc_qqmllistmodel_p_p.cpp"
+
#include "moc_qqmllistmodel_p.cpp"