Section headers ignore list delegate size changes when "colliding"
[profile/ivi/qtdeclarative.git] / src / quick / items / qquicklistview.cpp
index eb0d013..80b4cb5 100644 (file)
@@ -88,7 +88,7 @@ public:
     virtual void init();
     virtual void clear();
 
-    virtual bool addVisibleItems(qreal fillFrom, qreal fillTo, bool doBuffer);
+    virtual bool addVisibleItems(qreal fillFrom, qreal fillTo, qreal bufferFrom, qreal bufferTo, bool doBuffer);
     virtual bool removeNonVisibleItems(qreal bufferFrom, qreal bufferTo);
     virtual void visibleItemsChanged();
 
@@ -110,9 +110,11 @@ public:
     virtual bool applyInsertionChange(const QQuickChangeSet::Insert &insert, ChangeResult *changeResult, QList<FxViewItem *> *addedItems, QList<MovedItem> *movingIntoView);
     virtual void translateAndTransitionItemsAfter(int afterIndex, const ChangeResult &insertionResult, const ChangeResult &removalResult);
 
+    virtual void updateSectionCriteria();
     virtual void updateSections();
     QQuickItem *getSectionItem(const QString &section);
     void releaseSectionItem(QQuickItem *item);
+    void releaseSectionItems();
     void updateInlineSection(FxListItemSG *);
     void updateCurrentSection();
     void updateStickySections();
@@ -143,6 +145,8 @@ public:
 
     QSmoothedAnimation *highlightPosAnimator;
     QSmoothedAnimation *highlightSizeAnimator;
+    qreal highlightMoveVelocity;
+    qreal highlightResizeVelocity;
     int highlightResizeDuration;
 
     QQuickViewSection *sectionCriteria;
@@ -166,7 +170,7 @@ public:
         , averageSize(100.0), spacing(0.0)
         , snapMode(QQuickListView::NoSnap)
         , highlightPosAnimator(0), highlightSizeAnimator(0)
-        , highlightResizeDuration(250)
+        , highlightMoveVelocity(400), highlightResizeVelocity(400), highlightResizeDuration(-1)
         , sectionCriteria(0), currentSectionItem(0), nextSectionItem(0)
         , overshootDist(0.0), correctFlick(false), inFlickCorrection(false)
     {}
@@ -191,7 +195,8 @@ void QQuickViewSection::setProperty(const QString &property)
     if (property != m_property) {
         m_property = property;
         emit propertyChanged();
-        m_view->updateSections();
+        // notify view that the contents of the sections must be recalculated
+        m_view->updateSectionCriteria();
     }
 }
 
@@ -200,16 +205,19 @@ void QQuickViewSection::setCriteria(QQuickViewSection::SectionCriteria criteria)
     if (criteria != m_criteria) {
         m_criteria = criteria;
         emit criteriaChanged();
-        m_view->updateSections();
+        // notify view that the contents of the sections must be recalculated
+        m_view->updateSectionCriteria();
     }
 }
 
 void QQuickViewSection::setDelegate(QQmlComponent *delegate)
 {
     if (delegate != m_delegate) {
+        if (m_delegate)
+            m_view->releaseSectionItems();
         m_delegate = delegate;
         emit delegateChanged();
-        m_view->updateSections();
+        m_view->forceLayoutPolish();
     }
 }
 
@@ -226,7 +234,7 @@ void QQuickViewSection::setLabelPositioning(int l)
     if (m_labelPositioning != l) {
         m_labelPositioning = l;
         emit labelPositioningChanged();
-        m_view->updateSections();
+        m_view->forceLayoutPolish();
     }
 }
 
