aboutsummaryrefslogtreecommitdiffstats
path: root/src/qmlmodels/qqmldmabstractitemmodeldata_p.h
diff options
context:
space:
mode:
Diffstat (limited to 'src/qmlmodels/qqmldmabstractitemmodeldata_p.h')
-rw-r--r--src/qmlmodels/qqmldmabstractitemmodeldata_p.h334
1 files changed, 334 insertions, 0 deletions
diff --git a/src/qmlmodels/qqmldmabstractitemmodeldata_p.h b/src/qmlmodels/qqmldmabstractitemmodeldata_p.h
new file mode 100644
index 0000000000..e3769b6d98
--- /dev/null
+++ b/src/qmlmodels/qqmldmabstractitemmodeldata_p.h
@@ -0,0 +1,334 @@
+// Copyright (C) 2023 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
+
+#ifndef QQMLDMABSTRACTITEMMODELDATA_P_H
+#define QQMLDMABSTRACTITEMMODELDATA_P_H
+
+//
+// W A R N I N G
+// -------------
+//
+// This file is not part of the Qt API. It exists purely as an
+// implementation detail. This header file may change from version to
+// version without notice, or even be removed.
+//
+// We mean it.
+//
+
+#include <private/qqmladaptormodelenginedata_p.h>
+#include <private/qqmldelegatemodel_p_p.h>
+#include <private/qobject_p.h>
+
+QT_BEGIN_NAMESPACE
+
+class VDMAbstractItemModelDataType;
+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 FINAL)
+
+public:
+ QQmlDMAbstractItemModelData(
+ const QQmlRefPointer<QQmlDelegateModelItemMetaType> &metaType,
+ VDMAbstractItemModelDataType *dataType,
+ int index, int row, int column);
+
+ int metaCall(QMetaObject::Call call, int id, void **arguments);
+ bool hasModelChildren() const;
+
+ QV4::ReturnedValue get() override;
+ 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 *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);
+
+ VDMAbstractItemModelDataType *m_type;
+ QVector<QVariant> m_cachedData;
+};
+
+class VDMAbstractItemModelDataType final
+ : public QQmlRefCounted<VDMAbstractItemModelDataType>
+ , public QQmlAdaptorModel::Accessors
+ , public QAbstractDynamicMetaObject
+{
+public:
+ VDMAbstractItemModelDataType(QQmlAdaptorModel *model)
+ : model(model)
+ , propertyOffset(0)
+ , signalOffset(0)
+ {
+ }
+
+ bool notify(
+ const QQmlAdaptorModel &,
+ const QList<QQmlDelegateModelItem *> &items,
+ int index,
+ int count,
+ const QVector<int> &roles) const override
+ {
+ bool changed = roles.isEmpty() && !watchedRoles.isEmpty();
+ if (!changed && !watchedRoles.isEmpty() && watchedRoleIds.isEmpty()) {
+ QList<int> roleIds;
+ for (const QByteArray &r : watchedRoles) {
+ QHash<QByteArray, int>::const_iterator it = roleNames.find(r);
+ if (it != roleNames.end())
+ roleIds << it.value();
+ }
+ const_cast<VDMAbstractItemModelDataType *>(this)->watchedRoleIds = roleIds;
+ }
+
+ QVector<int> signalIndexes;
+ for (int i = 0; i < roles.size(); ++i) {
+ const int role = roles.at(i);
+ if (!changed && watchedRoleIds.contains(role))
+ changed = true;
+
+ int propertyId = propertyRoles.indexOf(role);
+ if (propertyId != -1)
+ signalIndexes.append(propertyId + signalOffset);
+ }
+ if (roles.isEmpty()) {
+ const int propertyRolesCount = propertyRoles.size();
+ signalIndexes.reserve(propertyRolesCount);
+ for (int propertyId = 0; propertyId < propertyRolesCount; ++propertyId)
+ signalIndexes.append(propertyId + signalOffset);
+ }
+
+ 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())
+ continue;
+
+ const int idx = item->modelIndex();
+ 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;
+ }
+
+ void replaceWatchedRoles(
+ QQmlAdaptorModel &,
+ const QList<QByteArray> &oldRoles,
+ const QList<QByteArray> &newRoles) const override
+ {
+ VDMAbstractItemModelDataType *dataType = const_cast<VDMAbstractItemModelDataType *>(this);
+
+ dataType->watchedRoleIds.clear();
+ for (const QByteArray &oldRole : oldRoles)
+ dataType->watchedRoles.removeOne(oldRole);
+ dataType->watchedRoles += newRoles;
+ }
+
+ static QV4::ReturnedValue get_hasModelChildren(const QV4::FunctionObject *b, const QV4::Value *thisObject, const QV4::Value *, int)
+ {
+ QV4::Scope scope(b);
+ QV4::Scoped<QQmlDelegateModelItemObject> o(scope, thisObject->as<QQmlDelegateModelItemObject>());
+ if (!o)
+ RETURN_RESULT(scope.engine->throwTypeError(QStringLiteral("Not a valid DelegateModel object")));
+
+ const QQmlAdaptorModel *const model
+ = static_cast<QQmlDMAbstractItemModelData *>(o->d()->item)->type()->model;
+ if (o->d()->item->index >= 0) {
+ if (const QAbstractItemModel *const aim = model->aim())
+ RETURN_RESULT(QV4::Encode(aim->hasChildren(aim->index(o->d()->item->index, 0, model->rootIndex))));
+ }
+ RETURN_RESULT(QV4::Encode(false));
+ }
+
+
+ void initializeConstructor(QQmlAdaptorModelEngineData *const data)
+ {
+ QV4::ExecutionEngine *v4 = data->v4;
+ QV4::Scope scope(v4);
+ 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;
+ for (iterator it = roleNames.constBegin(), end = roleNames.constEnd(); it != end; ++it) {
+ const qsizetype propertyId = propertyRoles.indexOf(it.value());
+ const QByteArray &propertyName = it.key();
+
+ QV4::ScopedString name(scope, v4->newString(QString::fromUtf8(propertyName)));
+ QV4::ExecutionContext *global = v4->rootContext();
+ QV4::ScopedFunctionObject g(scope, v4->memoryManager->allocate<QV4::IndexedBuiltinFunction>(global, propertyId, QQmlDMAbstractItemModelData::get_property));
+ QV4::ScopedFunctionObject s(scope, v4->memoryManager->allocate<QV4::IndexedBuiltinFunction>(global, propertyId, QQmlDMAbstractItemModelData::set_property));
+ p->setGetter(g);
+ p->setSetter(s);
+ proto->insertMember(name, p, QV4::Attr_Accessor|QV4::Attr_NotEnumerable|QV4::Attr_NotConfigurable);
+ }
+ prototype.set(v4, proto);
+ }
+
+ // QAbstractDynamicMetaObject
+
+ void objectDestroyed(QObject *) override
+ {
+ release();
+ }
+
+ int metaCall(QObject *object, QMetaObject::Call call, int id, void **arguments) override
+ {
+ return static_cast<QQmlDMAbstractItemModelData *>(object)->metaCall(call, id, arguments);
+ }
+
+ int rowCount(const QQmlAdaptorModel &model) const override
+ {
+ if (const QAbstractItemModel *aim = model.aim())
+ return aim->rowCount(model.rootIndex);
+ return 0;
+ }
+
+ int columnCount(const QQmlAdaptorModel &model) const override
+ {
+ if (const QAbstractItemModel *aim = model.aim())
+ return aim->columnCount(model.rootIndex);
+ return 0;
+ }
+
+ void cleanup(QQmlAdaptorModel &) const override
+ {
+ release();
+ }
+
+ QVariant value(const QQmlAdaptorModel &model, int index, const QString &role) const override
+ {
+ if (!metaObject) {
+ VDMAbstractItemModelDataType *dataType = const_cast<VDMAbstractItemModelDataType *>(this);
+ dataType->initializeMetaType(model);
+ }
+
+ if (const QAbstractItemModel *aim = model.aim()) {
+ 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();
+ }
+
+ QVariant parentModelIndex(const QQmlAdaptorModel &model) const override
+ {
+ if (const QAbstractItemModel *aim = model.aim())
+ return QVariant::fromValue(aim->parent(model.rootIndex));
+ return QVariant();
+ }
+
+ QVariant modelIndex(const QQmlAdaptorModel &model, int index) const override
+ {
+ if (const QAbstractItemModel *aim = model.aim())
+ return QVariant::fromValue(aim->index(model.rowAt(index), model.columnAt(index),
+ model.rootIndex));
+ return QVariant();
+ }
+
+ bool canFetchMore(const QQmlAdaptorModel &model) const override
+ {
+ if (const QAbstractItemModel *aim = model.aim())
+ return aim->canFetchMore(model.rootIndex);
+ return false;
+ }
+
+ void fetchMore(QQmlAdaptorModel &model) const override
+ {
+ if (QAbstractItemModel *aim = model.aim())
+ aim->fetchMore(model.rootIndex);
+ }
+
+ QQmlDelegateModelItem *createItem(
+ QQmlAdaptorModel &model,
+ const QQmlRefPointer<QQmlDelegateModelItemMetaType> &metaType,
+ int index, int row, int column) override
+ {
+ if (!metaObject)
+ initializeMetaType(model);
+ return new QQmlDMAbstractItemModelData(metaType, this, index, row, column);
+ }
+
+ void initializeMetaType(const QQmlAdaptorModel &model)
+ {
+ QMetaObjectBuilder builder;
+ QQmlAdaptorModelEngineData::setModelDataType<QQmlDMAbstractItemModelData>(&builder, this);
+
+ const QByteArray propertyType = QByteArrayLiteral("QVariant");
+ const QAbstractItemModel *aim = model.aim();
+ const QHash<int, QByteArray> names = aim ? aim->roleNames() : QHash<int, QByteArray>();
+ for (QHash<int, QByteArray>::const_iterator it = names.begin(), cend = names.end(); it != cend; ++it) {
+ const int propertyId = propertyRoles.size();
+ propertyRoles.append(it.key());
+ roleNames.insert(it.value(), it.key());
+ QQmlAdaptorModelEngineData::addProperty(&builder, propertyId, it.value(), propertyType);
+ }
+
+ metaObject.reset(builder.toMetaObject());
+ *static_cast<QMetaObject *>(this) = *metaObject;
+ propertyCache = QQmlPropertyCache::createStandalone(
+ metaObject.data(), model.modelItemRevision);
+ }
+
+ QV4::PersistentValue prototype;
+ QList<int> propertyRoles;
+ QList<int> watchedRoleIds;
+ QList<QByteArray> watchedRoles;
+ QHash<QByteArray, int> roleNames;
+ QQmlAdaptorModel *model;
+ int propertyOffset;
+ int signalOffset;
+};
+
+QT_END_NAMESPACE
+
+#endif // QQMLDMABSTRACTITEMMODELDATA_P_H