Qt
Internal/Contributor docs for the Qt SDK. Note: These are NOT official API docs; those are found at https://doc.qt.io/
Loading...
Searching...
No Matches
qqmldmabstractitemmodeldata.cpp
Go to the documentation of this file.
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// Qt-Security score:significant
4
5#include <private/qqmldmabstractitemmodeldata_p.h>
6
7QT_BEGIN_NAMESPACE
8
9QQmlDMAbstractItemModelData::QQmlDMAbstractItemModelData(
10 const QQmlRefPointer<QQmlDelegateModelItemMetaType> &metaType,
11 VDMAbstractItemModelDataType *dataType, int index, int row, int column)
12 : QQmlDelegateModelItem(metaType, dataType, index, row, column)
13 , m_type(dataType)
14{
15 if (index == -1)
16 m_cachedData.resize(m_type->propertyRoles.size());
17
18 QObjectPrivate::get(this)->metaObject = m_type;
19
20 m_type->addref();
21}
22
23int QQmlDMAbstractItemModelData::metaCall(QMetaObject::Call call, int id, void **arguments)
24{
25 if (call == QMetaObject::ReadProperty && id >= m_type->propertyOffset) {
26 const int propertyIndex = id - m_type->propertyOffset;
27 if (index == -1) {
28 if (!m_cachedData.isEmpty())
29 *static_cast<QVariant *>(arguments[0]) = m_cachedData.at(propertyIndex);
30 } else if (*m_type->model) {
31 *static_cast<QVariant *>(arguments[0]) = value(m_type->propertyRoles.at(propertyIndex));
32 }
33 return -1;
34 } else if (call == QMetaObject::WriteProperty && id >= m_type->propertyOffset) {
35 const int propertyIndex = id - m_type->propertyOffset;
36 const QMetaObject *meta = metaObject();
37 if (index == -1) {
38 if (m_cachedData.size() > 1) {
39 m_cachedData[propertyIndex] = *static_cast<QVariant *>(arguments[0]);
40 QMetaObject::activate(this, meta, propertyIndex, nullptr);
41 } else if (m_cachedData.size() == 1) {
42 m_cachedData[0] = *static_cast<QVariant *>(arguments[0]);
43 QMetaObject::activate(this, meta, 0, nullptr);
44 }
45
46 emit modelDataChanged();
47 } else if (*m_type->model) {
48 setValue(m_type->propertyRoles.at(propertyIndex),
49 *static_cast<QVariant *>(arguments[0]));
50 }
51 return -1;
52 } else {
53 return qt_metacall(call, id, arguments);
54 }
55}
56
57void QQmlDMAbstractItemModelData::setValue(const QString &role, const QVariant &value)
58{
59 // Used only for initialization of the cached data. Does not have to emit change signals.
60
61 if (m_type->propertyRoles.size() == 1
62 && (role.isEmpty() || role == QLatin1String("modelData"))) {
63 // If the model has only a single role, the modelData is that role.
64 m_cachedData[0] = value;
65 return;
66 }
67
68 const auto it = m_type->roleNames.constFind(role.toUtf8());
69 if (it != m_type->roleNames.cend()) {
70 for (int i = 0; i < m_type->propertyRoles.size(); ++i) {
71 if (m_type->propertyRoles.at(i) == *it) {
72 m_cachedData[i] = value;
73 return;
74 }
75 }
76 }
77}
78
79bool QQmlDMAbstractItemModelData::resolveIndex(const QQmlAdaptorModel &adaptorModel, int idx)
80{
81 if (index == -1) {
82 Q_ASSERT(idx >= 0);
83 m_cachedData.clear();
84 setModelIndex(idx, adaptorModel.rowAt(idx), adaptorModel.columnAt(idx));
85 const QMetaObject *meta = metaObject();
86 const int propertyCount = m_type->propertyRoles.size();
87 for (int i = 0; i < propertyCount; ++i)
88 QMetaObject::activate(this, meta, i, nullptr);
89 emit modelDataChanged();
90 return true;
91 } else {
92 return false;
93 }
94}
95
96QV4::ReturnedValue QQmlDMAbstractItemModelData::get_property(const QV4::FunctionObject *b, const QV4::Value *thisObject, const QV4::Value *, int)
97{
98 QV4::Scope scope(b);
99 QV4::Scoped<QQmlDelegateModelItemObject> o(scope, thisObject->as<QQmlDelegateModelItemObject>());
100 if (!o)
101 return scope.engine->throwTypeError(QStringLiteral("Not a valid DelegateModel object"));
102
103 const qsizetype propertyId = static_cast<const QV4::IndexedBuiltinFunction *>(b)->d()->index;
104
105 QQmlDMAbstractItemModelData *modelData = static_cast<QQmlDMAbstractItemModelData *>(o->d()->item);
106 if (o->d()->item->modelIndex() == -1) {
107 if (!modelData->m_cachedData.isEmpty())
108 return scope.engine->fromVariant(modelData->m_cachedData.at(propertyId));
109 } else if (*modelData->m_type->model) {
110 return scope.engine->fromVariant(
111 modelData->value(modelData->m_type->propertyRoles.at(propertyId)));
112 }
113 return QV4::Encode::undefined();
114}
115
116QV4::ReturnedValue QQmlDMAbstractItemModelData::set_property(const QV4::FunctionObject *b, const QV4::Value *thisObject, const QV4::Value *argv, int argc)
117{
118 QV4::Scope scope(b);
119 QV4::Scoped<QQmlDelegateModelItemObject> o(scope, thisObject->as<QQmlDelegateModelItemObject>());
120 if (!o)
121 return scope.engine->throwTypeError(QStringLiteral("Not a valid DelegateModel object"));
122 if (!argc)
123 return scope.engine->throwTypeError();
124
125 const qsizetype propertyId = static_cast<const QV4::IndexedBuiltinFunction *>(b)->d()->index;
126
127 if (o->d()->item->modelIndex() == -1) {
128 QQmlDMAbstractItemModelData *modelData = static_cast<QQmlDMAbstractItemModelData *>(o->d()->item);
129 if (!modelData->m_cachedData.isEmpty()) {
130 if (modelData->m_cachedData.size() > 1) {
131 modelData->m_cachedData[propertyId]
132 = QV4::ExecutionEngine::toVariant(argv[0], QMetaType {});
133 QMetaObject::activate(o->d()->item, o->d()->item->metaObject(), propertyId, nullptr);
134 } else if (modelData->m_cachedData.size() == 1) {
135 modelData->m_cachedData[0] = QV4::ExecutionEngine::toVariant(argv[0], QMetaType {});
136 QMetaObject::activate(o->d()->item, o->d()->item->metaObject(), 0, nullptr);
137 }
138 emit modelData->modelDataChanged();
139 }
140 }
141 return QV4::Encode::undefined();
142}
143
144QV4::ReturnedValue QQmlDMAbstractItemModelData::get_modelData(
145 const QV4::FunctionObject *b, const QV4::Value *thisObject,
146 const QV4::Value *argv, int argc)
147{
148 Q_UNUSED(argv)
149 Q_UNUSED(argc)
150
151 QV4::Scope scope(b);
152 QV4::Scoped<QQmlDelegateModelItemObject> o(
153 scope, thisObject->as<QQmlDelegateModelItemObject>());
154 if (!o)
155 return scope.engine->throwTypeError(QStringLiteral("Not a valid DelegateModel object"));
156
157 return scope.engine->fromVariant(
158 static_cast<QQmlDMAbstractItemModelData *>(o->d()->item)->modelData());
159}
160
161QV4::ReturnedValue QQmlDMAbstractItemModelData::set_modelData(
162 const QV4::FunctionObject *b, const QV4::Value *thisObject,
163 const QV4::Value *argv, int argc)
164{
165 QV4::Scope scope(b);
166 QV4::Scoped<QQmlDelegateModelItemObject> o(scope, thisObject->as<QQmlDelegateModelItemObject>());
167 if (!o)
168 return scope.engine->throwTypeError(QStringLiteral("Not a valid DelegateModel object"));
169 if (!argc)
170 return scope.engine->throwTypeError();
171
172 static_cast<QQmlDMAbstractItemModelData *>(o->d()->item)->setModelData(
173 QV4::ExecutionEngine::toVariant(argv[0], QMetaType()));
174
175 return QV4::Encode::undefined();
176}
177
178QVariant QQmlDMAbstractItemModelData::modelData() const
179{
180 if (m_type->propertyRoles.size() == 1) {
181 // If the model has only a single role, the modelData is that role.
182 return index == -1
183 ? m_cachedData.isEmpty() ? QVariant() : m_cachedData[0]
184 : value(m_type->propertyRoles[0]);
185 }
186
187 return useStructuredModelData
188 ? QVariant::fromValue(this)
189 : QVariant();
190}
191
192void QQmlDMAbstractItemModelData::setModelData(const QVariant &modelData)
193{
194 if (m_type->propertyRoles.size() != 1) {
195 qWarning() << "Cannot overwrite model object";
196 return;
197 }
198
199 // If the model has only a single role, the modelData is that role.
200 if (index == -1) {
201 if (m_cachedData.isEmpty())
202 m_cachedData.append(modelData);
203 else
204 m_cachedData[0] = modelData;
205 } else {
206 setValue(m_type->propertyRoles[0], modelData);
207 }
208
209 QMetaObject::activate(this, metaObject(), 0, nullptr);
210 emit modelDataChanged();
211}
212
213bool QQmlDMAbstractItemModelData::hasModelChildren() const
214{
215 if (index >= 0) {
216 if (const QAbstractItemModel *const model = m_type->model->aim())
217 return model->hasChildren(model->index(row, column, m_type->model->rootIndex));
218 }
219 return false;
220}
221
222QVariant QQmlDMAbstractItemModelData::value(int role) const
223{
224 if (const QAbstractItemModel *aim = m_type->model->aim())
225 return aim->index(row, column, m_type->model->rootIndex).data(role);
226 return QVariant();
227}
228
229void QQmlDMAbstractItemModelData::setValue(int role, const QVariant &value)
230{
231 if (QAbstractItemModel *aim = m_type->model->aim())
232 aim->setData(aim->index(row, column, m_type->model->rootIndex), value, role);
233}
234
235QV4::ReturnedValue QQmlDMAbstractItemModelData::get()
236{
237 QV4::Scope scope(metaType->v4Engine);
238 if (m_type->prototype.isUndefined()) {
239 QQmlAdaptorModelEngineData *const data = QQmlAdaptorModelEngineData::get(scope.engine);
240 m_type->initializeConstructor(data);
241 }
242 QV4::ScopedObject proto(scope, m_type->prototype.value());
243 QV4::ScopedObject o(scope, proto->engine()->memoryManager->allocate<QQmlDelegateModelItemObject>(this));
244 o->setPrototypeOf(proto);
245 ++scriptRef;
246 return o.asReturnedValue();
247}
248
249QT_END_NAMESPACE