src/declarative/graphicsitems/qdeclarativelistview.cpp
changeset 37 758a864f9613
parent 33 3e2da88830cd
--- 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<QDeclarativeListViewAttached*>(qmlAttachedPropertiesObject<QDeclarativeListView>(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);
         }
     }