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 (!hasValidModelIndex()) {
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 (!hasValidModelIndex()) {
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 (hasValidModelIndex())
82 return false;
83
84 Q_ASSERT(idx >= 0);
85 m_cachedData.clear();
86 setModelIndex(idx, adaptorModel.rowAt(idx), adaptorModel.columnAt(idx));
87 const QMetaObject *meta = metaObject();
88 const int propertyCount = m_type->propertyRoles.size();
89 for (int i = 0; i < propertyCount; ++i)
90 QMetaObject::activate(this, meta, i, nullptr);
91 emit modelDataChanged();
92 return true;
93}
94
95QV4::ReturnedValue QQmlDMAbstractItemModelData::get_property(const QV4::FunctionObject *b, const QV4::Value *thisObject, const QV4::Value *, int)
96{
97 QV4::Scope scope(b);
98 QV4::Scoped<QQmlDelegateModelItemObject> o(scope, thisObject->as<QQmlDelegateModelItemObject>());
99 if (!o)
100 return scope.engine->throwTypeError(QStringLiteral("Not a valid DelegateModel object"));
101
102 const qsizetype propertyId = static_cast<const QV4::IndexedBuiltinFunction *>(b)->d()->index;
103
104 QQmlDelegateModelItem *item = o->d()->item();
105 QQmlDMAbstractItemModelData *modelData = static_cast<QQmlDMAbstractItemModelData *>(item);
106 if (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 QQmlDelegateModelItem *item = o->d()->item();
128 if (item->modelIndex() == -1) {
129 QQmlDMAbstractItemModelData *modelData = static_cast<QQmlDMAbstractItemModelData *>(item);
130 if (!modelData->m_cachedData.isEmpty()) {
131 if (modelData->m_cachedData.size() > 1) {
132 modelData->m_cachedData[propertyId]
133 = QV4::ExecutionEngine::toVariant(argv[0], QMetaType {});
134 QMetaObject::activate(item, item->metaObject(), propertyId, nullptr);
135 } else if (modelData->m_cachedData.size() == 1) {
136 modelData->m_cachedData[0] = QV4::ExecutionEngine::toVariant(argv[0], QMetaType {});
137 QMetaObject::activate(item, item->metaObject(), 0, nullptr);
138 }
139 emit modelData->modelDataChanged();
140 }
141 }
142 return QV4::Encode::undefined();
143}
144
145QV4::ReturnedValue QQmlDMAbstractItemModelData::get_modelData(
146 const QV4::FunctionObject *b, const QV4::Value *thisObject,
147 const QV4::Value *argv, int argc)
148{
149 Q_UNUSED(argv)
150 Q_UNUSED(argc)
151
152 QV4::Scope scope(b);
153 QV4::Scoped<QQmlDelegateModelItemObject> o(
154 scope, thisObject->as<QQmlDelegateModelItemObject>());
155 if (!o)
156 return scope.engine->throwTypeError(QStringLiteral("Not a valid DelegateModel object"));
157
158 return scope.engine->fromVariant(
159 static_cast<QQmlDMAbstractItemModelData *>(o->d()->item())->modelData());
160}
161
162QV4::ReturnedValue QQmlDMAbstractItemModelData::set_modelData(
163 const QV4::FunctionObject *b, const QV4::Value *thisObject,
164 const QV4::Value *argv, int argc)
165{
166 QV4::Scope scope(b);
167 QV4::Scoped<QQmlDelegateModelItemObject> o(scope, thisObject->as<QQmlDelegateModelItemObject>());
168 if (!o)
169 return scope.engine->throwTypeError(QStringLiteral("Not a valid DelegateModel object"));
170 if (!argc)
171 return scope.engine->throwTypeError();
172
173 static_cast<QQmlDMAbstractItemModelData *>(o->d()->item())->setModelData(
174 QV4::ExecutionEngine::toVariant(argv[0], QMetaType()));
175
176 return QV4::Encode::undefined();
177}
178
179QVariant QQmlDMAbstractItemModelData::modelData() const
180{
181 if (m_type->propertyRoles.size() == 1) {
182 // If the model has only a single role, the modelData is that role.
183 return hasValidModelIndex()
184 ? value(m_type->propertyRoles[0])
185 : m_cachedData.isEmpty() ? QVariant() : m_cachedData[0];
186 }
187
188 return usesStructuredModelData()
189 ? QVariant::fromValue(this)
190 : QVariant();
191}
192
193void QQmlDMAbstractItemModelData::setModelData(const QVariant &modelData)
194{
195 if (m_type->propertyRoles.size() != 1) {
196 qWarning() << "Cannot overwrite model object";
197 return;
198 }
199
200 // If the model has only a single role, the modelData is that role.
201 if (hasValidModelIndex()) {
202 setValue(m_type->propertyRoles[0], modelData);
203 } else {
204 if (m_cachedData.isEmpty())
205 m_cachedData.append(modelData);
206 else
207 m_cachedData[0] = modelData;
208 }
209
210 QMetaObject::activate(this, metaObject(), 0, nullptr);
211 emit modelDataChanged();
212}
213
214bool QQmlDMAbstractItemModelData::hasModelChildren() const
215{
216 if (hasValidModelIndex()) {
217 if (const QAbstractItemModel *const model = m_type->model->aim()) {
218 return model->hasChildren(
219 model->index(modelRow(), modelColumn(), m_type->model->rootIndex));
220 }
221 }
222 return false;
223}
224
225QVariant QQmlDMAbstractItemModelData::value(int role) const
226{
227 if (const QAbstractItemModel *aim = m_type->model->aim())
228 return aim->index(modelRow(), modelColumn(), m_type->model->rootIndex).data(role);
229 return QVariant();
230}
231
232void QQmlDMAbstractItemModelData::setValue(int role, const QVariant &value)
233{
234 if (QAbstractItemModel *aim = m_type->model->aim())
235 aim->setData(aim->index(modelRow(), modelColumn(), m_type->model->rootIndex), value, role);
236}
237
238QV4::ReturnedValue QQmlDMAbstractItemModelData::get()
239{
240 QV4::Scope scope(metaType()->v4Engine);
241 if (m_type->prototype.isUndefined()) {
242 QQmlAdaptorModelEngineData *const data = QQmlAdaptorModelEngineData::get(scope.engine);
243 m_type->initializeConstructor(data);
244 }
245 QV4::ScopedObject proto(scope, m_type->prototype.value());
246 QV4::ScopedObject o(scope, proto->engine()->memoryManager->allocate<QQmlDelegateModelItemObject>(this));
247 o->setPrototypeOf(proto);
248 return o.asReturnedValue();
249}
250
251QT_END_NAMESPACE