src/declarative/graphicsitems/qdeclarativelistview.cpp
changeset 33 3e2da88830cd
parent 30 5dc02b23752f
child 37 758a864f9613
equal deleted inserted replaced
30:5dc02b23752f 33:3e2da88830cd
   103         if (section)
   103         if (section)
   104             return (view->orientation() == QDeclarativeListView::Vertical ? section->y() : section->x());
   104             return (view->orientation() == QDeclarativeListView::Vertical ? section->y() : section->x());
   105         else
   105         else
   106             return (view->orientation() == QDeclarativeListView::Vertical ? item->y() : item->x());
   106             return (view->orientation() == QDeclarativeListView::Vertical ? item->y() : item->x());
   107     }
   107     }
   108     int size() const {
   108     qreal size() const {
   109         if (section)
   109         if (section)
   110             return (view->orientation() == QDeclarativeListView::Vertical ? item->height()+section->height() : item->width()+section->height());
   110             return (view->orientation() == QDeclarativeListView::Vertical ? item->height()+section->height() : item->width()+section->height());
   111         else
   111         else
   112             return (view->orientation() == QDeclarativeListView::Vertical ? item->height() : item->width());
   112             return (view->orientation() == QDeclarativeListView::Vertical ? item->height() : item->width());
   113     }
   113     }
   214         return orient == QDeclarativeListView::Vertical ? q->contentY() : q->contentX();
   214         return orient == QDeclarativeListView::Vertical ? q->contentY() : q->contentX();
   215     }
   215     }
   216     void setPosition(qreal pos) {
   216     void setPosition(qreal pos) {
   217         Q_Q(QDeclarativeListView);
   217         Q_Q(QDeclarativeListView);
   218         if (orient == QDeclarativeListView::Vertical)
   218         if (orient == QDeclarativeListView::Vertical)
   219             q->setContentY(pos);
   219             q->QDeclarativeFlickable::setContentY(pos);
   220         else
   220         else
   221             q->setContentX(pos);
   221             q->QDeclarativeFlickable::setContentX(pos);
   222     }
   222     }
   223     qreal size() const {
   223     qreal size() const {
   224         Q_Q(const QDeclarativeListView);
   224         Q_Q(const QDeclarativeListView);
   225         return orient == QDeclarativeListView::Vertical ? q->height() : q->width();
   225         return orient == QDeclarativeListView::Vertical ? q->height() : q->width();
   226     }
   226     }
   419     }
   419     }
   420 
   420 
   421     void itemGeometryChanged(QDeclarativeItem *item, const QRectF &newGeometry, const QRectF &oldGeometry) {
   421     void itemGeometryChanged(QDeclarativeItem *item, const QRectF &newGeometry, const QRectF &oldGeometry) {
   422         Q_Q(QDeclarativeListView);
   422         Q_Q(QDeclarativeListView);
   423         QDeclarativeFlickablePrivate::itemGeometryChanged(item, newGeometry, oldGeometry);
   423         QDeclarativeFlickablePrivate::itemGeometryChanged(item, newGeometry, oldGeometry);
   424         if (item != viewport && (!highlight || item != highlight->item)) {
   424         if (item != contentItem && (!highlight || item != highlight->item)) {
   425             if ((orient == QDeclarativeListView::Vertical && newGeometry.height() != oldGeometry.height())
   425             if ((orient == QDeclarativeListView::Vertical && newGeometry.height() != oldGeometry.height())
   426                 || (orient == QDeclarativeListView::Horizontal && newGeometry.width() != oldGeometry.width())) {
   426                 || (orient == QDeclarativeListView::Horizontal && newGeometry.width() != oldGeometry.width())) {
   427                 scheduleLayout();
   427                 scheduleLayout();
   428             }
   428             }
   429         }
   429         }
       
   430         if ((header && header->item == item) || (footer && footer->item == item)) {
       
   431             updateHeader();
       
   432             updateFooter();
       
   433         }
       
   434         if (currentItem && currentItem->item == item)
       
   435             updateHighlight();
   430         if (trackedItem && trackedItem->item == item)
   436         if (trackedItem && trackedItem->item == item)
   431             q->trackedPositionChanged();
   437             q->trackedPositionChanged();
   432     }
   438     }
   433 
   439 
   434     // for debugging only
   440     // for debugging only
   468     QVariant modelVariant;
   474     QVariant modelVariant;
   469     QList<FxListItem*> visibleItems;
   475     QList<FxListItem*> visibleItems;
   470     QHash<QDeclarativeItem*,int> unrequestedItems;
   476     QHash<QDeclarativeItem*,int> unrequestedItems;
   471     FxListItem *currentItem;
   477     FxListItem *currentItem;
   472     QDeclarativeListView::Orientation orient;
   478     QDeclarativeListView::Orientation orient;
   473     int visiblePos;
   479     qreal visiblePos;
   474     int visibleIndex;
   480     int visibleIndex;
   475     qreal averageSize;
   481     qreal averageSize;
   476     int currentIndex;
   482     int currentIndex;
   477     int requestedIndex;
   483     int requestedIndex;
   478     int itemCount;
   484     int itemCount;
   486     int buffer;
   492     int buffer;
   487     QSmoothedAnimation *highlightPosAnimator;
   493     QSmoothedAnimation *highlightPosAnimator;
   488     QSmoothedAnimation *highlightSizeAnimator;
   494     QSmoothedAnimation *highlightSizeAnimator;
   489     QDeclarativeViewSection *sectionCriteria;
   495     QDeclarativeViewSection *sectionCriteria;
   490     QString currentSection;
   496     QString currentSection;
   491     static const int sectionCacheSize = 3;
   497     static const int sectionCacheSize = 4;
   492     QDeclarativeItem *sectionCache[sectionCacheSize];
   498     QDeclarativeItem *sectionCache[sectionCacheSize];
   493     qreal spacing;
   499     qreal spacing;
   494     qreal highlightMoveSpeed;
   500     qreal highlightMoveSpeed;
   495     int highlightMoveDuration;
   501     int highlightMoveDuration;
   496     qreal highlightResizeSpeed;
   502     qreal highlightResizeSpeed;
   567             if (modelIndex > 0) {
   573             if (modelIndex > 0) {
   568                 if (FxListItem *item = visibleItem(modelIndex-1))
   574                 if (FxListItem *item = visibleItem(modelIndex-1))
   569                     listItem->attached->m_prevSection = item->attached->section();
   575                     listItem->attached->m_prevSection = item->attached->section();
   570                 else
   576                 else
   571                     listItem->attached->m_prevSection = sectionAt(modelIndex-1);
   577                     listItem->attached->m_prevSection = sectionAt(modelIndex-1);
       
   578                 if (FxListItem *item = visibleItem(modelIndex+1))
       
   579                     listItem->attached->m_nextSection = item->attached->section();
       
   580                 else if (modelIndex < model->count()-1)
       
   581                     listItem->attached->m_nextSection = sectionAt(modelIndex+1);
   572             }
   582             }
   573         }
   583         }
   574         if (model->completePending()) {
   584         if (model->completePending()) {
   575             // complete
   585             // complete
   576             listItem->item->setZValue(1);
   586             listItem->item->setZValue(1);
   577             listItem->item->setParentItem(q->viewport());
   587             listItem->item->setParentItem(q->contentItem());
   578             model->completeItem();
   588             model->completeItem();
   579         } else {
   589         } else {
   580             listItem->item->setParentItem(q->viewport());
   590             listItem->item->setParentItem(q->contentItem());
   581         }
   591         }
   582         QDeclarativeItemPrivate *itemPrivate = static_cast<QDeclarativeItemPrivate*>(QGraphicsItemPrivate::get(item));
   592         QDeclarativeItemPrivate *itemPrivate = static_cast<QDeclarativeItemPrivate*>(QGraphicsItemPrivate::get(item));
   583         itemPrivate->addItemChangeListener(this, QDeclarativeItemPrivate::Geometry);
   593         itemPrivate->addItemChangeListener(this, QDeclarativeItemPrivate::Geometry);
   584         if (sectionCriteria && sectionCriteria->delegate()) {
   594         if (sectionCriteria && sectionCriteria->delegate()) {
   585             if (listItem->attached->m_prevSection != listItem->attached->m_section)
   595             if (listItem->attached->m_prevSection != listItem->attached->m_section)
   647         modelIndex = visibleItems.at(i)->index + 1;
   657         modelIndex = visibleItems.at(i)->index + 1;
   648     }
   658     }
   649 
   659 
   650     bool changed = false;
   660     bool changed = false;
   651     FxListItem *item = 0;
   661     FxListItem *item = 0;
   652     int pos = itemEnd + 1;
   662     qreal pos = itemEnd + 1;
   653     while (modelIndex < model->count() && pos <= fillTo) {
   663     while (modelIndex < model->count() && pos <= fillTo) {
   654 //        qDebug() << "refill: append item" << modelIndex << "pos" << pos;
   664 //        qDebug() << "refill: append item" << modelIndex << "pos" << pos;
   655         if (!(item = createItem(modelIndex)))
   665         if (!(item = createItem(modelIndex)))
   656             break;
   666             break;
   657         item->setPosition(pos);
   667         item->setPosition(pos);
   729 
   739 
   730 void QDeclarativeListViewPrivate::layout()
   740 void QDeclarativeListViewPrivate::layout()
   731 {
   741 {
   732     Q_Q(QDeclarativeListView);
   742     Q_Q(QDeclarativeListView);
   733     layoutScheduled = false;
   743     layoutScheduled = false;
   734     if (!isValid()) {
   744     if (!isValid() && !visibleItems.count()) {
   735         clear();
   745         clear();
   736         setPosition(0);
   746         setPosition(0);
   737         return;
   747         return;
   738     }
   748     }
   739     updateSections();
   749     updateSections();
   740     if (!visibleItems.isEmpty()) {
   750     if (!visibleItems.isEmpty()) {
   741         int oldEnd = visibleItems.last()->endPosition();
   751         qreal oldEnd = visibleItems.last()->endPosition();
   742         int pos = visibleItems.first()->endPosition() + spacing + 1;
   752         qreal pos = visibleItems.first()->endPosition() + spacing + 1;
   743         for (int i=1; i < visibleItems.count(); ++i) {
   753         for (int i=1; i < visibleItems.count(); ++i) {
   744             FxListItem *item = visibleItems.at(i);
   754             FxListItem *item = visibleItems.at(i);
   745             item->setPosition(pos);
   755             item->setPosition(pos);
   746             pos += item->size() + spacing;
   756             pos += item->size() + spacing;
   747         }
   757         }
   832             }
   842             }
   833         } else {
   843         } else {
   834             item = new QDeclarativeItem;
   844             item = new QDeclarativeItem;
   835         }
   845         }
   836         if (item) {
   846         if (item) {
   837             QDeclarative_setParent_noEvent(item, q->viewport());
   847             QDeclarative_setParent_noEvent(item, q->contentItem());
   838             item->setParentItem(q->viewport());
   848             item->setParentItem(q->contentItem());
   839             highlight = new FxListItem(item, q);
   849             highlight = new FxListItem(item, q);
   840             if (currentItem && autoHighlight) {
   850             if (currentItem && autoHighlight) {
   841                 if (orient == QDeclarativeListView::Vertical) {
   851                 if (orient == QDeclarativeListView::Vertical) {
   842                     highlight->item->setHeight(currentItem->item->height());
   852                     highlight->item->setHeight(currentItem->item->height());
   843                 } else {
   853                 } else {
   913                     listItem->section = qobject_cast<QDeclarativeItem *>(nobj);
   923                     listItem->section = qobject_cast<QDeclarativeItem *>(nobj);
   914                     if (!listItem->section) {
   924                     if (!listItem->section) {
   915                         delete nobj;
   925                         delete nobj;
   916                     } else {
   926                     } else {
   917                         listItem->section->setZValue(1);
   927                         listItem->section->setZValue(1);
   918                         QDeclarative_setParent_noEvent(listItem->section, q->viewport());
   928                         QDeclarative_setParent_noEvent(listItem->section, q->contentItem());
   919                         listItem->section->setParentItem(q->viewport());
   929                         listItem->section->setParentItem(q->contentItem());
   920                     }
   930                     }
   921                 } else {
   931                 } else {
   922                     delete context;
   932                     delete context;
   923                 }
   933                 }
   924             }
   934             }
   943 {
   953 {
   944     if (sectionCriteria) {
   954     if (sectionCriteria) {
   945         QString prevSection;
   955         QString prevSection;
   946         if (visibleIndex > 0)
   956         if (visibleIndex > 0)
   947             prevSection = sectionAt(visibleIndex-1);
   957             prevSection = sectionAt(visibleIndex-1);
       
   958         QDeclarativeListViewAttached *prevAtt = 0;
       
   959         int idx = -1;
   948         for (int i = 0; i < visibleItems.count(); ++i) {
   960         for (int i = 0; i < visibleItems.count(); ++i) {
   949             if (visibleItems.at(i)->index != -1) {
   961             if (visibleItems.at(i)->index != -1) {
   950                 QDeclarativeListViewAttached *attached = visibleItems.at(i)->attached;
   962                 QDeclarativeListViewAttached *attached = visibleItems.at(i)->attached;
   951                 attached->setPrevSection(prevSection);
   963                 attached->setPrevSection(prevSection);
       
   964                 if (prevAtt)
       
   965                     prevAtt->setNextSection(attached->section());
   952                 createSection(visibleItems.at(i));
   966                 createSection(visibleItems.at(i));
   953                 prevSection = attached->section();
   967                 prevSection = attached->section();
   954             }
   968                 prevAtt = attached;
       
   969                 idx = visibleItems.at(i)->index;
       
   970             }
       
   971         }
       
   972         if (prevAtt) {
       
   973             if (idx > 0 && idx < model->count()-1)
       
   974                 prevAtt->setNextSection(sectionAt(idx+1));
       
   975             else
       
   976                 prevAtt->setNextSection(QString());
   955         }
   977         }
   956     }
   978     }
   957 }
   979 }
   958 
   980 
   959 void QDeclarativeListViewPrivate::updateCurrentSection()
   981 void QDeclarativeListViewPrivate::updateCurrentSection()
  1005             // Its position will be corrected when it becomes visible.
  1027             // Its position will be corrected when it becomes visible.
  1006             currentItem->setPosition(positionAt(modelIndex));
  1028             currentItem->setPosition(positionAt(modelIndex));
  1007         }
  1029         }
  1008         currentItem->item->setFocus(true);
  1030         currentItem->item->setFocus(true);
  1009         currentItem->attached->setIsCurrentItem(true);
  1031         currentItem->attached->setIsCurrentItem(true);
       
  1032         // Avoid showing section delegate twice.  We still need the section heading so that
       
  1033         // currentItem positioning works correctly.
       
  1034         // This is slightly sub-optimal, but section heading caching minimizes the impact.
       
  1035         if (currentItem->section)
       
  1036             currentItem->section->setVisible(false);
  1010     }
  1037     }
  1011     updateHighlight();
  1038     updateHighlight();
  1012     emit q->currentIndexChanged();
  1039     emit q->currentIndexChanged();
  1013     // Release the old current item
  1040     // Release the old current item
  1014     releaseItem(oldCurrentItem);
  1041     releaseItem(oldCurrentItem);
  1019     if (!visibleItems.count())
  1046     if (!visibleItems.count())
  1020         return;
  1047         return;
  1021     qreal sum = 0.0;
  1048     qreal sum = 0.0;
  1022     for (int i = 0; i < visibleItems.count(); ++i)
  1049     for (int i = 0; i < visibleItems.count(); ++i)
  1023         sum += visibleItems.at(i)->size();
  1050         sum += visibleItems.at(i)->size();
  1024     averageSize = sum / visibleItems.count();
  1051     averageSize = qRound(sum / visibleItems.count());
  1025 }
  1052 }
  1026 
  1053 
  1027 void QDeclarativeListViewPrivate::updateFooter()
  1054 void QDeclarativeListViewPrivate::updateFooter()
  1028 {
  1055 {
  1029     Q_Q(QDeclarativeListView);
  1056     Q_Q(QDeclarativeListView);
  1038                 delete nobj;
  1065                 delete nobj;
  1039         } else {
  1066         } else {
  1040             delete context;
  1067             delete context;
  1041         }
  1068         }
  1042         if (item) {
  1069         if (item) {
  1043             QDeclarative_setParent_noEvent(item, q->viewport());
  1070             QDeclarative_setParent_noEvent(item, q->contentItem());
  1044             item->setParentItem(q->viewport());
  1071             item->setParentItem(q->contentItem());
  1045             item->setZValue(1);
  1072             item->setZValue(1);
       
  1073             QDeclarativeItemPrivate *itemPrivate = static_cast<QDeclarativeItemPrivate*>(QGraphicsItemPrivate::get(item));
       
  1074             itemPrivate->addItemChangeListener(this, QDeclarativeItemPrivate::Geometry);
  1046             footer = new FxListItem(item, q);
  1075             footer = new FxListItem(item, q);
  1047         }
  1076         }
  1048     }
  1077     }
  1049     if (footer) {
  1078     if (footer) {
  1050         if (visibleItems.count()) {
  1079         if (visibleItems.count()) {
  1051             qreal endPos = endPosition();
  1080             qreal endPos = endPosition() + 1;
  1052             if (lastVisibleIndex() == model->count()-1) {
  1081             if (lastVisibleIndex() == model->count()-1) {
  1053                 footer->setPosition(endPos);
  1082                 footer->setPosition(endPos);
  1054             } else {
  1083             } else {
  1055                 qreal visiblePos = position() + q->height();
  1084                 qreal visiblePos = position() + q->height();
  1056                 if (endPos <= visiblePos || footer->position() < endPos)
  1085                 if (endPos <= visiblePos || footer->position() < endPos)
  1076                 delete nobj;
  1105                 delete nobj;
  1077         } else {
  1106         } else {
  1078             delete context;
  1107             delete context;
  1079         }
  1108         }
  1080         if (item) {
  1109         if (item) {
  1081             QDeclarative_setParent_noEvent(item, q->viewport());
  1110             QDeclarative_setParent_noEvent(item, q->contentItem());
  1082             item->setParentItem(q->viewport());
  1111             item->setParentItem(q->contentItem());
  1083             item->setZValue(1);
  1112             item->setZValue(1);
       
  1113             QDeclarativeItemPrivate *itemPrivate = static_cast<QDeclarativeItemPrivate*>(QGraphicsItemPrivate::get(item));
       
  1114             itemPrivate->addItemChangeListener(this, QDeclarativeItemPrivate::Geometry);
  1084             header = new FxListItem(item, q);
  1115             header = new FxListItem(item, q);
  1085             if (visibleItems.isEmpty())
  1116             if (visibleItems.isEmpty())
  1086                 visiblePos = header->size();
  1117                 visiblePos = header->size();
  1087         }
  1118         }
  1088     }
  1119     }
  1101     }
  1132     }
  1102 }
  1133 }
  1103 
  1134 
  1104 void QDeclarativeListViewPrivate::fixupPosition()
  1135 void QDeclarativeListViewPrivate::fixupPosition()
  1105 {
  1136 {
  1106     moveReason = Other;
  1137     if ((haveHighlightRange && highlightRange == QDeclarativeListView::StrictlyEnforceRange)
       
  1138         || snapMode != QDeclarativeListView::NoSnap)
       
  1139         moveReason = Other;
  1107     if (orient == QDeclarativeListView::Vertical)
  1140     if (orient == QDeclarativeListView::Vertical)
  1108         fixupY();
  1141         fixupY();
  1109     else
  1142     else
  1110         fixupX();
  1143         fixupX();
  1111 }
  1144 }
  1112 
  1145 
  1113 void QDeclarativeListViewPrivate::fixup(AxisData &data, qreal minExtent, qreal maxExtent)
  1146 void QDeclarativeListViewPrivate::fixup(AxisData &data, qreal minExtent, qreal maxExtent)
  1114 {
  1147 {
  1115     Q_Q(QDeclarativeListView);
       
  1116     if ((orient == QDeclarativeListView::Horizontal && &data == &vData)
  1148     if ((orient == QDeclarativeListView::Horizontal && &data == &vData)
  1117         || (orient == QDeclarativeListView::Vertical && &data == &hData))
  1149         || (orient == QDeclarativeListView::Vertical && &data == &hData))
  1118         return;
  1150         return;
  1119 
  1151 
  1120     int oldDuration = fixupDuration;
  1152     int oldDuration = fixupDuration;
  1121     fixupDuration = moveReason == Mouse ? fixupDuration : 0;
  1153     fixupDuration = moveReason == Mouse ? fixupDuration : 0;
  1122 
  1154 
  1123     if (haveHighlightRange && highlightRange == QDeclarativeListView::StrictlyEnforceRange) {
  1155     if (snapMode != QDeclarativeListView::NoSnap) {
       
  1156         FxListItem *topItem = snapItemAt(position()+highlightRangeStart);
       
  1157         FxListItem *bottomItem = snapItemAt(position()+highlightRangeEnd);
       
  1158         qreal pos;
       
  1159         if (topItem && bottomItem && haveHighlightRange && highlightRange == QDeclarativeListView::StrictlyEnforceRange) {
       
  1160             qreal topPos = qMin(topItem->position() - highlightRangeStart, -maxExtent);
       
  1161             qreal bottomPos = qMax(bottomItem->position() - highlightRangeEnd, -minExtent);
       
  1162             pos = qAbs(data.move + topPos) < qAbs(data.move + bottomPos) ? topPos : bottomPos;
       
  1163         } else if (topItem) {
       
  1164             pos = qMax(qMin(topItem->position() - highlightRangeStart, -maxExtent), -minExtent);
       
  1165         } else if (bottomItem) {
       
  1166             pos = qMax(qMin(bottomItem->position() - highlightRangeStart, -maxExtent), -minExtent);
       
  1167         } else {
       
  1168             fixupDuration = oldDuration;
       
  1169             return;
       
  1170         }
       
  1171         if (currentItem && haveHighlightRange && highlightRange == QDeclarativeListView::StrictlyEnforceRange) {
       
  1172             updateHighlight();
       
  1173             qreal currPos = currentItem->position();
       
  1174             if (pos < currPos + currentItem->size() - highlightRangeEnd)
       
  1175                 pos = currPos + currentItem->size() - highlightRangeEnd;
       
  1176             if (pos > currPos - highlightRangeStart)
       
  1177                 pos = currPos - highlightRangeStart;
       
  1178         }
       
  1179 
       
  1180         qreal dist = qAbs(data.move + pos);
       
  1181         if (dist > 0) {
       
  1182             timeline.reset(data.move);
       
  1183             if (fixupDuration)
       
  1184                 timeline.move(data.move, -pos, QEasingCurve(QEasingCurve::InOutQuad), fixupDuration/2);
       
  1185             else
       
  1186                 timeline.set(data.move, -pos);
       
  1187             vTime = timeline.time();
       
  1188         }
       
  1189     } else if (haveHighlightRange && highlightRange == QDeclarativeListView::StrictlyEnforceRange) {
  1124         if (currentItem) {
  1190         if (currentItem) {
  1125             updateHighlight();
  1191             updateHighlight();
  1126             qreal pos = currentItem->position();
  1192             qreal pos = currentItem->position();
  1127             qreal viewPos = position();
  1193             qreal viewPos = position();
  1128             if (viewPos < pos + currentItem->size() - highlightRangeEnd)
  1194             if (viewPos < pos + currentItem->size() - highlightRangeEnd)
  1130             if (viewPos > pos - highlightRangeStart)
  1196             if (viewPos > pos - highlightRangeStart)
  1131                 viewPos = pos - highlightRangeStart;
  1197                 viewPos = pos - highlightRangeStart;
  1132 
  1198 
  1133             timeline.reset(data.move);
  1199             timeline.reset(data.move);
  1134             if (viewPos != position()) {
  1200             if (viewPos != position()) {
  1135                 if (fixupDuration) {
  1201                 if (fixupDuration)
  1136                     timeline.move(data.move, -viewPos, QEasingCurve(QEasingCurve::InOutQuad), fixupDuration/2);
  1202                     timeline.move(data.move, -viewPos, QEasingCurve(QEasingCurve::InOutQuad), fixupDuration/2);
  1137                 } else {
  1203                 else
  1138                     data.move.setValue(-viewPos);
  1204                     timeline.set(data.move, -viewPos);
  1139                     q->viewportMoved();
       
  1140                 }
       
  1141             }
  1205             }
  1142             vTime = timeline.time();
  1206             vTime = timeline.time();
  1143         }
       
  1144     } else if (snapMode != QDeclarativeListView::NoSnap) {
       
  1145         if (FxListItem *item = snapItemAt(position())) {
       
  1146             qreal pos = qMin(item->position() - highlightRangeStart, -maxExtent);
       
  1147             qreal dist = qAbs(data.move + pos);
       
  1148             if (dist > 0) {
       
  1149                 timeline.reset(data.move);
       
  1150                 if (fixupDuration) {
       
  1151                     timeline.move(data.move, -pos, QEasingCurve(QEasingCurve::InOutQuad), fixupDuration/2);
       
  1152                 } else {
       
  1153                     data.move.setValue(-pos);
       
  1154                     q->viewportMoved();
       
  1155                 }
       
  1156                 vTime = timeline.time();
       
  1157             }
       
  1158         }
  1207         }
  1159     } else {
  1208     } else {
  1160         QDeclarativeFlickablePrivate::fixup(data, minExtent, maxExtent);
  1209         QDeclarativeFlickablePrivate::fixup(data, minExtent, maxExtent);
  1161     }
  1210     }
  1162     fixupDuration = oldDuration;
  1211     fixupDuration = oldDuration;
  1323 
  1372 
  1324     \snippet doc/src/snippets/declarative/listview/ContactModel.qml 0
  1373     \snippet doc/src/snippets/declarative/listview/ContactModel.qml 0
  1325 
  1374 
  1326     Another component can display this model data in a ListView, like this:
  1375     Another component can display this model data in a ListView, like this:
  1327 
  1376 
  1328     \table 
  1377     \snippet doc/src/snippets/declarative/listview/listview.qml import
  1329     \row 
       
  1330     \o \snippet doc/src/snippets/declarative/listview/listview.qml import
       
  1331     \codeline
  1378     \codeline
  1332     \snippet doc/src/snippets/declarative/listview/listview.qml classdocs simple
  1379     \snippet doc/src/snippets/declarative/listview/listview.qml classdocs simple
  1333     \o \image listview-simple.png
  1380 
  1334     \endtable
  1381     \image listview-simple.png
  1335 
  1382 
  1336     Here, the ListView creates a \c ContactModel component for its model, and a \l Text element
  1383     Here, the ListView creates a \c ContactModel component for its model, and a \l Text element
  1337     for its delegate. The view will create a new \l Text component for each item in the model. Notice
  1384     for its delegate. The view will create a new \l Text component for each item in the model. Notice
  1338     the delegate is able to access the model's \c name and \c number data directly.
  1385     the delegate is able to access the model's \c name and \c number data directly.
  1339 
  1386 
  1340     An improved list view is shown below. The delegate is visually improved and is moved 
  1387     An improved list view is shown below. The delegate is visually improved and is moved 
  1341     into a separate \c contactDelegate component. Also, the currently selected item is highlighted
  1388     into a separate \c contactDelegate component. Also, the currently selected item is highlighted
  1342     with a blue \l Rectangle using the \l highlight property, and \c focus is set to \c true
  1389     with a blue \l Rectangle using the \l highlight property, and \c focus is set to \c true
  1343     to enable keyboard navigation for the list view.
  1390     to enable keyboard navigation for the list view.
  1344     
  1391     
  1345     \table
  1392     \snippet doc/src/snippets/declarative/listview/listview.qml classdocs advanced
  1346     \row
  1393     \image listview-highlight.png
  1347     \o \snippet doc/src/snippets/declarative/listview/listview.qml classdocs advanced
  1394 
  1348     \o \image listview-highlight.png
  1395     In a GridView, delegates are instantiated as needed and may be destroyed at any time.
  1349     \endtable
       
  1350 
       
  1351     In a ListView, delegates are instantiated as needed and may be destroyed at any time.
       
  1352     State should \e never be stored in a delegate.
  1396     State should \e never be stored in a delegate.
  1353 
  1397 
  1354     \note Views do not enable \e clip automatically.  If the view
  1398     \note Views do not enable \e clip automatically.  If the view
  1355     is not clipped by another item or the screen, it will be necessary
  1399     is not clipped by another item or the screen, it will be necessary
  1356     to set \e {clip: true} in order to have the out of view items clipped
  1400     to set \e {clip: true} in order to have the out of view items clipped
  1357     nicely.
  1401     nicely.
       
  1402 
       
  1403     \sa {Data Models}, GridView, {declarative/modelviews/listview}{ListView examples}
  1358 */
  1404 */
  1359 
  1405 
  1360 QDeclarativeListView::QDeclarativeListView(QDeclarativeItem *parent)
  1406 QDeclarativeListView::QDeclarativeListView(QDeclarativeItem *parent)
  1361     : QDeclarativeFlickable(*(new QDeclarativeListViewPrivate), parent)
  1407     : QDeclarativeFlickable(*(new QDeclarativeListViewPrivate), parent)
  1362 {
  1408 {
  1391 
  1437 
  1392     It is attached to each instance of the delegate.
  1438     It is attached to each instance of the delegate.
  1393 */
  1439 */
  1394 
  1440 
  1395 /*!
  1441 /*!
  1396     \qmlattachedproperty string ListView::prevSection
  1442     \qmlattachedproperty string ListView::previousSection
  1397     This attached property holds the section of the previous element.
  1443     This attached property holds the section of the previous element.
       
  1444 
       
  1445     It is attached to each instance of the delegate.
       
  1446 
       
  1447     The section is evaluated using the \l {ListView::section.property}{section} properties.
       
  1448 */
       
  1449 
       
  1450 /*!
       
  1451     \qmlattachedproperty string ListView::nextSection
       
  1452     This attached property holds the section of the next element.
  1398 
  1453 
  1399     It is attached to each instance of the delegate.
  1454     It is attached to each instance of the delegate.
  1400 
  1455 
  1401     The section is evaluated using the \l {ListView::section.property}{section} properties.
  1456     The section is evaluated using the \l {ListView::section.property}{section} properties.
  1402 */
  1457 */
  1464         disconnect(d->model, SIGNAL(modelReset()), this, SLOT(modelReset()));
  1519         disconnect(d->model, SIGNAL(modelReset()), this, SLOT(modelReset()));
  1465         disconnect(d->model, SIGNAL(createdItem(int, QDeclarativeItem*)), this, SLOT(createdItem(int,QDeclarativeItem*)));
  1520         disconnect(d->model, SIGNAL(createdItem(int, QDeclarativeItem*)), this, SLOT(createdItem(int,QDeclarativeItem*)));
  1466         disconnect(d->model, SIGNAL(destroyingItem(QDeclarativeItem*)), this, SLOT(destroyingItem(QDeclarativeItem*)));
  1521         disconnect(d->model, SIGNAL(destroyingItem(QDeclarativeItem*)), this, SLOT(destroyingItem(QDeclarativeItem*)));
  1467     }
  1522     }
  1468     d->clear();
  1523     d->clear();
       
  1524     QDeclarativeVisualModel *oldModel = d->model;
       
  1525     d->model = 0;
  1469     d->setPosition(0);
  1526     d->setPosition(0);
  1470     d->modelVariant = model;
  1527     d->modelVariant = model;
  1471     QObject *object = qvariant_cast<QObject*>(model);
  1528     QObject *object = qvariant_cast<QObject*>(model);
  1472     QDeclarativeVisualModel *vim = 0;
  1529     QDeclarativeVisualModel *vim = 0;
  1473     if (object && (vim = qobject_cast<QDeclarativeVisualModel *>(object))) {
  1530     if (object && (vim = qobject_cast<QDeclarativeVisualModel *>(object))) {
  1474         if (d->ownModel) {
  1531         if (d->ownModel) {
  1475             delete d->model;
  1532             delete oldModel;
  1476             d->ownModel = false;
  1533             d->ownModel = false;
  1477         }
  1534         }
  1478         d->model = vim;
  1535         d->model = vim;
  1479     } else {
  1536     } else {
  1480         if (!d->ownModel) {
  1537         if (!d->ownModel) {
  1481             d->model = new QDeclarativeVisualDataModel(qmlContext(this), this);
  1538             d->model = new QDeclarativeVisualDataModel(qmlContext(this), this);
  1482             d->ownModel = true;
  1539             d->ownModel = true;
       
  1540         } else {
       
  1541             d->model = oldModel;
  1483         }
  1542         }
  1484         if (QDeclarativeVisualDataModel *dataModel = qobject_cast<QDeclarativeVisualDataModel*>(d->model))
  1543         if (QDeclarativeVisualDataModel *dataModel = qobject_cast<QDeclarativeVisualDataModel*>(d->model))
  1485             dataModel->setModel(model);
  1544             dataModel->setModel(model);
  1486     }
  1545     }
  1487     if (d->model) {
  1546     if (d->model) {
  1491             if (d->currentIndex >= d->model->count() || d->currentIndex < 0) {
  1550             if (d->currentIndex >= d->model->count() || d->currentIndex < 0) {
  1492                 setCurrentIndex(0);
  1551                 setCurrentIndex(0);
  1493             } else {
  1552             } else {
  1494                 d->moveReason = QDeclarativeListViewPrivate::SetIndex;
  1553                 d->moveReason = QDeclarativeListViewPrivate::SetIndex;
  1495                 d->updateCurrent(d->currentIndex);
  1554                 d->updateCurrent(d->currentIndex);
       
  1555                 if (d->highlight && d->currentItem) {
       
  1556                     d->highlight->setPosition(d->currentItem->position());
       
  1557                     d->updateTrackedItem();
       
  1558                 }
  1496             }
  1559             }
  1497         }
  1560         }
  1498         connect(d->model, SIGNAL(itemsInserted(int,int)), this, SLOT(itemsInserted(int,int)));
  1561         connect(d->model, SIGNAL(itemsInserted(int,int)), this, SLOT(itemsInserted(int,int)));
  1499         connect(d->model, SIGNAL(itemsRemoved(int,int)), this, SLOT(itemsRemoved(int,int)));
  1562         connect(d->model, SIGNAL(itemsRemoved(int,int)), this, SLOT(itemsRemoved(int,int)));
  1500         connect(d->model, SIGNAL(itemsMoved(int,int,int)), this, SLOT(itemsMoved(int,int,int)));
  1563         connect(d->model, SIGNAL(itemsMoved(int,int,int)), this, SLOT(itemsMoved(int,int,int)));
  1516     The number of elements in the delegate has a direct effect on the
  1579     The number of elements in the delegate has a direct effect on the
  1517     flicking performance of the view.  If at all possible, place functionality
  1580     flicking performance of the view.  If at all possible, place functionality
  1518     that is not needed for the normal display of the delegate in a \l Loader which
  1581     that is not needed for the normal display of the delegate in a \l Loader which
  1519     can load additional elements when needed.
  1582     can load additional elements when needed.
  1520 
  1583 
  1521     Tthe ListView will lay out the items based on the size of the root item
  1584     The ListView will lay out the items based on the size of the root item
  1522     in the delegate.
  1585     in the delegate.
       
  1586 
       
  1587     It is recommended that the delagate's size be a whole number to avoid sub-pixel
       
  1588     alignment of items.
  1523 
  1589 
  1524     \note Delegates are instantiated as needed and may be destroyed at any time.
  1590     \note Delegates are instantiated as needed and may be destroyed at any time.
  1525     State should \e never be stored in a delegate.
  1591     State should \e never be stored in a delegate.
  1526 */
  1592 */
  1527 QDeclarativeComponent *QDeclarativeListView::delegate() const
  1593 QDeclarativeComponent *QDeclarativeListView::delegate() const
  1551                 d->releaseItem(d->visibleItems.at(i));
  1617                 d->releaseItem(d->visibleItems.at(i));
  1552             d->visibleItems.clear();
  1618             d->visibleItems.clear();
  1553             refill();
  1619             refill();
  1554             d->moveReason = QDeclarativeListViewPrivate::SetIndex;
  1620             d->moveReason = QDeclarativeListViewPrivate::SetIndex;
  1555             d->updateCurrent(d->currentIndex);
  1621             d->updateCurrent(d->currentIndex);
       
  1622             if (d->highlight && d->currentItem) {
       
  1623                 d->highlight->setPosition(d->currentItem->position());
       
  1624                 d->updateTrackedItem();
       
  1625             }
  1556         }
  1626         }
  1557     }
  1627     }
  1558     emit delegateChanged();
  1628     emit delegateChanged();
  1559 }
  1629 }
  1560 
  1630 
  1561 /*!
  1631 /*!
  1562     \qmlproperty int ListView::currentIndex
  1632     \qmlproperty int ListView::currentIndex
  1563     \qmlproperty Item ListView::currentItem
  1633     \qmlproperty Item ListView::currentItem
  1564 
  1634 
  1565     \c currentIndex holds the index of the current item.
  1635     The \c currentIndex property holds the index of the current item, and
  1566     \c currentItem is the current item.  Note that the position of the current item
  1636     \c currentItem holds the current item. 
       
  1637 
       
  1638     If highlightFollowsCurrentItem is \c true, setting either of these 
       
  1639     properties will smoothly scroll the ListView so that the current 
       
  1640     item becomes visible.
       
  1641     
       
  1642     Note that the position of the current item
  1567     may only be approximate until it becomes visible in the view.
  1643     may only be approximate until it becomes visible in the view.
  1568 */
  1644 */
  1569 int QDeclarativeListView::currentIndex() const
  1645 int QDeclarativeListView::currentIndex() const
  1570 {
  1646 {
  1571     Q_D(const QDeclarativeListView);
  1647     Q_D(const QDeclarativeListView);
  1577     Q_D(QDeclarativeListView);
  1653     Q_D(QDeclarativeListView);
  1578     if (d->requestedIndex >= 0)  // currently creating item
  1654     if (d->requestedIndex >= 0)  // currently creating item
  1579         return;
  1655         return;
  1580     if (isComponentComplete() && d->isValid() && index != d->currentIndex && index < d->model->count() && index >= 0) {
  1656     if (isComponentComplete() && d->isValid() && index != d->currentIndex && index < d->model->count() && index >= 0) {
  1581         d->moveReason = QDeclarativeListViewPrivate::SetIndex;
  1657         d->moveReason = QDeclarativeListViewPrivate::SetIndex;
  1582         cancelFlick();
       
  1583         d->updateCurrent(index);
  1658         d->updateCurrent(index);
  1584     } else if (index != d->currentIndex) {
  1659     } else if (index != d->currentIndex) {
  1585         d->currentIndex = index;
  1660         d->currentIndex = index;
  1586         emit currentIndexChanged();
  1661         emit currentIndexChanged();
  1587     }
  1662     }
  1628 /*!
  1703 /*!
  1629     \qmlproperty Component ListView::highlight
  1704     \qmlproperty Component ListView::highlight
  1630     This property holds the component to use as the highlight.
  1705     This property holds the component to use as the highlight.
  1631 
  1706 
  1632     An instance of the highlight component is created for each list.
  1707     An instance of the highlight component is created for each list.
  1633     The geometry of the resultant component instance is managed by the list
  1708     The geometry of the resulting component instance is managed by the list
  1634     so as to stay with the current item, unless the highlightFollowsCurrentItem
  1709     so as to stay with the current item, unless the highlightFollowsCurrentItem
  1635     property is false.
  1710     property is false.
  1636 
  1711 
  1637     \sa highlightItem, highlightFollowsCurrentItem
  1712     \sa highlightItem, highlightFollowsCurrentItem, {declarative/modelviews/listview}{ListView examples}
  1638 */
  1713 */
  1639 QDeclarativeComponent *QDeclarativeListView::highlight() const
  1714 QDeclarativeComponent *QDeclarativeListView::highlight() const
  1640 {
  1715 {
  1641     Q_D(const QDeclarativeListView);
  1716     Q_D(const QDeclarativeListView);
  1642     return d->highlightComponent;
  1717     return d->highlightComponent;
  1656 
  1731 
  1657 /*!
  1732 /*!
  1658     \qmlproperty bool ListView::highlightFollowsCurrentItem
  1733     \qmlproperty bool ListView::highlightFollowsCurrentItem
  1659     This property holds whether the highlight is managed by the view.
  1734     This property holds whether the highlight is managed by the view.
  1660 
  1735 
  1661     If this property is true, the highlight is moved smoothly
  1736     If this property is true (the default value), the highlight is moved smoothly
  1662     to follow the current item.  Otherwise, the
  1737     to follow the current item.  Otherwise, the
  1663     highlight is not moved by the view, and any movement must be implemented
  1738     highlight is not moved by the view, and any movement must be implemented
  1664     by the highlight.  
  1739     by the highlight.  
  1665     
  1740     
  1666     Here is a highlight with its motion defined by the a \l {SpringFollow} item:
  1741     Here is a highlight with its motion defined by a \l {SpringAnimation} item:
  1667 
  1742 
  1668     \snippet doc/src/snippets/declarative/listview/listview.qml highlightFollowsCurrentItem
  1743     \snippet doc/src/snippets/declarative/listview/listview.qml highlightFollowsCurrentItem
  1669 
  1744 
  1670     Note that the highlight animation also affects the way that the view
  1745     Note that the highlight animation also affects the way that the view
  1671     is scrolled.  This is because the view moves to maintain the
  1746     is scrolled.  This is because the view moves to maintain the
  1777 
  1852 
  1778 /*!
  1853 /*!
  1779     \qmlproperty real ListView::spacing
  1854     \qmlproperty real ListView::spacing
  1780 
  1855 
  1781     This property holds the spacing between items.
  1856     This property holds the spacing between items.
       
  1857 
       
  1858     The default value is 0.
  1782 */
  1859 */
  1783 qreal QDeclarativeListView::spacing() const
  1860 qreal QDeclarativeListView::spacing() const
  1784 {
  1861 {
  1785     Q_D(const QDeclarativeListView);
  1862     Q_D(const QDeclarativeListView);
  1786     return d->spacing;
  1863     return d->spacing;
  1843     }
  1920     }
  1844 }
  1921 }
  1845 
  1922 
  1846 /*!
  1923 /*!
  1847     \qmlproperty bool ListView::keyNavigationWraps
  1924     \qmlproperty bool ListView::keyNavigationWraps
  1848     This property holds whether the list wraps key navigation.
  1925     This property holds whether the list wraps key navigation. 
  1849 
  1926 
  1850     If this is true, key navigation that would move the current item selection
  1927     If this is true, key navigation that would move the current item selection
  1851     past the end of the list instead wraps around and moves the selection to
  1928     past the end of the list instead wraps around and moves the selection to
  1852     the start of the list, and vice-versa.
  1929     the start of the list, and vice-versa.
       
  1930 
       
  1931     By default, key navigation is not wrapped.
  1853 */
  1932 */
  1854 bool QDeclarativeListView::isWrapEnabled() const
  1933 bool QDeclarativeListView::isWrapEnabled() const
  1855 {
  1934 {
  1856     Q_D(const QDeclarativeListView);
  1935     Q_D(const QDeclarativeListView);
  1857     return d->wrap;
  1936     return d->wrap;
  1905 }
  1984 }
  1906 
  1985 
  1907 /*!
  1986 /*!
  1908     \qmlproperty string ListView::section.property
  1987     \qmlproperty string ListView::section.property
  1909     \qmlproperty enumeration ListView::section.criteria
  1988     \qmlproperty enumeration ListView::section.criteria
       
  1989     \qmlproperty Component ListView::section.delegate
       
  1990 
  1910     These properties hold the expression to be evaluated for the \l section attached property.
  1991     These properties hold the expression to be evaluated for the \l section attached property.
  1911 
  1992 
  1912     \c section.property hold the name of the property to use to determine
  1993     The \l section attached property enables a ListView to be visually
  1913     the section that holds the item.
  1994     separated into different parts. These properties determine how sections
  1914 
  1995     are created.
  1915     \c section.criteria holds the criteria to use to access the section. It
  1996     
  1916     can be either:
  1997     \c section.property holds the name of the property that is the basis
       
  1998     of each section.
       
  1999 
       
  2000     \c section.criteria holds the criteria for forming each section based on
       
  2001     \c section.property. This value can be one of:
  1917 
  2002 
  1918     \list
  2003     \list
  1919     \o ViewSection.FullString (default) - section is the value of the property.
  2004     \o ViewSection.FullString (default) - sections are created based on the 
  1920     \o ViewSection.FirstCharacter - section is the first character of the property value.
  2005     \c section.property value.
       
  2006     \o ViewSection.FirstCharacter - sections are created based on the first
       
  2007     character of the \c section.property value (for example, 'A', 'B', 'C' 
       
  2008     sections, etc. for an address book)
  1921     \endlist
  2009     \endlist
  1922 
  2010 
  1923     Each item in the list has attached properties named \c ListView.section and
  2011     \c section.delegate holds the delegate component for each section.
  1924     \c ListView.prevSection.  These may be used to place a section header for
  2012 
  1925     related items.  The example below assumes that the model is sorted by size of
  2013     Each item in the list has attached properties named \c ListView.section,
  1926     pet.  The section expression is the size property.  If \c ListView.section and
  2014     \c ListView.previousSection and \c ListView.nextSection.  These may be
  1927     \c ListView.prevSection differ, the item will display a section header.
  2015     used to place a section header for related items.
  1928 
  2016 
       
  2017     For example, here is a ListView that displays a list of animals, separated 
       
  2018     into sections. Each item in the ListView is placed in a different section 
       
  2019     depending on the "size" property of the model item. The \c sectionHeading
       
  2020     delegate component provides the light blue bar that marks the beginning of
       
  2021     each section.
       
  2022        
  1929     \snippet examples/declarative/modelviews/listview/sections.qml 0
  2023     \snippet examples/declarative/modelviews/listview/sections.qml 0
  1930 
  2024 
  1931     \image ListViewSections.png
  2025     \image qml-listview-sections-example.png
       
  2026 
       
  2027     \sa {declarative/modelviews/listview}{ListView examples}
  1932 */
  2028 */
  1933 QDeclarativeViewSection *QDeclarativeListView::sectionCriteria()
  2029 QDeclarativeViewSection *QDeclarativeListView::sectionCriteria()
  1934 {
  2030 {
  1935     Q_D(QDeclarativeListView);
  2031     Q_D(QDeclarativeListView);
  1936     if (!d->sectionCriteria)
  2032     if (!d->sectionCriteria)
  1954     \qmlproperty real ListView::highlightResizeSpeed
  2050     \qmlproperty real ListView::highlightResizeSpeed
  1955     \qmlproperty int ListView::highlightResizeDuration
  2051     \qmlproperty int ListView::highlightResizeDuration
  1956 
  2052 
  1957     These properties hold the move and resize animation speed of the highlight delegate.
  2053     These properties hold the move and resize animation speed of the highlight delegate.
  1958 
  2054 
  1959     \c highlightFollowsCurrentItem must be true for these properties
  2055     \l highlightFollowsCurrentItem must be true for these properties
  1960     to have effect.
  2056     to have effect.
  1961 
  2057 
  1962     The default value for the speed properties is 400 pixels/second.
  2058     The default value for the speed properties is 400 pixels/second.
  1963     The default value for the duration properties is -1, i.e. the
  2059     The default value for the duration properties is -1, i.e. the
  1964     highlight will take as much time as necessary to move at the set speed.
  2060     highlight will take as much time as necessary to move at the set speed.
  2036 }
  2132 }
  2037 
  2133 
  2038 /*!
  2134 /*!
  2039     \qmlproperty enumeration ListView::snapMode
  2135     \qmlproperty enumeration ListView::snapMode
  2040 
  2136 
  2041     This property determines where the view's scrolling behavior stops following a drag or flick.
  2137     This property determines how the view scrolling will settle following a drag or flick.
  2042     The allowed values are:
  2138     The possible values are:
  2043 
  2139 
  2044     \list
  2140     \list
  2045     \o ListView.NoSnap (default) - the view stops anywhere within the visible area.
  2141     \o ListView.NoSnap (default) - the view stops anywhere within the visible area.
  2046     \o ListView.SnapToItem - the view settles with an item aligned with the start of
  2142     \o ListView.SnapToItem - the view settles with an item aligned with the start of
  2047     the view.
  2143     the view.
  2069         d->snapMode = mode;
  2165         d->snapMode = mode;
  2070         emit snapModeChanged();
  2166         emit snapModeChanged();
  2071     }
  2167     }
  2072 }
  2168 }
  2073 
  2169 
       
  2170 /*!
       
  2171     \qmlproperty Component ListView::footer
       
  2172     This property holds the component to use as the footer.
       
  2173 
       
  2174     An instance of the footer component is created for each view.  The
       
  2175     footer is positioned at the end of the view, after any items.
       
  2176 
       
  2177     \sa header
       
  2178 */
  2074 QDeclarativeComponent *QDeclarativeListView::footer() const
  2179 QDeclarativeComponent *QDeclarativeListView::footer() const
  2075 {
  2180 {
  2076     Q_D(const QDeclarativeListView);
  2181     Q_D(const QDeclarativeListView);
  2077     return d->footerComponent;
  2182     return d->footerComponent;
  2078 }
  2183 }
  2092         d->updateViewport();
  2197         d->updateViewport();
  2093         emit footerChanged();
  2198         emit footerChanged();
  2094     }
  2199     }
  2095 }
  2200 }
  2096 
  2201 
       
  2202 /*!
       
  2203     \qmlproperty Component ListView::header
       
  2204     This property holds the component to use as the header.
       
  2205 
       
  2206     An instance of the header component is created for each view.  The
       
  2207     header is positioned at the beginning of the view, before any items.
       
  2208 
       
  2209     \sa footer
       
  2210 */
  2097 QDeclarativeComponent *QDeclarativeListView::header() const
  2211 QDeclarativeComponent *QDeclarativeListView::header() const
  2098 {
  2212 {
  2099     Q_D(const QDeclarativeListView);
  2213     Q_D(const QDeclarativeListView);
  2100     return d->headerComponent;
  2214     return d->headerComponent;
  2101 }
  2215 }
  2114         d->updateHeader();
  2228         d->updateHeader();
  2115         d->updateFooter();
  2229         d->updateFooter();
  2116         d->updateViewport();
  2230         d->updateViewport();
  2117         emit headerChanged();
  2231         emit headerChanged();
  2118     }
  2232     }
       
  2233 }
       
  2234 
       
  2235 void QDeclarativeListView::setContentX(qreal pos)
       
  2236 {
       
  2237     Q_D(QDeclarativeListView);
       
  2238     // Positioning the view manually should override any current movement state
       
  2239     d->moveReason = QDeclarativeListViewPrivate::Other;
       
  2240     QDeclarativeFlickable::setContentX(pos);
       
  2241 }
       
  2242 
       
  2243 void QDeclarativeListView::setContentY(qreal pos)
       
  2244 {
       
  2245     Q_D(QDeclarativeListView);
       
  2246     // Positioning the view manually should override any current movement state
       
  2247     d->moveReason = QDeclarativeListViewPrivate::Other;
       
  2248     QDeclarativeFlickable::setContentY(pos);
  2119 }
  2249 }
  2120 
  2250 
  2121 bool QDeclarativeListView::event(QEvent *event)
  2251 bool QDeclarativeListView::event(QEvent *event)
  2122 {
  2252 {
  2123     Q_D(QDeclarativeListView);
  2253     Q_D(QDeclarativeListView);
  2217 {
  2347 {
  2218     Q_D(const QDeclarativeListView);
  2348     Q_D(const QDeclarativeListView);
  2219     if (d->orient == QDeclarativeListView::Horizontal)
  2349     if (d->orient == QDeclarativeListView::Horizontal)
  2220         return height();
  2350         return height();
  2221     if (d->maxExtentDirty) {
  2351     if (d->maxExtentDirty) {
  2222         if (d->haveHighlightRange && d->highlightRange == StrictlyEnforceRange) {
  2352         if (!d->model || !d->model->count()) {
       
  2353             d->maxExtent = 0;
       
  2354         } else if (d->haveHighlightRange && d->highlightRange == StrictlyEnforceRange) {
  2223             d->maxExtent = -(d->positionAt(d->model->count()-1) - d->highlightRangeStart);
  2355             d->maxExtent = -(d->positionAt(d->model->count()-1) - d->highlightRangeStart);
  2224             if (d->highlightRangeEnd != d->highlightRangeStart)
  2356             if (d->highlightRangeEnd != d->highlightRangeStart)
  2225                 d->maxExtent = qMin(d->maxExtent, -(d->endPosition() - d->highlightRangeEnd + 1));
  2357                 d->maxExtent = qMin(d->maxExtent, -(d->endPosition() - d->highlightRangeEnd + 1));
  2226         } else {
  2358         } else {
  2227             d->maxExtent = -(d->endPosition() - height() + 1);
  2359             d->maxExtent = -(d->endPosition() - height() + 1);
  2259 {
  2391 {
  2260     Q_D(const QDeclarativeListView);
  2392     Q_D(const QDeclarativeListView);
  2261     if (d->orient == QDeclarativeListView::Vertical)
  2393     if (d->orient == QDeclarativeListView::Vertical)
  2262         return width();
  2394         return width();
  2263     if (d->maxExtentDirty) {
  2395     if (d->maxExtentDirty) {
  2264         if (d->haveHighlightRange && d->highlightRange == StrictlyEnforceRange) {
  2396         if (!d->model || !d->model->count()) {
       
  2397             d->maxExtent = 0;
       
  2398         } else if (d->haveHighlightRange && d->highlightRange == StrictlyEnforceRange) {
  2265             d->maxExtent = -(d->positionAt(d->model->count()-1) - d->highlightRangeStart);
  2399             d->maxExtent = -(d->positionAt(d->model->count()-1) - d->highlightRangeStart);
  2266             if (d->highlightRangeEnd != d->highlightRangeStart)
  2400             if (d->highlightRangeEnd != d->highlightRangeStart)
  2267                 d->maxExtent = qMin(d->maxExtent, -(d->endPosition() - d->highlightRangeEnd + 1));
  2401                 d->maxExtent = qMin(d->maxExtent, -(d->endPosition() - d->highlightRangeEnd + 1));
  2268         } else {
  2402         } else {
  2269             d->maxExtent = -(d->endPosition() - width() + 1);
  2403             d->maxExtent = -(d->endPosition() - width() + 1);
  2316 /*!
  2450 /*!
  2317     \qmlmethod ListView::incrementCurrentIndex()
  2451     \qmlmethod ListView::incrementCurrentIndex()
  2318 
  2452 
  2319     Increments the current index.  The current index will wrap
  2453     Increments the current index.  The current index will wrap
  2320     if keyNavigationWraps is true and it is currently at the end.
  2454     if keyNavigationWraps is true and it is currently at the end.
       
  2455 
       
  2456     \bold Note: methods should only be called after the Component has completed.
  2321 */
  2457 */
  2322 void QDeclarativeListView::incrementCurrentIndex()
  2458 void QDeclarativeListView::incrementCurrentIndex()
  2323 {
  2459 {
  2324     Q_D(QDeclarativeListView);
  2460     Q_D(QDeclarativeListView);
  2325     if (currentIndex() < d->model->count() - 1 || d->wrap) {
  2461     if (currentIndex() < d->model->count() - 1 || d->wrap) {
  2326         d->moveReason = QDeclarativeListViewPrivate::SetIndex;
  2462         d->moveReason = QDeclarativeListViewPrivate::SetIndex;
  2327         int index = currentIndex()+1;
  2463         int index = currentIndex()+1;
  2328         cancelFlick();
       
  2329         d->updateCurrent(index < d->model->count() ? index : 0);
  2464         d->updateCurrent(index < d->model->count() ? index : 0);
  2330     }
  2465     }
  2331 }
  2466 }
  2332 
  2467 
  2333 /*!
  2468 /*!
  2334     \qmlmethod ListView::decrementCurrentIndex()
  2469     \qmlmethod ListView::decrementCurrentIndex()
  2335 
  2470 
  2336     Decrements the current index.  The current index will wrap
  2471     Decrements the current index.  The current index will wrap
  2337     if keyNavigationWraps is true and it is currently at the beginning.
  2472     if keyNavigationWraps is true and it is currently at the beginning.
       
  2473 
       
  2474     \bold Note: methods should only be called after the Component has completed.
  2338 */
  2475 */
  2339 void QDeclarativeListView::decrementCurrentIndex()
  2476 void QDeclarativeListView::decrementCurrentIndex()
  2340 {
  2477 {
  2341     Q_D(QDeclarativeListView);
  2478     Q_D(QDeclarativeListView);
  2342     if (currentIndex() > 0 || d->wrap) {
  2479     if (currentIndex() > 0 || d->wrap) {
  2343         d->moveReason = QDeclarativeListViewPrivate::SetIndex;
  2480         d->moveReason = QDeclarativeListViewPrivate::SetIndex;
  2344         int index = currentIndex()-1;
  2481         int index = currentIndex()-1;
  2345         cancelFlick();
       
  2346         d->updateCurrent(index >= 0 ? index : d->model->count()-1);
  2482         d->updateCurrent(index >= 0 ? index : d->model->count()-1);
  2347     }
  2483     }
  2348 }
  2484 }
  2349 
  2485 
  2350 /*!
  2486 /*!
  2369     It is not recommended to use \l {Flickable::}{contentX} or \l {Flickable::}{contentY} to position the view
  2505     It is not recommended to use \l {Flickable::}{contentX} or \l {Flickable::}{contentY} to position the view
  2370     at a particular index.  This is unreliable since removing items from the start
  2506     at a particular index.  This is unreliable since removing items from the start
  2371     of the list does not cause all other items to be repositioned, and because
  2507     of the list does not cause all other items to be repositioned, and because
  2372     the actual start of the view can vary based on the size of the delegates.
  2508     the actual start of the view can vary based on the size of the delegates.
  2373     The correct way to bring an item into view is with \c positionViewAtIndex.
  2509     The correct way to bring an item into view is with \c positionViewAtIndex.
       
  2510 
       
  2511     \bold Note: methods should only be called after the Component has completed.  To position
       
  2512     the view at startup, this method should be called by Component.onCompleted.  For
       
  2513     example, to position the view at the end:
       
  2514 
       
  2515     \code
       
  2516     Component.onCompleted: positionViewAtIndex(count - 1, ListView.Beginning)
       
  2517     \endcode
  2374 */
  2518 */
  2375 void QDeclarativeListView::positionViewAtIndex(int index, int mode)
  2519 void QDeclarativeListView::positionViewAtIndex(int index, int mode)
  2376 {
  2520 {
  2377     Q_D(QDeclarativeListView);
  2521     Q_D(QDeclarativeListView);
  2378     if (!d->isValid() || index < 0 || index >= d->model->count())
  2522     if (!d->isValid() || index < 0 || index >= d->model->count())
  2379         return;
  2523         return;
  2380     if (mode < Beginning || mode > Contain)
  2524     if (mode < Beginning || mode > Contain)
  2381         return;
  2525         return;
  2382 
  2526 
       
  2527     if (d->layoutScheduled)
       
  2528         d->layout();
  2383     qreal pos = d->position();
  2529     qreal pos = d->position();
  2384     FxListItem *item = d->visibleItem(index);
  2530     FxListItem *item = d->visibleItem(index);
  2385     if (!item) {
  2531     if (!item) {
  2386         int itemPos = d->positionAt(index);
  2532         int itemPos = d->positionAt(index);
  2387         // save the currently visible items in case any of them end up visible again
  2533         // save the currently visible items in case any of them end up visible again
  2421         }
  2567         }
  2422         qreal maxExtent = d->orient == QDeclarativeListView::Vertical ? -maxYExtent() : -maxXExtent();
  2568         qreal maxExtent = d->orient == QDeclarativeListView::Vertical ? -maxYExtent() : -maxXExtent();
  2423         pos = qMin(pos, maxExtent);
  2569         pos = qMin(pos, maxExtent);
  2424         qreal minExtent = d->orient == QDeclarativeListView::Vertical ? -minYExtent() : -minXExtent();
  2570         qreal minExtent = d->orient == QDeclarativeListView::Vertical ? -minYExtent() : -minXExtent();
  2425         pos = qMax(pos, minExtent);
  2571         pos = qMax(pos, minExtent);
       
  2572         d->moveReason = QDeclarativeListViewPrivate::Other;
       
  2573         cancelFlick();
  2426         d->setPosition(pos);
  2574         d->setPosition(pos);
  2427     }
  2575     }
  2428     d->fixupPosition();
  2576     d->fixupPosition();
  2429 }
  2577 }
  2430 
  2578 
  2435     coordinates.  If there is no item at the point specified, or the item is
  2583     coordinates.  If there is no item at the point specified, or the item is
  2436     not visible -1 is returned.
  2584     not visible -1 is returned.
  2437 
  2585 
  2438     If the item is outside the visible area, -1 is returned, regardless of
  2586     If the item is outside the visible area, -1 is returned, regardless of
  2439     whether an item will exist at that point when scrolled into view.
  2587     whether an item will exist at that point when scrolled into view.
       
  2588 
       
  2589     \bold Note: methods should only be called after the Component has completed.
  2440 */
  2590 */
  2441 int QDeclarativeListView::indexAt(int x, int y) const
  2591 int QDeclarativeListView::indexAt(int x, int y) const
  2442 {
  2592 {
  2443     Q_D(const QDeclarativeListView);
  2593     Q_D(const QDeclarativeListView);
  2444     for (int i = 0; i < d->visibleItems.count(); ++i) {
  2594     for (int i = 0; i < d->visibleItems.count(); ++i) {
  2459         d->moveReason = QDeclarativeListViewPrivate::SetIndex;
  2609         d->moveReason = QDeclarativeListViewPrivate::SetIndex;
  2460         if (d->currentIndex < 0)
  2610         if (d->currentIndex < 0)
  2461             d->updateCurrent(0);
  2611             d->updateCurrent(0);
  2462         else
  2612         else
  2463             d->updateCurrent(d->currentIndex);
  2613             d->updateCurrent(d->currentIndex);
       
  2614         if (d->highlight && d->currentItem) {
       
  2615             d->highlight->setPosition(d->currentItem->position());
       
  2616             d->updateTrackedItem();
       
  2617         }
       
  2618         d->moveReason = QDeclarativeListViewPrivate::Other;
  2464         d->fixupPosition();
  2619         d->fixupPosition();
  2465     }
  2620     }
  2466 }
  2621 }
  2467 
  2622 
  2468 void QDeclarativeListView::refill()
  2623 void QDeclarativeListView::refill()
  2474 void QDeclarativeListView::trackedPositionChanged()
  2629 void QDeclarativeListView::trackedPositionChanged()
  2475 {
  2630 {
  2476     Q_D(QDeclarativeListView);
  2631     Q_D(QDeclarativeListView);
  2477     if (!d->trackedItem || !d->currentItem)
  2632     if (!d->trackedItem || !d->currentItem)
  2478         return;
  2633         return;
  2479     if (!d->flickingHorizontally && !d->flickingVertically && !d->movingHorizontally && !d->movingVertically
  2634     if (d->moveReason == QDeclarativeListViewPrivate::SetIndex) {
  2480         && d->moveReason == QDeclarativeListViewPrivate::SetIndex) {
       
  2481         const qreal trackedPos = qCeil(d->trackedItem->position());
  2635         const qreal trackedPos = qCeil(d->trackedItem->position());
  2482         const qreal viewPos = d->position();
  2636         const qreal viewPos = d->position();
       
  2637         qreal pos = viewPos;
  2483         if (d->haveHighlightRange) {
  2638         if (d->haveHighlightRange) {
  2484             if (d->highlightRange == StrictlyEnforceRange) {
  2639             if (d->highlightRange == StrictlyEnforceRange) {
  2485                 qreal pos = viewPos;
       
  2486                 if (trackedPos > pos + d->highlightRangeEnd - d->trackedItem->size())
  2640                 if (trackedPos > pos + d->highlightRangeEnd - d->trackedItem->size())
  2487                     pos = trackedPos - d->highlightRangeEnd + d->trackedItem->size();
  2641                     pos = trackedPos - d->highlightRangeEnd + d->trackedItem->size();
  2488                 if (trackedPos < pos + d->highlightRangeStart)
  2642                 if (trackedPos < pos + d->highlightRangeStart)
  2489                     pos = trackedPos - d->highlightRangeStart;
  2643                     pos = trackedPos - d->highlightRangeStart;
  2490                 d->setPosition(pos);
       
  2491             } else {
  2644             } else {
  2492                 qreal pos = viewPos;
       
  2493                 if (trackedPos < d->startPosition() + d->highlightRangeStart) {
  2645                 if (trackedPos < d->startPosition() + d->highlightRangeStart) {
  2494                     pos = d->startPosition();
  2646                     pos = d->startPosition();
  2495                 } else if (d->trackedItem->endPosition() > d->endPosition() - d->size() + d->highlightRangeEnd) {
  2647                 } else if (d->trackedItem->endPosition() > d->endPosition() - d->size() + d->highlightRangeEnd) {
  2496                     pos = d->endPosition() - d->size();
  2648                     pos = d->endPosition() - d->size();
  2497                     if (pos < d->startPosition())
  2649                     if (pos < d->startPosition())
  2501                         pos = trackedPos - d->highlightRangeStart;
  2653                         pos = trackedPos - d->highlightRangeStart;
  2502                     } else if (trackedPos > viewPos + d->highlightRangeEnd - d->trackedItem->size()) {
  2654                     } else if (trackedPos > viewPos + d->highlightRangeEnd - d->trackedItem->size()) {
  2503                         pos = trackedPos - d->highlightRangeEnd + d->trackedItem->size();
  2655                         pos = trackedPos - d->highlightRangeEnd + d->trackedItem->size();
  2504                     }
  2656                     }
  2505                 }
  2657                 }
  2506                 d->setPosition(pos);
       
  2507             }
  2658             }
  2508         } else {
  2659         } else {
  2509             if (trackedPos < viewPos && d->currentItem->position() < viewPos) {
  2660             if (trackedPos < viewPos && d->currentItem->position() < viewPos) {
  2510                 d->setPosition(d->currentItem->position() < trackedPos ? trackedPos : d->currentItem->position());
  2661                 pos = d->currentItem->position() < trackedPos ? trackedPos : d->currentItem->position();
  2511             } else if (d->trackedItem->endPosition() > viewPos + d->size()
  2662             } else if (d->trackedItem->endPosition() > viewPos + d->size()
  2512                         && d->currentItem->endPosition() > viewPos + d->size()) {
  2663                         && d->currentItem->endPosition() > viewPos + d->size()) {
  2513                 qreal pos;
       
  2514                 if (d->trackedItem->endPosition() < d->currentItem->endPosition()) {
  2664                 if (d->trackedItem->endPosition() < d->currentItem->endPosition()) {
  2515                     pos = d->trackedItem->endPosition() - d->size();
  2665                     pos = d->trackedItem->endPosition() - d->size();
  2516                     if (d->trackedItem->size() > d->size())
  2666                     if (d->trackedItem->size() > d->size())
  2517                         pos = trackedPos;
  2667                         pos = trackedPos;
  2518                 } else {
  2668                 } else {
  2519                     pos = d->currentItem->endPosition() - d->size();
  2669                     pos = d->currentItem->endPosition() - d->size();
  2520                     if (d->currentItem->size() > d->size())
  2670                     if (d->currentItem->size() > d->size())
  2521                         pos = d->currentItem->position();
  2671                         pos = d->currentItem->position();
  2522                 }
  2672                 }
  2523                 d->setPosition(pos);
  2673             }
  2524             }
  2674         }
       
  2675         if (viewPos != pos) {
       
  2676             cancelFlick();
       
  2677             d->setPosition(pos);
  2525         }
  2678         }
  2526     }
  2679     }
  2527 }
  2680 }
  2528 
  2681 
  2529 void QDeclarativeListView::itemsInserted(int modelIndex, int count)
  2682 void QDeclarativeListView::itemsInserted(int modelIndex, int count)
  2748     if (removedVisible && d->visibleItems.isEmpty()) {
  2901     if (removedVisible && d->visibleItems.isEmpty()) {
  2749         d->visibleIndex = 0;
  2902         d->visibleIndex = 0;
  2750         d->visiblePos = d->header ? d->header->size() : 0;
  2903         d->visiblePos = d->header ? d->header->size() : 0;
  2751         d->timeline.clear();
  2904         d->timeline.clear();
  2752         d->setPosition(0);
  2905         d->setPosition(0);
  2753         if (d->itemCount == 0)
  2906         if (d->itemCount == 0) {
       
  2907             d->updateHeader();
       
  2908             d->updateFooter();
  2754             update();
  2909             update();
       
  2910         }
  2755     }
  2911     }
  2756 
  2912 
  2757     emit countChanged();
  2913     emit countChanged();
  2758 }
  2914 }
  2759 
  2915 
  2884     d->clear();
  3040     d->clear();
  2885     d->setPosition(0);
  3041     d->setPosition(0);
  2886     refill();
  3042     refill();
  2887     d->moveReason = QDeclarativeListViewPrivate::SetIndex;
  3043     d->moveReason = QDeclarativeListViewPrivate::SetIndex;
  2888     d->updateCurrent(d->currentIndex);
  3044     d->updateCurrent(d->currentIndex);
       
  3045     if (d->highlight && d->currentItem) {
       
  3046         d->highlight->setPosition(d->currentItem->position());
       
  3047         d->updateTrackedItem();
       
  3048     }
       
  3049     d->moveReason = QDeclarativeListViewPrivate::Other;
  2889     emit countChanged();
  3050     emit countChanged();
  2890 }
  3051 }
  2891 
  3052 
  2892 void QDeclarativeListView::createdItem(int index, QDeclarativeItem *item)
  3053 void QDeclarativeListView::createdItem(int index, QDeclarativeItem *item)
  2893 {
  3054 {
  2894     Q_D(QDeclarativeListView);
  3055     Q_D(QDeclarativeListView);
  2895     if (d->requestedIndex != index) {
  3056     if (d->requestedIndex != index) {
  2896         item->setParentItem(viewport());
  3057         item->setParentItem(contentItem());
  2897         d->unrequestedItems.insert(item, index);
  3058         d->unrequestedItems.insert(item, index);
  2898         if (d->orient == QDeclarativeListView::Vertical)
  3059         if (d->orient == QDeclarativeListView::Vertical)
  2899             item->setY(d->positionAt(index));
  3060             item->setY(d->positionAt(index));
  2900         else
  3061         else
  2901             item->setX(d->positionAt(index));
  3062             item->setX(d->positionAt(index));