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
qquickrepeater.cpp
Go to the documentation of this file.
1// Copyright (C) 2016 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#include "qquickrepeater_p.h"
6
7#include <private/qqmlglobal_p.h>
8#include <private/qqmlchangeset_p.h>
9#include <private/qqmldelegatemodel_p.h>
10
11#include <QtQml/QQmlInfo>
12
14
16 : model(nullptr)
17 , ownModel(false)
18 , dataSourceIsObject(false)
19 , delegateValidated(false)
20 , itemCount(0)
21{
23}
24
26{
27 if (ownModel)
28 delete model;
29}
30
122
126
146{
147 Q_D(const QQuickRepeater);
148
149 if (d->dataSourceIsObject) {
150 QObject *o = d->dataSourceAsObject;
151 return QVariant::fromValue(o);
152 }
153
154 return d->dataSource;
155}
156
158{
159 Q_D(QQuickRepeater);
160 QVariant model = m;
161 if (model.userType() == qMetaTypeId<QJSValue>())
163
164 if (d->dataSource == model)
165 return;
166
167 clear();
168 if (d->model) {
169 qmlobject_disconnect(d->model, QQmlInstanceModel, SIGNAL(modelUpdated(QQmlChangeSet,bool)),
170 this, QQuickRepeater, SLOT(modelUpdated(QQmlChangeSet,bool)));
171 qmlobject_disconnect(d->model, QQmlInstanceModel, SIGNAL(createdItem(int,QObject*)),
172 this, QQuickRepeater, SLOT(createdItem(int,QObject*)));
173 qmlobject_disconnect(d->model, QQmlInstanceModel, SIGNAL(initItem(int,QObject*)),
174 this, QQuickRepeater, SLOT(initItem(int,QObject*)));
175 }
176 d->dataSource = model;
177 QObject *object = qvariant_cast<QObject*>(model);
178 d->dataSourceAsObject = object;
179 d->dataSourceIsObject = object != nullptr;
180 QQmlInstanceModel *vim = nullptr;
181 if (object && (vim = qobject_cast<QQmlInstanceModel *>(object))) {
182 if (d->ownModel) {
183 delete d->model;
184 d->ownModel = false;
185 }
186 d->model = vim;
187 } else {
188 if (!d->ownModel) {
189 d->model = new QQmlDelegateModel(qmlContext(this));
190 d->ownModel = true;
192 static_cast<QQmlDelegateModel *>(d->model.data())->componentComplete();
193 }
194 if (QQmlDelegateModel *dataModel = qobject_cast<QQmlDelegateModel*>(d->model))
195 dataModel->setModel(model);
196 }
197 if (d->model) {
198 qmlobject_connect(d->model, QQmlInstanceModel, SIGNAL(modelUpdated(QQmlChangeSet,bool)),
199 this, QQuickRepeater, SLOT(modelUpdated(QQmlChangeSet,bool)));
200 qmlobject_connect(d->model, QQmlInstanceModel, SIGNAL(createdItem(int,QObject*)),
201 this, QQuickRepeater, SLOT(createdItem(int,QObject*)));
202 qmlobject_connect(d->model, QQmlInstanceModel, SIGNAL(initItem(int,QObject*)),
203 this, QQuickRepeater, SLOT(initItem(int,QObject*)));
204 regenerate();
205 }
208}
209
244{
245 Q_D(const QQuickRepeater);
246 if (d->model) {
247 if (QQmlDelegateModel *dataModel = qobject_cast<QQmlDelegateModel*>(d->model))
248 return dataModel->delegate();
249 }
250
251 return nullptr;
252}
253
255{
256 Q_D(QQuickRepeater);
257 if (QQmlDelegateModel *dataModel = qobject_cast<QQmlDelegateModel*>(d->model))
258 if (delegate == dataModel->delegate())
259 return;
260
261 if (!d->ownModel) {
262 d->model = new QQmlDelegateModel(qmlContext(this));
263 d->ownModel = true;
264 }
265
266 if (QQmlDelegateModel *dataModel = qobject_cast<QQmlDelegateModel*>(d->model)) {
267 dataModel->setDelegate(delegate);
268 regenerate();
270 d->delegateValidated = false;
271 }
272}
273
284{
285 Q_D(const QQuickRepeater);
286 if (d->model)
287 return d->model->count();
288 return 0;
289}
290
298{
299 Q_D(const QQuickRepeater);
300 if (index >= 0 && index < d->deletables.size())
301 return d->deletables[index];
302 return nullptr;
303}
304
306{
307 Q_D(QQuickRepeater);
308 if (d->model && d->ownModel)
309 static_cast<QQmlDelegateModel *>(d->model.data())->componentComplete();
311 regenerate();
312 if (d->model && d->model->count())
314}
315
317{
319 if (change == ItemParentHasChanged) {
320 regenerate();
321 }
322}
323
324void QQuickRepeater::clear()
325{
326 Q_D(QQuickRepeater);
327 bool complete = isComponentComplete();
328
329 if (d->model) {
330 // We remove in reverse order deliberately; so that signals are emitted
331 // with sensible indices.
332 for (int i = d->deletables.size() - 1; i >= 0; --i) {
333 if (QQuickItem *item = d->deletables.at(i)) {
334 if (complete)
336 d->model->release(item);
337 }
338 }
339 for (QQuickItem *item : std::as_const(d->deletables)) {
340 if (item)
341 item->setParentItem(nullptr);
342 }
343 }
344 d->deletables.clear();
345 d->itemCount = 0;
346}
347
348void QQuickRepeater::regenerate()
349{
350 Q_D(QQuickRepeater);
351 if (!isComponentComplete())
352 return;
353
354 clear();
355
356 if (!d->model || !d->model->count() || !d->model->isValid() || !parentItem() || !isComponentComplete())
357 return;
358
359 d->itemCount = count();
360 d->deletables.resize(d->itemCount);
361 d->requestItems();
362}
363
364void QQuickRepeaterPrivate::requestItems()
365{
366 for (int i = 0; i < itemCount; i++) {
368 if (object)
369 model->release(object);
370 }
371}
372
373void QQuickRepeater::createdItem(int index, QObject *)
374{
375 Q_D(QQuickRepeater);
376 QObject *object = d->model->object(index, QQmlIncubator::AsynchronousIfNested);
379}
380
381void QQuickRepeater::initItem(int index, QObject *object)
382{
383 Q_D(QQuickRepeater);
384 if (index >= d->deletables.size()) {
385 // this can happen when Package is used
386 // calling regenerate does too much work, all we need is to call resize
387 // so that d->deletables[index] = item below works
388 d->deletables.resize(d->model->count() + 1);
389 }
391
392 if (!d->deletables.at(index)) {
393 if (!item) {
394 if (object) {
395 d->model->release(object);
396 if (!d->delegateValidated) {
397 d->delegateValidated = true;
398 QObject* delegate = this->delegate();
399 qmlWarning(delegate ? delegate : this) << QQuickRepeater::tr("Delegate must be of Item type");
400 }
401 }
402 return;
403 }
404 d->deletables[index] = item;
406
407 // If the item comes from an ObjectModel, it might be used as
408 // ComboBox/Menu/TabBar's contentItem. These types unconditionally cull items
409 // that are inserted, so account for that here.
410 if (d->dataSourceIsObject)
411 QQuickItemPrivate::get(item)->setCulled(false);
412 if (index > 0 && d->deletables.at(index-1)) {
413 item->stackAfter(d->deletables.at(index-1));
414 } else {
415 QQuickItem *after = this;
416 for (int si = index+1; si < d->itemCount; ++si) {
417 if (d->deletables.at(si)) {
418 after = d->deletables.at(si);
419 break;
420 }
421 }
422 item->stackBefore(after);
423 }
424 }
425}
426
427void QQuickRepeater::modelUpdated(const QQmlChangeSet &changeSet, bool reset)
428{
429 Q_D(QQuickRepeater);
430
431 if (!isComponentComplete())
432 return;
433
434 if (reset) {
435 regenerate();
436 if (changeSet.difference() != 0)
438 return;
439 }
440
441 int difference = 0;
442 QHash<int, QVector<QPointer<QQuickItem> > > moved;
443 for (const QQmlChangeSet::Change &remove : changeSet.removes()) {
444 int index = qMin(remove.index, d->deletables.size());
445 int count = qMin(remove.index + remove.count, d->deletables.size()) - index;
446 if (remove.isMove()) {
447 moved.insert(remove.moveId, d->deletables.mid(index, count));
448 d->deletables.erase(
449 d->deletables.begin() + index,
450 d->deletables.begin() + index + count);
451 } else while (count--) {
452 QQuickItem *item = d->deletables.at(index);
453 d->deletables.remove(index);
455 if (item) {
456 d->model->release(item);
457 item->setParentItem(nullptr);
458 }
459 --d->itemCount;
460 }
461
462 difference -= remove.count;
463 }
464
465 for (const QQmlChangeSet::Change &insert : changeSet.inserts()) {
466 int index = qMin(insert.index, d->deletables.size());
467 if (insert.isMove()) {
468 QVector<QPointer<QQuickItem> > items = moved.value(insert.moveId);
469 d->deletables = d->deletables.mid(0, index) + items + d->deletables.mid(index);
470 QQuickItem *stackBefore = index + items.size() < d->deletables.size()
471 ? d->deletables.at(index + items.size())
472 : this;
473 if (stackBefore) {
474 for (int i = index; i < index + items.size(); ++i) {
475 if (i < d->deletables.size()) {
476 QPointer<QQuickItem> item = d->deletables.at(i);
477 if (item)
479 }
480 }
481 }
482 } else for (int i = 0; i < insert.count; ++i) {
483 int modelIndex = index + i;
484 ++d->itemCount;
485 d->deletables.insert(modelIndex, nullptr);
486 QObject *object = d->model->object(modelIndex, QQmlIncubator::AsynchronousIfNested);
487 if (object)
488 d->model->release(object);
489 }
490 difference += insert.count;
491 }
492
493 if (difference != 0)
495}
496
498
499#include "moc_qquickrepeater_p.cpp"
void stackBefore(const QGraphicsItem *sibling)
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
qsizetype size() const noexcept
Definition qlist.h:397
\inmodule QtCore
Definition qobject.h:103
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 &)
virtual ReleaseFlags release(QObject *object, ReusableFlag reusableFlag=NotReusable)=0
void setTransparentForPositioner(bool trans)
static QQuickItemPrivate * get(QQuickItem *item)
The QQuickItem class provides the most basic of all visual items in \l {Qt Quick}.
Definition qquickitem.h:63
void componentComplete() override
\reimp Derived classes should call the base class method before adding their own actions to perform a...
QQuickItem * parentItem() const
virtual void itemChange(ItemChange, const ItemChangeData &)
Called when change occurs for this item.
bool isComponentComplete() const
Returns true if construction of the QML component is complete; otherwise returns false.
ItemChange
Used in conjunction with QQuickItem::itemChange() to notify the item about certain types of changes.
Definition qquickitem.h:144
@ ItemParentHasChanged
Definition qquickitem.h:149
void stackBefore(const QQuickItem *)
Moves the specified sibling item to the index before this item within the list of children.
QQmlComponent * delegate
void modelChanged()
void countChanged()
void itemChange(ItemChange change, const ItemChangeData &value) override
Called when change occurs for this item.
void componentComplete() override
\reimp Derived classes should call the base class method before adding their own actions to perform a...
void itemAdded(int index, QQuickItem *item)
void setDelegate(QQmlComponent *)
void itemRemoved(int index, QQuickItem *item)
virtual ~QQuickRepeater()
Q_INVOKABLE QQuickItem * itemAt(int index) const
\qmlmethod Item QtQuick::Repeater::itemAt(index)
void setModel(const QVariant &)
QQuickRepeater(QQuickItem *parent=nullptr)
\qmlsignal QtQuick::Repeater::itemAdded(int index, Item item)
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.
QQuickItem * qmlobject_cast< QQuickItem * >(QObject *object)
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)
QSqlQueryModel * model
[16]
settings remove("monkey")
QObject::connect nullptr
QGraphicsItem * item
QList< QTreeWidgetItem * > items
\inmodule QtQuick
Definition qquickitem.h:159