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 "qquickitemview_p_p.h"
5#include "qquickitemviewfxitem_p_p.h"
6#include <QtQuick/private/qquicktransition_p.h>
7#include <QtQml/QQmlInfo>
8#include "qplatformdefs.h"
9
10QT_BEGIN_NAMESPACE
11
12Q_LOGGING_CATEGORY(lcItemViewDelegateLifecycle, "qt.quick.itemview.lifecycle")
13Q_LOGGING_CATEGORY(lcCount, "qt.quick.itemview.count")
14
15// Default cacheBuffer for all views.
16#ifndef QML_VIEW_DEFAULTCACHEBUFFER
17#define QML_VIEW_DEFAULTCACHEBUFFER 320
18#endif
19
20FxViewItem::FxViewItem(QQuickItem *i, QQuickItemView *v, bool own, QQuickItemViewAttached *attached)
21 : QQuickItemViewFxItem(i, own, QQuickItemViewPrivate::get(o: v))
22 , view(v)
23 , attached(attached)
24{
25}
26
27QQuickItemViewChangeSet::QQuickItemViewChangeSet()
28 : active(false)
29{
30 reset();
31}
32
33bool QQuickItemViewChangeSet::hasPendingChanges() const
34{
35 return !pendingChanges.isEmpty();
36}
37
38void QQuickItemViewChangeSet::applyChanges(const QQmlChangeSet &changeSet)
39{
40 pendingChanges.apply(changeSet);
41
42 int moveId = -1;
43 int moveOffset = 0;
44
45 for (const QQmlChangeSet::Change &r : changeSet.removes()) {
46 itemCount -= r.count;
47 if (moveId == -1 && newCurrentIndex >= r.index + r.count) {
48 newCurrentIndex -= r.count;
49 currentChanged = true;
50 } else if (moveId == -1 && newCurrentIndex >= r.index && newCurrentIndex < r.index + r.count) {
51 // current item has been removed.
52 if (r.isMove()) {
53 moveId = r.moveId;
54 moveOffset = newCurrentIndex - r.index;
55 } else {
56 currentRemoved = true;
57 newCurrentIndex = -1;
58 if (itemCount)
59 newCurrentIndex = qMin(a: r.index, b: itemCount - 1);
60 }
61 currentChanged = true;
62 }
63 }
64 for (const QQmlChangeSet::Change &i : changeSet.inserts()) {
65 if (moveId == -1) {
66 if (itemCount && newCurrentIndex >= i.index) {
67 newCurrentIndex += i.count;
68 currentChanged = true;
69 } else if (newCurrentIndex < 0) {
70 newCurrentIndex = 0;
71 currentChanged = true;
72 } else if (newCurrentIndex == 0 && !itemCount) {
73 // this is the first item, set the initial current index
74 currentChanged = true;
75 }
76 } else if (moveId == i.moveId) {
77 newCurrentIndex = i.index + moveOffset;
78 }
79 itemCount += i.count;
80 }
81}
82
83void QQuickItemViewChangeSet::applyBufferedChanges(const QQuickItemViewChangeSet &other)
84{
85 if (!other.hasPendingChanges())
86 return;
87
88 pendingChanges.apply(changeSet: other.pendingChanges);
89 itemCount = other.itemCount;
90 newCurrentIndex = other.newCurrentIndex;
91 currentChanged = other.currentChanged;
92 currentRemoved = other.currentRemoved;
93}
94
95void QQuickItemViewChangeSet::prepare(int currentIndex, int count)
96{
97 if (active)
98 return;
99 reset();
100 active = true;
101 itemCount = count;
102 newCurrentIndex = currentIndex;
103}
104
105void QQuickItemViewChangeSet::reset()
106{
107 itemCount = 0;
108 newCurrentIndex = -1;
109 pendingChanges.clear();
110 removedItems.clear();
111 active = false;
112 currentChanged = false;
113 currentRemoved = false;
114}
115
116//-----------------------------------
117
118QQuickItemView::QQuickItemView(QQuickFlickablePrivate &dd, QQuickItem *parent)
119 : QQuickFlickable(dd, parent)
120{
121 Q_D(QQuickItemView);
122 d->init();
123}
124
125QQuickItemView::~QQuickItemView()
126{
127 Q_D(QQuickItemView);
128 d->clear(onDestruction: true);
129 if (d->ownModel)
130 delete d->model;
131 delete d->header;
132 delete d->footer;
133}
134
135
136QQuickItem *QQuickItemView::currentItem() const
137{
138 Q_D(const QQuickItemView);
139 return d->currentItem ? d->currentItem->item : nullptr;
140}
141
142QVariant QQuickItemView::model() const
143{
144 Q_D(const QQuickItemView);
145 return d->modelVariant;
146}
147
148void QQuickItemView::setModel(const QVariant &m)
149{
150 Q_D(QQuickItemView);
151 QVariant model = m;
152 if (model.userType() == qMetaTypeId<QJSValue>())
153 model = model.value<QJSValue>().toVariant();
154
155 if (d->modelVariant == model)
156 return;
157 if (d->model) {
158 disconnect(sender: d->model, SIGNAL(modelUpdated(QQmlChangeSet,bool)),
159 receiver: this, SLOT(modelUpdated(QQmlChangeSet,bool)));
160 disconnect(sender: d->model, SIGNAL(initItem(int,QObject*)), receiver: this, SLOT(initItem(int,QObject*)));
161 disconnect(sender: d->model, SIGNAL(createdItem(int,QObject*)), receiver: this, SLOT(createdItem(int,QObject*)));
162 disconnect(sender: d->model, SIGNAL(destroyingItem(QObject*)), receiver: this, SLOT(destroyingItem(QObject*)));
163 if (QQmlDelegateModel *delegateModel = qobject_cast<QQmlDelegateModel*>(object: d->model)) {
164 disconnect(sender: delegateModel, SIGNAL(itemPooled(int,QObject*)), receiver: this, SLOT(onItemPooled(int,QObject*)));
165 disconnect(sender: delegateModel, SIGNAL(itemReused(int,QObject*)), receiver: this, SLOT(onItemReused(int,QObject*)));
166 }
167 }
168
169 QQmlInstanceModel *oldModel = d->model;
170
171 d->clear();
172 d->model = nullptr;
173 d->setPosition(d->contentStartOffset());
174 d->modelVariant = model;
175
176 QObject *object = qvariant_cast<QObject*>(v: model);
177 QQmlInstanceModel *vim = nullptr;
178 if (object && (vim = qobject_cast<QQmlInstanceModel *>(object))) {
179 if (d->ownModel) {
180 delete oldModel;
181 d->ownModel = false;
182 }
183 d->model = vim;
184 } else {
185 if (!d->ownModel) {
186 d->model = new QQmlDelegateModel(qmlContext(this), this);
187 d->ownModel = true;
188 if (isComponentComplete())
189 static_cast<QQmlDelegateModel *>(d->model.data())->componentComplete();
190 } else {
191 d->model = oldModel;
192 }
193 if (QQmlDelegateModel *dataModel = qobject_cast<QQmlDelegateModel*>(object: d->model))
194 dataModel->setModel(model);
195 }
196
197 if (d->model) {
198 d->bufferMode = QQuickItemViewPrivate::BufferBefore | QQuickItemViewPrivate::BufferAfter;
199 connect(sender: d->model, SIGNAL(createdItem(int,QObject*)), receiver: this, SLOT(createdItem(int,QObject*)));
200 connect(sender: d->model, SIGNAL(initItem(int,QObject*)), receiver: this, SLOT(initItem(int,QObject*)));
201 connect(sender: d->model, SIGNAL(destroyingItem(QObject*)), receiver: this, SLOT(destroyingItem(QObject*)));
202 if (QQmlDelegateModel *delegateModel = qobject_cast<QQmlDelegateModel*>(object: d->model)) {
203 connect(sender: delegateModel, SIGNAL(itemPooled(int,QObject*)), receiver: this, SLOT(onItemPooled(int,QObject*)));
204 connect(sender: delegateModel, SIGNAL(itemReused(int,QObject*)), receiver: this, SLOT(onItemReused(int,QObject*)));
205 }
206 if (isComponentComplete()) {
207 d->updateSectionCriteria();
208 d->refill();
209 /* Setting currentIndex to -2 ensures that we always enter the "currentIndex changed"
210 code path in setCurrentIndex, updating bindings depending on currentIndex.*/
211 d->currentIndex = -2;
212 setCurrentIndex(d->model->count() > 0 ? 0 : -1);
213 d->updateViewport();
214
215#if QT_CONFIG(quick_viewtransitions)
216 if (d->transitioner && d->transitioner->populateTransition) {
217 d->transitioner->setPopulateTransitionEnabled(true);
218 d->forceLayoutPolish();
219 }
220#endif
221 }
222
223 connect(sender: d->model, SIGNAL(modelUpdated(QQmlChangeSet,bool)),
224 receiver: this, SLOT(modelUpdated(QQmlChangeSet,bool)));
225 if (QQmlDelegateModel *dataModel = qobject_cast<QQmlDelegateModel*>(object: d->model))
226 QObjectPrivate::connect(sender: dataModel, signal: &QQmlDelegateModel::delegateChanged, receiverPrivate: d, slot: &QQuickItemViewPrivate::applyDelegateChange);
227 d->emitCountChanged();
228 }
229 emit modelChanged();
230 d->moveReason = QQuickItemViewPrivate::Other;
231}
232
233QQmlComponent *QQuickItemView::delegate() const
234{
235 Q_D(const QQuickItemView);
236 if (d->model) {
237 if (QQmlDelegateModel *dataModel = qobject_cast<QQmlDelegateModel*>(object: d->model))
238 return dataModel->delegate();
239 }
240
241 return nullptr;
242}
243
244void QQuickItemView::setDelegate(QQmlComponent *delegate)
245{
246 Q_D(QQuickItemView);
247 if (delegate == this->delegate())
248 return;
249 if (!d->ownModel) {
250 d->model = new QQmlDelegateModel(qmlContext(this));
251 d->ownModel = true;
252 if (isComponentComplete())
253 static_cast<QQmlDelegateModel *>(d->model.data())->componentComplete();
254 }
255 if (QQmlDelegateModel *dataModel = qobject_cast<QQmlDelegateModel*>(object: d->model)) {
256 int oldCount = dataModel->count();
257 dataModel->setDelegate(delegate);
258 if (oldCount != dataModel->count())
259 d->emitCountChanged();
260 }
261 emit delegateChanged();
262 d->delegateValidated = false;
263}
264
265
266int QQuickItemView::count() const
267{
268 Q_D(const QQuickItemView);
269 if (!d->model)
270 return 0;
271 return d->model->count();
272}
273
274int QQuickItemView::currentIndex() const
275{
276 Q_D(const QQuickItemView);
277 return d->currentIndex;
278}
279
280void QQuickItemView::setCurrentIndex(int index)
281{
282 Q_D(QQuickItemView);
283 if (d->inRequest) // currently creating item
284 return;
285 d->currentIndexCleared = (index == -1);
286
287 d->applyPendingChanges();
288 if (index == d->currentIndex)
289 return;
290 if (isComponentComplete() && d->isValid()) {
291 d->moveReason = QQuickItemViewPrivate::SetIndex;
292 d->updateCurrent(modelIndex: index);
293 } else if (d->currentIndex != index) {
294 d->currentIndex = index;
295 emit currentIndexChanged();
296 }
297}
298
299
300bool QQuickItemView::isWrapEnabled() const
301{
302 Q_D(const QQuickItemView);
303 return d->wrap;
304}
305
306void QQuickItemView::setWrapEnabled(bool wrap)
307{
308 Q_D(QQuickItemView);
309 if (d->wrap == wrap)
310 return;
311 d->wrap = wrap;
312 emit keyNavigationWrapsChanged();
313}
314
315bool QQuickItemView::isKeyNavigationEnabled() const
316{
317 Q_D(const QQuickItemView);
318 return d->explicitKeyNavigationEnabled ? d->keyNavigationEnabled : d->interactive;
319}
320
321void QQuickItemView::setKeyNavigationEnabled(bool keyNavigationEnabled)
322{
323 // TODO: default binding to "interactive" can be removed in Qt 6; it only exists for compatibility reasons.
324 Q_D(QQuickItemView);
325 const bool wasImplicit = !d->explicitKeyNavigationEnabled;
326 if (wasImplicit)
327 QObject::disconnect(sender: this, signal: &QQuickFlickable::interactiveChanged, receiver: this, slot: &QQuickItemView::keyNavigationEnabledChanged);
328
329 d->explicitKeyNavigationEnabled = true;
330
331 // Ensure that we emit the change signal in case there is no different in value.
332 if (d->keyNavigationEnabled != keyNavigationEnabled || wasImplicit) {
333 d->keyNavigationEnabled = keyNavigationEnabled;
334 emit keyNavigationEnabledChanged();
335 }
336}
337
338int QQuickItemView::cacheBuffer() const
339{
340 Q_D(const QQuickItemView);
341 return d->buffer;
342}
343
344void QQuickItemView::setCacheBuffer(int b)
345{
346 Q_D(QQuickItemView);
347 if (b < 0) {
348 qmlWarning(me: this) << "Cannot set a negative cache buffer";
349 return;
350 }
351
352 if (d->buffer != b) {
353 d->buffer = b;
354 if (isComponentComplete()) {
355 d->bufferMode = QQuickItemViewPrivate::BufferBefore | QQuickItemViewPrivate::BufferAfter;
356 d->refillOrLayout();
357 }
358 emit cacheBufferChanged();
359 }
360}
361
362int QQuickItemView::displayMarginBeginning() const
363{
364 Q_D(const QQuickItemView);
365 return d->displayMarginBeginning;
366}
367
368void QQuickItemView::setDisplayMarginBeginning(int margin)
369{
370 Q_D(QQuickItemView);
371 if (d->displayMarginBeginning != margin) {
372 d->displayMarginBeginning = margin;
373 if (isComponentComplete()) {
374 d->forceLayoutPolish();
375 }
376 emit displayMarginBeginningChanged();
377 }
378}
379
380int QQuickItemView::displayMarginEnd() const
381{
382 Q_D(const QQuickItemView);
383 return d->displayMarginEnd;
384}
385
386void QQuickItemView::setDisplayMarginEnd(int margin)
387{
388 Q_D(QQuickItemView);
389 if (d->displayMarginEnd != margin) {
390 d->displayMarginEnd = margin;
391 if (isComponentComplete()) {
392 d->forceLayoutPolish();
393 }
394 emit displayMarginEndChanged();
395 }
396}
397
398Qt::LayoutDirection QQuickItemView::layoutDirection() const
399{
400 Q_D(const QQuickItemView);
401 return d->layoutDirection;
402}
403
404void QQuickItemView::setLayoutDirection(Qt::LayoutDirection layoutDirection)
405{
406 Q_D(QQuickItemView);
407 if (d->layoutDirection != layoutDirection) {
408 d->layoutDirection = layoutDirection;
409 d->regenerate();
410 emit layoutDirectionChanged();
411 emit effectiveLayoutDirectionChanged();
412 }
413}
414
415Qt::LayoutDirection QQuickItemView::effectiveLayoutDirection() const
416{
417 Q_D(const QQuickItemView);
418 if (d->effectiveLayoutMirror)
419 return d->layoutDirection == Qt::RightToLeft ? Qt::LeftToRight : Qt::RightToLeft;
420 else
421 return d->layoutDirection;
422}
423
424QQuickItemView::VerticalLayoutDirection QQuickItemView::verticalLayoutDirection() const
425{
426 Q_D(const QQuickItemView);
427 return d->verticalLayoutDirection;
428}
429
430void QQuickItemView::setVerticalLayoutDirection(VerticalLayoutDirection layoutDirection)
431{
432 Q_D(QQuickItemView);
433 if (d->verticalLayoutDirection != layoutDirection) {
434 d->verticalLayoutDirection = layoutDirection;
435 d->regenerate();
436 emit verticalLayoutDirectionChanged();
437 }
438}
439
440QQmlComponent *QQuickItemView::header() const
441{
442 Q_D(const QQuickItemView);
443 return d->headerComponent;
444}
445
446QQuickItem *QQuickItemView::headerItem() const
447{
448 Q_D(const QQuickItemView);
449 return d->header ? d->header->item : nullptr;
450}
451
452void QQuickItemView::setHeader(QQmlComponent *headerComponent)
453{
454 Q_D(QQuickItemView);
455 if (d->headerComponent != headerComponent) {
456 d->applyPendingChanges();
457 delete d->header;
458 d->header = nullptr;
459 d->headerComponent = headerComponent;
460
461 d->markExtentsDirty();
462
463 if (isComponentComplete()) {
464 d->updateHeader();
465 d->updateFooter();
466 d->updateViewport();
467 d->fixupPosition();
468 } else {
469 emit headerItemChanged();
470 }
471 emit headerChanged();
472 }
473}
474
475QQmlComponent *QQuickItemView::footer() const
476{
477 Q_D(const QQuickItemView);
478 return d->footerComponent;
479}
480
481QQuickItem *QQuickItemView::footerItem() const
482{
483 Q_D(const QQuickItemView);
484 return d->footer ? d->footer->item : nullptr;
485}
486
487void QQuickItemView::setFooter(QQmlComponent *footerComponent)
488{
489 Q_D(QQuickItemView);
490 if (d->footerComponent != footerComponent) {
491 d->applyPendingChanges();
492 delete d->footer;
493 d->footer = nullptr;
494 d->footerComponent = footerComponent;
495
496 if (isComponentComplete()) {
497 d->updateFooter();
498 d->updateViewport();
499 d->fixupPosition();
500 } else {
501 emit footerItemChanged();
502 }
503 emit footerChanged();
504 }
505}
506
507QQmlComponent *QQuickItemView::highlight() const
508{
509 Q_D(const QQuickItemView);
510 return d->highlightComponent;
511}
512
513void QQuickItemView::setHighlight(QQmlComponent *highlightComponent)
514{
515 Q_D(QQuickItemView);
516 if (highlightComponent != d->highlightComponent) {
517 d->applyPendingChanges();
518 d->highlightComponent = highlightComponent;
519 d->createHighlight();
520 if (d->currentItem)
521 d->updateHighlight();
522 emit highlightChanged();
523 }
524}
525
526QQuickItem *QQuickItemView::highlightItem() const
527{
528 Q_D(const QQuickItemView);
529 return d->highlight ? d->highlight->item : nullptr;
530}
531
532bool QQuickItemView::highlightFollowsCurrentItem() const
533{
534 Q_D(const QQuickItemView);
535 return d->autoHighlight;
536}
537
538void QQuickItemView::setHighlightFollowsCurrentItem(bool autoHighlight)
539{
540 Q_D(QQuickItemView);
541 if (d->autoHighlight != autoHighlight) {
542 d->autoHighlight = autoHighlight;
543 if (autoHighlight)
544 d->updateHighlight();
545 emit highlightFollowsCurrentItemChanged();
546 }
547}
548
549QQuickItemView::HighlightRangeMode QQuickItemView::highlightRangeMode() const
550{
551 Q_D(const QQuickItemView);
552 return static_cast<QQuickItemView::HighlightRangeMode>(d->highlightRange);
553}
554
555void QQuickItemView::setHighlightRangeMode(HighlightRangeMode mode)
556{
557 Q_D(QQuickItemView);
558 if (d->highlightRange == mode)
559 return;
560 d->highlightRange = mode;
561 d->haveHighlightRange = d->highlightRange != NoHighlightRange && d->highlightRangeStart <= d->highlightRangeEnd;
562 if (isComponentComplete()) {
563 d->updateViewport();
564 d->moveReason = QQuickItemViewPrivate::Other;
565 d->fixupPosition();
566 }
567 emit highlightRangeModeChanged();
568}
569
570//###Possibly rename these properties, since they are very useful even without a highlight?
571qreal QQuickItemView::preferredHighlightBegin() const
572{
573 Q_D(const QQuickItemView);
574 return d->highlightRangeStart;
575}
576
577void QQuickItemView::setPreferredHighlightBegin(qreal start)
578{
579 Q_D(QQuickItemView);
580 d->highlightRangeStartValid = true;
581 if (d->highlightRangeStart == start)
582 return;
583 d->highlightRangeStart = start;
584 d->haveHighlightRange = d->highlightRange != NoHighlightRange && d->highlightRangeStart <= d->highlightRangeEnd;
585 if (isComponentComplete()) {
586 d->updateViewport();
587 if (!isMoving() && !isFlicking()) {
588 d->moveReason = QQuickItemViewPrivate::Other;
589 d->fixupPosition();
590 }
591 }
592 emit preferredHighlightBeginChanged();
593}
594
595void QQuickItemView::resetPreferredHighlightBegin()
596{
597 Q_D(QQuickItemView);
598 d->highlightRangeStartValid = false;
599 if (d->highlightRangeStart == 0)
600 return;
601 d->highlightRangeStart = 0;
602 if (isComponentComplete()) {
603 d->updateViewport();
604 if (!isMoving() && !isFlicking()) {
605 d->moveReason = QQuickItemViewPrivate::Other;
606 d->fixupPosition();
607 }
608 }
609 emit preferredHighlightBeginChanged();
610}
611
612qreal QQuickItemView::preferredHighlightEnd() const
613{
614 Q_D(const QQuickItemView);
615 return d->highlightRangeEnd;
616}
617
618void QQuickItemView::setPreferredHighlightEnd(qreal end)
619{
620 Q_D(QQuickItemView);
621 d->highlightRangeEndValid = true;
622 if (d->highlightRangeEnd == end)
623 return;
624 d->highlightRangeEnd = end;
625 d->haveHighlightRange = d->highlightRange != NoHighlightRange && d->highlightRangeStart <= d->highlightRangeEnd;
626 if (isComponentComplete()) {
627 d->updateViewport();
628 if (!isMoving() && !isFlicking()) {
629 d->moveReason = QQuickItemViewPrivate::Other;
630 d->fixupPosition();
631 }
632 }
633 emit preferredHighlightEndChanged();
634}
635
636void QQuickItemView::resetPreferredHighlightEnd()
637{
638 Q_D(QQuickItemView);
639 d->highlightRangeEndValid = false;
640 if (d->highlightRangeEnd == 0)
641 return;
642 d->highlightRangeEnd = 0;
643 if (isComponentComplete()) {
644 d->updateViewport();
645 if (!isMoving() && !isFlicking()) {
646 d->moveReason = QQuickItemViewPrivate::Other;
647 d->fixupPosition();
648 }
649 }
650 emit preferredHighlightEndChanged();
651}
652
653int QQuickItemView::highlightMoveDuration() const
654{
655 Q_D(const QQuickItemView);
656 return d->highlightMoveDuration;
657}
658
659void QQuickItemView::setHighlightMoveDuration(int duration)
660{
661 Q_D(QQuickItemView);
662 if (d->highlightMoveDuration != duration) {
663 d->highlightMoveDuration = duration;
664 emit highlightMoveDurationChanged();
665 }
666}
667
668bool QQuickItemView::reuseItems() const
669{
670 return bool(d_func()->reusableFlag == QQmlDelegateModel::Reusable);
671}
672
673void QQuickItemView::setReuseItems(bool reuse)
674{
675 Q_D(QQuickItemView);
676 if (reuseItems() == reuse)
677 return;
678
679 d->reusableFlag = reuse ? QQmlDelegateModel::Reusable : QQmlDelegateModel::NotReusable;
680
681 if (!reuse && d->model) {
682 // When we're told to not reuse items, we
683 // immediately, as documented, drain the pool.
684 d->model->drainReusableItemsPool(maxPoolTime: 0);
685 }
686
687 emit reuseItemsChanged();
688}
689
690#if QT_CONFIG(quick_viewtransitions)
691QQuickTransition *QQuickItemView::populateTransition() const
692{
693 Q_D(const QQuickItemView);
694 return d->transitioner ? d->transitioner->populateTransition : nullptr;
695}
696
697void QQuickItemView::setPopulateTransition(QQuickTransition *transition)
698{
699 Q_D(QQuickItemView);
700 d->createTransitioner();
701 if (d->transitioner->populateTransition != transition) {
702 d->transitioner->populateTransition = transition;
703 emit populateTransitionChanged();
704 }
705}
706
707QQuickTransition *QQuickItemView::addTransition() const
708{
709 Q_D(const QQuickItemView);
710 return d->transitioner ? d->transitioner->addTransition : nullptr;
711}
712
713void QQuickItemView::setAddTransition(QQuickTransition *transition)
714{
715 Q_D(QQuickItemView);
716 d->createTransitioner();
717 if (d->transitioner->addTransition != transition) {
718 d->transitioner->addTransition = transition;
719 emit addTransitionChanged();
720 }
721}
722
723QQuickTransition *QQuickItemView::addDisplacedTransition() const
724{
725 Q_D(const QQuickItemView);
726 return d->transitioner ? d->transitioner->addDisplacedTransition : nullptr;
727}
728
729void QQuickItemView::setAddDisplacedTransition(QQuickTransition *transition)
730{
731 Q_D(QQuickItemView);
732 d->createTransitioner();
733 if (d->transitioner->addDisplacedTransition != transition) {
734 d->transitioner->addDisplacedTransition = transition;
735 emit addDisplacedTransitionChanged();
736 }
737}
738
739QQuickTransition *QQuickItemView::moveTransition() const
740{
741 Q_D(const QQuickItemView);
742 return d->transitioner ? d->transitioner->moveTransition : nullptr;
743}
744
745void QQuickItemView::setMoveTransition(QQuickTransition *transition)
746{
747 Q_D(QQuickItemView);
748 d->createTransitioner();
749 if (d->transitioner->moveTransition != transition) {
750 d->transitioner->moveTransition = transition;
751 emit moveTransitionChanged();
752 }
753}
754
755QQuickTransition *QQuickItemView::moveDisplacedTransition() const
756{
757 Q_D(const QQuickItemView);
758 return d->transitioner ? d->transitioner->moveDisplacedTransition : nullptr;
759}
760
761void QQuickItemView::setMoveDisplacedTransition(QQuickTransition *transition)
762{
763 Q_D(QQuickItemView);
764 d->createTransitioner();
765 if (d->transitioner->moveDisplacedTransition != transition) {
766 d->transitioner->moveDisplacedTransition = transition;
767 emit moveDisplacedTransitionChanged();
768 }
769}
770
771QQuickTransition *QQuickItemView::removeTransition() const
772{
773 Q_D(const QQuickItemView);
774 return d->transitioner ? d->transitioner->removeTransition : nullptr;
775}
776
777void QQuickItemView::setRemoveTransition(QQuickTransition *transition)
778{
779 Q_D(QQuickItemView);
780 d->createTransitioner();
781 if (d->transitioner->removeTransition != transition) {
782 d->transitioner->removeTransition = transition;
783 emit removeTransitionChanged();
784 }
785}
786
787QQuickTransition *QQuickItemView::removeDisplacedTransition() const
788{
789 Q_D(const QQuickItemView);
790 return d->transitioner ? d->transitioner->removeDisplacedTransition : nullptr;
791}
792
793void QQuickItemView::setRemoveDisplacedTransition(QQuickTransition *transition)
794{
795 Q_D(QQuickItemView);
796 d->createTransitioner();
797 if (d->transitioner->removeDisplacedTransition != transition) {
798 d->transitioner->removeDisplacedTransition = transition;
799 emit removeDisplacedTransitionChanged();
800 }
801}
802
803QQuickTransition *QQuickItemView::displacedTransition() const
804{
805 Q_D(const QQuickItemView);
806 return d->transitioner ? d->transitioner->displacedTransition : nullptr;
807}
808
809void QQuickItemView::setDisplacedTransition(QQuickTransition *transition)
810{
811 Q_D(QQuickItemView);
812 d->createTransitioner();
813 if (d->transitioner->displacedTransition != transition) {
814 d->transitioner->displacedTransition = transition;
815 emit displacedTransitionChanged();
816 }
817}
818#endif
819
820void QQuickItemViewPrivate::positionViewAtIndex(int index, int mode)
821{
822 if (!isValid())
823 return;
824 if (mode < QQuickItemView::Beginning || mode > QQuickItemView::SnapPosition)
825 return;
826
827 Q_Q(QQuickItemView);
828 q->cancelFlick();
829 applyPendingChanges();
830 const int modelCount = model->count();
831 int idx = qMax(a: qMin(a: index, b: modelCount - 1), b: 0);
832
833 const auto viewSize = size();
834 qreal pos = isContentFlowReversed() ? -position() - viewSize : position();
835 FxViewItem *item = visibleItem(modelIndex: idx);
836 qreal maxExtent = calculatedMaxExtent();
837 if (!item) {
838 qreal itemPos = positionAt(index: idx);
839 changedVisibleIndex(newIndex: idx);
840 // save the currently visible items in case any of them end up visible again
841 const QList<FxViewItem *> oldVisible = visibleItems;
842 visibleItems.clear();
843 setPosition(qMin(a: itemPos, b: maxExtent));
844 // now release the reference to all the old visible items.
845 for (FxViewItem *item : oldVisible)
846 releaseItem(item, reusableFlag);
847 item = visibleItem(modelIndex: idx);
848 }
849 if (item) {
850 const bool stickyHeader = hasStickyHeader();
851 const bool stickyFooter = hasStickyFooter();
852 const qreal stickyHeaderSize = stickyHeader ? headerSize() : 0;
853 const qreal stickyFooterSize = stickyFooter ? footerSize() : 0;
854
855 const qreal itemPos = item->position();
856 switch (mode) {
857 case QQuickItemView::Beginning:
858 pos = itemPos;
859 if (header && (index < 0 || stickyHeader))
860 pos -= headerSize();
861 break;
862 case QQuickItemView::Center:
863 pos = itemPos - (viewSize - item->size())/2;
864 break;
865 case QQuickItemView::End:
866 pos = itemPos - viewSize + item->size();
867 if (footer && (index >= modelCount || stickyFooter))
868 pos += footerSize();
869 break;
870 case QQuickItemView::Visible:
871 if (itemPos > pos + viewSize - stickyFooterSize)
872 pos = item->endPosition() - viewSize + stickyFooterSize;
873 else if (item->endPosition() <= pos - stickyHeaderSize)
874 pos = itemPos - stickyHeaderSize;
875 break;
876 case QQuickItemView::Contain:
877 if (item->endPosition() >= pos + viewSize + stickyFooterSize)
878 pos = itemPos - viewSize + item->size() + stickyFooterSize;
879 if (itemPos - stickyHeaderSize < pos)
880 pos = itemPos - stickyHeaderSize;
881 break;
882 case QQuickItemView::SnapPosition:
883 pos = itemPos - highlightRangeStart - stickyHeaderSize;
884 break;
885 }
886 pos = qMin(a: pos, b: maxExtent);
887 qreal minExtent = calculatedMinExtent();
888 pos = qMax(a: pos, b: minExtent);
889 moveReason = QQuickItemViewPrivate::Other;
890 setPosition(pos);
891
892 if (highlight) {
893 if (autoHighlight)
894 resetHighlightPosition();
895 updateHighlight();
896 }
897 }
898 fixupPosition();
899}
900
901void QQuickItemView::positionViewAtIndex(int index, int mode)
902{
903 Q_D(QQuickItemView);
904 if (!d->isValid() || index < 0 || index >= d->model->count())
905 return;
906 d->positionViewAtIndex(index, mode);
907}
908
909
910void QQuickItemView::positionViewAtBeginning()
911{
912 Q_D(QQuickItemView);
913 if (!d->isValid())
914 return;
915 d->positionViewAtIndex(index: -1, mode: Beginning);
916}
917
918void QQuickItemView::positionViewAtEnd()
919{
920 Q_D(QQuickItemView);
921 if (!d->isValid())
922 return;
923 d->positionViewAtIndex(index: d->model->count(), mode: End);
924}
925
926static FxViewItem * fxViewItemAtPosition(const QList<FxViewItem *> &items, qreal x, qreal y)
927{
928 for (FxViewItem *item : items) {
929 if (item->contains(x, y))
930 return item;
931 }
932 return nullptr;
933}
934
935int QQuickItemView::indexAt(qreal x, qreal y) const
936{
937 Q_D(const QQuickItemView);
938 const FxViewItem *item = fxViewItemAtPosition(items: d->visibleItems, x, y);
939 return item ? item->index : -1;
940}
941
942QQuickItem *QQuickItemView::itemAt(qreal x, qreal y) const
943{
944 Q_D(const QQuickItemView);
945 const FxViewItem *item = fxViewItemAtPosition(items: d->visibleItems, x, y);
946 return item ? item->item : nullptr;
947}
948
949QQuickItem *QQuickItemView::itemAtIndex(int index) const
950{
951 Q_D(const QQuickItemView);
952 const FxViewItem *item = d->visibleItem(modelIndex: index);
953 return item ? item->item : nullptr;
954}
955
956void QQuickItemView::forceLayout()
957{
958 Q_D(QQuickItemView);
959 if (isComponentComplete() && (d->currentChanges.hasPendingChanges() || d->forceLayout))
960 d->layout();
961}
962
963void QQuickItemViewPrivate::applyPendingChanges()
964{
965 Q_Q(QQuickItemView);
966 if (q->isComponentComplete() && currentChanges.hasPendingChanges())
967 layout();
968}
969
970int QQuickItemViewPrivate::findMoveKeyIndex(QQmlChangeSet::MoveKey key, const QVector<QQmlChangeSet::Change> &changes) const
971{
972 for (int i=0; i<changes.size(); i++) {
973 for (int j=changes[i].index; j<changes[i].index + changes[i].count; j++) {
974 if (changes[i].moveKey(index: j) == key)
975 return j;
976 }
977 }
978 return -1;
979}
980
981qreal QQuickItemViewPrivate::minExtentForAxis(const AxisData &axisData, bool forXAxis) const
982{
983 Q_Q(const QQuickItemView);
984
985 qreal highlightStart;
986 qreal highlightEnd;
987 qreal endPositionFirstItem = 0;
988 qreal extent = -startPosition() + axisData.startMargin;
989 if (isContentFlowReversed()) {
990 if (model && model->count())
991 endPositionFirstItem = positionAt(index: model->count()-1);
992 else
993 extent += headerSize();
994 highlightStart = highlightRangeEndValid ? size() - highlightRangeEnd : size();
995 highlightEnd = highlightRangeStartValid ? size() - highlightRangeStart : size();
996 extent += footerSize();
997 qreal maxExtentAlongAxis = forXAxis ? q->maxXExtent() : q->maxYExtent();
998 if (extent < maxExtentAlongAxis)
999 extent = maxExtentAlongAxis;
1000 } else {
1001 endPositionFirstItem = endPositionAt(index: 0);
1002 highlightStart = highlightRangeStart;
1003 highlightEnd = highlightRangeEnd;
1004 extent += headerSize();
1005 }
1006 if (haveHighlightRange && highlightRange == QQuickItemView::StrictlyEnforceRange) {
1007 extent += highlightStart;
1008 FxViewItem *firstItem = visibleItem(modelIndex: 0);
1009 if (firstItem)
1010 extent -= firstItem->sectionSize();
1011 extent = isContentFlowReversed()
1012 ? qMin(a: extent, b: endPositionFirstItem + highlightEnd)
1013 : qMax(a: extent, b: -(endPositionFirstItem - highlightEnd));
1014 }
1015 return extent;
1016}
1017
1018qreal QQuickItemViewPrivate::maxExtentForAxis(const AxisData &axisData, bool forXAxis) const
1019{
1020 Q_Q(const QQuickItemView);
1021
1022 qreal highlightStart;
1023 qreal highlightEnd;
1024 qreal lastItemPosition = 0;
1025 qreal extent = 0;
1026 if (isContentFlowReversed()) {
1027 highlightStart = highlightRangeEndValid ? size() - highlightRangeEnd : size();
1028 highlightEnd = highlightRangeStartValid ? size() - highlightRangeStart : size();
1029 lastItemPosition = endPosition();
1030 } else {
1031 highlightStart = highlightRangeStart;
1032 highlightEnd = highlightRangeEnd;
1033 if (model && model->count())
1034 lastItemPosition = positionAt(index: model->count()-1);
1035 }
1036 if (!model || !model->count()) {
1037 if (!isContentFlowReversed())
1038 maxExtent = header ? -headerSize() : 0;
1039 extent += forXAxis ? q->width() : q->height();
1040 } else if (haveHighlightRange && highlightRange == QQuickItemView::StrictlyEnforceRange) {
1041 extent = -(lastItemPosition - highlightStart);
1042 if (highlightEnd != highlightStart) {
1043 extent = isContentFlowReversed()
1044 ? qMax(a: extent, b: -(endPosition() - highlightEnd))
1045 : qMin(a: extent, b: -(endPosition() - highlightEnd));
1046 }
1047 } else {
1048 extent = -(endPosition() - (forXAxis ? q->width() : q->height()));
1049 }
1050 if (isContentFlowReversed()) {
1051 extent -= headerSize();
1052 extent -= axisData.endMargin;
1053 } else {
1054 extent -= footerSize();
1055 extent -= axisData.endMargin;
1056 qreal minExtentAlongAxis = forXAxis ? q->minXExtent() : q->minYExtent();
1057 if (extent > minExtentAlongAxis)
1058 extent = minExtentAlongAxis;
1059 }
1060
1061 return extent;
1062}
1063
1064qreal QQuickItemViewPrivate::calculatedMinExtent() const
1065{
1066 Q_Q(const QQuickItemView);
1067 qreal minExtent;
1068 if (layoutOrientation() == Qt::Vertical)
1069 minExtent = isContentFlowReversed() ? q->maxYExtent() - size(): -q->minYExtent();
1070 else
1071 minExtent = isContentFlowReversed() ? q->maxXExtent() - size(): -q->minXExtent();
1072 return minExtent;
1073
1074}
1075
1076qreal QQuickItemViewPrivate::calculatedMaxExtent() const
1077{
1078 Q_Q(const QQuickItemView);
1079 qreal maxExtent;
1080 if (layoutOrientation() == Qt::Vertical)
1081 maxExtent = isContentFlowReversed() ? q->minYExtent() - size(): -q->maxYExtent();
1082 else
1083 maxExtent = isContentFlowReversed() ? q->minXExtent() - size(): -q->maxXExtent();
1084 return maxExtent;
1085}
1086
1087void QQuickItemViewPrivate::applyDelegateChange()
1088{
1089 releaseVisibleItems(reusableFlag: QQmlDelegateModel::NotReusable);
1090 releaseCurrentItem(reusableFlag: QQmlDelegateModel::NotReusable);
1091 updateSectionCriteria();
1092 refill();
1093 moveReason = QQuickItemViewPrivate::SetIndex;
1094 updateCurrent(modelIndex: currentIndex);
1095 if (highlight && currentItem) {
1096 if (autoHighlight)
1097 resetHighlightPosition();
1098 updateTrackedItem();
1099 }
1100 moveReason = QQuickItemViewPrivate::Other;
1101 updateViewport();
1102}
1103
1104// for debugging only
1105void QQuickItemViewPrivate::checkVisible() const
1106{
1107 int skip = 0;
1108 for (int i = 0; i < visibleItems.size(); ++i) {
1109 FxViewItem *item = visibleItems.at(i);
1110 if (item->index == -1) {
1111 ++skip;
1112 } else if (item->index != visibleIndex + i - skip) {
1113 qFatal(msg: "index %d %d %d", visibleIndex, i, item->index);
1114 }
1115 }
1116}
1117
1118// for debugging only
1119void QQuickItemViewPrivate::showVisibleItems() const
1120{
1121 qDebug() << "Visible items:";
1122 for (FxViewItem *item : visibleItems) {
1123 qDebug() << "\t" << item->index
1124 << item->item->objectName()
1125 << item->position();
1126 }
1127}
1128
1129// Simplifies debugging of count.
1130void QQuickItemViewPrivate::emitCountChanged()
1131{
1132 Q_Q(QQuickItemView);
1133 qCDebug(lcCount).nospace() << "about to emit countChanged for " << q << "; count changed to " << q->count();
1134 emit q->countChanged();
1135}
1136
1137void QQuickItemViewPrivate::itemGeometryChanged(QQuickItem *item, QQuickGeometryChange change,
1138 const QRectF &oldGeometry)
1139{
1140 Q_Q(QQuickItemView);
1141 QQuickFlickablePrivate::itemGeometryChanged(item, change, oldGeometry);
1142 if (!q->isComponentComplete())
1143 return;
1144
1145 if (header && header->item == item) {
1146 updateHeader();
1147 markExtentsDirty();
1148 updateViewport();
1149 if (!q->isMoving() && !q->isFlicking())
1150 fixupPosition();
1151 } else if (footer && footer->item == item) {
1152 updateFooter();
1153 markExtentsDirty();
1154 updateViewport();
1155 if (!q->isMoving() && !q->isFlicking())
1156 fixupPosition();
1157 }
1158
1159 if (currentItem && currentItem->item == item) {
1160 // don't allow item movement transitions to trigger a re-layout and
1161 // start new transitions
1162 bool prevInLayout = inLayout;
1163#if QT_CONFIG(quick_viewtransitions)
1164 if (!inLayout) {
1165 FxViewItem *actualItem = transitioner ? visibleItem(modelIndex: currentIndex) : nullptr;
1166 if (actualItem && actualItem->transitionRunning())
1167 inLayout = true;
1168 }
1169#endif
1170 updateHighlight();
1171 inLayout = prevInLayout;
1172 }
1173
1174 if (trackedItem && trackedItem->item == item)
1175 q->trackedPositionChanged();
1176}
1177
1178void QQuickItemView::destroyRemoved()
1179{
1180 Q_D(QQuickItemView);
1181
1182#if QT_CONFIG(quick_viewtransitions)
1183 bool hasRemoveTransition = false;
1184 bool hasRemoveTransitionAsTarget = false;
1185 if (d->transitioner) {
1186 hasRemoveTransition = d->transitioner->canTransition(type: QQuickItemViewTransitioner::RemoveTransition, asTarget: false);
1187 hasRemoveTransitionAsTarget = d->transitioner->canTransition(type: QQuickItemViewTransitioner::RemoveTransition, asTarget: true);
1188 }
1189#endif
1190
1191 for (QList<FxViewItem*>::Iterator it = d->visibleItems.begin();
1192 it != d->visibleItems.end();) {
1193 FxViewItem *item = *it;
1194 if (item->index == -1 && (!item->attached || item->attached->delayRemove() == false)) {
1195#if QT_CONFIG(quick_viewtransitions)
1196 if (hasRemoveTransitionAsTarget) {
1197 // don't remove from visibleItems until next layout()
1198 d->runDelayedRemoveTransition = true;
1199 QObject::disconnect(sender: item->attached, SIGNAL(delayRemoveChanged()), receiver: this, SLOT(destroyRemoved()));
1200 ++it;
1201 } else {
1202 if (hasRemoveTransition)
1203 d->runDelayedRemoveTransition = true;
1204#endif
1205 d->releaseItem(item, reusableFlag: d->reusableFlag);
1206 it = d->visibleItems.erase(pos: it);
1207#if QT_CONFIG(quick_viewtransitions)
1208 }
1209#endif
1210 } else {
1211 ++it;
1212 }
1213 }
1214
1215 // Correct the positioning of the items
1216 d->forceLayoutPolish();
1217}
1218
1219void QQuickItemView::modelUpdated(const QQmlChangeSet &changeSet, bool reset)
1220{
1221 Q_D(QQuickItemView);
1222 if (reset) {
1223 cancelFlick();
1224#if QT_CONFIG(quick_viewtransitions)
1225 if (d->transitioner)
1226 d->transitioner->setPopulateTransitionEnabled(true);
1227#endif
1228 d->moveReason = QQuickItemViewPrivate::SetIndex;
1229 d->regenerate();
1230 if (d->highlight && d->currentItem) {
1231 if (d->autoHighlight)
1232 d->resetHighlightPosition();
1233 d->updateTrackedItem();
1234 }
1235 d->moveReason = QQuickItemViewPrivate::Other;
1236 d->emitCountChanged();
1237#if QT_CONFIG(quick_viewtransitions)
1238 if (d->transitioner && d->transitioner->populateTransition)
1239 d->forceLayoutPolish();
1240#endif
1241 } else {
1242 if (d->inLayout) {
1243 d->bufferedChanges.prepare(currentIndex: d->currentIndex, count: d->itemCount);
1244 d->bufferedChanges.applyChanges(changeSet);
1245 } else {
1246 if (d->bufferedChanges.hasPendingChanges()) {
1247 d->currentChanges.applyBufferedChanges(other: d->bufferedChanges);
1248 d->bufferedChanges.reset();
1249 }
1250 d->currentChanges.prepare(currentIndex: d->currentIndex, count: d->itemCount);
1251 d->currentChanges.applyChanges(changeSet);
1252 }
1253 polish();
1254 }
1255}
1256
1257void QQuickItemView::animStopped()
1258{
1259 Q_D(QQuickItemView);
1260 d->bufferMode = QQuickItemViewPrivate::BufferBefore | QQuickItemViewPrivate::BufferAfter;
1261 d->refillOrLayout();
1262 if (d->haveHighlightRange && d->highlightRange == QQuickItemView::StrictlyEnforceRange)
1263 d->updateHighlight();
1264}
1265
1266
1267void QQuickItemView::trackedPositionChanged()
1268{
1269 Q_D(QQuickItemView);
1270 if (!d->trackedItem || !d->currentItem)
1271 return;
1272
1273 if (d->inLayout) {
1274 polish();
1275 return;
1276 }
1277
1278 const bool needMoveToTrackHighlight = d->autoHighlight || d->highlightRange != NoHighlightRange;
1279
1280 if (d->moveReason == QQuickItemViewPrivate::SetIndex && needMoveToTrackHighlight) {
1281 qreal trackedPos = d->trackedItem->position();
1282 qreal trackedSize = d->trackedItem->size();
1283 qreal viewPos = d->isContentFlowReversed() ? -d->position()-d->size() : d->position();
1284 qreal pos = viewPos;
1285 if (d->haveHighlightRange) {
1286 if (trackedPos > pos + d->highlightRangeEnd - trackedSize)
1287 pos = trackedPos - d->highlightRangeEnd + trackedSize;
1288 if (trackedPos < pos + d->highlightRangeStart)
1289 pos = trackedPos - d->highlightRangeStart;
1290 if (d->highlightRange != StrictlyEnforceRange) {
1291 qreal maxExtent = d->calculatedMaxExtent();
1292 if (pos > maxExtent)
1293 pos = maxExtent;
1294 qreal minExtent = d->calculatedMinExtent();
1295 if (pos < minExtent)
1296 pos = minExtent;
1297 }
1298 } else {
1299 if (d->trackedItem != d->currentItem) {
1300 // also make section header visible
1301 trackedPos -= d->currentItem->sectionSize();
1302 trackedSize += d->currentItem->sectionSize();
1303 }
1304 qreal trackedEndPos = d->trackedItem->endPosition();
1305 qreal toItemPos = d->currentItem->position();
1306 qreal toItemEndPos = d->currentItem->endPosition();
1307 if (d->showHeaderForIndex(index: d->currentIndex)) {
1308 qreal startOffset = -d->contentStartOffset();
1309 trackedPos -= startOffset;
1310 trackedEndPos -= startOffset;
1311 toItemPos -= startOffset;
1312 toItemEndPos -= startOffset;
1313 } else if (d->showFooterForIndex(index: d->currentIndex)) {
1314 qreal endOffset = d->footerSize();
1315 if (d->layoutOrientation() == Qt::Vertical) {
1316 if (d->isContentFlowReversed())
1317 endOffset += d->vData.startMargin;
1318 else
1319 endOffset += d->vData.endMargin;
1320 } else {
1321 if (d->isContentFlowReversed())
1322 endOffset += d->hData.startMargin;
1323 else
1324 endOffset += d->hData.endMargin;
1325 }
1326 trackedPos += endOffset;
1327 trackedEndPos += endOffset;
1328 toItemPos += endOffset;
1329 toItemEndPos += endOffset;
1330 }
1331
1332 if (trackedEndPos >= viewPos + d->size()
1333 && toItemEndPos >= viewPos + d->size()) {
1334 if (trackedEndPos <= toItemEndPos) {
1335 pos = trackedEndPos - d->size();
1336 if (trackedSize > d->size())
1337 pos = trackedPos;
1338 } else {
1339 pos = toItemEndPos - d->size();
1340 if (d->currentItem->size() > d->size())
1341 pos = d->currentItem->position();
1342 }
1343 }
1344 if (trackedPos < pos && toItemPos < pos)
1345 pos = qMax(a: trackedPos, b: toItemPos);
1346 }
1347 if (viewPos != pos) {
1348 d->calcVelocity = true;
1349 d->setPosition(pos);
1350 d->calcVelocity = false;
1351 }
1352 }
1353}
1354
1355void QQuickItemView::geometryChange(const QRectF &newGeometry, const QRectF &oldGeometry)
1356{
1357 Q_D(QQuickItemView);
1358 d->markExtentsDirty();
1359 if (isComponentComplete() && (d->isValid() || !d->visibleItems.isEmpty()))
1360 d->forceLayoutPolish();
1361 QQuickFlickable::geometryChange(newGeometry, oldGeometry);
1362}
1363
1364qreal QQuickItemView::minYExtent() const
1365{
1366 Q_D(const QQuickItemView);
1367 if (d->layoutOrientation() == Qt::Horizontal)
1368 return QQuickFlickable::minYExtent();
1369
1370 if (d->vData.minExtentDirty) {
1371 d->minExtent = d->minExtentForAxis(axisData: d->vData, forXAxis: false);
1372 d->vData.minExtentDirty = false;
1373 }
1374
1375 return d->minExtent;
1376}
1377
1378qreal QQuickItemView::maxYExtent() const
1379{
1380 Q_D(const QQuickItemView);
1381 if (d->layoutOrientation() == Qt::Horizontal)
1382 return QQuickFlickable::maxYExtent();
1383
1384 if (d->vData.maxExtentDirty) {
1385 d->maxExtent = d->maxExtentForAxis(axisData: d->vData, forXAxis: false);
1386 d->vData.maxExtentDirty = false;
1387 }
1388
1389 return d->maxExtent;
1390}
1391
1392qreal QQuickItemView::minXExtent() const
1393{
1394 Q_D(const QQuickItemView);
1395 if (d->layoutOrientation() == Qt::Vertical)
1396 return QQuickFlickable::minXExtent();
1397
1398 if (d->hData.minExtentDirty) {
1399 d->minExtent = d->minExtentForAxis(axisData: d->hData, forXAxis: true);
1400 d->hData.minExtentDirty = false;
1401 }
1402
1403 return d->minExtent;
1404}
1405
1406qreal QQuickItemView::maxXExtent() const
1407{
1408 Q_D(const QQuickItemView);
1409 if (d->layoutOrientation() == Qt::Vertical)
1410 return QQuickFlickable::maxXExtent();
1411
1412 if (d->hData.maxExtentDirty) {
1413 d->maxExtent = d->maxExtentForAxis(axisData: d->hData, forXAxis: true);
1414 d->hData.maxExtentDirty = false;
1415 }
1416
1417 return d->maxExtent;
1418}
1419
1420void QQuickItemView::setContentX(qreal pos)
1421{
1422 Q_D(QQuickItemView);
1423 // Positioning the view manually should override any current movement state
1424 d->moveReason = QQuickItemViewPrivate::Other;
1425 QQuickFlickable::setContentX(pos);
1426}
1427
1428void QQuickItemView::setContentY(qreal pos)
1429{
1430 Q_D(QQuickItemView);
1431 // Positioning the view manually should override any current movement state
1432 d->moveReason = QQuickItemViewPrivate::Other;
1433 QQuickFlickable::setContentY(pos);
1434}
1435
1436qreal QQuickItemView::originX() const
1437{
1438 Q_D(const QQuickItemView);
1439 if (d->layoutOrientation() == Qt::Horizontal
1440 && effectiveLayoutDirection() == Qt::RightToLeft
1441 && contentWidth() < width()) {
1442 return -d->lastPosition() - d->footerSize();
1443 }
1444 return QQuickFlickable::originX();
1445}
1446
1447qreal QQuickItemView::originY() const
1448{
1449 Q_D(const QQuickItemView);
1450 if (d->layoutOrientation() == Qt::Vertical
1451 && d->verticalLayoutDirection == QQuickItemView::BottomToTop
1452 && contentHeight() < height()) {
1453 return -d->lastPosition() - d->footerSize();
1454 }
1455 return QQuickFlickable::originY();
1456}
1457
1458void QQuickItemView::updatePolish()
1459{
1460 Q_D(QQuickItemView);
1461 QQuickFlickable::updatePolish();
1462 d->layout();
1463}
1464
1465void QQuickItemView::componentComplete()
1466{
1467 Q_D(QQuickItemView);
1468 if (d->model && d->ownModel)
1469 static_cast<QQmlDelegateModel *>(d->model.data())->componentComplete();
1470
1471 QQuickFlickable::componentComplete();
1472
1473 d->updateSectionCriteria();
1474 d->updateHeader();
1475 d->updateFooter();
1476 d->updateViewport();
1477 d->setPosition(d->contentStartOffset());
1478#if QT_CONFIG(quick_viewtransitions)
1479 if (d->transitioner)
1480 d->transitioner->setPopulateTransitionEnabled(true);
1481#endif
1482
1483 if (d->isValid()) {
1484 d->refill();
1485 d->moveReason = QQuickItemViewPrivate::SetIndex;
1486 if (d->currentIndex < 0 && !d->currentIndexCleared)
1487 d->updateCurrent(modelIndex: 0);
1488 else
1489 d->updateCurrent(modelIndex: d->currentIndex);
1490 if (d->highlight && d->currentItem) {
1491 if (d->autoHighlight)
1492 d->resetHighlightPosition();
1493 d->updateTrackedItem();
1494 }
1495 d->moveReason = QQuickItemViewPrivate::Other;
1496 d->fixupPosition();
1497 }
1498 if (d->model && d->model->count())
1499 d->emitCountChanged();
1500}
1501
1502
1503
1504QQuickItemViewPrivate::QQuickItemViewPrivate()
1505 : itemCount(0)
1506 , buffer(QML_VIEW_DEFAULTCACHEBUFFER), bufferMode(BufferBefore | BufferAfter)
1507 , displayMarginBeginning(0), displayMarginEnd(0)
1508 , layoutDirection(Qt::LeftToRight), verticalLayoutDirection(QQuickItemView::TopToBottom)
1509 , visibleIndex(0)
1510 , currentIndex(-1), currentItem(nullptr)
1511 , trackedItem(nullptr), requestedIndex(-1)
1512 , highlightComponent(nullptr), highlight(nullptr)
1513 , highlightRange(QQuickItemView::NoHighlightRange)
1514 , highlightRangeStart(0), highlightRangeEnd(0)
1515 , highlightMoveDuration(150)
1516 , headerComponent(nullptr), header(nullptr), footerComponent(nullptr), footer(nullptr)
1517#if QT_CONFIG(quick_viewtransitions)
1518 , transitioner(nullptr)
1519#endif
1520 , minExtent(0), maxExtent(0)
1521 , ownModel(false), wrap(false)
1522 , keyNavigationEnabled(true)
1523 , explicitKeyNavigationEnabled(false)
1524 , inLayout(false), inViewportMoved(false), forceLayout(false), currentIndexCleared(false)
1525 , haveHighlightRange(false), autoHighlight(true), highlightRangeStartValid(false), highlightRangeEndValid(false)
1526 , fillCacheBuffer(false), inRequest(false)
1527#if QT_CONFIG(quick_viewtransitions)
1528 , runDelayedRemoveTransition(false)
1529#endif
1530 , delegateValidated(false), isClearing(false)
1531{
1532 bufferPause.addAnimationChangeListener(listener: this, QAbstractAnimationJob::Completion);
1533 bufferPause.setLoopCount(1);
1534 bufferPause.setDuration(16);
1535}
1536
1537QQuickItemViewPrivate::~QQuickItemViewPrivate()
1538{
1539#if QT_CONFIG(quick_viewtransitions)
1540 if (transitioner)
1541 transitioner->setChangeListener(nullptr);
1542 delete transitioner;
1543#endif
1544}
1545
1546bool QQuickItemViewPrivate::isValid() const
1547{
1548 return model && model->count() && model->isValid();
1549}
1550
1551qreal QQuickItemViewPrivate::position() const
1552{
1553 Q_Q(const QQuickItemView);
1554 return layoutOrientation() == Qt::Vertical ? q->contentY() : q->contentX();
1555}
1556
1557qreal QQuickItemViewPrivate::size() const
1558{
1559 Q_Q(const QQuickItemView);
1560 return layoutOrientation() == Qt::Vertical ? q->height() : q->width();
1561}
1562
1563qreal QQuickItemViewPrivate::startPosition() const
1564{
1565 return isContentFlowReversed() ? -lastPosition() : originPosition();
1566}
1567
1568qreal QQuickItemViewPrivate::endPosition() const
1569{
1570 return isContentFlowReversed() ? -originPosition() : lastPosition();
1571}
1572
1573qreal QQuickItemViewPrivate::contentStartOffset() const
1574{
1575 qreal pos = -headerSize();
1576 if (layoutOrientation() == Qt::Vertical) {
1577 if (isContentFlowReversed())
1578 pos -= vData.endMargin;
1579 else
1580 pos -= vData.startMargin;
1581 } else {
1582 if (isContentFlowReversed())
1583 pos -= hData.endMargin;
1584 else
1585 pos -= hData.startMargin;
1586 }
1587 return pos;
1588}
1589
1590int QQuickItemViewPrivate::findLastVisibleIndex(int defaultValue) const
1591{
1592 for (auto it = visibleItems.rbegin(), end = visibleItems.rend(); it != end; ++it) {
1593 auto item = *it;
1594 if (item->index != -1)
1595 return item->index;
1596 }
1597 return defaultValue;
1598}
1599
1600FxViewItem *QQuickItemViewPrivate::visibleItem(int modelIndex) const {
1601 if (modelIndex >= visibleIndex && modelIndex < visibleIndex + visibleItems.size()) {
1602 for (int i = modelIndex - visibleIndex; i < visibleItems.size(); ++i) {
1603 FxViewItem *item = visibleItems.at(i);
1604 if (item->index == modelIndex)
1605 return item;
1606 }
1607 }
1608 return nullptr;
1609}
1610
1611FxViewItem *QQuickItemViewPrivate::firstItemInView() const {
1612 const qreal pos = isContentFlowReversed() ? -position()-size() : position();
1613 for (FxViewItem *item : visibleItems) {
1614 if (item->index != -1 && item->endPosition() > pos)
1615 return item;
1616 }
1617 return visibleItems.size() ? visibleItems.first() : 0;
1618}
1619
1620int QQuickItemViewPrivate::findLastIndexInView() const
1621{
1622 const qreal viewEndPos = isContentFlowReversed() ? -position() : position() + size();
1623 for (auto it = visibleItems.rbegin(), end = visibleItems.rend(); it != end; ++it) {
1624 auto item = *it;
1625 if (item->index != -1 && item->position() <= viewEndPos)
1626 return item->index;
1627 }
1628 return -1;
1629}
1630
1631// Map a model index to visibleItems list index.
1632// These may differ if removed items are still present in the visible list,
1633// e.g. doing a removal animation
1634int QQuickItemViewPrivate::mapFromModel(int modelIndex) const
1635{
1636 if (modelIndex < visibleIndex || modelIndex >= visibleIndex + visibleItems.size())
1637 return -1;
1638 for (int i = 0; i < visibleItems.size(); ++i) {
1639 FxViewItem *item = visibleItems.at(i);
1640 if (item->index == modelIndex)
1641 return i;
1642 if (item->index > modelIndex)
1643 return -1;
1644 }
1645 return -1; // Not in visibleList
1646}
1647
1648void QQuickItemViewPrivate::init()
1649{
1650 Q_Q(QQuickItemView);
1651 q->setFlag(flag: QQuickItem::ItemIsFocusScope);
1652 QObject::connect(sender: q, SIGNAL(movementEnded()), receiver: q, SLOT(animStopped()));
1653 QObject::connect(sender: q, signal: &QQuickFlickable::interactiveChanged, context: q, slot: &QQuickItemView::keyNavigationEnabledChanged);
1654 q->setFlickableDirection(QQuickFlickable::VerticalFlick);
1655}
1656
1657void QQuickItemViewPrivate::updateCurrent(int modelIndex)
1658{
1659 Q_Q(QQuickItemView);
1660 applyPendingChanges();
1661 if (!q->isComponentComplete() || !isValid() || modelIndex < 0 || modelIndex >= model->count()) {
1662 if (currentItem) {
1663 if (currentItem->attached)
1664 currentItem->attached->setIsCurrentItem(false);
1665 releaseCurrentItem(reusableFlag);
1666 currentIndex = modelIndex;
1667 emit q->currentIndexChanged();
1668 emit q->currentItemChanged();
1669 updateHighlight();
1670 } else if (currentIndex != modelIndex) {
1671 currentIndex = modelIndex;
1672 emit q->currentIndexChanged();
1673 }
1674 return;
1675 }
1676
1677 if (currentItem && currentIndex == modelIndex) {
1678 updateHighlight();
1679 return;
1680 }
1681
1682 FxViewItem *oldCurrentItem = currentItem;
1683 int oldCurrentIndex = currentIndex;
1684 currentIndex = modelIndex;
1685 currentItem = createItem(modelIndex, incubationMode: QQmlIncubator::AsynchronousIfNested);
1686 if (oldCurrentItem && oldCurrentItem->attached && (!currentItem || oldCurrentItem->item != currentItem->item))
1687 oldCurrentItem->attached->setIsCurrentItem(false);
1688 if (currentItem) {
1689 currentItem->item->setFocus(true);
1690 if (currentItem->attached)
1691 currentItem->attached->setIsCurrentItem(true);
1692 initializeCurrentItem();
1693 }
1694
1695 updateHighlight();
1696 if (oldCurrentIndex != currentIndex)
1697 emit q->currentIndexChanged();
1698 if (oldCurrentItem != currentItem
1699 && (!oldCurrentItem || !currentItem || oldCurrentItem->item != currentItem->item))
1700 emit q->currentItemChanged();
1701 releaseItem(item: oldCurrentItem, reusableFlag);
1702}
1703
1704void QQuickItemViewPrivate::clear(bool onDestruction)
1705{
1706 Q_Q(QQuickItemView);
1707
1708 isClearing = true;
1709 auto cleanup = qScopeGuard(f: [this] { isClearing = false; });
1710
1711 currentChanges.reset();
1712 bufferedChanges.reset();
1713 timeline.clear();
1714
1715 releaseVisibleItems(reusableFlag: QQmlInstanceModel::NotReusable);
1716 visibleIndex = 0;
1717
1718#if QT_CONFIG(quick_viewtransitions)
1719 for (FxViewItem *item : std::as_const(t&: releasePendingTransition)) {
1720 item->releaseAfterTransition = false;
1721 releaseItem(item, reusableFlag: QQmlInstanceModel::NotReusable);
1722 }
1723 releasePendingTransition.clear();
1724#endif
1725
1726 const bool hadCurrentItem = currentItem != nullptr;
1727 releaseCurrentItem(reusableFlag: QQmlDelegateModel::NotReusable);
1728 if (hadCurrentItem)
1729 emit q->currentItemChanged();
1730 createHighlight(onDestruction);
1731 trackedItem = nullptr;
1732
1733 if (requestedIndex >= 0) {
1734 if (model)
1735 model->cancel(requestedIndex);
1736 requestedIndex = -1;
1737 }
1738
1739 markExtentsDirty();
1740 itemCount = 0;
1741}
1742
1743
1744void QQuickItemViewPrivate::mirrorChange()
1745{
1746 Q_Q(QQuickItemView);
1747 regenerate();
1748 emit q->effectiveLayoutDirectionChanged();
1749}
1750
1751void QQuickItemViewPrivate::animationFinished(QAbstractAnimationJob *)
1752{
1753 Q_Q(QQuickItemView);
1754 fillCacheBuffer = true;
1755 q->polish();
1756}
1757
1758void QQuickItemViewPrivate::refill()
1759{
1760 qreal s = qMax(a: size(), b: qreal(0.));
1761 const auto pos = position();
1762 if (isContentFlowReversed())
1763 refill(from: -pos - displayMarginBeginning-s, to: -pos + displayMarginEnd);
1764 else
1765 refill(from: pos - displayMarginBeginning, to: pos + displayMarginEnd+s);
1766}
1767
1768void QQuickItemViewPrivate::refill(qreal from, qreal to)
1769{
1770 Q_Q(QQuickItemView);
1771 if (!model || !model->isValid() || !q->isComponentComplete())
1772 return;
1773 if (q->size().isNull() && visibleItems.isEmpty())
1774 return;
1775 if (!model->count()) {
1776 updateHeader();
1777 updateFooter();
1778 updateViewport();
1779 return;
1780 }
1781
1782 do {
1783 bufferPause.stop();
1784 if (currentChanges.hasPendingChanges() || bufferedChanges.hasPendingChanges() || currentChanges.active) {
1785 currentChanges.reset();
1786 bufferedChanges.reset();
1787 releaseVisibleItems(reusableFlag);
1788 }
1789
1790 int prevCount = itemCount;
1791 itemCount = model->count();
1792 qreal bufferFrom = from - buffer;
1793 qreal bufferTo = to + buffer;
1794 qreal fillFrom = from;
1795 qreal fillTo = to;
1796
1797 bool added = addVisibleItems(fillFrom, fillTo, bufferFrom, bufferTo, doBuffer: false);
1798
1799 if (requestedIndex == -1 && buffer && bufferMode != NoBuffer) {
1800 if (added) {
1801 // We've already created a new delegate this frame.
1802 // Just schedule a buffer refill.
1803 bufferPause.start();
1804 } else {
1805 if (bufferMode & BufferAfter)
1806 fillTo = bufferTo;
1807 if (bufferMode & BufferBefore)
1808 fillFrom = bufferFrom;
1809 added |= addVisibleItems(fillFrom, fillTo, bufferFrom, bufferTo, doBuffer: true);
1810 }
1811 }
1812
1813 bool removed = removeNonVisibleItems(bufferFrom, bufferTo);
1814
1815 if (added || removed) {
1816 markExtentsDirty();
1817 updateBeginningEnd();
1818 visibleItemsChanged();
1819 updateHeader();
1820 updateFooter();
1821 updateViewport();
1822 }
1823
1824 if (prevCount != itemCount)
1825 emitCountChanged();
1826 } while (currentChanges.hasPendingChanges() || bufferedChanges.hasPendingChanges());
1827 storeFirstVisibleItemPosition();
1828}
1829
1830void QQuickItemViewPrivate::regenerate(bool orientationChanged)
1831{
1832 Q_Q(QQuickItemView);
1833 if (q->isComponentComplete()) {
1834 if (orientationChanged) {
1835 delete header;
1836 header = nullptr;
1837 delete footer;
1838 footer = nullptr;
1839 }
1840 clear();
1841 updateHeader();
1842 updateFooter();
1843 updateViewport();
1844 setPosition(contentStartOffset());
1845 refill();
1846 updateCurrent(modelIndex: currentIndex);
1847 }
1848}
1849
1850void QQuickItemViewPrivate::updateViewport()
1851{
1852 Q_Q(QQuickItemView);
1853 qreal extra = headerSize() + footerSize();
1854 qreal contentSize = isValid() || !visibleItems.isEmpty() ? (endPosition() - startPosition()) : 0.0;
1855 if (layoutOrientation() == Qt::Vertical)
1856 q->setContentHeight(contentSize + extra);
1857 else
1858 q->setContentWidth(contentSize + extra);
1859}
1860
1861void QQuickItemViewPrivate::layout()
1862{
1863 Q_Q(QQuickItemView);
1864 if (inLayout)
1865 return;
1866
1867 inLayout = true;
1868
1869 // viewBounds contains bounds before any add/remove/move operation to the view
1870 QRectF viewBounds(q->contentX(), q->contentY(), q->width(), q->height());
1871
1872 // We use isNull for the size check, because isEmpty returns true
1873 // if either dimension is negative, but apparently we support negative-sized
1874 // views (see tst_QQuickListView::resizeView).
1875 if ((!isValid() && !visibleItems.size()) || q->size().isNull()) {
1876 if (q->size().isNull() && hasPendingChanges()) {
1877 // count() refers to the number of items in the model, not in the view
1878 // (which is why we don't emit for the !visibleItems.size() case).
1879 // If there are pending model changes, emit countChanged in order to
1880 // support the use case of QTBUG-129165, where visible is bound to count > 0
1881 // and the ListView is in a layout with Layout.preferredHeight bound to
1882 // contentHeight. This ensures that a hidden ListView will become visible.
1883 emitCountChanged();
1884 }
1885
1886 clear();
1887 setPosition(contentStartOffset());
1888 updateViewport();
1889#if QT_CONFIG(quick_viewtransitions)
1890 if (transitioner)
1891 transitioner->setPopulateTransitionEnabled(false);
1892#endif
1893 inLayout = false;
1894 return;
1895 }
1896
1897#if QT_CONFIG(quick_viewtransitions)
1898 if (runDelayedRemoveTransition && transitioner
1899 && transitioner->canTransition(type: QQuickItemViewTransitioner::RemoveTransition, asTarget: false)) {
1900 // assume that any items moving now are moving due to the remove - if they schedule
1901 // a different transition, that will override this one anyway
1902 for (int i=0; i<visibleItems.size(); i++)
1903 visibleItems[i]->transitionNextReposition(transitioner, type: QQuickItemViewTransitioner::RemoveTransition, asTarget: false);
1904 }
1905#endif
1906
1907 ChangeResult insertionPosChanges;
1908 ChangeResult removalPosChanges;
1909 if (!applyModelChanges(insertionResult: &insertionPosChanges, removalResult: &removalPosChanges) && !forceLayout) {
1910 if (fillCacheBuffer) {
1911 fillCacheBuffer = false;
1912 refill();
1913 }
1914 inLayout = false;
1915 return;
1916 }
1917 forceLayout = false;
1918
1919#if QT_CONFIG(quick_viewtransitions)
1920 if (transitioner && transitioner->canTransition(type: QQuickItemViewTransitioner::PopulateTransition, asTarget: true)) {
1921 // Give the view one more chance to refill itself,
1922 // in case its size is changed such that more delegates become visible after component completed
1923 refill();
1924 for (FxViewItem *item : std::as_const(t&: visibleItems)) {
1925 if (!item->transitionScheduledOrRunning())
1926 item->transitionNextReposition(transitioner, type: QQuickItemViewTransitioner::PopulateTransition, asTarget: true);
1927 }
1928 }
1929#endif
1930
1931 updateSections();
1932 layoutVisibleItems();
1933 storeFirstVisibleItemPosition();
1934
1935#if QT_CONFIG(quick_viewtransitions)
1936 int lastIndexInView = findLastIndexInView();
1937#endif
1938 refill();
1939 markExtentsDirty();
1940 updateHighlight();
1941
1942 if (!q->isMoving() && !q->isFlicking() && !movingFromHighlight()) {
1943 fixupPosition();
1944 refill();
1945 }
1946
1947 updateHeader();
1948 updateFooter();
1949 updateViewport();
1950 updateUnrequestedPositions();
1951
1952#if QT_CONFIG(quick_viewtransitions)
1953 if (transitioner) {
1954 // items added in the last refill() may need to be transitioned in - e.g. a remove
1955 // causes items to slide up into view
1956 if (lastIndexInView != -1 &&
1957 (transitioner->canTransition(type: QQuickItemViewTransitioner::MoveTransition, asTarget: false)
1958 || transitioner->canTransition(type: QQuickItemViewTransitioner::RemoveTransition, asTarget: false))) {
1959 translateAndTransitionItemsAfter(afterIndex: lastIndexInView, insertionResult: insertionPosChanges, removalResult: removalPosChanges);
1960 }
1961
1962 prepareVisibleItemTransitions();
1963
1964 // We cannot use iterators here as erasing from a container invalidates them.
1965 for (int i = 0, count = releasePendingTransition.size(); i < count;) {
1966 auto success = prepareNonVisibleItemTransition(item: releasePendingTransition[i], viewBounds);
1967 // prepareNonVisibleItemTransition() may remove items while in fast flicking.
1968 // Invisible animating items are kicked in or out the viewPort.
1969 // Recheck count to test if the item got removed. In that case the same index points
1970 // to a different item now.
1971 const int old_count = count;
1972 count = releasePendingTransition.size();
1973 if (old_count > count)
1974 continue;
1975
1976 if (!success) {
1977 releaseItem(item: releasePendingTransition[i], reusableFlag);
1978 releasePendingTransition.remove(i);
1979 --count;
1980 } else {
1981 ++i;
1982 }
1983 }
1984
1985 for (int i=0; i<visibleItems.size(); i++)
1986 visibleItems[i]->startTransition(transitioner);
1987 for (int i=0; i<releasePendingTransition.size(); i++)
1988 releasePendingTransition[i]->startTransition(transitioner);
1989
1990 transitioner->setPopulateTransitionEnabled(false);
1991 transitioner->resetTargetLists();
1992 }
1993#endif
1994
1995 if (!currentItem)
1996 updateCurrent(modelIndex: currentIndex);
1997
1998#if QT_CONFIG(quick_viewtransitions)
1999 runDelayedRemoveTransition = false;
2000#endif
2001 inLayout = false;
2002}
2003
2004bool QQuickItemViewPrivate::applyModelChanges(ChangeResult *totalInsertionResult, ChangeResult *totalRemovalResult)
2005{
2006 Q_Q(QQuickItemView);
2007 if (!q->isComponentComplete() || !hasPendingChanges())
2008 return false;
2009
2010 if (bufferedChanges.hasPendingChanges()) {
2011 currentChanges.applyBufferedChanges(other: bufferedChanges);
2012 bufferedChanges.reset();
2013 }
2014
2015 updateUnrequestedIndexes();
2016
2017 FxViewItem *prevVisibleItemsFirst = visibleItems.size() ? *visibleItems.constBegin() : nullptr;
2018 int prevItemCount = itemCount;
2019 int prevVisibleItemsCount = visibleItems.size();
2020 bool visibleAffected = false;
2021 bool viewportChanged = !currentChanges.pendingChanges.removes().isEmpty()
2022 || !currentChanges.pendingChanges.inserts().isEmpty();
2023
2024 FxViewItem *prevFirstItemInView = firstItemInView();
2025 QQmlNullableValue<qreal> prevFirstItemInViewPos;
2026 int prevFirstItemInViewIndex = -1;
2027 if (prevFirstItemInView) {
2028 prevFirstItemInViewPos = prevFirstItemInView->position();
2029 prevFirstItemInViewIndex = prevFirstItemInView->index;
2030 }
2031 qreal prevVisibleItemsFirstPos = visibleItems.size() ? firstVisibleItemPosition : 0.0;
2032
2033 totalInsertionResult->visiblePos = prevFirstItemInViewPos;
2034 totalRemovalResult->visiblePos = prevFirstItemInViewPos;
2035
2036 const QVector<QQmlChangeSet::Change> &removals = currentChanges.pendingChanges.removes();
2037 const QVector<QQmlChangeSet::Change> &insertions = currentChanges.pendingChanges.inserts();
2038 ChangeResult insertionResult(prevFirstItemInViewPos);
2039 ChangeResult removalResult(prevFirstItemInViewPos);
2040
2041 int removedCount = 0;
2042 for (const QQmlChangeSet::Change &r : removals) {
2043 itemCount -= r.count;
2044 if (applyRemovalChange(removal: r, changeResult: &removalResult, removedCount: &removedCount))
2045 visibleAffected = true;
2046 if (!visibleAffected && needsRefillForAddedOrRemovedIndex(r.index))
2047 visibleAffected = true;
2048 const int correctedFirstVisibleIndex = prevFirstItemInViewIndex - removalResult.countChangeBeforeVisible;
2049 if (correctedFirstVisibleIndex >= 0 && r.index < correctedFirstVisibleIndex) {
2050 if (r.index + r.count < correctedFirstVisibleIndex)
2051 removalResult.countChangeBeforeVisible += r.count;
2052 else
2053 removalResult.countChangeBeforeVisible += (correctedFirstVisibleIndex - r.index);
2054 }
2055 }
2056#if QT_CONFIG(quick_viewtransitions)
2057 if (runDelayedRemoveTransition) {
2058 QQmlChangeSet::Change removal;
2059 for (QList<FxViewItem*>::Iterator it = visibleItems.begin(); it != visibleItems.end();) {
2060 FxViewItem *item = *it;
2061 if (item->index == -1 && (!item->attached || !item->attached->delayRemove())) {
2062 removeItem(item, removal, removeResult: &removalResult);
2063 removedCount++;
2064 it = visibleItems.erase(pos: it);
2065 } else {
2066 ++it;
2067 }
2068 }
2069 }
2070#endif
2071 *totalRemovalResult += removalResult;
2072 if (!removals.isEmpty()) {
2073 updateVisibleIndex();
2074
2075 // set positions correctly for the next insertion
2076 if (!insertions.isEmpty()) {
2077 repositionFirstItem(prevVisibleItemsFirst, prevVisibleItemsFirstPos, prevFirstVisible: prevFirstItemInView, insertionResult: &insertionResult, removalResult: &removalResult);
2078 layoutVisibleItems(fromModelIndex: removals.first().index);
2079 storeFirstVisibleItemPosition();
2080 }
2081 }
2082
2083 QList<FxViewItem *> newItems;
2084 QList<MovedItem> movingIntoView;
2085
2086 for (int i=0; i<insertions.size(); i++) {
2087 bool wasEmpty = visibleItems.isEmpty();
2088 if (applyInsertionChange(insert: insertions[i], changeResult: &insertionResult, newItems: &newItems, movingIntoView: &movingIntoView))
2089 visibleAffected = true;
2090 if (!visibleAffected && needsRefillForAddedOrRemovedIndex(insertions[i].index))
2091 visibleAffected = true;
2092 if (wasEmpty && !visibleItems.isEmpty())
2093 resetFirstItemPosition();
2094 *totalInsertionResult += insertionResult;
2095
2096 // set positions correctly for the next insertion
2097 if (i < insertions.size() - 1) {
2098 repositionFirstItem(prevVisibleItemsFirst, prevVisibleItemsFirstPos, prevFirstVisible: prevFirstItemInView, insertionResult: &insertionResult, removalResult: &removalResult);
2099 layoutVisibleItems(fromModelIndex: insertions[i].index);
2100 storeFirstVisibleItemPosition();
2101 }
2102 itemCount += insertions[i].count;
2103 }
2104 for (FxViewItem *item : std::as_const(t&: newItems)) {
2105 if (item->attached)
2106 item->attached->emitAdd();
2107 }
2108
2109#if QT_CONFIG(quick_viewtransitions)
2110 // for each item that was moved directly into the view as a result of a move(),
2111 // find the index it was moved from in order to set its initial position, so that we
2112 // can transition it from this "original" position to its new position in the view
2113 if (transitioner && transitioner->canTransition(type: QQuickItemViewTransitioner::MoveTransition, asTarget: true)) {
2114 for (const MovedItem &m : std::as_const(t&: movingIntoView)) {
2115 int fromIndex = findMoveKeyIndex(key: m.moveKey, changes: removals);
2116 if (fromIndex >= 0) {
2117 if (prevFirstItemInViewIndex >= 0 && fromIndex < prevFirstItemInViewIndex)
2118 repositionItemAt(item: m.item, index: fromIndex, sizeBuffer: -totalInsertionResult->sizeChangesAfterVisiblePos);
2119 else
2120 repositionItemAt(item: m.item, index: fromIndex, sizeBuffer: totalInsertionResult->sizeChangesAfterVisiblePos);
2121 m.item->transitionNextReposition(transitioner, type: QQuickItemViewTransitioner::MoveTransition, asTarget: true);
2122 }
2123 }
2124 }
2125#endif
2126
2127 // reposition visibleItems.first() correctly so that the content y doesn't jump
2128 if (removedCount != prevVisibleItemsCount)
2129 repositionFirstItem(prevVisibleItemsFirst, prevVisibleItemsFirstPos, prevFirstVisible: prevFirstItemInView, insertionResult: &insertionResult, removalResult: &removalResult);
2130
2131 // Whatever removed/moved items remain are no longer visible items.
2132#if QT_CONFIG(quick_viewtransitions)
2133 prepareRemoveTransitions(removedItems: &currentChanges.removedItems);
2134#endif
2135 for (auto it = currentChanges.removedItems.begin();
2136 it != currentChanges.removedItems.end(); ++it) {
2137 releaseItem(item: it.value(), reusableFlag);
2138 }
2139 currentChanges.removedItems.clear();
2140
2141 if (currentChanges.currentChanged) {
2142 if (currentChanges.currentRemoved && currentItem) {
2143 if (currentItem->item && currentItem->attached)
2144 currentItem->attached->setIsCurrentItem(false);
2145 const bool hadCurrentItem = currentItem != nullptr;
2146 releaseCurrentItem(reusableFlag);
2147 if (hadCurrentItem)
2148 emit q->currentItemChanged();
2149 }
2150 if (!currentIndexCleared)
2151 updateCurrent(modelIndex: currentChanges.newCurrentIndex);
2152 }
2153
2154 if (!visibleAffected)
2155 visibleAffected = !currentChanges.pendingChanges.changes().isEmpty();
2156 currentChanges.reset();
2157
2158 updateSections();
2159 if (prevItemCount != itemCount)
2160 emitCountChanged();
2161 if (!visibleAffected && viewportChanged)
2162 updateViewport();
2163
2164 return visibleAffected;
2165}
2166
2167bool QQuickItemViewPrivate::applyRemovalChange(const QQmlChangeSet::Change &removal, ChangeResult *removeResult, int *removedCount)
2168{
2169 Q_Q(QQuickItemView);
2170 bool visibleAffected = false;
2171
2172 if (visibleItems.size() && removal.index + removal.count > visibleItems.constLast()->index) {
2173 if (removal.index > visibleItems.constLast()->index)
2174 removeResult->countChangeAfterVisibleItems += removal.count;
2175 else
2176 removeResult->countChangeAfterVisibleItems += ((removal.index + removal.count - 1) - visibleItems.constLast()->index);
2177 }
2178
2179 QList<FxViewItem*>::Iterator it = visibleItems.begin();
2180 while (it != visibleItems.end()) {
2181 FxViewItem *item = *it;
2182 if (item->index == -1 || item->index < removal.index) {
2183 // already removed, or before removed items
2184 if (!visibleAffected && item->index < removal.index)
2185 visibleAffected = true;
2186 ++it;
2187 } else if (item->index >= removal.index + removal.count) {
2188 // after removed items
2189 item->index -= removal.count;
2190#if QT_CONFIG(quick_viewtransitions)
2191 if (removal.isMove())
2192 item->transitionNextReposition(transitioner, type: QQuickItemViewTransitioner::MoveTransition, asTarget: false);
2193 else
2194 item->transitionNextReposition(transitioner, type: QQuickItemViewTransitioner::RemoveTransition, asTarget: false);
2195#endif
2196 ++it;
2197 } else {
2198 // removed item
2199 visibleAffected = true;
2200 if (!removal.isMove() && item->item && item->attached)
2201 item->attached->emitRemove();
2202
2203 if (item->item && item->attached && item->attached->delayRemove() && !removal.isMove()) {
2204 item->index = -1;
2205 QObject::connect(sender: item->attached, SIGNAL(delayRemoveChanged()), receiver: q, SLOT(destroyRemoved()), Qt::QueuedConnection);
2206 ++it;
2207 } else {
2208 removeItem(item, removal, removeResult);
2209 if (!removal.isMove())
2210 (*removedCount)++;
2211 it = visibleItems.erase(pos: it);
2212 }
2213 }
2214 }
2215
2216 return visibleAffected;
2217}
2218
2219void QQuickItemViewPrivate::removeItem(FxViewItem *item, const QQmlChangeSet::Change &removal, ChangeResult *removeResult)
2220{
2221 if (removeResult->visiblePos.isValid()) {
2222 if (item->position() < removeResult->visiblePos)
2223 updateSizeChangesBeforeVisiblePos(item, removeResult);
2224 else
2225 removeResult->sizeChangesAfterVisiblePos += item->size();
2226 }
2227 if (removal.isMove()) {
2228 currentChanges.removedItems.replace(key: removal.moveKey(index: item->index), value: item);
2229#if QT_CONFIG(quick_viewtransitions)
2230 item->transitionNextReposition(transitioner, type: QQuickItemViewTransitioner::MoveTransition, asTarget: true);
2231#endif
2232 } else {
2233 // track item so it is released later
2234 currentChanges.removedItems.insert(key: QQmlChangeSet::MoveKey(), value: item);
2235 }
2236 if (!removeResult->changedFirstItem && item == *visibleItems.constBegin())
2237 removeResult->changedFirstItem = true;
2238}
2239
2240void QQuickItemViewPrivate::updateSizeChangesBeforeVisiblePos(FxViewItem *item, ChangeResult *removeResult)
2241{
2242 removeResult->sizeChangesBeforeVisiblePos += item->size();
2243}
2244
2245void QQuickItemViewPrivate::repositionFirstItem(FxViewItem *prevVisibleItemsFirst,
2246 qreal prevVisibleItemsFirstPos,
2247 FxViewItem *prevFirstVisible,
2248 ChangeResult *insertionResult,
2249 ChangeResult *removalResult)
2250{
2251 const QQmlNullableValue<qreal> prevViewPos = insertionResult->visiblePos;
2252
2253 // reposition visibleItems.first() correctly so that the content y doesn't jump
2254 if (visibleItems.size()) {
2255 if (prevVisibleItemsFirst && insertionResult->changedFirstItem)
2256 resetFirstItemPosition(pos: prevVisibleItemsFirstPos);
2257
2258 if (prevFirstVisible && prevVisibleItemsFirst == prevFirstVisible
2259 && prevFirstVisible != *visibleItems.constBegin()) {
2260 // the previous visibleItems.first() was also the first visible item, and it has been
2261 // moved/removed, so move the new visibleItems.first() to the pos of the previous one
2262 if (!insertionResult->changedFirstItem)
2263 resetFirstItemPosition(pos: prevVisibleItemsFirstPos);
2264
2265 } else if (prevViewPos.isValid()) {
2266 qreal moveForwardsBy = 0;
2267 qreal moveBackwardsBy = 0;
2268
2269 // shift visibleItems.first() relative to the number of added/removed items
2270 const auto pos = visibleItems.constFirst()->position();
2271 if (pos > prevViewPos) {
2272 moveForwardsBy = insertionResult->sizeChangesAfterVisiblePos;
2273 moveBackwardsBy = removalResult->sizeChangesAfterVisiblePos;
2274 } else if (pos < prevViewPos) {
2275 moveForwardsBy = removalResult->sizeChangesBeforeVisiblePos;
2276 moveBackwardsBy = insertionResult->sizeChangesBeforeVisiblePos;
2277 }
2278 adjustFirstItem(forwards: moveForwardsBy, backwards: moveBackwardsBy, changeBeforeVisible: insertionResult->countChangeBeforeVisible - removalResult->countChangeBeforeVisible);
2279 }
2280 insertionResult->reset();
2281 removalResult->reset();
2282 }
2283}
2284
2285#if QT_CONFIG(quick_viewtransitions)
2286void QQuickItemViewPrivate::createTransitioner()
2287{
2288 if (!transitioner) {
2289 transitioner = new QQuickItemViewTransitioner;
2290 transitioner->setChangeListener(this);
2291 }
2292}
2293
2294void QQuickItemViewPrivate::prepareVisibleItemTransitions()
2295{
2296 Q_Q(QQuickItemView);
2297 if (!transitioner)
2298 return;
2299
2300 // must call for every visible item to init or discard transitions
2301 QRectF viewBounds(q->contentX(), q->contentY(), q->width(), q->height());
2302 for (int i=0; i<visibleItems.size(); i++)
2303 visibleItems[i]->prepareTransition(transitioner, viewBounds);
2304}
2305
2306void QQuickItemViewPrivate::prepareRemoveTransitions(QMultiHash<QQmlChangeSet::MoveKey, FxViewItem *> *removedItems)
2307{
2308 if (!transitioner)
2309 return;
2310
2311 if (transitioner->canTransition(type: QQuickItemViewTransitioner::RemoveTransition, asTarget: true)
2312 || transitioner->canTransition(type: QQuickItemViewTransitioner::RemoveTransition, asTarget: false)) {
2313 for (auto it = removedItems->begin(); it != removedItems->end(); ) {
2314 bool isRemove = it.key().moveId < 0;
2315 if (isRemove) {
2316 FxViewItem *item = *it;
2317 item->trackGeometry(track: false);
2318 item->releaseAfterTransition = true;
2319 releasePendingTransition.append(t: item);
2320 item->transitionNextReposition(transitioner, type: QQuickItemViewTransitioner::RemoveTransition, asTarget: true);
2321 it = removedItems->erase(it);
2322 } else {
2323 ++it;
2324 }
2325 }
2326 }
2327}
2328
2329bool QQuickItemViewPrivate::prepareNonVisibleItemTransition(FxViewItem *item, const QRectF &viewBounds)
2330{
2331 // Called for items that have been removed from visibleItems and may now be
2332 // transitioned out of the view. This applies to items that are being directly
2333 // removed, or moved to outside of the view, as well as those that are
2334 // displaced to a position outside of the view due to an insert or move.
2335
2336 if (!transitioner)
2337 return false;
2338
2339 if (item->scheduledTransitionType() == QQuickItemViewTransitioner::MoveTransition)
2340 repositionItemAt(item, index: item->index, sizeBuffer: 0);
2341
2342 bool success = false;
2343 ACTION_IF_DELETED(item, success = item->prepareTransition(transitioner, viewBounds), return success);
2344
2345 if (success) {
2346 item->releaseAfterTransition = true;
2347 return true;
2348 }
2349 return false;
2350}
2351
2352void QQuickItemViewPrivate::viewItemTransitionFinished(QQuickItemViewTransitionableItem *item)
2353{
2354 for (int i=0; i<releasePendingTransition.size(); i++) {
2355 if (releasePendingTransition.at(i)->transitionableItem == item) {
2356 releaseItem(item: releasePendingTransition.takeAt(i), reusableFlag);
2357 return;
2358 }
2359 }
2360}
2361#endif
2362
2363/*
2364 This may return 0 if the item is being created asynchronously.
2365 When the item becomes available, refill() will be called and the item
2366 will be returned on the next call to createItem().
2367*/
2368FxViewItem *QQuickItemViewPrivate::createItem(int modelIndex, QQmlIncubator::IncubationMode incubationMode)
2369{
2370 Q_Q(QQuickItemView);
2371
2372 if (requestedIndex == modelIndex && incubationMode == QQmlIncubator::Asynchronous)
2373 return nullptr;
2374
2375#if QT_CONFIG(quick_viewtransitions)
2376 for (int i=0; i<releasePendingTransition.size(); i++) {
2377 if (releasePendingTransition.at(i)->index == modelIndex
2378 && !releasePendingTransition.at(i)->isPendingRemoval()) {
2379 releasePendingTransition[i]->releaseAfterTransition = false;
2380 return releasePendingTransition.takeAt(i);
2381 }
2382 }
2383#endif
2384
2385 inRequest = true;
2386
2387 // The model will run this same range check internally but produce a warning and return nullptr.
2388 // Since we handle this result graciously in our code, we preempt this warning by checking the range ourselves.
2389 QObject* object = modelIndex < model->count() ? model->object(index: modelIndex, incubationMode) : nullptr;
2390 QQuickItem *item = qmlobject_cast<QQuickItem*>(object);
2391
2392 if (!item) {
2393 if (!object) {
2394 if (requestedIndex == -1 && model->incubationStatus(index: modelIndex) == QQmlIncubator::Loading) {
2395 // The reason we didn't receive an item is because it's incubating async. We keep track
2396 // of this by assigning the index we're waiting for to 'requestedIndex'. This will e.g. let
2397 // the view avoid unnecessary layout calls until the item has been loaded.
2398 requestedIndex = modelIndex;
2399 }
2400 } else {
2401 model->release(object);
2402 if (!delegateValidated) {
2403 delegateValidated = true;
2404 QObject* delegate = q->delegate();
2405 qmlWarning(me: delegate ? delegate : q) << QQuickItemView::tr(s: "Delegate must be of Item type");
2406 }
2407 }
2408 inRequest = false;
2409 return nullptr;
2410 } else {
2411 item->setParentItem(q->contentItem());
2412 if (requestedIndex == modelIndex)
2413 requestedIndex = -1;
2414 FxViewItem *viewItem = newViewItem(index: modelIndex, item);
2415 if (viewItem) {
2416 viewItem->index = modelIndex;
2417 // do other set up for the new item that should not happen
2418 // until after bindings are evaluated
2419 initializeViewItem(viewItem);
2420 unrequestedItems.remove(key: item);
2421 }
2422 inRequest = false;
2423 return viewItem;
2424 }
2425}
2426
2427void QQuickItemView::createdItem(int index, QObject* object)
2428{
2429 Q_D(QQuickItemView);
2430
2431 QQuickItem* item = qmlobject_cast<QQuickItem*>(object);
2432 if (!d->inRequest) {
2433 d->unrequestedItems.insert(key: item, value: index);
2434 d->requestedIndex = -1;
2435 if (d->hasPendingChanges())
2436 d->layout();
2437 else
2438 d->refill();
2439 if (d->unrequestedItems.contains(key: item))
2440 d->repositionPackageItemAt(item, index);
2441 else if (index == d->currentIndex)
2442 d->updateCurrent(modelIndex: index);
2443 }
2444}
2445
2446void QQuickItemView::initItem(int, QObject *object)
2447{
2448 QQuickItem* item = qmlobject_cast<QQuickItem*>(object);
2449 if (item) {
2450 if (qFuzzyIsNull(d: item->z()))
2451 item->setZ(1);
2452 item->setParentItem(contentItem());
2453 QQuickItemPrivate::get(item)->setCulled(true);
2454 }
2455}
2456
2457void QQuickItemView::destroyingItem(QObject *object)
2458{
2459 Q_D(QQuickItemView);
2460 QQuickItem* item = qmlobject_cast<QQuickItem*>(object);
2461 if (item) {
2462 item->setParentItem(nullptr);
2463 d->unrequestedItems.remove(key: item);
2464 }
2465}
2466
2467void QQuickItemView::onItemPooled(int modelIndex, QObject *object)
2468{
2469 Q_UNUSED(modelIndex);
2470
2471 if (auto *attached = d_func()->getAttachedObject(object))
2472 emit attached->pooled();
2473}
2474
2475void QQuickItemView::onItemReused(int modelIndex, QObject *object)
2476{
2477 Q_UNUSED(modelIndex);
2478
2479 if (auto *attached = d_func()->getAttachedObject(object))
2480 emit attached->reused();
2481}
2482
2483bool QQuickItemViewPrivate::releaseItem(FxViewItem *item, QQmlInstanceModel::ReusableFlag reusableFlag)
2484{
2485 Q_Q(QQuickItemView);
2486 if (!item)
2487 return true;
2488 if (trackedItem == item)
2489 trackedItem = nullptr;
2490 item->trackGeometry(track: false);
2491
2492 QQmlInstanceModel::ReleaseFlags flags = {};
2493 if (model && item->item) {
2494 flags = model->release(object: item->item, reusableFlag);
2495 if (!flags) {
2496 // item was not destroyed, and we no longer reference it.
2497 if (item->item->parentItem() == contentItem) {
2498 // Only cull the item if its parent item is still our contentItem.
2499 // One case where this can happen is moving an item out of one ObjectModel and into another.
2500 QQuickItemPrivate::get(item: item->item)->setCulled(true);
2501 }
2502 // If deleteLater was called, the item isn't long for this world and so we shouldn't store references to it.
2503 // This can happen when a Repeater is used to populate items in SwipeView's ListView contentItem.
2504 if (!isClearing && !QObjectPrivate::get(o: item->item)->deleteLaterCalled)
2505 unrequestedItems.insert(key: item->item, value: model->indexOf(object: item->item, objectContext: q));
2506 } else if (flags & QQmlInstanceModel::Destroyed) {
2507 item->item->setParentItem(nullptr);
2508 } else if (flags & QQmlInstanceModel::Pooled) {
2509 item->setVisible(false);
2510 }
2511 }
2512 delete item;
2513 return flags != QQmlInstanceModel::Referenced;
2514}
2515
2516QQuickItem *QQuickItemViewPrivate::createHighlightItem()
2517{
2518 QQuickItem *item = nullptr;
2519 if (!inRequest) {
2520 inRequest = true;
2521 item = createComponentItem(component: highlightComponent, zValue: 0.0, createDefault: true);
2522 inRequest = false;
2523 }
2524 return item;
2525}
2526
2527QQuickItem *QQuickItemViewPrivate::createComponentItem(QQmlComponent *component, qreal zValue, bool createDefault) const
2528{
2529 Q_Q(const QQuickItemView);
2530
2531 QQuickItem *item = nullptr;
2532 if (component) {
2533 QQmlContext *context = component->creationContext();
2534 if (!context)
2535 context = qmlContext(q);
2536
2537 if (QObject *nobj = component->beginCreate(context)) {
2538 item = qobject_cast<QQuickItem *>(o: nobj);
2539 if (!item)
2540 delete nobj;
2541 }
2542 } else if (createDefault) {
2543 item = new QQuickItem;
2544 }
2545 if (item) {
2546 if (qFuzzyIsNull(d: item->z()))
2547 item->setZ(zValue);
2548 QQml_setParent_noEvent(object: item, parent: q->contentItem());
2549 item->setParentItem(q->contentItem());
2550
2551 initializeComponentItem(item);
2552 }
2553 if (component)
2554 component->completeCreate();
2555 return item;
2556}
2557
2558/*!
2559 \internal
2560
2561 Allows derived classes to do any initialization required for \a item
2562 before completeCreate() is called on it. For example, any attached
2563 properties required by the item can be set.
2564
2565 This is similar to initItem(), but as that has logic specific to
2566 delegate items, we use a separate function for non-delegates.
2567*/
2568void QQuickItemViewPrivate::initializeComponentItem(QQuickItem *item) const
2569{
2570 Q_UNUSED(item);
2571}
2572
2573void QQuickItemViewPrivate::updateTrackedItem()
2574{
2575 Q_Q(QQuickItemView);
2576 FxViewItem *item = currentItem;
2577 if (highlight)
2578 item = highlight.get();
2579 trackedItem = item;
2580
2581 if (trackedItem)
2582 q->trackedPositionChanged();
2583}
2584
2585void QQuickItemViewPrivate::updateUnrequestedIndexes()
2586{
2587 Q_Q(QQuickItemView);
2588 for (QHash<QQuickItem*,int>::iterator it = unrequestedItems.begin(), end = unrequestedItems.end(); it != end; ++it)
2589 *it = model->indexOf(object: it.key(), objectContext: q);
2590}
2591
2592void QQuickItemViewPrivate::updateUnrequestedPositions()
2593{
2594 for (QHash<QQuickItem*,int>::const_iterator it = unrequestedItems.cbegin(), cend = unrequestedItems.cend(); it != cend; ++it) {
2595 if (it.value() >= 0)
2596 repositionPackageItemAt(item: it.key(), index: it.value());
2597 }
2598}
2599
2600void QQuickItemViewPrivate::updateVisibleIndex()
2601{
2602 typedef QList<FxViewItem*>::const_iterator FxViewItemListConstIt;
2603
2604 visibleIndex = 0;
2605 for (FxViewItemListConstIt it = visibleItems.constBegin(), cend = visibleItems.constEnd(); it != cend; ++it) {
2606 if ((*it)->index != -1) {
2607 visibleIndex = (*it)->index;
2608 break;
2609 }
2610 }
2611}
2612
2613QT_END_NAMESPACE
2614
2615#include "moc_qquickitemview_p.cpp"
2616

Provided by KDAB

Privacy Policy
Learn Advanced QML with KDAB
Find out more

source code of qtdeclarative/src/quick/items/qquickitemview.cpp