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 QQMLDMLISTACCESSORDATA_P_H
5#define QQMLDMLISTACCESSORDATA_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#include <private/qobject_p.h>
21
22QT_BEGIN_NAMESPACE
23
24class VDMListDelegateDataType;
25
26class QQmlDMListAccessorData : public QQmlDelegateModelItem
27{
28 Q_OBJECT
29 Q_PROPERTY(QVariant modelData READ modelData WRITE setModelData NOTIFY modelDataChanged FINAL)
30 QT_ANONYMOUS_PROPERTY(QVariant READ modelData WRITE setModelData NOTIFY modelDataChanged)
31public:
32 QQmlDMListAccessorData(const QQmlRefPointer<QQmlDelegateModelItemMetaType> &metaType,
33 VDMListDelegateDataType *dataType, int index, int row, int column, const QVariant &value);
34
35 QVariant modelData() const
36 {
37 return cachedData;
38 }
39
40 void setModelData(const QVariant &data);
41
42 static QV4::ReturnedValue get_modelData(const QV4::FunctionObject *b, const QV4::Value *thisObject, const QV4::Value *, int)
43 {
44 QV4::ExecutionEngine *v4 = b->engine();
45 const QQmlDelegateModelItemObject *o = thisObject->as<QQmlDelegateModelItemObject>();
46 if (!o)
47 return v4->throwTypeError(QStringLiteral("Not a valid DelegateModel object"));
48
49 return v4->fromVariant(static_cast<QQmlDMListAccessorData *>(o->d()->item)->cachedData);
50 }
51
52 static QV4::ReturnedValue set_modelData(const QV4::FunctionObject *b, const QV4::Value *thisObject, const QV4::Value *argv, int argc)
53 {
54 QV4::ExecutionEngine *v4 = b->engine();
55 const QQmlDelegateModelItemObject *o = thisObject->as<QQmlDelegateModelItemObject>();
56 if (!o)
57 return v4->throwTypeError(QStringLiteral("Not a valid DelegateModel object"));
58 if (!argc)
59 return v4->throwTypeError();
60
61 static_cast<QQmlDMListAccessorData *>(o->d()->item)->setModelData(
62 QV4::ExecutionEngine::toVariant(value: argv[0], typeHint: QMetaType {}));
63 return QV4::Encode::undefined();
64 }
65
66 QV4::ReturnedValue get() override
67 {
68 QQmlAdaptorModelEngineData *data = QQmlAdaptorModelEngineData::get(engine: v4);
69 QV4::Scope scope(v4);
70 QV4::ScopedObject o(scope, v4->memoryManager->allocate<QQmlDelegateModelItemObject>(args: this));
71 QV4::ScopedObject p(scope, data->listItemProto.value());
72 o->setPrototypeOf(p);
73 ++scriptRef;
74 return o.asReturnedValue();
75 }
76
77 void setValue(const QString &role, const QVariant &value) override;
78 bool resolveIndex(const QQmlAdaptorModel &model, int idx) override;
79
80Q_SIGNALS:
81 void modelDataChanged();
82
83private:
84 friend class VDMListDelegateDataType;
85 QVariant cachedData;
86};
87
88
89class VDMListDelegateDataType
90 : public QQmlRefCounted<VDMListDelegateDataType>
91 , public QQmlAdaptorModel::Accessors
92 , public QAbstractDynamicMetaObject
93{
94public:
95 VDMListDelegateDataType(QQmlAdaptorModel *model)
96 : model(model)
97 {
98 QQmlAdaptorModelEngineData::setModelDataType<QQmlDMListAccessorData>(builder: &builder, metaType: this);
99 metaObject.reset(other: builder.toMetaObject());
100 *static_cast<QMetaObject *>(this) = *metaObject.data();
101 }
102
103 void cleanup(QQmlAdaptorModel &) const override
104 {
105 release();
106 }
107
108 int rowCount(const QQmlAdaptorModel &model) const override
109 {
110 return model.list.count();
111 }
112
113 int columnCount(const QQmlAdaptorModel &model) const override
114 {
115 switch (model.list.type()) {
116 case QQmlListAccessor::Invalid:
117 return 0;
118 case QQmlListAccessor::StringList:
119 case QQmlListAccessor::UrlList:
120 case QQmlListAccessor::Integer:
121 return 1;
122 default:
123 break;
124 }
125
126 // If there are no properties, we can get modelData itself.
127 return std::max(a: 1, b: propertyCount() - propertyOffset);
128 }
129
130 static const QMetaObject *metaObjectFromType(QMetaType type)
131 {
132 if (const QMetaObject *metaObject = type.metaObject())
133 return metaObject;
134
135 // NB: This acquires the lock on QQmlMetaTypeData. If we had a QQmlEngine here,
136 // we could use QQmlGadgetPtrWrapper::instance() to avoid this.
137 if (const QQmlValueType *valueType = QQmlMetaType::valueType(metaType: type))
138 return valueType->staticMetaObject();
139
140 return nullptr;
141 }
142
143 template<typename String>
144 static QString toQString(const String &string)
145 {
146 if constexpr (std::is_same_v<String, QString>)
147 return string;
148 else if constexpr (std::is_same_v<String, QByteArray>)
149 return QString::fromUtf8(string);
150 Q_UNREACHABLE_RETURN(QString());
151 }
152
153 template<typename String>
154 static QByteArray toUtf8(const String &string)
155 {
156 if constexpr (std::is_same_v<String, QString>)
157 return string.toUtf8().constData();
158 else if constexpr (std::is_same_v<String, QByteArray>)
159 return string;
160 Q_UNREACHABLE_RETURN(QByteArray());
161 }
162
163 template<typename String>
164 static QVariant value(const QVariant *row, const String &role)
165 {
166 const QMetaType type = row->metaType();
167 if (type == QMetaType::fromType<QVariantMap>())
168 return row->toMap().value(key: toQString(role));
169
170 if (type == QMetaType::fromType<QVariantHash>())
171 return row->toHash().value(toQString(role));
172
173 const QMetaType::TypeFlags typeFlags = type.flags();
174 if (typeFlags & QMetaType::PointerToQObject)
175 return row->value<QObject *>()->property(name: toUtf8(role));
176
177 if (const QMetaObject *metaObject = metaObjectFromType(type)) {
178 const int propertyIndex = metaObject->indexOfProperty(name: toUtf8(role));
179 if (propertyIndex >= 0)
180 return metaObject->property(index: propertyIndex).readOnGadget(gadget: row->constData());
181 }
182
183 return QVariant();
184 }
185
186 template<typename String>
187 static void setValue(QVariant *row, const String &role, const QVariant &value)
188 {
189 const QMetaType type = row->metaType();
190 if (type == QMetaType::fromType<QVariantMap>()) {
191 static_cast<QVariantMap *>(row->data())->insert(toQString(role), value);
192 } else if (type == QMetaType::fromType<QVariantHash>()) {
193 static_cast<QVariantHash *>(row->data())->insert(toQString(role), value);
194 } else if (type.flags() & QMetaType::PointerToQObject) {
195 row->value<QObject *>()->setProperty(toUtf8(role), value);
196 } else if (const QMetaObject *metaObject = metaObjectFromType(type)) {
197 const int propertyIndex = metaObject->indexOfProperty(name: toUtf8(role));
198 if (propertyIndex >= 0)
199 metaObject->property(index: propertyIndex).writeOnGadget(gadget: row->data(), value);
200 }
201 }
202
203 QVariant value(const QQmlAdaptorModel &model, int index, const QString &role) const override
204 {
205 const QVariant entry = model.list.at(index);
206 if (role == QLatin1String("modelData") || role.isEmpty())
207 return entry;
208
209 return value(row: &entry, role);
210 }
211
212 QQmlDelegateModelItem *createItem(
213 QQmlAdaptorModel &model,
214 const QQmlRefPointer<QQmlDelegateModelItemMetaType> &metaType,
215 int index, int row, int column) override
216 {
217 const QVariant value = (index >= 0 && index < model.list.count())
218 ? model.list.at(index)
219 : QVariant();
220 return new QQmlDMListAccessorData(metaType, this, index, row, column, value);
221 }
222
223 bool notify(const QQmlAdaptorModel &model, const QList<QQmlDelegateModelItem *> &items, int index, int count, const QVector<int> &) const override
224 {
225 for (auto modelItem : items) {
226 const int modelItemIndex = modelItem->index;
227 if (modelItemIndex < index || modelItemIndex >= index + count)
228 continue;
229
230 auto listModelItem = static_cast<QQmlDMListAccessorData *>(modelItem);
231 QVariant updatedModelData = model.list.at(listModelItem->index);
232 listModelItem->setModelData(updatedModelData);
233 }
234 return true;
235 }
236
237 void objectDestroyed(QObject *) override
238 {
239 release();
240 }
241
242 void emitAllSignals(QQmlDMListAccessorData *accessor) const;
243
244 int metaCall(QObject *object, QMetaObject::Call call, int id, void **arguments) final;
245 int createProperty(const char *name, const char *) final;
246 QMetaObject *toDynamicMetaObject(QObject *accessors) final;
247
248 QMetaObjectBuilder builder;
249 QQmlAdaptorModel *model = nullptr;
250 int propertyOffset = 0;
251 int signalOffset = 0;
252};
253
254QT_END_NAMESPACE
255
256#endif // QQMLDMLISTACCESSORDATA_P_H
257

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