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