@@ -121,6 +121,7 @@ void ListViewWithPageHeader::ListItem::setCulled(bool culled)
122ListViewWithPageHeader::ListViewWithPageHeader()
122ListViewWithPageHeader::ListViewWithPageHeader()
123 : m_delegateModel(nullptr)
123 : m_delegateModel(nullptr)
124+ , m_asyncRequestedIndex(-1)
124 , m_delegateValidated(false)
125 , m_delegateValidated(false)
125 , m_firstVisibleIndex(-1)
126 , m_firstVisibleIndex(-1)
126 , m_minYExtent(0)
127 , m_minYExtent(0)
@@ -503,7 +504,7 @@ void ListViewWithPageHeader::updateWatchedRoles()
506−QQuickItem *ListViewWithPageHeader::getSectionItem(int modelIndex)
507+QQuickItem *ListViewWithPageHeader::getSectionItem(int modelIndex, bool alreadyInserted)
508 if (!m_sectionDelegate)
509 if (!m_sectionDelegate)
509 return nullptr;
510 return nullptr;
@@ -514,6 +515,19 @@ QQuickItem *ListViewWithPageHeader::getSectionItem(int modelIndex)
514 if (section == prevSection)
515 if (section == prevSection)
515 return nullptr;
516 return nullptr;
518+ if (modelIndex + 1 < model()->rowCount() && !alreadyInserted) {
519+ // Already inserted items can't steal next section header
520+ const QString nextSection = m_delegateModel->stringValue(modelIndex + 1, m_sectionProperty);
521+ if (section == nextSection) {
522+ // Steal the section header
523+ ListItem *nextItem = itemAtIndex(modelIndex); // Not +1 since not yet inserted into m_visibleItems
525+ QQuickItem *sectionItem = nextItem->m_sectionItem;
526+ nextItem->m_sectionItem = nullptr;
518 return getSectionItem(section);
532 return getSectionItem(section);
@@ -580,21 +594,24 @@ bool ListViewWithPageHeader::removeNonVisibleItems(qreal bufferFrom, qreal buffe
580ListViewWithPageHeader::ListItem *ListViewWithPageHeader::createItem(int modelIndex, bool asynchronous)
594ListViewWithPageHeader::ListItem *ListViewWithPageHeader::createItem(int modelIndex, bool asynchronous)
582// qDebug() << "CREATE ITEM" << modelIndex;
596// qDebug() << "CREATE ITEM" << modelIndex;
583− if (asynchronous && m_asyncRequestedIndexes.contains(modelIndex))
597+ if (asynchronous && m_asyncRequestedIndex != -1)
584 return nullptr;
598 return nullptr;
586− m_asyncRequestedIndexes.remove(modelIndex);
600+ m_asyncRequestedIndex = -1;
587 QQuickItem *item = m_delegateModel->item(modelIndex, asynchronous);
601 QQuickItem *item = m_delegateModel->item(modelIndex, asynchronous);
588 if (!item) {
602 if (!item) {
589− m_asyncRequestedIndexes << modelIndex;
603+ m_asyncRequestedIndex = modelIndex;
590 return 0;
604 return 0;
592// qDebug() << "ListViewWithPageHeader::createItem::We have the item" << modelIndex << item;
606// qDebug() << "ListViewWithPageHeader::createItem::We have the item" << modelIndex << item;
593 ListItem *listItem = new ListItem;
607 ListItem *listItem = new ListItem;
594 listItem->m_item = item;
608 listItem->m_item = item;
595− listItem->m_sectionItem = getSectionItem(modelIndex);
609+ listItem->m_sectionItem = getSectionItem(modelIndex, false /*Not yet inserted into m_visibleItems*/);
596 QQuickItemPrivate::get(item)->addItemChangeListener(this, QQuickItemPrivate::Geometry);
610 QQuickItemPrivate::get(item)->addItemChangeListener(this, QQuickItemPrivate::Geometry);
597 ListItem *prevItem = itemAtIndex(modelIndex - 1);
611 ListItem *prevItem = itemAtIndex(modelIndex - 1);
612+ bool lostItem = false; // Is an item that we requested async but because of model changes
613+ // it is no longer attached to any of the existing items (has no prev nor next item)
614+ // nor is the first item
598 if (prevItem) {
615 if (prevItem) {
599 listItem->setY(prevItem->y() + prevItem->height());
616 listItem->setY(prevItem->y() + prevItem->height());
@@ -603,18 +620,25 @@ ListViewWithPageHeader::ListItem *ListViewWithPageHeader::createItem(int modelIn
603 listItem->setY(nextItem->y() - listItem ->height());
620 listItem->setY(nextItem->y() - listItem ->height());
604 } else if (modelIndex == 0 && m_headerItem) {
621 } else if (modelIndex == 0 && m_headerItem) {
605 listItem->setY(m_headerItem->height());
622 listItem->setY(m_headerItem->height());
623+ } else if (!m_visibleItems.isEmpty()) {
608− listItem->setCulled(listItem->y() + listItem->height() + m_clipItem->y() < contentY() || listItem->y() + m_clipItem->y() >= contentY() + height());
627+ if (lostItem) {
609− if (m_visibleItems.isEmpty()) {
628+ releaseItem(listItem);
610− m_visibleItems << listItem;
629+ listItem = nullptr;
631+ listItem->setCulled(listItem->y() + listItem->height() + m_clipItem->y() < contentY() || listItem->y() + m_clipItem->y() >= contentY() + height());
632+ if (m_visibleItems.isEmpty()) {
633+ m_visibleItems << listItem;
612− m_visibleItems.insert(modelIndex - m_firstVisibleIndex, listItem);
635+ m_visibleItems.insert(modelIndex - m_firstVisibleIndex, listItem);
614− if (m_firstVisibleIndex < 0 || modelIndex < m_firstVisibleIndex) {
637+ if (m_firstVisibleIndex < 0 || modelIndex < m_firstVisibleIndex) {
615− m_firstVisibleIndex = modelIndex;
638+ m_firstVisibleIndex = modelIndex;
616− adjustMinYExtent();
639+ adjustMinYExtent();
617− qDebug() << "ListViewWithPageHeader::createItem" << m_minYExtent;
640+ qDebug() << "ListViewWithPageHeader::createItem" << m_minYExtent;
619 return listItem;
643 return listItem;
@@ -627,7 +651,7 @@ void ListViewWithPageHeader::itemCreated(int modelIndex, QQuickItem *item)
627 item->setParentItem(m_clipItem);
651 item->setParentItem(m_clipItem);
628 QQmlContext *context = QQmlEngine::contextForObject(item)->parentContext();
652 QQmlContext *context = QQmlEngine::contextForObject(item)->parentContext();
629 context->setContextProperty(QLatin1String("ListViewWithPageHeader"), this);
653 context->setContextProperty(QLatin1String("ListViewWithPageHeader"), this);
630− if (m_asyncRequestedIndexes.remove(modelIndex)) {
654+ if (modelIndex == m_asyncRequestedIndex) {
631 createItem(modelIndex, false);
655 createItem(modelIndex, false);
@@ -677,6 +701,14 @@ void ListViewWithPageHeader::onModelUpdated(const QQuickChangeSet &changeSet, bo
677 const int visibleIndex = remove.index + i - m_firstVisibleIndex;
701 const int visibleIndex = remove.index + i - m_firstVisibleIndex;
678 if (visibleIndex >= 0 && visibleIndex < m_visibleItems.count()) {
702 if (visibleIndex >= 0 && visibleIndex < m_visibleItems.count()) {
679 ListItem *item = m_visibleItems[visibleIndex];
703 ListItem *item = m_visibleItems[visibleIndex];
704+ // Pass the section item down if needed
705+ if (item->m_sectionItem && visibleIndex + 1 < m_visibleItems.count()) {
706+ ListItem *nextItem = m_visibleItems[visibleIndex + 1];
707+ if (!nextItem->m_sectionItem) {
708+ nextItem->m_sectionItem = item->m_sectionItem;
709+ item->m_sectionItem = nullptr;
680 releaseItem(item);
712 releaseItem(item);
681 m_visibleItems.removeAt(visibleIndex);
713 m_visibleItems.removeAt(visibleIndex);
@@ -692,6 +724,14 @@ void ListViewWithPageHeader::onModelUpdated(const QQuickChangeSet &changeSet, bo
692 } else if (remove.index + remove.count <= m_firstVisibleIndex) {
724 } else if (remove.index + remove.count <= m_firstVisibleIndex) {
693 m_firstVisibleIndex -= remove.count;
725 m_firstVisibleIndex -= remove.count;
727+ for (int i = remove.count - 1; i >= 0; --i) {
728+ const int modelIndex = remove.index + i;
729+ if (modelIndex == m_asyncRequestedIndex) {
730+ m_asyncRequestedIndex = -1;
731+ } else if (modelIndex < m_asyncRequestedIndex) {
732+ m_asyncRequestedIndex--;
697 foreach(const QQuickChangeSet::Insert &insert, changeSet.inserts()) {
737 foreach(const QQuickChangeSet::Insert &insert, changeSet.inserts()) {
@@ -724,6 +764,19 @@ void ListViewWithPageHeader::onModelUpdated(const QQuickChangeSet &changeSet, bo
724 adjustMinYExtent();
764 adjustMinYExtent();
725 qDebug() << "ListViewWithPageHeader::onModelUpdated growed up" << m_minYExtent;
765 qDebug() << "ListViewWithPageHeader::onModelUpdated growed up" << m_minYExtent;
767+ // Adding an item may break a "same section" chain, so check
768+ // if we need adding a new section item
769+ if (m_sectionDelegate) {
770+ ListItem *nextItem = itemAtIndex(modelIndex + 1);
771+ if (nextItem && !nextItem->m_sectionItem) {
772+ nextItem->m_sectionItem = getSectionItem(modelIndex + 1, true /* alredy inserted into m_visibleItems*/);
774+ ListItem *firstItem = m_visibleItems.first();
775+ firstItem->setY(firstItem->y() - nextItem->m_sectionItem->height());
728 if (firstItemWithViewOnTop) {
781 if (firstItemWithViewOnTop) {
729 ListItem *firstItem = m_visibleItems.first();
782 ListItem *firstItem = m_visibleItems.first();
@@ -732,6 +785,13 @@ void ListViewWithPageHeader::onModelUpdated(const QQuickChangeSet &changeSet, bo
732 } else if (insert.index <= m_firstVisibleIndex) {
785 } else if (insert.index <= m_firstVisibleIndex) {
733 m_firstVisibleIndex += insert.count;
786 m_firstVisibleIndex += insert.count;
789+ for (int i = insert.count - 1; i >= 0; --i) {
790+ const int modelIndex = insert.index + i;
791+ if (modelIndex <= m_asyncRequestedIndex) {
792+ m_asyncRequestedIndex++;
737 polish();
797 polish();
@@ -860,13 +920,15 @@ void ListViewWithPageHeader::updatePolish()
860 // Second step of section sticky item positioning
920 // Second step of section sticky item positioning
861 // Look at the next section header, check if it's pushing up the sticky one
921 // Look at the next section header, check if it's pushing up the sticky one
862 if (m_topSectionItem) {
922 if (m_topSectionItem) {
923+ if (firstReallyVisibleItem >= 0) {
863− for (int i = firstReallyVisibleItem - m_firstVisibleIndex + 1; i < m_visibleItems.count(); ++i) {
924+ for (int i = firstReallyVisibleItem - m_firstVisibleIndex + 1; i < m_visibleItems.count(); ++i) {
864− ListItem *item = m_visibleItems[i];
925+ ListItem *item = m_visibleItems[i];
865− if (item->m_sectionItem) {
926+ if (item->m_sectionItem) {
866− if (m_topSectionItem->y() + m_topSectionItem->height() > item->y()) {
927+ if (m_topSectionItem->y() + m_topSectionItem->height() > item->y()) {
867− m_topSectionItem->setY(item->y() - m_topSectionItem->height());
928+ m_topSectionItem->setY(item->y() - m_topSectionItem->height());