diff -r ef0373b55136 -r 758a864f9613 src/declarative/graphicsitems/qdeclarativelistview.cpp --- a/src/declarative/graphicsitems/qdeclarativelistview.cpp Fri Sep 17 08:34:18 2010 +0300 +++ b/src/declarative/graphicsitems/qdeclarativelistview.cpp Mon Oct 04 01:19:32 2010 +0300 @@ -60,7 +60,7 @@ { if (property != m_property) { m_property = property; - emit changed(); + emit propertyChanged(); } } @@ -68,7 +68,7 @@ { if (criteria != m_criteria) { m_criteria = criteria; - emit changed(); + emit criteriaChanged(); } } @@ -96,7 +96,7 @@ FxListItem(QDeclarativeItem *i, QDeclarativeListView *v) : item(i), section(0), view(v) { attached = static_cast(qmlAttachedPropertiesObject(item)); if (attached) - attached->m_view = view; + attached->setView(view); } ~FxListItem() {} qreal position() const { @@ -105,12 +105,23 @@ else return (view->orientation() == QDeclarativeListView::Vertical ? item->y() : item->x()); } + qreal itemPosition() const { + return (view->orientation() == QDeclarativeListView::Vertical ? item->y() : item->x()); + } qreal size() const { if (section) - return (view->orientation() == QDeclarativeListView::Vertical ? item->height()+section->height() : item->width()+section->height()); + return (view->orientation() == QDeclarativeListView::Vertical ? item->height()+section->height() : item->width()+section->width()); else return (view->orientation() == QDeclarativeListView::Vertical ? item->height() : item->width()); } + qreal itemSize() const { + return (view->orientation() == QDeclarativeListView::Vertical ? item->height() : item->width()); + } + qreal sectionSize() const { + if (section) + return (view->orientation() == QDeclarativeListView::Vertical ? section->height() : section->width()); + return 0.0; + } qreal endPosition() const { return (view->orientation() == QDeclarativeListView::Vertical ? item->y() + (item->height() > 0 ? item->height() : 1) @@ -131,6 +142,12 @@ item->setX(pos); } } + void setSize(qreal size) { + if (view->orientation() == QDeclarativeListView::Vertical) + item->setHeight(size); + else + item->setWidth(size); + } bool contains(int x, int y) const { return (x >= item->x() && x < item->x() + item->width() && y >= item->y() && y < item->y() + item->height()); @@ -256,7 +273,12 @@ if (!visibleItems.isEmpty()) { if (modelIndex < visibleIndex) { int count = visibleIndex - modelIndex; - return (*visibleItems.constBegin())->position() - count * (averageSize + spacing); + qreal cs = 0; + if (modelIndex == currentIndex && currentItem) { + cs = currentItem->size() + spacing; + --count; + } + return (*visibleItems.constBegin())->position() - count * (averageSize + spacing) - cs; } else { int idx = visibleItems.count() - 1; while (idx >= 0 && visibleItems.at(idx)->index == -1) @@ -575,9 +597,11 @@ listItem->attached->m_prevSection = item->attached->section(); else listItem->attached->m_prevSection = sectionAt(modelIndex-1); + } + if (modelIndex < model->count()-1) { if (FxListItem *item = visibleItem(modelIndex+1)) listItem->attached->m_nextSection = item->attached->section(); - else if (modelIndex < model->count()-1) + else listItem->attached->m_nextSection = sectionAt(modelIndex+1); } } @@ -714,6 +738,11 @@ if (visibleItems.count()) visiblePos = (*visibleItems.constBegin())->position(); updateAverage(); + if (currentIndex >= 0 && currentItem && !visibleItem(currentIndex)) { + currentItem->setPosition(positionAt(currentIndex)); + updateHighlight(); + } + if (sectionCriteria) updateCurrentSection(); if (header) @@ -883,8 +912,8 @@ createHighlight(); if (currentItem && autoHighlight && highlight && !movingHorizontally && !movingVertically) { // auto-update highlight - highlightPosAnimator->to = currentItem->position(); - highlightSizeAnimator->to = currentItem->size(); + highlightPosAnimator->to = currentItem->itemPosition(); + highlightSizeAnimator->to = currentItem->itemSize(); if (orient == QDeclarativeListView::Vertical) { if (highlight->item->width() == 0) highlight->item->setWidth(currentItem->item->width()); @@ -981,11 +1010,11 @@ void QDeclarativeListViewPrivate::updateCurrentSection() { if (!sectionCriteria || visibleItems.isEmpty()) { - currentSection = QString(); + currentSection.clear(); return; } int index = 0; - while (visibleItems.at(index)->endPosition() < position() && index < visibleItems.count()) + while (index < visibleItems.count() && visibleItems.at(index)->endPosition() < position()) ++index; if (index < visibleItems.count()) @@ -1019,7 +1048,7 @@ if (oldCurrentItem && (!currentItem || oldCurrentItem->item != currentItem->item)) oldCurrentItem->attached->setIsCurrentItem(false); if (currentItem) { - if (modelIndex == visibleIndex - 1) { + if (modelIndex == visibleIndex - 1 && visibleItems.count()) { // We can calculate exact postion in this case currentItem->setPosition(visibleItems.first()->position() - currentItem->size() - spacing); } else { @@ -1170,9 +1199,9 @@ } if (currentItem && haveHighlightRange && highlightRange == QDeclarativeListView::StrictlyEnforceRange) { updateHighlight(); - qreal currPos = currentItem->position(); - if (pos < currPos + currentItem->size() - highlightRangeEnd) - pos = currPos + currentItem->size() - highlightRangeEnd; + qreal currPos = currentItem->itemPosition(); + if (pos < currPos + currentItem->itemSize() - highlightRangeEnd) + pos = currPos + currentItem->itemSize() - highlightRangeEnd; if (pos > currPos - highlightRangeStart) pos = currPos - highlightRangeStart; } @@ -1189,10 +1218,10 @@ } else if (haveHighlightRange && highlightRange == QDeclarativeListView::StrictlyEnforceRange) { if (currentItem) { updateHighlight(); - qreal pos = currentItem->position(); + qreal pos = currentItem->itemPosition(); qreal viewPos = position(); - if (viewPos < pos + currentItem->size() - highlightRangeEnd) - viewPos = pos + currentItem->size() - highlightRangeEnd; + if (viewPos < pos + currentItem->itemSize() - highlightRangeEnd) + viewPos = pos + currentItem->itemSize() - highlightRangeEnd; if (viewPos > pos - highlightRangeStart) viewPos = pos - highlightRangeStart; @@ -1355,6 +1384,7 @@ /*! \qmlclass ListView QDeclarativeListView + \ingroup qml-view-elements \since 4.7 \inherits Flickable \brief The ListView item provides a list view of items provided by a model. @@ -1385,14 +1415,16 @@ the delegate is able to access the model's \c name and \c number data directly. An improved list view is shown below. The delegate is visually improved and is moved - into a separate \c contactDelegate component. Also, the currently selected item is highlighted - with a blue \l Rectangle using the \l highlight property, and \c focus is set to \c true - to enable keyboard navigation for the list view. + into a separate \c contactDelegate component. \snippet doc/src/snippets/declarative/listview/listview.qml classdocs advanced \image listview-highlight.png - In a GridView, delegates are instantiated as needed and may be destroyed at any time. + The currently selected item is highlighted with a blue \l Rectangle using the \l highlight property, + and \c focus is set to \c true to enable keyboard navigation for the list view. + The list view itself is a focus scope (see \l{qmlfocus#Acquiring Focus and Focus Scopes}{the focus documentation page} for more details). + + Delegates are instantiated as needed and may be destroyed at any time. State should \e never be stored in a delegate. \note Views do not enable \e clip automatically. If the view @@ -1616,6 +1648,8 @@ for (int i = 0; i < d->visibleItems.count(); ++i) d->releaseItem(d->visibleItems.at(i)); d->visibleItems.clear(); + d->releaseItem(d->currentItem); + d->currentItem = 0; refill(); d->moveReason = QDeclarativeListViewPrivate::SetIndex; d->updateCurrent(d->currentIndex); @@ -2335,6 +2369,10 @@ d->minExtent += d->header->size(); if (d->haveHighlightRange && d->highlightRange == StrictlyEnforceRange) { d->minExtent += d->highlightRangeStart; + if (d->sectionCriteria) { + if (d->visibleItem(0)) + d->minExtent -= d->visibleItem(0)->sectionSize(); + } d->minExtent = qMax(d->minExtent, -(d->endPositionAt(0) - d->highlightRangeEnd + 1)); } d->minExtentDirty = false; @@ -2447,6 +2485,16 @@ QDeclarativeFlickable::keyPressEvent(event); } +void QDeclarativeListView::geometryChanged(const QRectF &newGeometry, + const QRectF &oldGeometry) +{ + Q_D(QDeclarativeListView); + d->maxExtentDirty = true; + d->minExtentDirty = true; + QDeclarativeFlickable::geometryChanged(newGeometry, oldGeometry); +} + + /*! \qmlmethod ListView::incrementCurrentIndex() @@ -2572,6 +2620,11 @@ d->moveReason = QDeclarativeListViewPrivate::Other; cancelFlick(); d->setPosition(pos); + if (d->highlight) { + d->highlight->setPosition(d->currentItem->itemPosition()); + d->highlight->setSize(d->currentItem->itemSize()); + d->updateHighlight(); + } } d->fixupPosition(); } @@ -2632,7 +2685,12 @@ if (!d->trackedItem || !d->currentItem) return; if (d->moveReason == QDeclarativeListViewPrivate::SetIndex) { - const qreal trackedPos = qCeil(d->trackedItem->position()); + qreal trackedPos = qCeil(d->trackedItem->position()); + qreal trackedSize = d->trackedItem->size(); + if (d->trackedItem != d->currentItem) { + trackedPos -= d->currentItem->sectionSize(); + trackedSize += d->currentItem->sectionSize(); + } const qreal viewPos = d->position(); qreal pos = viewPos; if (d->haveHighlightRange) { @@ -2645,28 +2703,28 @@ if (trackedPos < d->startPosition() + d->highlightRangeStart) { pos = d->startPosition(); } else if (d->trackedItem->endPosition() > d->endPosition() - d->size() + d->highlightRangeEnd) { - pos = d->endPosition() - d->size(); + pos = d->endPosition() - d->size() + 1; if (pos < d->startPosition()) pos = d->startPosition(); } else { if (trackedPos < viewPos + d->highlightRangeStart) { pos = trackedPos - d->highlightRangeStart; - } else if (trackedPos > viewPos + d->highlightRangeEnd - d->trackedItem->size()) { - pos = trackedPos - d->highlightRangeEnd + d->trackedItem->size(); + } else if (trackedPos > viewPos + d->highlightRangeEnd - trackedSize) { + pos = trackedPos - d->highlightRangeEnd + trackedSize; } } } } else { if (trackedPos < viewPos && d->currentItem->position() < viewPos) { pos = d->currentItem->position() < trackedPos ? trackedPos : d->currentItem->position(); - } else if (d->trackedItem->endPosition() > viewPos + d->size() - && d->currentItem->endPosition() > viewPos + d->size()) { - if (d->trackedItem->endPosition() < d->currentItem->endPosition()) { - pos = d->trackedItem->endPosition() - d->size(); - if (d->trackedItem->size() > d->size()) + } else if (d->trackedItem->endPosition() >= viewPos + d->size() + && d->currentItem->endPosition() >= viewPos + d->size()) { + if (d->trackedItem->endPosition() <= d->currentItem->endPosition()) { + pos = d->trackedItem->endPosition() - d->size() + 1; + if (trackedSize > d->size()) pos = trackedPos; } else { - pos = d->currentItem->endPosition() - d->size(); + pos = d->currentItem->endPosition() - d->size() + 1; if (d->currentItem->size() > d->size()) pos = d->currentItem->position(); } @@ -2899,14 +2957,18 @@ } if (removedVisible && d->visibleItems.isEmpty()) { - d->visibleIndex = 0; - d->visiblePos = d->header ? d->header->size() : 0; d->timeline.clear(); - d->setPosition(0); if (d->itemCount == 0) { + d->visibleIndex = 0; + d->visiblePos = d->header ? d->header->size() : 0; + d->setPosition(0); d->updateHeader(); d->updateFooter(); update(); + } else { + if (modelIndex < d->visibleIndex) + d->visibleIndex = modelIndex+1; + d->visibleIndex = qMax(qMin(d->visibleIndex, d->itemCount-1), 0); } }