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 | |
20 | QT_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 | |
34 | QT_BEGIN_NAMESPACE |
35 | |
36 | class Q_AUTOTEST_EXPORT FxViewItem : public QQuickItemViewFxItem |
37 | { |
38 | public: |
39 | FxViewItem(QQuickItem *, QQuickItemView *, bool own, QQuickItemViewAttached *attached); |
40 | |
41 | QQuickItemView *view; |
42 | QQuickItemViewAttached *attached; |
43 | }; |
44 | |
45 | |
46 | class Q_AUTOTEST_EXPORT QQuickItemViewChangeSet |
47 | { |
48 | public: |
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 | |
70 | class Q_QUICK_AUTOTEST_EXPORT QQuickItemViewPrivate |
71 | : public QQuickFlickablePrivate |
72 | #if QT_CONFIG(quick_viewtransitions) |
73 | , public QQuickItemViewTransitionChangeListener |
74 | #endif |
75 | , public QAnimationJobChangeListener |
76 | { |
77 | public: |
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 | |
155 | QQuickItem *createHighlightItem(); |
156 | QQuickItem *createComponentItem(QQmlComponent *component, qreal zValue, bool createDefault = false) const; |
157 | virtual void initializeComponentItem(QQuickItem *) const; |
158 | |
159 | void updateCurrent(int modelIndex); |
160 | void updateTrackedItem(); |
161 | void updateUnrequestedIndexes(); |
162 | void updateUnrequestedPositions(); |
163 | void updateVisibleIndex(); |
164 | void positionViewAtIndex(int index, int mode); |
165 | |
166 | qreal minExtentForAxis(const AxisData &axisData, bool forXAxis) const; |
167 | qreal maxExtentForAxis(const AxisData &axisData, bool forXAxis) const; |
168 | qreal calculatedMinExtent() const; |
169 | qreal calculatedMaxExtent() const; |
170 | |
171 | void applyDelegateChange(); |
172 | |
173 | void applyPendingChanges(); |
174 | bool applyModelChanges(ChangeResult *insertionResult, ChangeResult *removalResult); |
175 | bool applyRemovalChange(const QQmlChangeSet::Change &removal, ChangeResult *changeResult, int *removedCount); |
176 | void removeItem(FxViewItem *item, const QQmlChangeSet::Change &removal, ChangeResult *removeResult); |
177 | virtual void updateSizeChangesBeforeVisiblePos(FxViewItem *item, ChangeResult *removeResult); |
178 | void repositionFirstItem(FxViewItem *prevVisibleItemsFirst, qreal prevVisibleItemsFirstPos, |
179 | FxViewItem *prevFirstVisible, ChangeResult *insertionResult, ChangeResult *removalResult); |
180 | |
181 | #if QT_CONFIG(quick_viewtransitions) |
182 | void createTransitioner(); |
183 | void prepareVisibleItemTransitions(); |
184 | void prepareRemoveTransitions(QMultiHash<QQmlChangeSet::MoveKey, FxViewItem *> *removedItems); |
185 | bool prepareNonVisibleItemTransition(FxViewItem *item, const QRectF &viewBounds); |
186 | void viewItemTransitionFinished(QQuickItemViewTransitionableItem *item) override; |
187 | #endif |
188 | |
189 | int findMoveKeyIndex(QQmlChangeSet::MoveKey key, const QVector<QQmlChangeSet::Change> &changes) const; |
190 | |
191 | void checkVisible() const; |
192 | void showVisibleItems() const; |
193 | |
194 | void markExtentsDirty() { |
195 | if (layoutOrientation() == Qt::Vertical) |
196 | vData.markExtentsDirty(); |
197 | else |
198 | hData.markExtentsDirty(); |
199 | } |
200 | |
201 | bool hasPendingChanges() const { |
202 | return currentChanges.hasPendingChanges() |
203 | || bufferedChanges.hasPendingChanges() |
204 | #if QT_CONFIG(quick_viewtransitions) |
205 | ||runDelayedRemoveTransition |
206 | #endif |
207 | ; |
208 | } |
209 | |
210 | void refillOrLayout() { |
211 | if (hasPendingChanges()) |
212 | layout(); |
213 | else |
214 | refill(); |
215 | } |
216 | |
217 | void forceLayoutPolish() { |
218 | Q_Q(QQuickItemView); |
219 | forceLayout = true; |
220 | q->polish(); |
221 | } |
222 | |
223 | void releaseVisibleItems(QQmlInstanceModel::ReusableFlag reusableFlag) { |
224 | // make a copy and clear the visibleItems first to avoid destroyed |
225 | // items being accessed during the loop (QTBUG-61294) |
226 | const QList<FxViewItem *> oldVisible = visibleItems; |
227 | visibleItems.clear(); |
228 | for (FxViewItem *item : oldVisible) |
229 | releaseItem(item, reusableFlag); |
230 | } |
231 | |
232 | void emitCountChanged(); |
233 | |
234 | virtual QQuickItemViewAttached *getAttachedObject(const QObject *) const { return nullptr; } |
235 | |
236 | QPointer<QQmlInstanceModel> model; |
237 | QVariant modelVariant; |
238 | int itemCount; |
239 | int buffer; |
240 | int bufferMode; |
241 | int displayMarginBeginning; |
242 | int displayMarginEnd; |
243 | Qt::LayoutDirection layoutDirection; |
244 | QQuickItemView::VerticalLayoutDirection verticalLayoutDirection; |
245 | |
246 | QList<FxViewItem *> visibleItems; |
247 | qreal firstVisibleItemPosition = 0; |
248 | void storeFirstVisibleItemPosition() { |
249 | if (!visibleItems.isEmpty()) { |
250 | firstVisibleItemPosition = visibleItems.constFirst()->position(); |
251 | } |
252 | } |
253 | int visibleIndex; |
254 | int currentIndex; |
255 | FxViewItem *currentItem; |
256 | FxViewItem *trackedItem; |
257 | QHash<QQuickItem*,int> unrequestedItems; |
258 | int requestedIndex; |
259 | QQuickItemViewChangeSet currentChanges; |
260 | QQuickItemViewChangeSet bufferedChanges; |
261 | QPauseAnimationJob bufferPause; |
262 | |
263 | QQmlComponent *highlightComponent; |
264 | std::unique_ptr<FxViewItem> highlight; |
265 | int highlightRange; // enum value |
266 | qreal highlightRangeStart; |
267 | qreal highlightRangeEnd; |
268 | int highlightMoveDuration; |
269 | |
270 | QQmlComponent *headerComponent; |
271 | FxViewItem *header; |
272 | QQmlComponent *footerComponent; |
273 | FxViewItem *footer; |
274 | |
275 | // Reusing delegate items cannot be on by default for backwards compatibility. |
276 | // Reusing an item will e.g mean that Component.onCompleted will only be called for an |
277 | // item when it's created and not when it's reused, which will break legacy applications. |
278 | QQmlInstanceModel::ReusableFlag reusableFlag = QQmlInstanceModel::NotReusable; |
279 | |
280 | struct MovedItem { |
281 | FxViewItem *item; |
282 | QQmlChangeSet::MoveKey moveKey; |
283 | MovedItem(FxViewItem *i, QQmlChangeSet::MoveKey k) |
284 | : item(i), moveKey(k) {} |
285 | }; |
286 | #if QT_CONFIG(quick_viewtransitions) |
287 | QQuickItemViewTransitioner *transitioner; |
288 | QVector<FxViewItem *> releasePendingTransition; |
289 | #endif |
290 | |
291 | mutable qreal minExtent; |
292 | mutable qreal maxExtent; |
293 | |
294 | bool ownModel : 1; |
295 | bool wrap : 1; |
296 | bool keyNavigationEnabled : 1; |
297 | bool explicitKeyNavigationEnabled : 1; |
298 | bool inLayout : 1; |
299 | bool inViewportMoved : 1; |
300 | bool forceLayout : 1; |
301 | bool currentIndexCleared : 1; |
302 | bool haveHighlightRange : 1; |
303 | bool autoHighlight : 1; |
304 | bool highlightRangeStartValid : 1; |
305 | bool highlightRangeEndValid : 1; |
306 | bool fillCacheBuffer : 1; |
307 | bool inRequest : 1; |
308 | #if QT_CONFIG(quick_viewtransitions) |
309 | bool runDelayedRemoveTransition : 1; |
310 | #endif |
311 | bool delegateValidated : 1; |
312 | bool isClearing : 1; |
313 | |
314 | protected: |
315 | virtual Qt::Orientation layoutOrientation() const = 0; |
316 | virtual bool isContentFlowReversed() const = 0; |
317 | |
318 | virtual qreal positionAt(int index) const = 0; |
319 | virtual qreal endPositionAt(int index) const = 0; |
320 | virtual qreal originPosition() const = 0; |
321 | virtual qreal lastPosition() const = 0; |
322 | |
323 | virtual qreal headerSize() const = 0; |
324 | virtual qreal footerSize() const = 0; |
325 | virtual bool showHeaderForIndex(int index) const = 0; |
326 | virtual bool showFooterForIndex(int index) const = 0; |
327 | virtual void updateHeader() = 0; |
328 | virtual void updateFooter() = 0; |
329 | virtual bool hasStickyHeader() const { return false; } |
330 | virtual bool hasStickyFooter() const { return false; } |
331 | |
332 | virtual void createHighlight(bool onDestruction = false) = 0; |
333 | virtual void updateHighlight() = 0; |
334 | virtual void resetHighlightPosition() = 0; |
335 | virtual bool movingFromHighlight() { return false; } |
336 | |
337 | virtual void setPosition(qreal pos) = 0; |
338 | virtual void fixupPosition() = 0; |
339 | |
340 | virtual bool addVisibleItems(qreal fillFrom, qreal fillTo, qreal bufferFrom, qreal bufferTo, bool doBuffer) = 0; |
341 | virtual bool removeNonVisibleItems(qreal bufferFrom, qreal bufferTo) = 0; |
342 | virtual void visibleItemsChanged() {} |
343 | |
344 | virtual FxViewItem *newViewItem(int index, QQuickItem *item) = 0; |
345 | virtual void repositionItemAt(FxViewItem *item, int index, qreal sizeBuffer) = 0; |
346 | virtual void repositionPackageItemAt(QQuickItem *item, int index) = 0; |
347 | virtual void resetFirstItemPosition(qreal pos = 0.0) = 0; |
348 | virtual void adjustFirstItem(qreal forwards, qreal backwards, int changeBeforeVisible) = 0; |
349 | |
350 | virtual void layoutVisibleItems(int fromModelIndex = 0) = 0; |
351 | virtual void changedVisibleIndex(int newIndex) = 0; |
352 | |
353 | virtual bool applyInsertionChange(const QQmlChangeSet::Change &insert, ChangeResult *changeResult, |
354 | QList<FxViewItem *> *newItems, QList<MovedItem> *movingIntoView) = 0; |
355 | |
356 | virtual bool needsRefillForAddedOrRemovedIndex(int) const { return false; } |
357 | #if QT_CONFIG(quick_viewtransitions) |
358 | virtual void translateAndTransitionItemsAfter(int afterIndex, const ChangeResult &insertionResult, const ChangeResult &removalResult) = 0; |
359 | #endif |
360 | |
361 | virtual void initializeViewItem(FxViewItem *) {} |
362 | virtual void initializeCurrentItem() {} |
363 | virtual void updateSectionCriteria() {} |
364 | virtual void updateSections() {} |
365 | |
366 | void itemGeometryChanged(QQuickItem *item, QQuickGeometryChange change, const QRectF &) override; |
367 | }; |
368 | |
369 | |
370 | QT_END_NAMESPACE |
371 | |
372 | #endif // QQUICKITEMVIEW_P_P_H |
373 |
Definitions
- FxViewItem
- QQuickItemViewChangeSet
- QQuickItemViewPrivate
- get
- ChangeResult
- ChangeResult
- ChangeResult
- operator+=
- reset
- BufferMode
- releaseCurrentItem
- markExtentsDirty
- hasPendingChanges
- refillOrLayout
- forceLayoutPolish
- releaseVisibleItems
- getAttachedObject
- storeFirstVisibleItemPosition
- MovedItem
- MovedItem
- hasStickyHeader
- hasStickyFooter
- movingFromHighlight
- visibleItemsChanged
- needsRefillForAddedOrRemovedIndex
- initializeViewItem
- initializeCurrentItem
- updateSectionCriteria
Start learning QML with our Intro Training
Find out more