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