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#ifndef QQUICKITEMVIEW_P_P_H
5#define QQUICKITEMVIEW_P_P_H
6
7//
8// W A R N I N G
9// -------------
10//
11// This file is not part of the Qt API. It exists purely as an
12// implementation detail. This header file may change from version to
13// version without notice, or even be removed.
14//
15// We mean it.
16//
17
18#include <QtQuick/private/qtquickglobal_p.h>
19
20QT_REQUIRE_CONFIG(quick_itemview);
21
22#include "qquickitemview_p.h"
23#include "qquickitemviewfxitem_p_p.h"
24#if QT_CONFIG(quick_viewtransitions)
25#include "qquickitemviewtransition_p.h"
26#endif
27#include "qquickflickable_p_p.h"
28#include <QtQmlModels/private/qqmlobjectmodel_p.h>
29#include <QtQmlModels/private/qqmldelegatemodel_p.h>
30#include <QtQmlModels/private/qqmlchangeset_p.h>
31
32#include <QtCore/qpointer.h>
33
34QT_BEGIN_NAMESPACE
35
36class Q_AUTOTEST_EXPORT FxViewItem : public QQuickItemViewFxItem
37{
38public:
39 FxViewItem(QQuickItem *, QQuickItemView *, bool own, QQuickItemViewAttached *attached);
40
41 QQuickItemView *view;
42 QQuickItemViewAttached *attached;
43};
44
45
46class Q_QUICK_EXPORT QQuickItemViewChangeSet
47{
48public:
49 QQuickItemViewChangeSet();
50
51 bool hasPendingChanges() const;
52 void prepare(int currentIndex, int count);
53 void reset();
54
55 void applyChanges(const QQmlChangeSet &changeSet);
56
57 void applyBufferedChanges(const QQuickItemViewChangeSet &other);
58
59 int itemCount;
60 int newCurrentIndex;
61 QQmlChangeSet pendingChanges;
62 QMultiHash<QQmlChangeSet::MoveKey, FxViewItem *> removedItems;
63
64 bool active : 1;
65 bool currentChanged : 1;
66 bool currentRemoved : 1;
67};
68
69
70class Q_QUICK_AUTOTEST_EXPORT QQuickItemViewPrivate
71 : public QQuickFlickablePrivate
72#if QT_CONFIG(quick_viewtransitions)
73 , public QQuickItemViewTransitionChangeListener
74#endif
75 , public QAnimationJobChangeListener
76{
77public:
78 Q_DECLARE_PUBLIC(QQuickItemView)
79 QQuickItemViewPrivate();
80 ~QQuickItemViewPrivate();
81
82 static inline QQuickItemViewPrivate *get(QQuickItemView *o) { return o->d_func(); }
83
84 struct ChangeResult {
85 QQmlNullableValue<qreal> visiblePos;
86 bool changedFirstItem;
87 qreal sizeChangesBeforeVisiblePos;
88 qreal sizeChangesAfterVisiblePos;
89 int countChangeBeforeVisible;
90 int countChangeAfterVisibleItems;
91
92 ChangeResult()
93 : visiblePos(0), changedFirstItem(false),
94 sizeChangesBeforeVisiblePos(0), sizeChangesAfterVisiblePos(0),
95 countChangeBeforeVisible(0), countChangeAfterVisibleItems(0) {}
96
97 ChangeResult(const QQmlNullableValue<qreal> &p)
98 : visiblePos(p), changedFirstItem(false),
99 sizeChangesBeforeVisiblePos(0), sizeChangesAfterVisiblePos(0),
100 countChangeBeforeVisible(0), countChangeAfterVisibleItems(0) {}
101
102 ChangeResult &operator+=(const ChangeResult &other) {
103 if (&other == this)
104 return *this;
105 changedFirstItem &= other.changedFirstItem;
106 sizeChangesBeforeVisiblePos += other.sizeChangesBeforeVisiblePos;
107 sizeChangesAfterVisiblePos += other.sizeChangesAfterVisiblePos;
108 countChangeBeforeVisible += other.countChangeBeforeVisible;
109 countChangeAfterVisibleItems += other.countChangeAfterVisibleItems;
110 return *this;
111 }
112
113 void reset() {
114 changedFirstItem = false;
115 sizeChangesBeforeVisiblePos = 0.0;
116 sizeChangesAfterVisiblePos = 0.0;
117 countChangeBeforeVisible = 0;
118 countChangeAfterVisibleItems = 0;
119 }
120 };
121
122 enum BufferMode { NoBuffer = 0x00, BufferBefore = 0x01, BufferAfter = 0x02 };
123
124 bool isValid() const;
125 qreal position() const;
126 qreal size() const;
127 qreal startPosition() const;
128 qreal endPosition() const;
129 qreal contentStartOffset() const;
130 int findLastVisibleIndex(int defaultValue = -1) const;
131 FxViewItem *visibleItem(int modelIndex) const;
132 FxViewItem *firstItemInView() const;
133 int findLastIndexInView() const;
134 int mapFromModel(int modelIndex) const;
135
136 virtual void init();
137 virtual void clear(bool onDestruction=false);
138 virtual void updateViewport();
139
140 void regenerate(bool orientationChanged=false);
141 void layout();
142 void animationFinished(QAbstractAnimationJob *) override;
143 void refill();
144 void refill(qreal from, qreal to);
145 void mirrorChange() override;
146
147 FxViewItem *createItem(int modelIndex,QQmlIncubator::IncubationMode incubationMode = QQmlIncubator::AsynchronousIfNested);
148 bool releaseCurrentItem(QQmlInstanceModel::ReusableFlag reusableFlag)
149 {
150 auto oldCurrentItem = std::exchange(obj&: currentItem, new_val: nullptr);
151 return releaseItem(item: oldCurrentItem, reusableFlag);
152 }
153 virtual bool releaseItem(FxViewItem *item, QQmlInstanceModel::ReusableFlag reusableFlag);
154 void itemDestroyed(QQuickItem *item) override;
155
156 QQuickItem *createHighlightItem();
157 QQuickItem *createComponentItem(QQmlComponent *component, qreal zValue, bool createDefault = false) const;
158 virtual void initializeComponentItem(QQuickItem *) const;
159
160 void updateCurrent(int modelIndex);
161 void updateTrackedItem();
162 void updateUnrequestedIndexes();
163 void updateUnrequestedPositions();
164 void updateVisibleIndex();
165 void positionViewAtIndex(int index, int mode);
166
167 qreal minExtentForAxis(const AxisData &axisData, bool forXAxis) const;
168 qreal maxExtentForAxis(const AxisData &axisData, bool forXAxis) const;
169 qreal calculatedMinExtent() const;
170 qreal calculatedMaxExtent() const;
171
172 void connectModel(QQuickItemView *q, QQmlDelegateModelPointer *model);
173 void disconnectModel(QQuickItemView *q, QQmlDelegateModelPointer *model);
174
175 void applyDelegateChange();
176 void applyDelegateModelAccessChange()
177 {
178 QQmlDelegateModel::applyDelegateModelAccessChangeOnView(q: q_func(), d: this);
179 }
180
181 void applyPendingChanges();
182 bool applyModelChanges(ChangeResult *insertionResult, ChangeResult *removalResult);
183 bool applyRemovalChange(const QQmlChangeSet::Change &removal, ChangeResult *changeResult, int *removedCount);
184 void removeItem(FxViewItem *item, const QQmlChangeSet::Change &removal, ChangeResult *removeResult);
185 virtual void updateSizeChangesBeforeVisiblePos(FxViewItem *item, ChangeResult *removeResult);
186 void repositionFirstItem(FxViewItem *prevVisibleItemsFirst, qreal prevVisibleItemsFirstPos,
187 FxViewItem *prevFirstVisible, ChangeResult *insertionResult, ChangeResult *removalResult);
188
189#if QT_CONFIG(quick_viewtransitions)
190 void createTransitioner();
191 void prepareVisibleItemTransitions();
192 void prepareRemoveTransitions(QMultiHash<QQmlChangeSet::MoveKey, FxViewItem *> *removedItems);
193 bool prepareNonVisibleItemTransition(FxViewItem *item, const QRectF &viewBounds);
194 void viewItemTransitionFinished(QQuickItemViewTransitionableItem *item) override;
195#endif
196
197 int findMoveKeyIndex(QQmlChangeSet::MoveKey key, const QVector<QQmlChangeSet::Change> &changes) const;
198
199 void checkVisible() const;
200 void showVisibleItems() const;
201
202 void markExtentsDirty() {
203 if (layoutOrientation() == Qt::Vertical)
204 vData.markExtentsDirty();
205 else
206 hData.markExtentsDirty();
207 }
208
209 bool hasPendingChanges() const {
210 return currentChanges.hasPendingChanges()
211 || bufferedChanges.hasPendingChanges()
212#if QT_CONFIG(quick_viewtransitions)
213 ||runDelayedRemoveTransition
214#endif
215 ;
216 }
217
218 void refillOrLayout() {
219 if (hasPendingChanges())
220 layout();
221 else
222 refill();
223 }
224
225 void forceLayoutPolish() {
226 Q_Q(QQuickItemView);
227 forceLayout = true;
228 q->polish();
229 }
230
231 void releaseVisibleItems(QQmlInstanceModel::ReusableFlag reusableFlag) {
232 // make a copy and clear the visibleItems first to avoid destroyed
233 // items being accessed during the loop (QTBUG-61294)
234 const QList<FxViewItem *> oldVisible = visibleItems;
235 visibleItems.clear();
236 for (FxViewItem *item : oldVisible)
237 releaseItem(item, reusableFlag);
238 }
239
240 void emitCountChanged();
241
242 virtual QQuickItemViewAttached *getAttachedObject(const QObject *) const { return nullptr; }
243
244 QPointer<QQmlInstanceModel> model;
245 QVariant modelVariant;
246 int itemCount;
247 int buffer;
248 int bufferMode;
249 int displayMarginBeginning;
250 int displayMarginEnd;
251 Qt::LayoutDirection layoutDirection;
252 QQuickItemView::VerticalLayoutDirection verticalLayoutDirection;
253
254 QList<FxViewItem *> visibleItems;
255 qreal firstVisibleItemPosition = 0;
256 void storeFirstVisibleItemPosition() {
257 if (!visibleItems.isEmpty()) {
258 firstVisibleItemPosition = visibleItems.constFirst()->position();
259 }
260 }
261 int visibleIndex;
262 int currentIndex;
263 FxViewItem *currentItem;
264 FxViewItem *trackedItem;
265 QHash<QQuickItem*,int> unrequestedItems;
266 int requestedIndex;
267 QQuickItemViewChangeSet currentChanges;
268 QQuickItemViewChangeSet bufferedChanges;
269 QPauseAnimationJob bufferPause;
270
271 QQmlComponent *highlightComponent;
272 std::unique_ptr<FxViewItem> highlight;
273 int highlightRange; // enum value
274 qreal highlightRangeStart;
275 qreal highlightRangeEnd;
276 int highlightMoveDuration;
277
278 QQmlComponent *headerComponent;
279 FxViewItem *header;
280 QQmlComponent *footerComponent;
281 FxViewItem *footer;
282
283 // Reusing delegate items cannot be on by default for backwards compatibility.
284 // Reusing an item will e.g mean that Component.onCompleted will only be called for an
285 // item when it's created and not when it's reused, which will break legacy applications.
286 QQmlInstanceModel::ReusableFlag reusableFlag = QQmlInstanceModel::NotReusable;
287
288 struct MovedItem {
289 FxViewItem *item;
290 QQmlChangeSet::MoveKey moveKey;
291 MovedItem(FxViewItem *i, QQmlChangeSet::MoveKey k)
292 : item(i), moveKey(k) {}
293 };
294#if QT_CONFIG(quick_viewtransitions)
295 QQuickItemViewTransitioner *transitioner;
296 QVector<FxViewItem *> releasePendingTransition;
297#endif
298
299 mutable qreal minExtent;
300 mutable qreal maxExtent;
301
302 bool ownModel : 1;
303 bool wrap : 1;
304 bool keyNavigationEnabled : 1;
305 bool explicitKeyNavigationEnabled : 1;
306 bool inLayout : 1;
307 bool inViewportMoved : 1;
308 bool forceLayout : 1;
309 bool currentIndexCleared : 1;
310 bool haveHighlightRange : 1;
311 bool autoHighlight : 1;
312 bool highlightRangeStartValid : 1;
313 bool highlightRangeEndValid : 1;
314 bool fillCacheBuffer : 1;
315 bool inRequest : 1;
316#if QT_CONFIG(quick_viewtransitions)
317 bool runDelayedRemoveTransition : 1;
318#endif
319 bool delegateValidated : 1;
320 bool isClearing : 1;
321 bool explicitDelegate: 1;
322 bool explicitDelegateModelAccess: 1;
323
324protected:
325 virtual Qt::Orientation layoutOrientation() const = 0;
326 virtual bool isContentFlowReversed() const = 0;
327
328 virtual qreal positionAt(int index) const = 0;
329 virtual qreal endPositionAt(int index) const = 0;
330 virtual qreal originPosition() const = 0;
331 virtual qreal lastPosition() const = 0;
332
333 virtual qreal headerSize() const = 0;
334 virtual qreal footerSize() const = 0;
335 virtual bool showHeaderForIndex(int index) const = 0;
336 virtual bool showFooterForIndex(int index) const = 0;
337 virtual void updateHeader() = 0;
338 virtual void updateFooter() = 0;
339 virtual bool hasStickyHeader() const { return false; }
340 virtual bool hasStickyFooter() const { return false; }
341
342 virtual void createHighlight(bool onDestruction = false) = 0;
343 virtual void updateHighlight() = 0;
344 virtual void resetHighlightPosition() = 0;
345 virtual bool movingFromHighlight() { return false; }
346
347 virtual void setPosition(qreal pos) = 0;
348 virtual void fixupPosition() = 0;
349
350 virtual bool addVisibleItems(qreal fillFrom, qreal fillTo, qreal bufferFrom, qreal bufferTo, bool doBuffer) = 0;
351 virtual bool removeNonVisibleItems(qreal bufferFrom, qreal bufferTo) = 0;
352 virtual void visibleItemsChanged() {}
353
354 virtual FxViewItem *newViewItem(int index, QQuickItem *item) = 0;
355 virtual void repositionItemAt(FxViewItem *item, int index, qreal sizeBuffer) = 0;
356 virtual void repositionPackageItemAt(QQuickItem *item, int index) = 0;
357 virtual void resetFirstItemPosition(qreal pos = 0.0) = 0;
358 virtual void adjustFirstItem(qreal forwards, qreal backwards, int changeBeforeVisible) = 0;
359
360 virtual void layoutVisibleItems(int fromModelIndex = 0) = 0;
361 virtual void changedVisibleIndex(int newIndex) = 0;
362
363 virtual bool applyInsertionChange(const QQmlChangeSet::Change &insert, ChangeResult *changeResult,
364 QList<FxViewItem *> *newItems, QList<MovedItem> *movingIntoView) = 0;
365
366 virtual bool needsRefillForAddedOrRemovedIndex(int) const { return false; }
367#if QT_CONFIG(quick_viewtransitions)
368 virtual void translateAndTransitionItemsAfter(int afterIndex, const ChangeResult &insertionResult, const ChangeResult &removalResult) = 0;
369#endif
370
371 virtual void initializeViewItem(FxViewItem *) {}
372 virtual void initializeCurrentItem() {}
373 virtual void updateSectionCriteria() {}
374 virtual void updateSections() {}
375
376 void itemGeometryChanged(QQuickItem *item, QQuickGeometryChange change, const QRectF &) override;
377};
378
379
380QT_END_NAMESPACE
381
382#endif // QQUICKITEMVIEW_P_P_H
383

source code of qtdeclarative/src/quick/items/qquickitemview_p_p.h