aboutsummaryrefslogtreecommitdiffstats
path: root/src/qmlmodels/qqmldmlistaccessordata_p.h
diff options
context:
space:
mode:
Diffstat (limited to 'src/qmlmodels/qqmldmlistaccessordata_p.h')
-rw-r--r--src/qmlmodels/qqmldmlistaccessordata_p.h293
1 files changed, 293 insertions, 0 deletions
diff --git a/src/qmlmodels/qqmldmlistaccessordata_p.h b/src/qmlmodels/qqmldmlistaccessordata_p.h
new file mode 100644
index 0000000000..e02c3a88f6
--- /dev/null
+++ b/src/qmlmodels/qqmldmlistaccessordata_p.h
@@ -0,0 +1,293 @@
+// 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 QQMLDMLISTACCESSORDATA_P_H
+#define QQMLDMLISTACCESSORDATA_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 VDMListDelegateDataType;
+
+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 FINAL)
+public:
+ QQmlDMListAccessorData(
+ const QQmlRefPointer<QQmlDelegateModelItemMetaType> &metaType,
+ VDMListDelegateDataType *dataType, int index, int row, int column,
+ const QVariant &value);
+ ~QQmlDMListAccessorData();
+
+ QVariant modelData() const
+ {
+ return cachedData;
+ }
+
+ void setModelData(const QVariant &data);
+
+ static QV4::ReturnedValue get_modelData(const QV4::FunctionObject *b, const QV4::Value *thisObject, const QV4::Value *, int)
+ {
+ QV4::ExecutionEngine *v4 = b->engine();
+ const QQmlDelegateModelItemObject *o = thisObject->as<QQmlDelegateModelItemObject>();
+ if (!o)
+ return v4->throwTypeError(QStringLiteral("Not a valid DelegateModel object"));
+
+ return v4->fromVariant(static_cast<QQmlDMListAccessorData *>(o->d()->item)->cachedData);
+ }
+
+ static QV4::ReturnedValue set_modelData(const QV4::FunctionObject *b, const QV4::Value *thisObject, const QV4::Value *argv, int argc)
+ {
+ QV4::ExecutionEngine *v4 = b->engine();
+ const QQmlDelegateModelItemObject *o = thisObject->as<QQmlDelegateModelItemObject>();
+ if (!o)
+ return v4->throwTypeError(QStringLiteral("Not a valid DelegateModel object"));
+ if (!argc)
+ return v4->throwTypeError();
+
+ static_cast<QQmlDMListAccessorData *>(o->d()->item)->setModelData(
+ QV4::ExecutionEngine::toVariant(argv[0], QMetaType {}));
+ return QV4::Encode::undefined();
+ }
+
+ QV4::ReturnedValue get() override
+ {
+ QQmlAdaptorModelEngineData *data = QQmlAdaptorModelEngineData::get(v4);
+ QV4::Scope scope(v4);
+ QV4::ScopedObject o(scope, v4->memoryManager->allocate<QQmlDelegateModelItemObject>(this));
+ QV4::ScopedObject p(scope, data->listItemProto.value());
+ o->setPrototypeOf(p);
+ ++scriptRef;
+ return o.asReturnedValue();
+ }
+
+ void setValue(const QString &role, const QVariant &value) override;
+ bool resolveIndex(const QQmlAdaptorModel &model, int idx) override;
+
+Q_SIGNALS:
+ void modelDataChanged();
+
+private:
+ friend class VDMListDelegateDataType;
+ QVariant cachedData;
+
+ // Gets cleaned when the metaobject has processed it.
+ bool cachedDataClean = false;
+};
+
+
+class VDMListDelegateDataType final
+ : public QQmlRefCounted<VDMListDelegateDataType>
+ , public QQmlAdaptorModel::Accessors
+ , public QAbstractDynamicMetaObject
+{
+public:
+ VDMListDelegateDataType(QQmlAdaptorModel *model)
+ : model(model)
+ {
+ QQmlAdaptorModelEngineData::setModelDataType<QQmlDMListAccessorData>(&builder, this);
+ metaObject.reset(builder.toMetaObject());
+ *static_cast<QMetaObject *>(this) = *metaObject.data();
+ }
+
+ void cleanup(QQmlAdaptorModel &) const override
+ {
+ release();
+ }
+
+ int rowCount(const QQmlAdaptorModel &model) const override
+ {
+ return model.list.count();
+ }
+
+ int columnCount(const QQmlAdaptorModel &model) const override
+ {
+ switch (model.list.type()) {
+ case QQmlListAccessor::Invalid:
+ return 0;
+ case QQmlListAccessor::StringList:
+ case QQmlListAccessor::UrlList:
+ case QQmlListAccessor::Integer:
+ return 1;
+ default:
+ break;
+ }
+
+ // If there are no properties, we can get modelData itself.
+ return std::max(1, propertyCount() - propertyOffset);
+ }
+
+ static const QMetaObject *metaObjectFromType(QMetaType type)
+ {
+ if (const QMetaObject *metaObject = type.metaObject())
+ return metaObject;
+
+ // NB: This acquires the lock on QQmlMetaTypeData. If we had a QQmlEngine here,
+ // we could use QQmlGadgetPtrWrapper::instance() to avoid this.
+ if (const QQmlValueType *valueType = QQmlMetaType::valueType(type))
+ return valueType->staticMetaObject();
+
+ return nullptr;
+ }
+
+ template<typename String>
+ static QString toQString(const String &string)
+ {
+ if constexpr (std::is_same_v<String, QString>)
+ return string;
+ else if constexpr (std::is_same_v<String, QByteArray>)
+ return QString::fromUtf8(string);
+ else if constexpr (std::is_same_v<String, const char *>)
+ return QString::fromUtf8(string);
+ Q_UNREACHABLE_RETURN(QString());
+ }
+
+ template<typename String>
+ static QByteArray toUtf8(const String &string)
+ {
+ if constexpr (std::is_same_v<String, QString>)
+ return string.toUtf8();
+ else if constexpr (std::is_same_v<String, QByteArray>)
+ return string;
+ else if constexpr (std::is_same_v<String, const char *>)
+ return QByteArray::fromRawData(string, qstrlen(string));
+ Q_UNREACHABLE_RETURN(QByteArray());
+ }
+
+ template<typename String>
+ static QVariant value(const QVariant *row, const String &role)
+ {
+ const QMetaType type = row->metaType();
+ if (type == QMetaType::fromType<QVariantMap>())
+ return row->toMap().value(toQString(role));
+
+ if (type == QMetaType::fromType<QVariantHash>())
+ return row->toHash().value(toQString(role));
+
+ const QMetaType::TypeFlags typeFlags = type.flags();
+ if (typeFlags & QMetaType::PointerToQObject)
+ return row->value<QObject *>()->property(toUtf8(role));
+
+ if (const QMetaObject *metaObject = metaObjectFromType(type)) {
+ const int propertyIndex = metaObject->indexOfProperty(toUtf8(role));
+ if (propertyIndex >= 0)
+ return metaObject->property(propertyIndex).readOnGadget(row->constData());
+ }
+
+ return QVariant();
+ }
+
+ template<typename String>
+ void createPropertyIfMissing(const String &string)
+ {
+ for (int i = 0, end = propertyCount(); i < end; ++i) {
+ if (QAnyStringView(property(i).name()) == QAnyStringView(string))
+ return;
+ }
+
+ createProperty(toUtf8(string), nullptr);
+ }
+
+ void createMissingProperties(const QVariant *row)
+ {
+ const QMetaType type = row->metaType();
+ if (type == QMetaType::fromType<QVariantMap>()) {
+ const QVariantMap map = row->toMap();
+ for (auto it = map.keyBegin(), end = map.keyEnd(); it != end; ++it)
+ createPropertyIfMissing(*it);
+ } else if (type == QMetaType::fromType<QVariantHash>()) {
+ const QVariantHash map = row->toHash();
+ for (auto it = map.keyBegin(), end = map.keyEnd(); it != end; ++it)
+ createPropertyIfMissing(*it);
+ } else if (type.flags() & QMetaType::PointerToQObject) {
+ const QMetaObject *metaObject = row->value<QObject *>()->metaObject();
+ for (int i = 0, end = metaObject->propertyCount(); i < end; ++i)
+ createPropertyIfMissing(metaObject->property(i).name());
+ } else if (const QMetaObject *metaObject = metaObjectFromType(type)) {
+ for (int i = 0, end = metaObject->propertyCount(); i < end; ++i)
+ createPropertyIfMissing(metaObject->property(i).name());
+ }
+ }
+
+ template<typename String>
+ static void setValue(QVariant *row, const String &role, const QVariant &value)
+ {
+ const QMetaType type = row->metaType();
+ if (type == QMetaType::fromType<QVariantMap>()) {
+ static_cast<QVariantMap *>(row->data())->insert(toQString(role), value);
+ } else if (type == QMetaType::fromType<QVariantHash>()) {
+ static_cast<QVariantHash *>(row->data())->insert(toQString(role), value);
+ } else if (type.flags() & QMetaType::PointerToQObject) {
+ row->value<QObject *>()->setProperty(toUtf8(role), value);
+ } else if (const QMetaObject *metaObject = metaObjectFromType(type)) {
+ const int propertyIndex = metaObject->indexOfProperty(toUtf8(role));
+ if (propertyIndex >= 0)
+ metaObject->property(propertyIndex).writeOnGadget(row->data(), value);
+ }
+ }
+
+ QVariant value(const QQmlAdaptorModel &model, int index, const QString &role) const override
+ {
+ const QVariant entry = model.list.at(index);
+ if (role == QLatin1String("modelData") || role.isEmpty())
+ return entry;
+
+ return value(&entry, role);
+ }
+
+ QQmlDelegateModelItem *createItem(
+ QQmlAdaptorModel &model,
+ const QQmlRefPointer<QQmlDelegateModelItemMetaType> &metaType,
+ int index, int row, int column) override
+ {
+ const QVariant value = (index >= 0 && index < model.list.count())
+ ? model.list.at(index)
+ : QVariant();
+ return new QQmlDMListAccessorData(metaType, this, index, row, column, value);
+ }
+
+ bool notify(const QQmlAdaptorModel &model, const QList<QQmlDelegateModelItem *> &items, int index, int count, const QVector<int> &) const override
+ {
+ for (auto modelItem : items) {
+ const int modelItemIndex = modelItem->index;
+ if (modelItemIndex < index || modelItemIndex >= index + count)
+ continue;
+
+ auto listModelItem = static_cast<QQmlDMListAccessorData *>(modelItem);
+ QVariant updatedModelData = model.list.at(listModelItem->index);
+ listModelItem->setModelData(updatedModelData);
+ }
+ return true;
+ }
+
+ void emitAllSignals(QQmlDMListAccessorData *accessor) const;
+
+ int metaCall(QObject *object, QMetaObject::Call call, int id, void **arguments) final;
+ int createProperty(const char *name, const char *) final;
+ QMetaObject *toDynamicMetaObject(QObject *accessors) final;
+
+ QMetaObjectBuilder builder;
+ QQmlAdaptorModel *model = nullptr;
+ int propertyOffset = 0;
+ int signalOffset = 0;
+};
+
+QT_END_NAMESPACE
+
+#endif // QQMLDMLISTACCESSORDATA_P_H