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 |
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 { |
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 |
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. |
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) |
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)); |