aboutsummaryrefslogtreecommitdiffstats
path: root/src/qmlmodels/qqmldmobjectdata_p.h
diff options
context:
space:
mode:
Diffstat (limited to 'src/qmlmodels/qqmldmobjectdata_p.h')
-rw-r--r--src/qmlmodels/qqmldmobjectdata_p.h247
1 files changed, 247 insertions, 0 deletions
diff --git a/src/qmlmodels/qqmldmobjectdata_p.h b/src/qmlmodels/qqmldmobjectdata_p.h
new file mode 100644
index 0000000000..0368572b36
--- /dev/null
+++ b/src/qmlmodels/qqmldmobjectdata_p.h
@@ -0,0 +1,247 @@
+// 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 QQMLDMOBJECTDATA_P_H
+#define QQMLDMOBJECTDATA_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>
+#include <QtCore/qpointer.h>
+
+QT_BEGIN_NAMESPACE
+
+class VDMObjectDelegateDataType;
+class QQmlDMObjectData : public QQmlDelegateModelItem, public QQmlAdaptorModelProxyInterface
+{
+ Q_OBJECT
+ Q_PROPERTY(QObject *modelData READ modelData NOTIFY modelDataChanged)
+ QT_ANONYMOUS_PROPERTY(QObject * READ modelData NOTIFY modelDataChanged FINAL)
+ Q_INTERFACES(QQmlAdaptorModelProxyInterface)
+public:
+ QQmlDMObjectData(
+ const QQmlRefPointer<QQmlDelegateModelItemMetaType> &metaType,
+ VDMObjectDelegateDataType *dataType,
+ int index, int row, int column,
+ QObject *object);
+
+ void setModelData(QObject *modelData)
+ {
+ if (modelData == object)
+ return;
+
+ object = modelData;
+ emit modelDataChanged();
+ }
+
+ QObject *modelData() const { return object; }
+ QObject *proxiedObject() override { return object; }
+
+ QPointer<QObject> object;
+
+Q_SIGNALS:
+ void modelDataChanged();
+};
+
+class VDMObjectDelegateDataType final
+ : public QQmlRefCounted<VDMObjectDelegateDataType>,
+ public QQmlAdaptorModel::Accessors
+{
+public:
+ int propertyOffset;
+ int signalOffset;
+ bool shared;
+ QMetaObjectBuilder builder;
+
+ VDMObjectDelegateDataType()
+ : propertyOffset(0)
+ , signalOffset(0)
+ , shared(true)
+ {
+ }
+
+ VDMObjectDelegateDataType(const VDMObjectDelegateDataType &type)
+ : propertyOffset(type.propertyOffset)
+ , signalOffset(type.signalOffset)
+ , shared(false)
+ , builder(type.metaObject.data(), QMetaObjectBuilder::Properties
+ | QMetaObjectBuilder::Signals
+ | QMetaObjectBuilder::SuperClass
+ | QMetaObjectBuilder::ClassName)
+ {
+ builder.setFlags(MetaObjectFlag::DynamicMetaObject);
+ }
+
+ int rowCount(const QQmlAdaptorModel &model) const override
+ {
+ return model.list.count();
+ }
+
+ int columnCount(const QQmlAdaptorModel &) const override
+ {
+ return 1;
+ }
+
+ QVariant value(const QQmlAdaptorModel &model, int index, const QString &role) const override
+ {
+ if (QObject *object = model.list.at(index).value<QObject *>())
+ return object->property(role.toUtf8());
+ return QVariant();
+ }
+
+ QQmlDelegateModelItem *createItem(
+ QQmlAdaptorModel &model,
+ const QQmlRefPointer<QQmlDelegateModelItemMetaType> &metaType,
+ int index, int row, int column) override
+ {
+ if (!metaObject)
+ initializeMetaType(model);
+ return index >= 0 && index < model.list.count()
+ ? new QQmlDMObjectData(metaType, this, index, row, column, qvariant_cast<QObject *>(model.list.at(index)))
+ : nullptr;
+ }
+
+ void initializeMetaType(QQmlAdaptorModel &model)
+ {
+ Q_UNUSED(model);
+ QQmlAdaptorModelEngineData::setModelDataType<QQmlDMObjectData>(&builder, this);
+
+ 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
+ {
+ release();
+ }
+
+ 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 objectModelItem = static_cast<QQmlDMObjectData *>(modelItem);
+ QObject *updatedModelData = qvariant_cast<QObject *>(model.list.at(objectModelItem->index));
+ objectModelItem->setModelData(updatedModelData);
+ }
+ return true;
+ }
+};
+
+class QQmlDMObjectDataMetaObject : public QAbstractDynamicMetaObject
+{
+public:
+ QQmlDMObjectDataMetaObject(QQmlDMObjectData *data, VDMObjectDelegateDataType *type)
+ : m_data(data)
+ , m_type(type)
+ {
+ QObjectPrivate *op = QObjectPrivate::get(m_data);
+ *static_cast<QMetaObject *>(this) = *type->metaObject;
+ op->metaObject = this;
+ m_type->addref();
+ }
+
+ ~QQmlDMObjectDataMetaObject()
+ {
+ m_type->release();
+ }
+
+ int metaCall(QObject *o, QMetaObject::Call call, int id, void **arguments) override
+ {
+ Q_ASSERT(o == m_data);
+ Q_UNUSED(o);
+
+ static const int objectPropertyOffset = QObject::staticMetaObject.propertyCount();
+ if (id >= m_type->propertyOffset
+ && (call == QMetaObject::ReadProperty
+ || call == QMetaObject::WriteProperty
+ || call == QMetaObject::ResetProperty)) {
+ if (m_data->object)
+ QMetaObject::metacall(m_data->object, call, id - m_type->propertyOffset + objectPropertyOffset, arguments);
+ return -1;
+ } else if (id >= m_type->signalOffset && call == QMetaObject::InvokeMetaMethod) {
+ QMetaObject::activate(m_data, this, id - m_type->signalOffset, nullptr);
+ return -1;
+ } else {
+ return m_data->qt_metacall(call, id, arguments);
+ }
+ }
+
+ int createProperty(const char *name, const char *) override
+ {
+ if (!m_data->object)
+ return -1;
+ const QMetaObject *metaObject = m_data->object->metaObject();
+ static const int objectPropertyOffset = QObject::staticMetaObject.propertyCount();
+
+ const int previousPropertyCount = propertyCount() - propertyOffset();
+ int propertyIndex = metaObject->indexOfProperty(name);
+ if (propertyIndex == -1)
+ return -1;
+ if (previousPropertyCount + objectPropertyOffset == metaObject->propertyCount())
+ return propertyIndex + m_type->propertyOffset - objectPropertyOffset;
+
+ if (m_type->shared) {
+ VDMObjectDelegateDataType *type = m_type;
+ m_type = new VDMObjectDelegateDataType(*m_type);
+ type->release();
+ }
+
+ const int previousMethodCount = methodCount();
+ int notifierId = previousMethodCount - methodOffset();
+ for (int propertyId = previousPropertyCount; propertyId < metaObject->propertyCount() - objectPropertyOffset; ++propertyId) {
+ QMetaProperty property = metaObject->property(propertyId + objectPropertyOffset);
+ QMetaPropertyBuilder propertyBuilder;
+ if (property.hasNotifySignal()) {
+ m_type->builder.addSignal("__" + QByteArray::number(propertyId) + "()");
+ propertyBuilder = m_type->builder.addProperty(property.name(), property.typeName(), notifierId);
+ ++notifierId;
+ } else {
+ propertyBuilder = m_type->builder.addProperty(property.name(), property.typeName());
+ }
+ propertyBuilder.setWritable(property.isWritable());
+ propertyBuilder.setResettable(property.isResettable());
+ propertyBuilder.setConstant(property.isConstant());
+ }
+
+ m_type->metaObject.reset(m_type->builder.toMetaObject());
+ *static_cast<QMetaObject *>(this) = *m_type->metaObject;
+
+ notifierId = previousMethodCount;
+ for (int i = previousPropertyCount; i < metaObject->propertyCount() - objectPropertyOffset; ++i) {
+ QMetaProperty property = metaObject->property(i + objectPropertyOffset);
+ if (property.hasNotifySignal()) {
+ QQmlPropertyPrivate::connect(
+ m_data->object, property.notifySignalIndex(), m_data, notifierId);
+ ++notifierId;
+ }
+ }
+ return propertyIndex + m_type->propertyOffset - objectPropertyOffset;
+ }
+
+ QQmlDMObjectData *m_data;
+ VDMObjectDelegateDataType *m_type;
+};
+
+QT_END_NAMESPACE
+
+#endif // QQMLDMOBJECTDATA_P_H