1// Copyright (C) 2023 The Qt Company Ltd.
2// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only
3
4#ifndef QQMLDMOBJECTDATA_P_H
5#define QQMLDMOBJECTDATA_P_H
6
7//
8// W A R N I N G
9// -------------
10//
11// This file is not part of the Qt API. It exists purely as an
12// implementation detail. This header file may change from version to
13// version without notice, or even be removed.
14//
15// We mean it.
16//
17
18#include <private/qqmladaptormodelenginedata_p.h>
19#include <private/qqmldelegatemodel_p_p.h>
20
21#include <private/qobject_p.h>
22#include <QtCore/qpointer.h>
23
24QT_BEGIN_NAMESPACE
25
26class VDMObjectDelegateDataType;
27class QQmlDMObjectData : public QQmlDelegateModelItem, public QQmlAdaptorModelProxyInterface
28{
29 Q_OBJECT
30 Q_PROPERTY(QObject *modelData READ modelData NOTIFY modelDataChanged)
31 QT_ANONYMOUS_PROPERTY(QObject * READ modelData NOTIFY modelDataChanged FINAL)
32 Q_INTERFACES(QQmlAdaptorModelProxyInterface)
33public:
34 QQmlDMObjectData(
35 const QQmlRefPointer<QQmlDelegateModelItemMetaType> &metaType,
36 VDMObjectDelegateDataType *dataType,
37 int index, int row, int column,
38 QObject *object);
39
40 void setModelData(QObject *modelData)
41 {
42 if (modelData == object)
43 return;
44
45 object = modelData;
46 emit modelDataChanged();
47 }
48
49 QObject *modelData() const { return object; }
50 QObject *proxiedObject() override { return object; }
51
52 QPointer<QObject> object;
53
54Q_SIGNALS:
55 void modelDataChanged();
56};
57
58class VDMObjectDelegateDataType final
59 : public QQmlRefCounted<VDMObjectDelegateDataType>,
60 public QQmlAdaptorModel::Accessors
61{
62public:
63 int propertyOffset;
64 int signalOffset;
65 bool shared;
66 QMetaObjectBuilder builder;
67
68 VDMObjectDelegateDataType()
69 : propertyOffset(0)
70 , signalOffset(0)
71 , shared(true)
72 {
73 }
74
75 VDMObjectDelegateDataType(const VDMObjectDelegateDataType &type)
76 : propertyOffset(type.propertyOffset)
77 , signalOffset(type.signalOffset)
78 , shared(false)
79 , builder(type.metaObject.data(), QMetaObjectBuilder::Properties
80 | QMetaObjectBuilder::Signals
81 | QMetaObjectBuilder::SuperClass
82 | QMetaObjectBuilder::ClassName)
83 {
84 builder.setFlags(MetaObjectFlag::DynamicMetaObject);
85 }
86
87 int rowCount(const QQmlAdaptorModel &model) const override
88 {
89 return model.list.count();
90 }
91
92 int columnCount(const QQmlAdaptorModel &) const override
93 {
94 return 1;
95 }
96
97 QVariant value(const QQmlAdaptorModel &model, int index, const QString &role) const override
98 {
99 if (QObject *object = model.list.at(index).value<QObject *>())
100 return object->property(name: role.toUtf8());
101 return QVariant();
102 }
103
104 QQmlDelegateModelItem *createItem(
105 QQmlAdaptorModel &model,
106 const QQmlRefPointer<QQmlDelegateModelItemMetaType> &metaType,
107 int index, int row, int column) override
108 {
109 if (!metaObject)
110 initializeMetaType(model);
111 return index >= 0 && index < model.list.count()
112 ? new QQmlDMObjectData(metaType, this, index, row, column, qvariant_cast<QObject *>(v: model.list.at(index)))
113 : nullptr;
114 }
115
116 void initializeMetaType(QQmlAdaptorModel &model)
117 {
118 Q_UNUSED(model);
119 QQmlAdaptorModelEngineData::setModelDataType<QQmlDMObjectData>(builder: &builder, metaType: this);
120
121 metaObject.reset(other: builder.toMetaObject());
122 // Note: ATM we cannot create a shared property cache for this class, since each model
123 // object can have different properties. And to make those properties available to the
124 // delegate, QQmlDMObjectData makes use of a QAbstractDynamicMetaObject subclass
125 // (QQmlDMObjectDataMetaObject), which we cannot represent in a QQmlPropertyCache.
126 // By not having a shared property cache, revisioned properties in QQmlDelegateModelItem
127 // will always be available to the delegate, regardless of the import version.
128 }
129
130 void cleanup(QQmlAdaptorModel &) const override
131 {
132 release();
133 }
134
135 bool notify(const QQmlAdaptorModel &model, const QList<QQmlDelegateModelItem *> &items, int index, int count, const QVector<int> &) const override
136 {
137 for (auto modelItem : items) {
138 const int modelItemIndex = modelItem->index;
139 if (modelItemIndex < index || modelItemIndex >= index + count)
140 continue;
141
142 auto objectModelItem = static_cast<QQmlDMObjectData *>(modelItem);
143 QObject *updatedModelData = qvariant_cast<QObject *>(v: model.list.at(objectModelItem->index));
144 objectModelItem->setModelData(updatedModelData);
145 }
146 return true;
147 }
148};
149
150class QQmlDMObjectDataMetaObject : public QAbstractDynamicMetaObject
151{
152public:
153 QQmlDMObjectDataMetaObject(QQmlDMObjectData *data, VDMObjectDelegateDataType *type)
154 : m_data(data)
155 , m_type(type)
156 {
157 QObjectPrivate *op = QObjectPrivate::get(o: m_data);
158 *static_cast<QMetaObject *>(this) = *type->metaObject;
159 op->metaObject = this;
160 m_type->addref();
161 }
162
163 ~QQmlDMObjectDataMetaObject()
164 {
165 m_type->release();
166 }
167
168 int metaCall(QObject *o, QMetaObject::Call call, int id, void **arguments) override
169 {
170 Q_ASSERT(o == m_data);
171 Q_UNUSED(o);
172
173 static const int objectPropertyOffset = QObject::staticMetaObject.propertyCount();
174 if (id >= m_type->propertyOffset
175 && (call == QMetaObject::ReadProperty
176 || call == QMetaObject::WriteProperty
177 || call == QMetaObject::ResetProperty)) {
178 if (m_data->object)
179 QMetaObject::metacall(m_data->object, call, id - m_type->propertyOffset + objectPropertyOffset, arguments);
180 return -1;
181 } else if (id >= m_type->signalOffset && call == QMetaObject::InvokeMetaMethod) {
182 QMetaObject::activate(sender: m_data, this, local_signal_index: id - m_type->signalOffset, argv: nullptr);
183 return -1;
184 } else {
185 return m_data->qt_metacall(call, id, arguments);
186 }
187 }
188
189 int createProperty(const char *name, const char *) override
190 {
191 if (!m_data->object)
192 return -1;
193 const QMetaObject *metaObject = m_data->object->metaObject();
194 static const int objectPropertyOffset = QObject::staticMetaObject.propertyCount();
195
196 const int previousPropertyCount = propertyCount() - propertyOffset();
197 int propertyIndex = metaObject->indexOfProperty(name);
198 if (propertyIndex == -1)
199 return -1;
200 if (previousPropertyCount + objectPropertyOffset == metaObject->propertyCount())
201 return propertyIndex + m_type->propertyOffset - objectPropertyOffset;
202
203 if (m_type->shared) {
204 VDMObjectDelegateDataType *type = m_type;
205 m_type = new VDMObjectDelegateDataType(*m_type);
206 type->release();
207 }
208
209 const int previousMethodCount = methodCount();
210 int notifierId = previousMethodCount - methodOffset();
211 for (int propertyId = previousPropertyCount; propertyId < metaObject->propertyCount() - objectPropertyOffset; ++propertyId) {
212 QMetaProperty property = metaObject->property(index: propertyId + objectPropertyOffset);
213 QMetaPropertyBuilder propertyBuilder;
214 if (property.hasNotifySignal()) {
215 m_type->builder.addSignal(signature: "__" + QByteArray::number(propertyId) + "()");
216 propertyBuilder = m_type->builder.addProperty(name: property.name(), type: property.typeName(), notifierId);
217 ++notifierId;
218 } else {
219 propertyBuilder = m_type->builder.addProperty(name: property.name(), type: property.typeName());
220 }
221 propertyBuilder.setWritable(property.isWritable());
222 propertyBuilder.setResettable(property.isResettable());
223 propertyBuilder.setConstant(property.isConstant());
224 }
225
226 m_type->metaObject.reset(other: m_type->builder.toMetaObject());
227 *static_cast<QMetaObject *>(this) = *m_type->metaObject;
228
229 notifierId = previousMethodCount;
230 for (int i = previousPropertyCount; i < metaObject->propertyCount() - objectPropertyOffset; ++i) {
231 QMetaProperty property = metaObject->property(index: i + objectPropertyOffset);
232 if (property.hasNotifySignal()) {
233 QQmlPropertyPrivate::connect(
234 sender: m_data->object, signal_index: property.notifySignalIndex(), receiver: m_data, method_index: notifierId);
235 ++notifierId;
236 }
237 }
238 return propertyIndex + m_type->propertyOffset - objectPropertyOffset;
239 }
240
241 QQmlDMObjectData *m_data;
242 VDMObjectDelegateDataType *m_type;
243};
244
245QT_END_NAMESPACE
246
247#endif // QQMLDMOBJECTDATA_P_H
248

Provided by KDAB

Privacy Policy
Start learning QML with our Intro Training
Find out more

source code of qtdeclarative/src/qmlmodels/qqmldmobjectdata_p.h