@@ -237,8 +245,6 @@ class FxListItemSG : public FxViewItem
 public:
     FxListItemSG(QQuickItem *i, QQuickListView *v, bool own, bool trackGeometry) : FxViewItem(i, own, trackGeometry), view(v) {
         attached = static_cast<QQuickListViewAttached*>(qmlAttachedPropertiesObject<QQuickListView>(item));
-        if (attached)
-            static_cast<QQuickListViewAttached*>(attached)->setView(view);
         if (trackGeometry) {
             QQuickItemPrivate *itemPrivate = QQuickItemPrivate::get(item);
             itemPrivate->addItemChangeListener(QQuickItemViewPrivate::get(view), QQuickItemPrivate::Geometry);
@@ -569,18 +575,18 @@ FxViewItem *QQuickListViewPrivate::newViewItem(int modelIndex, QQuickItem *item)
     // initialise attached properties
     if (sectionCriteria) {
         QString propValue = model->stringValue(modelIndex, sectionCriteria->property());
-        listItem->attached->m_section = sectionCriteria->sectionString(propValue);
+        listItem->attached->setSection(sectionCriteria->sectionString(propValue));
         if (modelIndex > 0) {
             if (FxViewItem *item = itemBefore(modelIndex))
-                listItem->attached->m_prevSection = item->attached->section();
+                listItem->attached->setPrevSection(item->attached->section());
             else
-                listItem->attached->m_prevSection = sectionAt(modelIndex-1);
+                listItem->attached->setPrevSection(sectionAt(modelIndex-1));
         }
         if (modelIndex < model->count()-1) {
             if (FxViewItem *item = visibleItem(modelIndex+1))
-                listItem->attached->m_nextSection = static_cast<QQuickListViewAttached*>(item->attached)->section();
+                listItem->attached->setNextSection(static_cast<QQuickListViewAttached*>(item->attached)->section());
             else
-                listItem->attached->m_nextSection = sectionAt(modelIndex+1);
+                listItem->attached->setNextSection(sectionAt(modelIndex+1));
         }
     }
 
@@ -627,7 +633,7 @@ bool QQuickListViewPrivate::releaseItem(FxViewItem *item)
     return released;
 }
 
-bool QQuickListViewPrivate::addVisibleItems(qreal fillFrom, qreal fillTo, bool doBuffer)
+bool QQuickListViewPrivate::addVisibleItems(qreal fillFrom, qreal fillTo, qreal bufferFrom, qreal bufferTo, bool doBuffer)
 {
     qreal itemEnd = visiblePos;
     if (visibleItems.count()) {
@@ -639,8 +645,8 @@ bool QQuickListViewPrivate::addVisibleItems(qreal fillFrom, qreal fillTo, bool d
     bool haveValidItems = modelIndex >= 0;
     modelIndex = modelIndex < 0 ? visibleIndex : modelIndex + 1;
 
-    if (haveValidItems && (fillFrom > itemEnd+averageSize+spacing
-        || fillTo < visiblePos - averageSize - spacing)) {
+    if (haveValidItems && (bufferFrom > itemEnd+averageSize+spacing
+        || bufferTo < visiblePos - averageSize - spacing)) {
         // We've jumped more than a page.  Estimate which items are now
         // visible and fill from there.
         int count = (fillFrom - itemEnd) / (averageSize + spacing);
@@ -802,6 +808,9 @@ void QQuickListViewPrivate::layoutVisibleItems(int fromModelIndex)
         // move current item if it is not a visible item.
         if (currentIndex >= 0 && currentItem && !fixedCurrent)
             static_cast<FxListItemSG*>(currentItem)->setPosition(positionAt(currentIndex));
+
+        updateCurrentSection();
+        updateStickySections();
     }
 }
 
@@ -875,10 +884,12 @@ void QQuickListViewPrivate::createHighlight()
             const QLatin1String posProp(orient == QQuickListView::Vertical ? "y" : "x");
             highlightPosAnimator = new QSmoothedAnimation;
             highlightPosAnimator->target = QQmlProperty(item, posProp);
+            highlightPosAnimator->velocity = highlightMoveVelocity;
             highlightPosAnimator->userDuration = highlightMoveDuration;
 
             const QLatin1String sizeProp(orient == QQuickListView::Vertical ? "height" : "width");
             highlightSizeAnimator = new QSmoothedAnimation;
+            highlightSizeAnimator->velocity = highlightResizeVelocity;
             highlightSizeAnimator->userDuration = highlightResizeDuration;
             highlightSizeAnimator->target = QQmlProperty(item, sizeProp);
 
@@ -978,6 +989,24 @@ void QQuickListViewPrivate::releaseSectionItem(QQuickItem *item)
     delete item;
 }
 
+
+void QQuickListViewPrivate::releaseSectionItems()
+{
+    for (int i = 0; i < visibleItems.count(); ++i) {
+        FxListItemSG *listItem = static_cast<FxListItemSG *>(visibleItems.at(i));
+        if (listItem->section()) {
+            qreal pos = listItem->position();
+            releaseSectionItem(listItem->section());
+            listItem->setSection(0);
+            listItem->setPosition(pos);
+        }
+    }
+    for (int i = 0; i < sectionCacheSize; ++i) {
+        delete sectionCache[i];
+        sectionCache[i] = 0;
+    }
+}
+
 void QQuickListViewPrivate::updateInlineSection(FxListItemSG *listItem)
 {
     if (!sectionCriteria || !sectionCriteria->delegate())
@@ -1140,8 +1169,6 @@ void QQuickListViewPrivate::updateSections()
     }
 
     lastVisibleSection = QString();
-    updateCurrentSection();
-    updateStickySections();
 }
 
 void QQuickListViewPrivate::updateCurrentSection()
@@ -1353,8 +1380,7 @@ void QQuickListViewPrivate::itemGeometryChanged(QQuickItem *item, const QRectF &
                         listItem->setPosition(listItem->position() + diff, true);
                 }
             }
-            forceLayout = true;
-            q->polish();
+            forceLayoutPolish();
         }
     }
 }
@@ -1903,7 +1929,7 @@ QQuickListView::~QQuickListView()
     is scrolled.  This is because the view moves to maintain the
     highlight within the preferred highlight range (or visible viewport).
 
