Qt
Internal/Contributor docs for the Qt SDK. <b>Note:</b> These are NOT official API docs; those are found <a href='https://doc.qt.io/'>here</a>.
Loading...
Searching...
No Matches
qquick3drepeater.cpp
Go to the documentation of this file.
1// Copyright (C) 2019 The Qt Company Ltd.
2// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only
3
5
6#include <private/qqmlglobal_p.h>
7#include <private/qqmllistaccessor_p.h>
8#include <private/qqmlchangeset_p.h>
9#include <private/qqmldelegatemodel_p.h>
10
11#include <QtQml/QQmlInfo>
12
14
15
62 : QQuick3DNode(parent)
63 , m_model(nullptr)
64 , m_itemCount(0)
65 , m_ownModel(false)
66 , m_dataSourceIsObject(false)
67 , m_delegateValidated(false)
68{
69}
70
72{
73 if (m_ownModel)
74 delete m_model;
75}
76
97{
98 if (m_dataSourceIsObject) {
99 QObject *o = m_dataSourceAsObject;
100 return QVariant::fromValue(o);
101 }
102
103 return m_dataSource;
104
105}
106
108{
109 QVariant model = m;
110 if (model.userType() == qMetaTypeId<QJSValue>())
112
113 if (m_dataSource == model)
114 return;
115
116 clear();
117 if (m_model) {
118 qmlobject_disconnect(m_model, QQmlInstanceModel, SIGNAL(modelUpdated(QQmlChangeSet,bool)),
119 this, QQuick3DRepeater, SLOT(modelUpdated(QQmlChangeSet,bool)));
120 qmlobject_disconnect(m_model, QQmlInstanceModel, SIGNAL(createdItem(int,QObject*)),
121 this, QQuick3DRepeater, SLOT(createdObject(int,QObject*)));
122 qmlobject_disconnect(m_model, QQmlInstanceModel, SIGNAL(initItem(int,QObject*)),
123 this, QQuick3DRepeater, SLOT(initObject(int,QObject*)));
124 }
125 m_dataSource = model;
126 QObject *object = qvariant_cast<QObject*>(model);
127 m_dataSourceAsObject = object;
128 m_dataSourceIsObject = object != nullptr;
129 QQmlInstanceModel *vim = nullptr;
130 if (object && (vim = qobject_cast<QQmlInstanceModel *>(object))) {
131 if (m_ownModel) {
132 delete m_model;
133 m_ownModel = false;
134 }
135 m_model = vim;
136 } else {
137 if (!m_ownModel) {
138 m_model = new QQmlDelegateModel(qmlContext(this));
139 m_ownModel = true;
141 static_cast<QQmlDelegateModel *>(m_model.data())->componentComplete();
142 }
143 if (QQmlDelegateModel *dataModel = qobject_cast<QQmlDelegateModel*>(m_model))
144 dataModel->setModel(model);
145 }
146 if (m_model) {
147 qmlobject_connect(m_model, QQmlInstanceModel, SIGNAL(modelUpdated(QQmlChangeSet,bool)),
148 this, QQuick3DRepeater, SLOT(modelUpdated(QQmlChangeSet,bool)));
149 qmlobject_connect(m_model, QQmlInstanceModel, SIGNAL(createdItem(int,QObject*)),
150 this, QQuick3DRepeater, SLOT(createdObject(int,QObject*)));
151 qmlobject_connect(m_model, QQmlInstanceModel, SIGNAL(initItem(int,QObject*)),
152 this, QQuick3DRepeater, SLOT(initObject(int,QObject*)));
153 regenerate();
154 }
157}
158
176{
177 if (m_model) {
178 if (QQmlDelegateModel *dataModel = qobject_cast<QQmlDelegateModel*>(m_model))
179 return dataModel->delegate();
180 }
181
182 return nullptr;
183}
184
186{
187 if (QQmlDelegateModel *dataModel = qobject_cast<QQmlDelegateModel*>(m_model))
188 if (delegate == dataModel->delegate())
189 return;
190
191 if (!m_ownModel) {
192 m_model = new QQmlDelegateModel(qmlContext(this));
193 m_ownModel = true;
195 static_cast<QQmlDelegateModel *>(m_model.data())->componentComplete();
196 }
197
198 if (QQmlDelegateModel *dataModel = qobject_cast<QQmlDelegateModel*>(m_model)) {
199 dataModel->setDelegate(delegate);
200 regenerate();
202 m_delegateValidated = false;
203 }
204}
205
218{
219 if (m_model)
220 return m_model->count();
221 return 0;
222}
223
232{
233 if (index >= 0 && index < m_deletables.size())
234 return m_deletables[index];
235 return nullptr;
236}
237
238void QQuick3DRepeater::clear()
239{
240 bool complete = isComponentComplete();
241
242 if (m_model) {
243 // We remove in reverse order deliberately; so that signals are emitted
244 // with sensible indices.
245 for (int i = m_deletables.size() - 1; i >= 0; --i) {
246 if (QQuick3DObject *item = m_deletables.at(i)) {
247 if (complete)
249 m_model->release(item);
250 }
251 }
252 for (QQuick3DObject *item : std::as_const(m_deletables)) {
253 if (item)
254 item->setParentItem(nullptr);
255 }
256 }
257 m_deletables.clear();
258 m_itemCount = 0;
259}
260
261void QQuick3DRepeater::regenerate()
262{
263 if (!isComponentComplete())
264 return;
265
266 clear();
267
268 if (!m_model || !m_model->count() || !m_model->isValid() || !parentItem() || !isComponentComplete())
269 return;
270
271 m_itemCount = count();
272 m_deletables.resize(m_itemCount);
273 requestItems();
274}
275
277{
278 if (m_model && m_ownModel)
279 static_cast<QQmlDelegateModel *>(m_model.data())->componentComplete();
281 regenerate();
282 if (m_model && m_model->count())
284}
285
286void QQuick3DRepeater::itemChange(QQuick3DObject::ItemChange change, const QQuick3DObject::ItemChangeData &value)
287{
289 if (change == ItemParentHasChanged) {
290 regenerate();
291 }
292}
293
294void QQuick3DRepeater::createdObject(int index, QObject *)
295{
297 QQuick3DObject *item = qmlobject_cast<QQuick3DObject*>(object);
299}
300
301void QQuick3DRepeater::initObject(int index, QObject *object)
302{
303 QQuick3DNode *item = qmlobject_cast<QQuick3DNode*>(object);
304
305 if (!m_deletables.at(index)) {
306 if (!item) {
307 if (object) {
308 m_model->release(object);
309 if (!m_delegateValidated) {
310 m_delegateValidated = true;
311 QObject* delegate = this->delegate();
312 qmlWarning(delegate ? delegate : this) << QQuick3DRepeater::tr("Delegate must be of Node type");
313 }
314 }
315 return;
316 }
317 m_deletables[index] = item;
318 item->setParent(this);
319 item->setParentItem(static_cast<QQuick3DNode*>(this));
321 }
322}
323
324void QQuick3DRepeater::modelUpdated(const QQmlChangeSet &changeSet, bool reset)
325{
326 if (!isComponentComplete())
327 return;
328
329 if (reset) {
330 regenerate();
331 if (changeSet.difference() != 0)
333 return;
334 }
335
336 int difference = 0;
337 QHash<int, QVector<QPointer<QQuick3DNode> > > moved;
338 for (const QQmlChangeSet::Change &remove : changeSet.removes()) {
339 int index = qMin(remove.index, m_deletables.size());
340 int count = qMin(remove.index + remove.count, m_deletables.size()) - index;
341 if (remove.isMove()) {
342 moved.insert(remove.moveId, m_deletables.mid(index, count));
343 m_deletables.erase(
344 m_deletables.begin() + index,
345 m_deletables.begin() + index + count);
346 } else while (count--) {
347 QQuick3DNode *item = m_deletables.at(index);
348 m_deletables.remove(index);
350 if (item) {
351 m_model->release(item);
352 item->setParentItem(nullptr);
353 }
354 --m_itemCount;
355 }
356
357 difference -= remove.count;
358 }
359
360 for (const QQmlChangeSet::Change &insert : changeSet.inserts()) {
361 int index = qMin(insert.index, m_deletables.size());
362 if (insert.isMove()) {
363 QVector<QPointer<QQuick3DNode> > items = moved.value(insert.moveId);
364 m_deletables = m_deletables.mid(0, index) + items + m_deletables.mid(index);
365 } else for (int i = 0; i < insert.count; ++i) {
366 int modelIndex = index + i;
367 ++m_itemCount;
368 m_deletables.insert(modelIndex, nullptr);
369 QObject *object = m_model->object(modelIndex, QQmlIncubator::AsynchronousIfNested);
370 if (object)
371 m_model->release(object);
372 }
373 difference += insert.count;
374 }
375
376 if (difference != 0)
378}
379
380void QQuick3DRepeater::requestItems()
381{
382 for (int i = 0; i < m_itemCount; i++) {
384 if (object)
385 m_model->release(object);
386 }
387}
388
390
391#include "moc_qquick3drepeater_p.cpp"
void setParentItem(QGraphicsItem *parent)
Sets this item's parent item to newParent.
The QJSValue class acts as a container for Qt/JavaScript data types.
Definition qjsvalue.h:31
\inmodule QtCore
Definition qobject.h:103
T * data() const noexcept
Definition qpointer.h:73
The QQmlChangeSet class stores an ordered list of notifications about changes to a linear data set.
int difference() const
The QQmlComponent class encapsulates a QML component definition.
void setModel(const QVariant &)
void setDelegate(QQmlComponent *)
virtual bool isValid() const =0
virtual ReleaseFlags release(QObject *object, ReusableFlag reusableFlag=NotReusable)=0
void componentComplete() override
Invoked after the root component that caused this instantiation has completed construction.
\qmltype Object3D \inqmlmodule QtQuick3D \instantiates QQuick3DObject \inherits QtObject
virtual void itemChange(ItemChange, const ItemChangeData &)
bool isComponentComplete() const
void objectAdded(int index, QQuick3DObject *object)
virtual void initDelegate(int, QQuick3DNode *)
void setDelegate(QQmlComponent *)
QQmlComponent * delegate
~QQuick3DRepeater() override
Q_INVOKABLE QQuick3DObject * objectAt(int index) const
\qmlmethod Object3D QtQuick3D::Repeater3D::objectAt(index)
void objectRemoved(int index, QQuick3DObject *object)
void componentComplete() override
Invoked after the root component that caused this instantiation has completed construction.
void setModel(const QVariant &)
void itemChange(ItemChange change, const ItemChangeData &value) override
QQuick3DRepeater(QQuick3DNode *parent=nullptr)
\qmltype Repeater3D \inqmlmodule QtQuick3D \inherits Node
void delegateChanged()
\inmodule QtCore
Definition qvariant.h:65
T value() const &
Definition qvariant.h:516
int userType() const
Definition qvariant.h:339
static auto fromValue(T &&value) noexcept(std::is_nothrow_copy_constructible_v< T > &&Private::CanUseInternalSpace< T >) -> std::enable_if_t< std::conjunction_v< std::is_copy_constructible< T >, std::is_destructible< T > >, QVariant >
Definition qvariant.h:536
#define this
Definition dialogs.cpp:9
cache insert(employee->id(), employee)
Combined button and popup list for selecting options.
EGLOutputLayerEXT EGLint EGLAttrib value
[5]
constexpr const T & qMin(const T &a, const T &b)
Definition qminmax.h:40
#define SLOT(a)
Definition qobjectdefs.h:52
#define SIGNAL(a)
Definition qobjectdefs.h:53
const GLfloat * m
GLuint index
[2]
GLenum GLenum GLsizei count
GLuint object
[3]
GLboolean reset
QQmlContext * qmlContext(const QObject *obj)
Definition qqml.cpp:75
#define qmlobject_disconnect(Sender, SenderType, Signal, Receiver, ReceiverType, Method)
Disconnect Signal of Sender from Method of Receiver.
#define qmlobject_connect(Sender, SenderType, Signal, Receiver, ReceiverType, Method)
Connect Signal of Sender to Method of Receiver.
Q_QML_EXPORT QQmlInfo qmlWarning(const QObject *me)
#define tr(X)
#define emit
static QVariant toVariant(const QV4::Value &value, QMetaType typeHint, JSToQVariantConversionBehavior conversionBehavior, V4ObjectSet *visitedObjects)
settings remove("monkey")
QObject::connect nullptr
QGraphicsItem * item
QList< QTreeWidgetItem * > items