on xenial help sign in
Bring changes from the lvwph branch
9dc0f9cAlbert Astals
plugins/ListViewWithPageHeader/listviewwithpageheader.cpp+83−21
@@ -121,6 +121,7 @@ void ListViewWithPageHeader::ListItem::setCulled(bool culled)
121
121
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()
503 }
504 }
504}
505}
505
506
506−QQuickItem *ListViewWithPageHeader::getSectionItem(int modelIndex)
507+QQuickItem *ListViewWithPageHeader::getSectionItem(int modelIndex, bool alreadyInserted)
507{
508{
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;
516 }
517 }
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
524+ if (nextItem) {
525+ QQuickItem *sectionItem = nextItem->m_sectionItem;
526+ nextItem->m_sectionItem = nullptr;
527+ return sectionItem;
528+ }
529+ }
530+ }
517
531
518 return getSectionItem(section);
532 return getSectionItem(section);
519}
533}
@@ -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)
581{
595{
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;
585
599
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;
591 } else {
605 } else {
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());
600 } else {
617 } else {
@@ -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()) {
624+ lostItem = true;
606 }
625 }
607 }
626 }
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;
611 } else {
630 } else {
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;
634+ } else {
612− m_visibleItems.insert(modelIndex - m_firstVisibleIndex, listItem);
635+ m_visibleItems.insert(modelIndex - m_firstVisibleIndex, listItem);
613− }
636+ }
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;
641+ }
618 }
642 }
619 return listItem;
643 return listItem;
620 }
644 }
@@ -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);
632 }
656 }
633}
657}
@@ -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;
710+ }
711+ }
680 releaseItem(item);
712 releaseItem(item);
681 m_visibleItems.removeAt(visibleIndex);
713 m_visibleItems.removeAt(visibleIndex);
682 }
714 }
@@ -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;
694 }
726 }
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--;
733+ }
734+ }
695 }
735 }
696
736
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;
726 }
766 }
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*/);
773+ if (growUp) {
774+ ListItem *firstItem = m_visibleItems.first();
775+ firstItem->setY(firstItem->y() - nextItem->m_sectionItem->height());
776+ adjustMinYExtent();
777+ }
778+ }
779+ }
727 }
780 }
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;
734 }
787 }
788+
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++;
793+ }
794+ }
735 }
795 }
736
796
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());
929+ }
930+ break;
868 }
931 }
869− break;
870 }
932 }
871 }
933 }
872 }
934 }
plugins/ListViewWithPageHeader/listviewwithpageheader.h+3−3
@@ -113,13 +113,13 @@ private:
113 ListItem *itemAtIndex(int modelIndex) const; // Returns the item at modelIndex if has been created
113 ListItem *itemAtIndex(int modelIndex) const; // Returns the item at modelIndex if has been created
114 void releaseItem(ListItem *item);
114 void releaseItem(ListItem *item);
115 void updateWatchedRoles();
115 void updateWatchedRoles();
116− QQuickItem *getSectionItem(int modelIndex);
116+ QQuickItem *getSectionItem(int modelIndex, bool alreadyInserted);
117 QQuickItem *getSectionItem(const QString &sectionText);
117 QQuickItem *getSectionItem(const QString &sectionText);
118
118
119 QQuickVisualDataModel *m_delegateModel;
119 QQuickVisualDataModel *m_delegateModel;
120
120
121− // List of indexes we are still waiting because we requested them asynchronously
121+ // Index we are waiting because we requested it asynchronously
122− QSet<int> m_asyncRequestedIndexes;
122+ int m_asyncRequestedIndex;
123
123
124 // Used to only give a warning once if the delegate does not return objects
124 // Used to only give a warning once if the delegate does not return objects
125 bool m_delegateValidated;
125 bool m_delegateValidated;