-    \sa highlight
+    \sa highlight, highlightMoveVelocity
 */
 //###Possibly rename these properties, since they are very useful even without a highlight?
 /*!
@@ -1968,8 +1994,7 @@ void QQuickListView::setSpacing(qreal spacing)
     Q_D(QQuickListView);
     if (spacing != d->spacing) {
         d->spacing = spacing;
-        d->forceLayout = true;
-        polish();
+        d->forceLayoutPolish();
         emit spacingChanged();
     }
 }
@@ -2174,10 +2199,8 @@ void QQuickListView::setOrientation(QQuickListView::Orientation orientation)
 QQuickViewSection *QQuickListView::sectionCriteria()
 {
     Q_D(QQuickListView);
-    if (!d->sectionCriteria) {
+    if (!d->sectionCriteria)
         d->sectionCriteria = new QQuickViewSection(this);
-        connect(d->sectionCriteria, SIGNAL(propertyChanged()), this, SLOT(updateSections()));
-    }
     return d->sectionCriteria;
 }
 
@@ -2192,20 +2215,42 @@ QString QQuickListView::currentSection() const
 }
 
 /*!
+    \qmlproperty real QtQuick2::ListView::highlightMoveVelocity
     \qmlproperty int QtQuick2::ListView::highlightMoveDuration
+    \qmlproperty real QtQuick2::ListView::highlightResizeVelocity
     \qmlproperty int QtQuick2::ListView::highlightResizeDuration
 
-    These properties hold the move and resize animation duration of
-    the highlight delegate.
+    These properties control the speed of the move and resize animations for the
+    highlight delegate.
 
     \l highlightFollowsCurrentItem must be true for these properties
     to have effect.
 
-    The default value for highlightMoveDuration is 150ms and the
-    default value for highlightResizeDuration is 250ms.
+    The default value for the velocity properties is 400 pixels/second.
+    The default value for the duration properties is -1, i.e. the
+    highlight will take as much time as necessary to move at the set speed.
+
+    These properties have the same characteristics as a SmoothedAnimation.
 
     \sa highlightFollowsCurrentItem
 */
+qreal QQuickListView::highlightMoveVelocity() const
+{
+    Q_D(const QQuickListView);
+    return d->highlightMoveVelocity;
+}
+
+void QQuickListView::setHighlightMoveVelocity(qreal speed)
+{
+    Q_D(QQuickListView);
+    if (d->highlightMoveVelocity != speed) {
+        d->highlightMoveVelocity = speed;
+        if (d->highlightPosAnimator)
+            d->highlightPosAnimator->velocity = d->highlightMoveVelocity;
+        emit highlightMoveVelocityChanged();
+    }
+}
+
 void QQuickListView::setHighlightMoveDuration(int duration)
 {
     Q_D(QQuickListView);
@@ -2216,6 +2261,23 @@ void QQuickListView::setHighlightMoveDuration(int duration)
     }
 }
 
+qreal QQuickListView::highlightResizeVelocity() const
+{
+    Q_D(const QQuickListView);
+    return d->highlightResizeVelocity;
+}
+
+void QQuickListView::setHighlightResizeVelocity(qreal speed)
+{
+    Q_D(QQuickListView);
+    if (d->highlightResizeVelocity != speed) {
+        d->highlightResizeVelocity = speed;
+        if (d->highlightSizeAnimator)
+            d->highlightSizeAnimator->velocity = d->highlightResizeVelocity;
+        emit highlightResizeVelocityChanged();
+    }
+}
+
 int QQuickListView::highlightResizeDuration() const
 {
     Q_D(const QQuickListView);
@@ -2739,6 +2801,15 @@ void QQuickListView::geometryChanged(const QRectF &newGeometry, const QRectF &ol
     QQuickItemView::geometryChanged(newGeometry, oldGeometry);
 }
 
+void QQuickListView::initItem(int index, QQuickItem *item)
+{
+    QQuickItemView::initItem(index, item);
+    QQuickListViewAttached *attached = static_cast<QQuickListViewAttached *>(
+            qmlAttachedPropertiesObject<QQuickListView>(item));
+    if (attached)
+        attached->setView(this);
+}
+
 
 /*!
     \qmlmethod QtQuick2::ListView::incrementCurrentIndex()
@@ -2780,19 +2851,17 @@ void QQuickListView::decrementCurrentIndex()
     }
 }
 
-void QQuickListView::updateSections()
+void QQuickListViewPrivate::updateSectionCriteria()
 {
-    Q_D(QQuickListView);
-    if (isComponentComplete() && d->model) {
+    Q_Q(QQuickListView);
+    if (q->isComponentComplete() && model) {
         QList<QByteArray> roles;
-        if (d->sectionCriteria && !d->sectionCriteria->property().isEmpty())
-            roles << d->sectionCriteria->property().toUtf8();
-        d->model->setWatchedRoles(roles);
-        d->updateSections();
-        if (d->itemCount) {
-            d->forceLayout = true;
-            polish();
-        }
+        if (sectionCriteria && !sectionCriteria->property().isEmpty())
+            roles << sectionCriteria->property().toUtf8();
+        model->setWatchedRoles(roles);
+        updateSections();
+        if (itemCount)
+            forceLayoutPolish();
     }
 }