| 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 *; | 
| 271 |     FxViewItem *; | 
| 272 |     QQmlComponent *; | 
| 273 |     FxViewItem *; | 
| 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 () const = 0; | 
| 324 |     virtual qreal () const = 0; | 
| 325 |     virtual bool (int index) const = 0; | 
| 326 |     virtual bool (int index) const = 0; | 
| 327 |     virtual void () = 0; | 
| 328 |     virtual void () = 0; | 
| 329 |     virtual bool () const { return false; } | 
| 330 |     virtual bool () 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 |  |