Section headers ignore list delegate size changes when "colliding"
[profile/ivi/qtdeclarative.git] / src / quick / items / qquicklistview.cpp
index 5e9a685..80b4cb5 100644 (file)
@@ -73,6 +73,7 @@ public:
     virtual Qt::Orientation layoutOrientation() const;
     virtual bool isContentFlowReversed() const;
     bool isRightToLeft() const;
+    bool isBottomToTop() const;
 
     virtual qreal positionAt(int index) const;
     virtual qreal endPositionAt(int index) const;
@@ -87,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();
 
@@ -109,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();
@@ -131,7 +134,7 @@ public:
     void itemGeometryChanged(QQuickItem *item, const QRectF &newGeometry, const QRectF &oldGeometry);
     virtual void fixupPosition();
     virtual void fixup(AxisData &data, qreal minExtent, qreal maxExtent);
-    virtual void flick(QQuickItemViewPrivate::AxisData &data, qreal minExtent, qreal maxExtent, qreal vSize,
+    virtual bool flick(QQuickItemViewPrivate::AxisData &data, qreal minExtent, qreal maxExtent, qreal vSize,
                         QQuickTimeLineCallback::Callback fixupCallback, qreal velocity);
 
     QQuickListView::Orientation orient;
@@ -142,8 +145,8 @@ public:
 
     QSmoothedAnimation *highlightPosAnimator;
     QSmoothedAnimation *highlightSizeAnimator;
-    qreal highlightMoveSpeed;
-    qreal highlightResizeSpeed;
+    qreal highlightMoveVelocity;
+    qreal highlightResizeVelocity;
     int highlightResizeDuration;
 
     QQuickViewSection *sectionCriteria;
@@ -167,7 +170,7 @@ public:
         , averageSize(100.0), spacing(0.0)
         , snapMode(QQuickListView::NoSnap)
         , highlightPosAnimator(0), highlightSizeAnimator(0)
-        , highlightMoveSpeed(400), highlightResizeSpeed(400), highlightResizeDuration(-1)
+        , highlightMoveVelocity(400), highlightResizeVelocity(400), highlightResizeDuration(-1)
         , sectionCriteria(0), currentSectionItem(0), nextSectionItem(0)
         , overshootDist(0.0), correctFlick(false), inFlickCorrection(false)
     {}
@@ -192,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();
     }
 }
 
@@ -201,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();
     }
 }
 
@@ -227,7 +234,7 @@ void QQuickViewSection::setLabelPositioning(int l)
     if (m_labelPositioning != l) {
         m_labelPositioning = l;
         emit labelPositioningChanged();
-        m_view->updateSections();
+        m_view->forceLayoutPolish();
     }
 }
 
@@ -236,13 +243,20 @@ void QQuickViewSection::setLabelPositioning(int l)
 class FxListItemSG : public FxViewItem
 {
 public:
-    FxListItemSG(QQuickItem *i, QQuickListView *v, bool own) : FxViewItem(i, own), view(v) {
+    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);
+        }
     }
 
-    ~FxListItemSG() {}
+    ~FxListItemSG() {
+        if (trackGeom) {
+            QQuickItemPrivate *itemPrivate = QQuickItemPrivate::get(item);
+            itemPrivate->removeItemChangeListener(QQuickItemViewPrivate::get(view), QQuickItemPrivate::Geometry);
+        }
+    }
 
     inline QQuickItem *section() const {
         return attached ? static_cast<QQuickListViewAttached*>(attached)->m_sectionItem : 0;
@@ -256,7 +270,7 @@ public:
     qreal position() const {
         if (section()) {
             if (view->orientation() == QQuickListView::Vertical)
-                return section()->y();
+                return (view->verticalLayoutDirection() == QQuickItemView::BottomToTop ? -section()->height()-section()->y() : section()->y());
             else
                 return (view->effectiveLayoutDirection() == Qt::RightToLeft ? -section()->width()-section()->x() : section()->x());
         } else {
@@ -265,7 +279,7 @@ public:
     }
     qreal itemPosition() const {
         if (view->orientation() == QQuickListView::Vertical)
-            return itemY();
+            return (view->verticalLayoutDirection() == QQuickItemView::BottomToTop ? -item->height()-itemY() : itemY());
         else
             return (view->effectiveLayoutDirection() == Qt::RightToLeft ? -item->width()-itemX() : itemX());
     }
@@ -285,18 +299,23 @@ public:
     }
     qreal endPosition() const {
         if (view->orientation() == QQuickListView::Vertical) {
-            return itemY() + item->height();
+            return (view->verticalLayoutDirection() == QQuickItemView::BottomToTop
+                    ? -itemY()
+                    : itemY() + item->height());
         } else {
             return (view->effectiveLayoutDirection() == Qt::RightToLeft
                     ? -itemX()
                     : itemX() + item->width());
         }
     }
-    void setPosition(qreal pos) {
+    void setPosition(qreal pos, bool immediate = false) {
         // position the section immediately even if there is a transition
         if (section()) {
             if (view->orientation() == QQuickListView::Vertical) {
-                section()->setY(pos);
+                if (view->verticalLayoutDirection() == QQuickItemView::BottomToTop)
+                    section()->setY(-section()->height()-pos);
+                else
+                    section()->setY(pos);
             } else {
                 if (view->effectiveLayoutDirection() == Qt::RightToLeft)
                     section()->setX(-section()->width()-pos);
@@ -304,7 +323,7 @@ public:
                     section()->setX(pos);
             }
         }
-        moveTo(pointForPosition(pos));
+        moveTo(pointForPosition(pos), immediate);
     }
     void setSize(qreal size) {
         if (view->orientation() == QQuickListView::Vertical)
@@ -322,9 +341,15 @@ public:
 private:
     QPointF pointForPosition(qreal pos) const {
         if (view->orientation() == QQuickListView::Vertical) {
-            if (section())
-                pos += section()->height();
-            return QPointF(itemX(), pos);
+            if (view->verticalLayoutDirection() == QQuickItemView::BottomToTop) {
+                if (section())
+                    pos += section()->height();
+                return QPointF(itemX(), -item->height() - pos);
+            } else {
+                if (section())
+                    pos += section()->height();
+                return QPointF(itemX(), pos);
+            }
         } else {
             if (view->effectiveLayoutDirection() == Qt::RightToLeft) {
                 if (section())
@@ -343,7 +368,7 @@ private:
 
 bool QQuickListViewPrivate::isContentFlowReversed() const
 {
-    return isRightToLeft();
+    return isRightToLeft() || isBottomToTop();
 }
 
 Qt::Orientation QQuickListViewPrivate::layoutOrientation() const
@@ -357,6 +382,11 @@ bool QQuickListViewPrivate::isRightToLeft() const
     return orient == QQuickListView::Horizontal && q->effectiveLayoutDirection() == Qt::RightToLeft;
 }
 
+bool QQuickListViewPrivate::isBottomToTop() const
+{
+    return orient == QQuickListView::Vertical && verticalLayoutDirection == QQuickItemView::BottomToTop;
+}
+
 // Returns the item before modelIndex, if created.
 // May return an item marked for removal.
 FxViewItem *QQuickListViewPrivate::itemBefore(int modelIndex) const
@@ -382,7 +412,10 @@ void QQuickListViewPrivate::setPosition(qreal pos)
 {
     Q_Q(QQuickListView);
     if (orient == QQuickListView::Vertical) {
-        q->QQuickFlickable::setContentY(pos);
+        if (isBottomToTop())
+            q->QQuickFlickable::setContentY(-pos-size());
+        else
+            q->QQuickFlickable::setContentY(pos);
     } else {
         if (isRightToLeft())
             q->QQuickFlickable::setContentX(-pos-size());
@@ -524,7 +557,9 @@ void QQuickListViewPrivate::clear()
         sectionCache[i] = 0;
     }
     visiblePos = 0;
+    releaseSectionItem(currentSectionItem);
     currentSectionItem = 0;
+    releaseSectionItem(nextSectionItem);
     nextSectionItem = 0;
     lastVisibleSection = QString();
     QQuickItemViewPrivate::clear();
@@ -534,24 +569,24 @@ FxViewItem *QQuickListViewPrivate::newViewItem(int modelIndex, QQuickItem *item)
 {
     Q_Q(QQuickListView);
 
-    FxListItemSG *listItem = new FxListItemSG(item, q, false);
+    FxListItemSG *listItem = new FxListItemSG(item, q, false, false);
     listItem->index = modelIndex;
 
     // 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));
         }
     }
 
@@ -566,7 +601,7 @@ void QQuickListViewPrivate::initializeViewItem(FxViewItem *item)
     itemPrivate->addItemChangeListener(this, QQuickItemPrivate::Geometry);
 
     if (sectionCriteria && sectionCriteria->delegate()) {
-        if (item->attached->m_prevSection != item->attached->m_section)
+        if (QString::compare(item->attached->m_prevSection, item->attached->m_section, Qt::CaseInsensitive))
             updateInlineSection(static_cast<FxListItemSG*>(item));
     }
 }
@@ -598,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()) {
@@ -610,25 +645,22 @@ 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);
-        for (int i = 0; i < visibleItems.count(); ++i)
-            releaseItem(visibleItems.at(i));
-        visibleItems.clear();
-        modelIndex += count;
-        if (modelIndex >= model->count()) {
-            count -= modelIndex - model->count() + 1;
-            modelIndex = model->count() - 1;
-        } else if (modelIndex < 0) {
-            count -= modelIndex;
-            modelIndex = 0;
-        }
-        visibleIndex = modelIndex;
-        visiblePos = itemEnd + count * (averageSize + spacing);
-        itemEnd = visiblePos;
+        int newModelIdx = qBound(0, modelIndex + count, model->count());
+        count = newModelIdx - modelIndex;
+        if (count) {
+            for (int i = 0; i < visibleItems.count(); ++i)
+                releaseItem(visibleItems.at(i));
+            visibleItems.clear();
+            modelIndex = newModelIdx;
+            visibleIndex = modelIndex;
+            visiblePos = itemEnd + count * (averageSize + spacing);
+            itemEnd = visiblePos;
+        }
     }
 
     bool changed = false;
@@ -636,13 +668,13 @@ bool QQuickListViewPrivate::addVisibleItems(qreal fillFrom, qreal fillTo, bool d
     qreal pos = itemEnd;
     while (modelIndex < model->count() && pos <= fillTo) {
 #ifdef DEBUG_DELEGATE_LIFECYCLE
-        qDebug() << "refill: append item" << modelIndex << "pos" << pos;
+        qDebug() << "refill: append item" << modelIndex << "pos" << pos << "buffer" << doBuffer;
 #endif
         if (!(item = static_cast<FxListItemSG*>(createItem(modelIndex, doBuffer))))
             break;
         if (!transitioner || !transitioner->canTransition(QQuickItemViewTransitioner::PopulateTransition, true)) // pos will be set by layoutVisibleItems()
-            item->setPosition(pos);
-        item->item->setVisible(!doBuffer);
+            item->setPosition(pos, true);
+        QQuickItemPrivate::get(item->item)->setCulled(doBuffer);
         pos += item->size() + spacing;
         visibleItems.append(item);
         ++modelIndex;
@@ -654,15 +686,15 @@ bool QQuickListViewPrivate::addVisibleItems(qreal fillFrom, qreal fillTo, bool d
 
     while (visibleIndex > 0 && visibleIndex <= model->count() && visiblePos > fillFrom) {
 #ifdef DEBUG_DELEGATE_LIFECYCLE
-        qDebug() << "refill: prepend item" << visibleIndex-1 << "current top pos" << visiblePos;
+        qDebug() << "refill: prepend item" << visibleIndex-1 << "current top pos" << visiblePos << "buffer" << doBuffer;
 #endif
         if (!(item = static_cast<FxListItemSG*>(createItem(visibleIndex-1, doBuffer))))
             break;
         --visibleIndex;
         visiblePos -= item->size() + spacing;
         if (!transitioner || !transitioner->canTransition(QQuickItemViewTransitioner::PopulateTransition, true)) // pos will be set by layoutVisibleItems()
-            item->setPosition(visiblePos);
-        item->item->setVisible(!doBuffer);
+            item->setPosition(visiblePos, true);
+        QQuickItemPrivate::get(item->item)->setCulled(doBuffer);
         visibleItems.prepend(item);
         changed = true;
     }
@@ -759,7 +791,7 @@ void QQuickListViewPrivate::layoutVisibleItems(int fromModelIndex)
         bool fixedCurrent = currentItem && firstItem->item == currentItem->item;
         qreal sum = firstItem->size();
         qreal pos = firstItem->position() + firstItem->size() + spacing;
-        firstItem->item->setVisible(firstItem->endPosition() >= from && firstItem->position() <= to);
+        firstItem->setVisible(firstItem->endPosition() >= from && firstItem->position() <= to);
 
         for (int i=1; i < visibleItems.count(); ++i) {
             FxListItemSG *item = static_cast<FxListItemSG*>(visibleItems.at(i));
@@ -776,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();
     }
 }
 
@@ -789,8 +824,12 @@ void QQuickListViewPrivate::repositionPackageItemAt(QQuickItem *item, int index)
     Q_Q(QQuickListView);
     qreal pos = position();
     if (orient == QQuickListView::Vertical) {
-        if (item->y() + item->height() > pos && item->y() < pos + q->height())
-            item->setY(positionAt(index));
+        if (item->y() + item->height() > pos && item->y() < pos + q->height()) {
+            if (isBottomToTop())
+                item->setY(-positionAt(index)-item->height());
+            else
+                item->setY(positionAt(index));
+        }
     } else {
         if (item->x() + item->width() > pos && item->x() < pos + q->width()) {
             if (isRightToLeft())
@@ -836,7 +875,7 @@ void QQuickListViewPrivate::createHighlight()
     if (currentItem) {
         QQuickItem *item = createHighlightItem();
         if (item) {
-            FxListItemSG *newHighlight = new FxListItemSG(item, q, true);
+            FxListItemSG *newHighlight = new FxListItemSG(item, q, true, true);
 
             if (autoHighlight) {
                 newHighlight->setSize(static_cast<FxListItemSG*>(currentItem)->itemSize());
@@ -845,12 +884,12 @@ void QQuickListViewPrivate::createHighlight()
             const QLatin1String posProp(orient == QQuickListView::Vertical ? "y" : "x");
             highlightPosAnimator = new QSmoothedAnimation;
             highlightPosAnimator->target = QQmlProperty(item, posProp);
-            highlightPosAnimator->velocity = highlightMoveSpeed;
+            highlightPosAnimator->velocity = highlightMoveVelocity;
             highlightPosAnimator->userDuration = highlightMoveDuration;
 
             const QLatin1String sizeProp(orient == QQuickListView::Vertical ? "height" : "width");
             highlightSizeAnimator = new QSmoothedAnimation;
-            highlightSizeAnimator->velocity = highlightResizeSpeed;
+            highlightSizeAnimator->velocity = highlightResizeVelocity;
             highlightSizeAnimator->userDuration = highlightResizeDuration;
             highlightSizeAnimator->target = QQmlProperty(item, sizeProp);
 
@@ -872,7 +911,7 @@ void QQuickListViewPrivate::updateHighlight()
     if (currentItem && autoHighlight && highlight && (!strictHighlight || !pressed)) {
         // auto-update highlight
         FxListItemSG *listItem = static_cast<FxListItemSG*>(currentItem);
-        highlightPosAnimator->to = isRightToLeft()
+        highlightPosAnimator->to = isContentFlowReversed()
                 ? -listItem->itemPosition()-listItem->itemSize()
                 : listItem->itemPosition();
         highlightSizeAnimator->to = listItem->itemSize();
@@ -936,6 +975,8 @@ QQuickItem * QQuickListViewPrivate::getSectionItem(const QString &section)
 
 void QQuickListViewPrivate::releaseSectionItem(QQuickItem *item)
 {
+    if (!item)
+        return;
     int i = 0;
     do {
         if (!sectionCache[i]) {
@@ -948,11 +989,29 @@ 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())
         return;
-    if (listItem->attached->m_prevSection != listItem->attached->m_section
+    if (QString::compare(listItem->attached->m_prevSection, listItem->attached->m_section, Qt::CaseInsensitive)
             && (sectionCriteria->labelPositioning() & QQuickViewSection::InlineLabels
                 || (listItem->index == 0 && sectionCriteria->labelPositioning() & QQuickViewSection::CurrentLabelAtStart))) {
         if (!listItem->section()) {
@@ -973,12 +1032,12 @@ void QQuickListViewPrivate::updateInlineSection(FxListItemSG *listItem)
 
 void QQuickListViewPrivate::updateStickySections()
 {
-    if (!sectionCriteria || visibleItems.isEmpty()
+    if (!sectionCriteria
             || (!sectionCriteria->labelPositioning() && !currentSectionItem && !nextSectionItem))
         return;
 
-    bool isRtl = isRightToLeft();
-    qreal viewPos = isRightToLeft() ? -position()-size() : position();
+    bool isFlowReversed = isContentFlowReversed();
+    qreal viewPos = isFlowReversed ? -position()-size() : position();
     QQuickItem *sectionItem = 0;
     QQuickItem *lastSectionItem = 0;
     int index = 0;
@@ -990,14 +1049,14 @@ void QQuickListViewPrivate::updateStickySections()
             qreal sectionSize = orient == QQuickListView::Vertical ? section->height() : section->width();
             bool visTop = true;
             if (sectionCriteria->labelPositioning() & QQuickViewSection::CurrentLabelAtStart)
-                visTop = isRtl ? -sectionPos-sectionSize >= viewPos : sectionPos >= viewPos;
+                visTop = isFlowReversed ? -sectionPos-sectionSize >= viewPos : sectionPos >= viewPos;
             bool visBot = true;
             if (sectionCriteria->labelPositioning() & QQuickViewSection::NextLabelAtEnd)
-                visBot = isRtl ? -sectionPos <= viewPos + size() : sectionPos + sectionSize < viewPos + size();
+                visBot = isFlowReversed ? -sectionPos <= viewPos + size() : sectionPos + sectionSize < viewPos + size();
             section->setVisible(visBot && visTop);
             if (visTop && !sectionItem)
                 sectionItem = section;
-            if (isRtl) {
+            if (isFlowReversed) {
                if (-sectionPos <= viewPos + size())
                     lastSectionItem = section;
             } else {
@@ -1009,10 +1068,10 @@ void QQuickListViewPrivate::updateStickySections()
     }
 
     // Current section header
-    if (sectionCriteria->labelPositioning() & QQuickViewSection::CurrentLabelAtStart) {
+    if (sectionCriteria->labelPositioning() & QQuickViewSection::CurrentLabelAtStart && isValid() && visibleItems.count()) {
         if (!currentSectionItem) {
             currentSectionItem = getSectionItem(currentSection);
-        } else if (currentStickySection != currentSection) {
+        } else if (QString::compare(currentStickySection, currentSection, Qt::CaseInsensitive)) {
             QQmlContext *context = QQmlEngine::contextForObject(currentSectionItem)->parentContext();
             context->setContextProperty(QLatin1String("section"), currentSection);
         }
@@ -1021,17 +1080,18 @@ void QQuickListViewPrivate::updateStickySections()
             return;
 
         qreal sectionSize = orient == QQuickListView::Vertical ? currentSectionItem->height() : currentSectionItem->width();
-        bool atBeginning = orient == QQuickListView::Vertical ? vData.atBeginning : (isRightToLeft() ? hData.atEnd : hData.atBeginning);
+        bool atBeginning = orient == QQuickListView::Vertical ? (isBottomToTop() ? vData.atEnd : vData.atBeginning) : (isRightToLeft() ? hData.atEnd : hData.atBeginning);
+
         currentSectionItem->setVisible(!atBeginning && (!header || header->endPosition() < viewPos));
-        qreal pos = isRtl ? position() + size() - sectionSize : viewPos;
+        qreal pos = isFlowReversed ? position() + size() - sectionSize : viewPos;
         if (sectionItem) {
             qreal sectionPos = orient == QQuickListView::Vertical ? sectionItem->y() : sectionItem->x();
-            pos = isRtl ? qMax(pos, sectionPos + sectionSize) : qMin(pos, sectionPos - sectionSize);
+            pos = isFlowReversed ? qMax(pos, sectionPos + sectionSize) : qMin(pos, sectionPos - sectionSize);
         }
         if (header)
-            pos = isRtl ? qMin(header->endPosition(), pos) : qMax(header->endPosition(), pos);
+            pos = isFlowReversed ? qMin(header->endPosition(), pos) : qMax(header->endPosition(), pos);
         if (footer)
-            pos = isRtl ? qMax(-footer->position(), pos) : qMin(footer->position() - sectionSize, pos);
+            pos = isFlowReversed ? qMax(-footer->position(), pos) : qMin(footer->position() - sectionSize, pos);
         if (orient == QQuickListView::Vertical)
             currentSectionItem->setY(pos);
         else
@@ -1042,10 +1102,10 @@ void QQuickListViewPrivate::updateStickySections()
     }
 
     // Next section footer
-    if (sectionCriteria->labelPositioning() & QQuickViewSection::NextLabelAtEnd) {
+    if (sectionCriteria->labelPositioning() & QQuickViewSection::NextLabelAtEnd && isValid() && visibleItems.count()) {
         if (!nextSectionItem) {
             nextSectionItem = getSectionItem(nextSection);
-        } else if (nextStickySection != nextSection) {
+        } else if (QString::compare(nextStickySection, nextSection, Qt::CaseInsensitive)) {
             QQmlContext *context = QQmlEngine::contextForObject(nextSectionItem)->parentContext();
             context->setContextProperty(QLatin1String("section"), nextSection);
         }
@@ -1055,13 +1115,13 @@ void QQuickListViewPrivate::updateStickySections()
 
         qreal sectionSize = orient == QQuickListView::Vertical ? nextSectionItem->height() : nextSectionItem->width();
         nextSectionItem->setVisible(!nextSection.isEmpty());
-        qreal pos = isRtl ? position() : viewPos + size() - sectionSize;
+        qreal pos = isFlowReversed ? position() : viewPos + size() - sectionSize;
         if (lastSectionItem) {
             qreal sectionPos = orient == QQuickListView::Vertical ? lastSectionItem->y() : lastSectionItem->x();
-            pos = isRtl ? qMin(pos, sectionPos - sectionSize) : qMax(pos, sectionPos + sectionSize);
+            pos = isFlowReversed ? qMin(pos, sectionPos - sectionSize) : qMax(pos, sectionPos + sectionSize);
         }
         if (header)
-            pos = isRtl ? qMin(header->endPosition() - sectionSize, pos) : qMax(header->endPosition(), pos);
+            pos = isFlowReversed ? qMin(header->endPosition() - sectionSize, pos) : qMax(header->endPosition(), pos);
         if (orient == QQuickListView::Vertical)
             nextSectionItem->setY(pos);
         else
@@ -1080,7 +1140,7 @@ void QQuickListViewPrivate::updateSections()
 
     QQuickItemViewPrivate::updateSections();
 
-    if (sectionCriteria && !visibleItems.isEmpty()) {
+    if (sectionCriteria && !visibleItems.isEmpty() && isValid()) {
         QString prevSection;
         if (visibleIndex > 0)
             prevSection = sectionAt(visibleIndex-1);
@@ -1109,8 +1169,6 @@ void QQuickListViewPrivate::updateSections()
     }
 
     lastVisibleSection = QString();
-    updateCurrentSection();
-    updateStickySections();
 }
 
 void QQuickListViewPrivate::updateCurrentSection()
@@ -1152,7 +1210,7 @@ void QQuickListViewPrivate::updateCurrentSection()
         // section when that changes.  Clearing lastVisibleSection will also
         // force searching.
         QString lastSection = currentSection;
-        qreal endPos = isRightToLeft() ? -position() : position() + size();
+        qreal endPos = isContentFlowReversed() ? -position() : position() + size();
         if (nextSectionItem && !inlineSections)
             endPos -= orient == QQuickListView::Vertical ? nextSectionItem->height() : nextSectionItem->width();
         while (index < visibleItems.count() && static_cast<FxListItemSG*>(visibleItems.at(index))->itemPosition() < endPos) {
@@ -1237,11 +1295,10 @@ void QQuickListViewPrivate::updateFooter()
     Q_Q(QQuickListView);
     bool created = false;
     if (!footer) {
-        QQuickItem *item = createComponentItem(footerComponent, true);
+        QQuickItem *item = createComponentItem(footerComponent, 1.0);
         if (!item)
             return;
-        item->setZ(1);
-        footer = new FxListItemSG(item, q, true);
+        footer = new FxListItemSG(item, q, true, true);
         created = true;
     }
 
@@ -1268,11 +1325,10 @@ void QQuickListViewPrivate::updateHeader()
     Q_Q(QQuickListView);
     bool created = false;
     if (!header) {
-        QQuickItem *item = createComponentItem(headerComponent, true);
+        QQuickItem *item = createComponentItem(headerComponent, 1.0);
         if (!item)
             return;
-        item->setZ(1);
-        header = new FxListItemSG(item, q, true);
+        header = new FxListItemSG(item, q, true, true);
         created = true;
     }
 
@@ -1301,11 +1357,30 @@ void QQuickListViewPrivate::itemGeometryChanged(QQuickItem *item, const QRectF &
     QQuickItemViewPrivate::itemGeometryChanged(item, newGeometry, oldGeometry);
     if (!q->isComponentComplete())
         return;
+
     if (item != contentItem && (!highlight || item != highlight->item)) {
         if ((orient == QQuickListView::Vertical && newGeometry.height() != oldGeometry.height())
             || (orient == QQuickListView::Horizontal && newGeometry.width() != oldGeometry.width())) {
-            forceLayout = true;
-            q->polish();
+
+            // if visibleItems.first() has resized, adjust its pos since it is used to
+            // position all subsequent items
+            if (visibleItems.count() && item == visibleItems.first()->item) {
+                FxListItemSG *listItem = static_cast<FxListItemSG*>(visibleItems.first());
+                if (orient == QQuickListView::Vertical) {
+                    qreal diff = newGeometry.height() - oldGeometry.height();
+                    if (verticalLayoutDirection == QQuickListView::TopToBottom && listItem->endPosition() < q->contentY())
+                        listItem->setPosition(listItem->position() - diff, true);
+                    else if (verticalLayoutDirection == QQuickListView::BottomToTop && listItem->endPosition() > q->contentY())
+                        listItem->setPosition(listItem->position() + diff, true);
+                } else {
+                    qreal diff = newGeometry.width() - oldGeometry.width();
+                    if (q->effectiveLayoutDirection() == Qt::LeftToRight && listItem->endPosition() < q->contentX())
+                        listItem->setPosition(listItem->position() - diff, true);
+                    else if (q->effectiveLayoutDirection() == Qt::RightToLeft && listItem->endPosition() > q->contentX())
+                        listItem->setPosition(listItem->position() + diff, true);
+                }
+            }
+            forceLayoutPolish();
         }
     }
 }
@@ -1331,10 +1406,10 @@ void QQuickListViewPrivate::fixup(AxisData &data, qreal minExtent, qreal maxExte
     fixupMode = moveReason == Mouse ? fixupMode : Immediate;
     bool strictHighlightRange = haveHighlightRange && highlightRange == QQuickListView::StrictlyEnforceRange;
 
-    qreal viewPos = isRightToLeft() ? -position()-size() : position();
+    qreal viewPos = isContentFlowReversed() ? -position()-size() : position();
 
     if (snapMode != QQuickListView::NoSnap && moveReason != QQuickListViewPrivate::SetIndex) {
-        qreal tempPosition = isRightToLeft() ? -position()-size() : position();
+        qreal tempPosition = isContentFlowReversed() ? -position()-size() : position();
         if (snapMode == QQuickListView::SnapOneItem && moveReason == Mouse) {
             // if we've been dragged < averageSize/2 then bias towards the next item
             qreal dist = data.move.value() - (data.pressPos - data.dragStartOffset);
@@ -1343,7 +1418,7 @@ void QQuickListViewPrivate::fixup(AxisData &data, qreal minExtent, qreal maxExte
                 bias = averageSize/2;
             else if (data.velocity < 0 && dist < -QML_FLICK_SNAPONETHRESHOLD && dist > -averageSize/2)
                 bias = -averageSize/2;
-            if (isRightToLeft())
+            if (isContentFlowReversed())
                 bias = -bias;
             tempPosition -= bias;
         }
@@ -1363,15 +1438,15 @@ void QQuickListViewPrivate::fixup(AxisData &data, qreal minExtent, qreal maxExte
         bool isInBounds = -position() > maxExtent && -position() <= minExtent;
         if (topItem && (isInBounds || strictHighlightRange)) {
             if (topItem->index == 0 && header && tempPosition+highlightRangeStart < header->position()+header->size()/2 && !strictHighlightRange) {
-                pos = isRightToLeft() ? - header->position() + highlightRangeStart - size() : header->position() - highlightRangeStart;
+                pos = isContentFlowReversed() ? - header->position() + highlightRangeStart - size() : header->position() - highlightRangeStart;
             } else {
-                if (isRightToLeft())
+                if (isContentFlowReversed())
                     pos = qMax(qMin(-topItem->position() + highlightRangeStart - size(), -maxExtent), -minExtent);
                 else
                     pos = qMax(qMin(topItem->position() - highlightRangeStart, -maxExtent), -minExtent);
             }
         } else if (bottomItem && isInBounds) {
-            if (isRightToLeft())
+            if (isContentFlowReversed())
                 pos = qMax(qMin(-bottomItem->position() + highlightRangeEnd - size(), -maxExtent), -minExtent);
             else
                 pos = qMax(qMin(bottomItem->position() - highlightRangeEnd, -maxExtent), -minExtent);
@@ -1398,7 +1473,7 @@ void QQuickListViewPrivate::fixup(AxisData &data, qreal minExtent, qreal maxExte
             viewPos = pos + static_cast<FxListItemSG*>(currentItem)->itemSize() - highlightRangeEnd;
         if (viewPos > pos - highlightRangeStart)
             viewPos = pos - highlightRangeStart;
-        if (isRightToLeft())
+        if (isContentFlowReversed())
             viewPos = -viewPos-size();
 
         timeline.reset(data.move);
@@ -1418,20 +1493,17 @@ void QQuickListViewPrivate::fixup(AxisData &data, qreal minExtent, qreal maxExte
     fixupMode = Normal;
 }
 
-void QQuickListViewPrivate::flick(AxisData &data, qreal minExtent, qreal maxExtent, qreal vSize,
+bool QQuickListViewPrivate::flick(AxisData &data, qreal minExtent, qreal maxExtent, qreal vSize,
                                         QQuickTimeLineCallback::Callback fixupCallback, qreal velocity)
 {
-    Q_Q(QQuickListView);
-
     data.fixingUp = false;
     moveReason = Mouse;
     if ((!haveHighlightRange || highlightRange != QQuickListView::StrictlyEnforceRange) && snapMode == QQuickListView::NoSnap) {
         correctFlick = true;
-        QQuickItemViewPrivate::flick(data, minExtent, maxExtent, vSize, fixupCallback, velocity);
-        return;
+        return QQuickItemViewPrivate::flick(data, minExtent, maxExtent, vSize, fixupCallback, velocity);
     }
     qreal maxDistance = 0;
-    qreal dataValue = isRightToLeft() ? -data.move.value()+size() : data.move.value();
+    qreal dataValue = isContentFlowReversed() ? -data.move.value()+size() : data.move.value();
 
     // -ve velocity means list is moving up/left
     if (velocity > 0) {
@@ -1440,7 +1512,7 @@ void QQuickListViewPrivate::flick(AxisData &data, qreal minExtent, qreal maxExte
                 // if we've been dragged < averageSize/2 then bias towards the next item
                 qreal dist = data.move.value() - (data.pressPos - data.dragStartOffset);
                 qreal bias = dist < averageSize/2 ? averageSize/2 : 0;
-                if (isRightToLeft())
+                if (isContentFlowReversed())
                     bias = -bias;
                 data.flickTarget = -snapPosAt(-(dataValue - highlightRangeStart) - bias) + highlightRangeStart;
                 maxDistance = qAbs(data.flickTarget - data.move.value());
@@ -1457,7 +1529,7 @@ void QQuickListViewPrivate::flick(AxisData &data, qreal minExtent, qreal maxExte
                 // if we've been dragged < averageSize/2 then bias towards the next item
                 qreal dist = data.move.value() - (data.pressPos - data.dragStartOffset);
                 qreal bias = -dist < averageSize/2 ? averageSize/2 : 0;
-                if (isRightToLeft())
+                if (isContentFlowReversed())
                     bias = -bias;
                 data.flickTarget = -snapPosAt(-(dataValue - highlightRangeStart) + bias) + highlightRangeStart;
                 maxDistance = qAbs(data.flickTarget - data.move.value());
@@ -1495,10 +1567,10 @@ void QQuickListViewPrivate::flick(AxisData &data, qreal minExtent, qreal maxExte
                 dist = -dist;
             if ((maxDistance > 0.0 && v2 / (2.0f * maxDistance) < accel) || snapMode == QQuickListView::SnapOneItem) {
                 if (snapMode != QQuickListView::SnapOneItem) {
-                    qreal distTemp = isRightToLeft() ? -dist : dist;
+                    qreal distTemp = isContentFlowReversed() ? -dist : dist;
                     data.flickTarget = -snapPosAt(-(dataValue - highlightRangeStart) + distTemp) + highlightRangeStart;
                 }
-                data.flickTarget = isRightToLeft() ? -data.flickTarget+size() : data.flickTarget;
+                data.flickTarget = isContentFlowReversed() ? -data.flickTarget+size() : data.flickTarget;
                 if (overShoot) {
                     if (data.flickTarget >= minExtent) {
                         overshootDist = overShootDistance(vSize);
@@ -1534,26 +1606,15 @@ void QQuickListViewPrivate::flick(AxisData &data, qreal minExtent, qreal maxExte
             timeline.reset(data.move);
             timeline.accel(data.move, v, accel, maxDistance + overshootDist);
             timeline.callback(QQuickTimeLineCallback(&data.move, fixupCallback, this));
-            if (!hData.flicking && q->xflick()) {
-                hData.flicking = true;
-                emit q->flickingChanged();
-                emit q->flickingHorizontallyChanged();
-                emit q->flickStarted();
-            }
-            if (!vData.flicking && q->yflick()) {
-                vData.flicking = true;
-                emit q->flickingChanged();
-                emit q->flickingVerticallyChanged();
-                emit q->flickStarted();
-            }
             correctFlick = true;
+            return true;
         } else {
             // reevaluate the target boundary.
             qreal newtarget = data.flickTarget;
             if (snapMode != QQuickListView::NoSnap || highlightRange == QQuickListView::StrictlyEnforceRange) {
-                qreal tempFlickTarget = isRightToLeft() ? -data.flickTarget+size() : data.flickTarget;
+                qreal tempFlickTarget = isContentFlowReversed() ? -data.flickTarget+size() : data.flickTarget;
                 newtarget = -snapPosAt(-(tempFlickTarget - highlightRangeStart)) + highlightRangeStart;
-                newtarget = isRightToLeft() ? -newtarget+size() : newtarget;
+                newtarget = isContentFlowReversed() ? -newtarget+size() : newtarget;
             }
             if (velocity < 0 && newtarget <= maxExtent)
                 newtarget = maxExtent - overshootDist;
@@ -1562,7 +1623,7 @@ void QQuickListViewPrivate::flick(AxisData &data, qreal minExtent, qreal maxExte
             if (newtarget == data.flickTarget) { // boundary unchanged - nothing to do
                 if (qAbs(velocity) < MinimumFlickVelocity)
                     correctFlick = false;
-                return;
+                return false;
             }
             data.flickTarget = newtarget;
             qreal dist = -newtarget + data.move.value();
@@ -1570,16 +1631,18 @@ void QQuickListViewPrivate::flick(AxisData &data, qreal minExtent, qreal maxExte
                 correctFlick = false;
                 timeline.reset(data.move);
                 fixup(data, minExtent, maxExtent);
-                return;
+                return false;
             }
             timeline.reset(data.move);
             timeline.accelDistance(data.move, v, -dist);
             timeline.callback(QQuickTimeLineCallback(&data.move, fixupCallback, this));
+            return false;
         }
     } else {
         correctFlick = false;
         timeline.reset(data.move);
         fixup(data, minExtent, maxExtent);
+        return false;
     }
 }
 
@@ -1588,9 +1651,9 @@ void QQuickListViewPrivate::flick(AxisData &data, qreal minExtent, qreal maxExte
 /*!
     \qmlclass ListView QQuickListView
     \inqmlmodule QtQuick 2
-    \ingroup qml-view-elements
+    \ingroup qtquick-views
     \inherits Flickable
-    \brief The ListView item provides a list view of items provided by a model.
+    \brief Provides a list view of items provided by a model
 
     A ListView displays data from models created from built-in QML elements like ListModel
     and XmlListModel, or custom model classes defined in C++ that inherit from
@@ -1606,13 +1669,13 @@ void QQuickListViewPrivate::flick(AxisData &data, qreal minExtent, qreal maxExte
     The following example shows the definition of a simple list model defined
     in a file called \c ContactModel.qml:
 
-    \snippet doc/src/snippets/qml/listview/ContactModel.qml 0
+    \snippet qml/listview/ContactModel.qml 0
 
     Another component can display this model data in a ListView, like this:
 
-    \snippet doc/src/snippets/qml/listview/listview.qml import
+    \snippet qml/listview/listview.qml import
     \codeline
-    \snippet doc/src/snippets/qml/listview/listview.qml classdocs simple
+    \snippet qml/listview/listview.qml classdocs simple
 
     \image listview-simple.png
 
@@ -1623,7 +1686,7 @@ void QQuickListViewPrivate::flick(AxisData &data, qreal minExtent, qreal maxExte
     An improved list view is shown below. The delegate is visually improved and is moved
     into a separate \c contactDelegate component.
 
-    \snippet doc/src/snippets/qml/listview/listview.qml classdocs advanced
+    \snippet qml/listview/listview.qml classdocs advanced
     \image listview-highlight.png
 
     The currently selected item is highlighted with a blue \l Rectangle using the \l highlight property,
@@ -1638,14 +1701,53 @@ void QQuickListViewPrivate::flick(AxisData &data, qreal minExtent, qreal maxExte
     this attached property directly as \c ListView.isCurrentItem, while the child
     \c contactInfo object must refer to this property as \c wrapper.ListView.isCurrentItem.
 
-    \snippet doc/src/snippets/qml/listview/listview.qml isCurrentItem
+    \snippet qml/listview/listview.qml isCurrentItem
 
     \note Views do not enable \e clip automatically.  If the view
     is not clipped by another item or the screen, it will be necessary
     to set \e {clip: true} in order to have the out of view items clipped
     nicely.
 
-    \sa {QML Data Models}, GridView, {declarative/modelviews/listview}{ListView examples}
+
+    \section1 ListView layouts
+
+    The layout of the items in a ListView can be controlled by these properties:
+
+    \list
+    \li \l orientation - controls whether items flow horizontally or vertically.
+        This value can be either Qt.Horizontal or Qt.Vertical.
+    \li \l layoutDirection - controls the horizontal layout direction for a
+        horizontally-oriented view: that is, whether items are laid out from the left side of
+        the view to the right, or vice-versa. This value can be either Qt.LeftToRight or Qt.RightToLeft.
+    \li \l verticalLayoutDirection - controls the vertical layout direction for a vertically-oriented
+        view: that is, whether items are laid out from the top of the view down towards the bottom of
+        the view, or vice-versa. This value can be either ListView.TopToBottom or ListView.BottomToTop.
+    \endlist
+
+    By default, a ListView has a vertical orientation, and items are laid out from top to bottom. The
+    table below shows the different layouts that a ListView can have, depending on the values of
+    the properties listed above.
+
+    \table
+    \header
+        \li {2, 1}
+            \bold ListViews with Qt.Vertical orientation
+    \row
+        \li Top to bottom
+            \image listview-layout-toptobottom.png
+        \li Bottom to top
+            \image listview-layout-bottomtotop.png
+    \header
+        \li {2, 1}
+            \bold ListViews with Qt.Horizontal orientation
+    \row
+        \li Left to right
+            \image listview-layout-lefttoright.png
+        \li Right to left
+            \image listview-layout-righttoleft.png
+    \endtable
+
+    \sa {QML Data Models}, GridView, {quick/modelviews/listview}{ListView examples}
 */
 QQuickListView::QQuickListView(QQuickItem *parent)
     : QQuickItemView(*(new QQuickListViewPrivate), parent)
@@ -1664,7 +1766,7 @@ QQuickListView::~QQuickListView()
 
     This property may be used to adjust the appearance of the current item, for example:
 
-    \snippet doc/src/snippets/qml/listview/listview.qml isCurrentItem
+    \snippet qml/listview/listview.qml isCurrentItem
 */
 
 /*!
@@ -1711,7 +1813,7 @@ QQuickListView::~QQuickListView()
     until an animation completes. The example delegate below ensures that the
     animation completes before the item is removed from the list.
 
-    \snippet doc/src/snippets/qml/listview/listview.qml delayRemove
+    \snippet qml/listview/listview.qml delayRemove
 
     If a \l remove transition has been specified, it will not be applied until
     delayRemove is returned to \c false.
@@ -1807,7 +1909,7 @@ QQuickListView::~QQuickListView()
     so as to stay with the current item, unless the highlightFollowsCurrentItem
     property is false.
 
-    \sa highlightItem, highlightFollowsCurrentItem, {declarative/modelviews/listview}{ListView examples}
+    \sa highlightItem, highlightFollowsCurrentItem, {quick/modelviews/listview}{ListView examples}
 */
 
 /*!
@@ -1821,13 +1923,13 @@ QQuickListView::~QQuickListView()
 
     Here is a highlight with its motion defined by a \l {SpringAnimation} item:
 
-    \snippet doc/src/snippets/qml/listview/listview.qml highlightFollowsCurrentItem
+    \snippet qml/listview/listview.qml highlightFollowsCurrentItem
 
     Note that the highlight animation also affects the way that the view
     is scrolled.  This is because the view moves to maintain the
     highlight within the preferred highlight range (or visible viewport).
 
-    \sa highlight, highlightMoveSpeed
+    \sa highlight, highlightMoveVelocity
 */
 //###Possibly rename these properties, since they are very useful even without a highlight?
 /*!
@@ -1851,13 +1953,13 @@ QQuickListView::~QQuickListView()
     Valid values for \c highlightRangeMode are:
 
     \list
-    \o ListView.ApplyRange - the view attempts to maintain the highlight within the range.
+    \li ListView.ApplyRange - the view attempts to maintain the highlight within the range.
        However, the highlight can move outside of the range at the ends of the list or due
        to mouse interaction.
-    \o ListView.StrictlyEnforceRange - the highlight never moves outside of the range.
+    \li ListView.StrictlyEnforceRange - the highlight never moves outside of the range.
        The current item changes if a keyboard or mouse action would cause the highlight to move
        outside of the range.
-    \o ListView.NoHighlightRange - this is the default value.
+    \li ListView.NoHighlightRange - this is the default value.
     \endlist
 */
 void QQuickListView::setHighlightFollowsCurrentItem(bool autoHighlight)
@@ -1892,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();
     }
 }
@@ -1905,17 +2006,17 @@ void QQuickListView::setSpacing(qreal spacing)
     Possible values:
 
     \list
-    \o ListView.Horizontal - Items are laid out horizontally
-    \o ListView.Vertical (default) - Items are laid out vertically
+    \li ListView.Horizontal - Items are laid out horizontally
+    \li ListView.Vertical (default) - Items are laid out vertically
     \endlist
 
     \table
     \row
-    \o Horizontal orientation:
+    \li Horizontal orientation:
     \image ListViewHorizontal.png
 
     \row
-    \o Vertical orientation:
+    \li Vertical orientation:
     \image listview-highlight.png
     \endtable
 */
@@ -1946,22 +2047,24 @@ void QQuickListView::setOrientation(QQuickListView::Orientation orientation)
 
 /*!
   \qmlproperty enumeration QtQuick2::ListView::layoutDirection
-  This property holds the layout direction of the horizontal list.
+  This property holds the layout direction of a horizontally-oriented list.
 
   Possible values:
 
   \list
-  \o Qt.LeftToRight (default) - Items will be laid out from left to right.
-  \o Qt.RightToLeft - Items will be laid out from right to let.
+  \li Qt.LeftToRight (default) - Items will be laid out from left to right.
+  \li Qt.RightToLeft - Items will be laid out from right to let.
   \endlist
 
-  \sa ListView::effectiveLayoutDirection
+  Setting this property has no effect if the \l orientation is Qt.Vertical.
+
+  \sa ListView::effectiveLayoutDirection, ListView::verticalLayoutDirection
 */
 
 
 /*!
     \qmlproperty enumeration QtQuick2::ListView::effectiveLayoutDirection
-    This property holds the effective layout direction of the horizontal list.
+    This property holds the effective layout direction of a horizontally-oriented list.
 
     When using the attached property \l {LayoutMirroring::enabled}{LayoutMirroring::enabled} for locale layouts,
     the visual layout direction of the horizontal list will be mirrored. However, the
@@ -1970,6 +2073,24 @@ void QQuickListView::setOrientation(QQuickListView::Orientation orientation)
     \sa ListView::layoutDirection, {LayoutMirroring}{LayoutMirroring}
 */
 
+
+/*!
+  \qmlproperty enumeration QtQuick2::ListView::verticalLayoutDirection
+  This property holds the layout direction of a vertically-oriented list.
+
+  Possible values:
+
+  \list
+  \li ListView.TopToBottom (default) - Items are laid out from the top of the view down to the bottom of the view.
+  \li ListView.BottomToTop - Items are laid out from the bottom of the view up to the top of the view.
+  \endlist
+
+  Setting this property has no effect if the \l orientation is Qt.Horizontal.
+
+  \sa ListView::layoutDirection
+*/
+
+
 /*!
     \qmlproperty bool QtQuick2::ListView::keyNavigationWraps
     This property holds whether the list wraps key navigation.
@@ -1994,8 +2115,10 @@ void QQuickListView::setOrientation(QQuickListView::Orientation orientation)
     area may be created/retained.  The buffered delegates are created asynchronously,
     allowing creation to occur across multiple frames and reducing the
     likelihood of skipping frames.  In order to improve painting performance
-    delegates outside the visible area have their \l visible property set to
-    false until they are moved into the visible area.
+    delegates outside the visible area are not painted.
+
+    The default value of this property is platform dependent, but will usually
+    be a non-zero value.
 
     Note that cacheBuffer is not a pixel buffer - it only maintains additional
     instantiated delegates.
@@ -2023,13 +2146,16 @@ void QQuickListView::setOrientation(QQuickListView::Orientation orientation)
     \c section.property. This value can be one of:
 
     \list
-    \o ViewSection.FullString (default) - sections are created based on the
+    \li ViewSection.FullString (default) - sections are created based on the
     \c section.property value.
-    \o ViewSection.FirstCharacter - sections are created based on the first
+    \li ViewSection.FirstCharacter - sections are created based on the first
     character of the \c section.property value (for example, 'A', 'B', 'C'
     sections, etc. for an address book)
     \endlist
 
+    A case insensitive comparison is used when determining section
+    boundaries.
+
     \c section.delegate holds the delegate component for each section.
 
     \c section.labelPositioning determines whether the current and/or
@@ -2037,11 +2163,11 @@ void QQuickListView::setOrientation(QQuickListView::Orientation orientation)
     the labels are shown inline.  This value can be a combination of:
 
     \list
-    \o ViewSection.InlineLabels - section labels are shown inline between
+    \li ViewSection.InlineLabels - section labels are shown inline between
     the item delegates separating sections (default).
-    \o ViewSection.CurrentLabelAtStart - the current section label sticks to the
+    \li ViewSection.CurrentLabelAtStart - the current section label sticks to the
     start of the view as it is moved.
-    \o ViewSection.NextLabelAtEnd - the next section label (beyond all visible
+    \li ViewSection.NextLabelAtEnd - the next section label (beyond all visible
     sections) sticks to the end of the view as it is moved. \note Enabling
     \c ViewSection.NextLabelAtEnd requires the view to scan ahead for the next
     section, which has performance implications, especially for slower models.
@@ -2057,7 +2183,7 @@ void QQuickListView::setOrientation(QQuickListView::Orientation orientation)
     each section.
 
 
-    \snippet examples/declarative/modelviews/listview/sections.qml 0
+    \snippet examples/quick/modelviews/listview/sections.qml 0
 
     \image qml-listview-sections-example.png
 
@@ -2068,15 +2194,13 @@ void QQuickListView::setOrientation(QQuickListView::Orientation orientation)
     differing sections will result in a section header being created
     even if that section exists elsewhere.
 
-    \sa {declarative/modelviews/listview}{ListView examples}
+    \sa {quick/modelviews/listview}{ListView examples}
 */
 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;
 }
 
@@ -2091,17 +2215,18 @@ QString QQuickListView::currentSection() const
 }
 
 /*!
-    \qmlproperty real QtQuick2::ListView::highlightMoveSpeed
+    \qmlproperty real QtQuick2::ListView::highlightMoveVelocity
     \qmlproperty int QtQuick2::ListView::highlightMoveDuration
-    \qmlproperty real QtQuick2::ListView::highlightResizeSpeed
+    \qmlproperty real QtQuick2::ListView::highlightResizeVelocity
     \qmlproperty int QtQuick2::ListView::highlightResizeDuration
 
-    These properties hold the move and resize animation speed 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 the speed properties is 400 pixels/second.
+    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.
 
@@ -2109,20 +2234,20 @@ QString QQuickListView::currentSection() const
 
     \sa highlightFollowsCurrentItem
 */
-qreal QQuickListView::highlightMoveSpeed() const
+qreal QQuickListView::highlightMoveVelocity() const
 {
     Q_D(const QQuickListView);
-    return d->highlightMoveSpeed;
+    return d->highlightMoveVelocity;
 }
 
-void QQuickListView::setHighlightMoveSpeed(qreal speed)
+void QQuickListView::setHighlightMoveVelocity(qreal speed)
 {
     Q_D(QQuickListView);
-    if (d->highlightMoveSpeed != speed) {
-        d->highlightMoveSpeed = speed;
+    if (d->highlightMoveVelocity != speed) {
+        d->highlightMoveVelocity = speed;
         if (d->highlightPosAnimator)
-            d->highlightPosAnimator->velocity = d->highlightMoveSpeed;
-        emit highlightMoveSpeedChanged();
+            d->highlightPosAnimator->velocity = d->highlightMoveVelocity;
+        emit highlightMoveVelocityChanged();
     }
 }
 
@@ -2136,20 +2261,20 @@ void QQuickListView::setHighlightMoveDuration(int duration)
     }
 }
 
-qreal QQuickListView::highlightResizeSpeed() const
+qreal QQuickListView::highlightResizeVelocity() const
 {
     Q_D(const QQuickListView);
-    return d->highlightResizeSpeed;
+    return d->highlightResizeVelocity;
 }
 
-void QQuickListView::setHighlightResizeSpeed(qreal speed)
+void QQuickListView::setHighlightResizeVelocity(qreal speed)
 {
     Q_D(QQuickListView);
-    if (d->highlightResizeSpeed != speed) {
-        d->highlightResizeSpeed = speed;
+    if (d->highlightResizeVelocity != speed) {
+        d->highlightResizeVelocity = speed;
         if (d->highlightSizeAnimator)
-            d->highlightSizeAnimator->velocity = d->highlightResizeSpeed;
-        emit highlightResizeSpeedChanged();
+            d->highlightSizeAnimator->velocity = d->highlightResizeVelocity;
+        emit highlightResizeVelocityChanged();
     }
 }
 
@@ -2177,10 +2302,10 @@ void QQuickListView::setHighlightResizeDuration(int duration)
     The possible values are:
 
     \list
-    \o ListView.NoSnap (default) - the view stops anywhere within the visible area.
-    \o ListView.SnapToItem - the view settles with an item aligned with the start of
+    \li ListView.NoSnap (default) - the view stops anywhere within the visible area.
+    \li ListView.SnapToItem - the view settles with an item aligned with the start of
     the view.
-    \o ListView.SnapOneItem - the view settles no more than one item away from the first
+    \li ListView.SnapOneItem - the view settles no more than one item away from the first
     visible item at the time the mouse button is released.  This mode is particularly
     useful for moving one page at a time.
     \endlist
@@ -2257,9 +2382,9 @@ void QQuickListView::setSnapMode(SnapMode mode)
     It is applied to all items that are created when:
 
     \list
-    \o The view is first created
-    \o The view's \l model changes
-    \o The view's \l model is \l {QAbstractItemModel::reset}{reset}, if the model is a QAbstractItemModel subclass
+    \li The view is first created
+    \li The view's \l model changes
+    \li The view's \l model is \l {QAbstractItemModel::reset}{reset}, if the model is a QAbstractItemModel subclass
     \endlist
 
     For example, here is a view that specifies such a transition:
@@ -2526,10 +2651,10 @@ void QQuickListView::setSnapMode(SnapMode mode)
     \sa addDisplaced, moveDisplaced, removeDisplaced, ViewTransition
 */
 
-void QQuickListView::viewportMoved()
+void QQuickListView::viewportMoved(Qt::Orientations orient)
 {
     Q_D(QQuickListView);
-    QQuickItemView::viewportMoved();
+    QQuickItemView::viewportMoved(orient);
     if (!d->itemCount)
         return;
     // Recursion can occur due to refill changing the content size.
@@ -2537,22 +2662,29 @@ void QQuickListView::viewportMoved()
         return;
     d->inViewportMoved = true;
 
-    if (yflick())
-        d->bufferMode = d->vData.smoothVelocity < 0 ? QQuickListViewPrivate::BufferBefore : QQuickListViewPrivate::BufferAfter;
-    else if (d->isRightToLeft())
-        d->bufferMode = d->hData.smoothVelocity < 0 ? QQuickListViewPrivate::BufferAfter : QQuickListViewPrivate::BufferBefore;
-    else
-        d->bufferMode = d->hData.smoothVelocity < 0 ? QQuickListViewPrivate::BufferBefore : QQuickListViewPrivate::BufferAfter;
+    if (yflick()) {
+        if (d->isBottomToTop())
+            d->bufferMode = d->vData.smoothVelocity < 0 ? QQuickListViewPrivate::BufferAfter : QQuickListViewPrivate::BufferBefore;
+        else
+            d->bufferMode = d->vData.smoothVelocity < 0 ? QQuickListViewPrivate::BufferBefore : QQuickListViewPrivate::BufferAfter;
+    } else {
+        if (d->isRightToLeft())
+            d->bufferMode = d->hData.smoothVelocity < 0 ? QQuickListViewPrivate::BufferAfter : QQuickListViewPrivate::BufferBefore;
+        else
+            d->bufferMode = d->hData.smoothVelocity < 0 ? QQuickListViewPrivate::BufferBefore : QQuickListViewPrivate::BufferAfter;
+    }
 
-    d->refill();
+    d->refillOrLayout();
 
     // Set visibility of items to eliminate cost of items outside the visible area.
     qreal from = d->isContentFlowReversed() ? -d->position()-d->size() : d->position();
     qreal to = d->isContentFlowReversed() ? -d->position() : d->position()+d->size();
     for (int i = 0; i < d->visibleItems.count(); ++i) {
         FxViewItem *item = static_cast<FxListItemSG*>(d->visibleItems.at(i));
-        item->item->setVisible(item->endPosition() >= from && item->position() <= to);
+        QQuickItemPrivate::get(item->item)->setCulled(item->endPosition() < from || item->position() > to);
     }
+    if (d->currentItem)
+        QQuickItemPrivate::get(d->currentItem->item)->setCulled(d->currentItem->endPosition() < from || d->currentItem->position() > to);
 
     if (d->hData.flicking || d->vData.flicking || d->hData.moving || d->vData.moving)
         d->moveReason = QQuickListViewPrivate::Mouse;
@@ -2560,7 +2692,7 @@ void QQuickListView::viewportMoved()
         if (d->haveHighlightRange && d->highlightRange == StrictlyEnforceRange && d->highlight) {
             // reposition highlight
             qreal pos = d->highlight->position();
-            qreal viewPos = d->isRightToLeft() ? -d->position()-d->size() : d->position();
+            qreal viewPos = d->isContentFlowReversed() ? -d->position()-d->size() : d->position();
             if (pos > viewPos + d->highlightRangeEnd - d->highlight->size())
                 pos = viewPos + d->highlightRangeEnd - d->highlight->size();
             if (pos < viewPos + d->highlightRangeStart)
@@ -2626,7 +2758,8 @@ void QQuickListView::keyPressEvent(QKeyEvent *event)
     if (d->model && d->model->count() && d->interactive) {
         if ((d->orient == QQuickListView::Horizontal && !d->isRightToLeft() && event->key() == Qt::Key_Left)
                     || (d->orient == QQuickListView::Horizontal && d->isRightToLeft() && event->key() == Qt::Key_Right)
-                    || (d->orient == QQuickListView::Vertical && event->key() == Qt::Key_Up)) {
+                    || (d->orient == QQuickListView::Vertical && !d->isBottomToTop() && event->key() == Qt::Key_Up)
+                    || (d->orient == QQuickListView::Vertical && d->isBottomToTop() && event->key() == Qt::Key_Down)) {
             if (currentIndex() > 0 || (d->wrap && !event->isAutoRepeat())) {
                 decrementCurrentIndex();
                 event->accept();
@@ -2637,7 +2770,8 @@ void QQuickListView::keyPressEvent(QKeyEvent *event)
             }
         } else if ((d->orient == QQuickListView::Horizontal && !d->isRightToLeft() && event->key() == Qt::Key_Right)
                     || (d->orient == QQuickListView::Horizontal && d->isRightToLeft() && event->key() == Qt::Key_Left)
-                    || (d->orient == QQuickListView::Vertical && event->key() == Qt::Key_Down)) {
+                   || (d->orient == QQuickListView::Vertical && !d->isBottomToTop() && event->key() == Qt::Key_Down)
+                   || (d->orient == QQuickListView::Vertical && d->isBottomToTop() && event->key() == Qt::Key_Up)) {
             if (currentIndex() < d->model->count() - 1 || (d->wrap && !event->isAutoRepeat())) {
                 incrementCurrentIndex();
                 event->accept();
@@ -2655,14 +2789,27 @@ void QQuickListView::keyPressEvent(QKeyEvent *event)
 void QQuickListView::geometryChanged(const QRectF &newGeometry, const QRectF &oldGeometry)
 {
     Q_D(QQuickListView);
-    if (d->isRightToLeft() && d->orient == QQuickListView::Horizontal) {
+    if (d->isRightToLeft()) {
         // maintain position relative to the right edge
         int dx = newGeometry.width() - oldGeometry.width();
         setContentX(contentX() - dx);
+    } else if (d->isBottomToTop()) {
+        // maintain position relative to the bottom edge
+        int dy = newGeometry.height() - oldGeometry.height();
+        setContentY(contentY() - dy);
     }
     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()
@@ -2671,7 +2818,7 @@ void QQuickListView::geometryChanged(const QRectF &newGeometry, const QRectF &ol
     if keyNavigationWraps is true and it is currently at the end.
     This method has no effect if the \l count is zero.
 
-    \bold Note: methods should only be called after the Component has completed.
+    \b Note: methods should only be called after the Component has completed.
 */
 void QQuickListView::incrementCurrentIndex()
 {
@@ -2691,7 +2838,7 @@ void QQuickListView::incrementCurrentIndex()
     if keyNavigationWraps is true and it is currently at the beginning.
     This method has no effect if the \l count is zero.
 
-    \bold Note: methods should only be called after the Component has completed.
+    \b Note: methods should only be called after the Component has completed.
 */
 void QQuickListView::decrementCurrentIndex()
 {
@@ -2704,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();
     }
 }
 
@@ -2725,7 +2870,7 @@ bool QQuickListViewPrivate::applyInsertionChange(const QQuickChangeSet::Insert &
     int modelIndex = change.index;
     int count = change.count;
 
-    qreal tempPos = isRightToLeft() ? -position()-size() : position();
+    qreal tempPos = isContentFlowReversed() ? -position()-size() : position();
     int index = visibleItems.count() ? mapFromModel(modelIndex) : 0;
 
     if (index < 0) {
@@ -2787,8 +2932,7 @@ bool QQuickListViewPrivate::applyInsertionChange(const QQuickChangeSet::Insert &
                     insertResult->changedFirstItem = true;
                 if (!change.isMove()) {
                     addedItems->append(item);
-                    if (transitioner)
-                        transitioner->transitionNextReposition(item, QQuickItemViewTransitioner::AddTransition, true);
+                    item->transitionNextReposition(transitioner, QQuickItemViewTransitioner::AddTransition, true);
                 }
                 insertResult->sizeChangesBeforeVisiblePos += item->size() + spacing;
                 pos -= item->size() + spacing;
@@ -2818,8 +2962,7 @@ bool QQuickListViewPrivate::applyInsertionChange(const QQuickChangeSet::Insert &
                     movingIntoView->append(MovedItem(item, change.moveKey(item->index)));
             } else {
                 addedItems->append(item);
-                if (transitioner)
-                    transitioner->transitionNextReposition(item, QQuickItemViewTransitioner::AddTransition, true);
+                item->transitionNextReposition(transitioner, QQuickItemViewTransitioner::AddTransition, true);
             }
             insertResult->sizeChangesAfterVisiblePos += item->size() + spacing;
             pos += item->size() + spacing;
@@ -2829,13 +2972,12 @@ bool QQuickListViewPrivate::applyInsertionChange(const QQuickChangeSet::Insert &
 
     for (; index < visibleItems.count(); ++index) {
         FxViewItem *item = visibleItems.at(index);
-        if (item->index != -1)
+        if (item->index != -1) {
             item->index += count;
-        if (transitioner) {
             if (change.isMove())
-                transitioner->transitionNextReposition(item, QQuickItemViewTransitioner::MoveTransition, false);
+                item->transitionNextReposition(transitioner, QQuickItemViewTransitioner::MoveTransition, false);
             else
-                transitioner->transitionNextReposition(item, QQuickItemViewTransitioner::AddTransition, false);
+                item->transitionNextReposition(transitioner, QQuickItemViewTransitioner::AddTransition, false);
         }
     }
 
@@ -2870,7 +3012,7 @@ void QQuickListViewPrivate::translateAndTransitionItemsAfter(int afterModelIndex
         if (!listItem->transitionScheduledOrRunning()) {
             qreal pos = listItem->position();
             listItem->setPosition(pos - sizeRemoved);
-            transitioner->transitionNextReposition(listItem, QQuickItemViewTransitioner::RemoveTransition, false);
+            listItem->transitionNextReposition(transitioner, QQuickItemViewTransitioner::RemoveTransition, false);
             listItem->setPosition(pos);
         }
     }
@@ -2883,12 +3025,12 @@ void QQuickListViewPrivate::translateAndTransitionItemsAfter(int afterModelIndex
     \a mode:
 
     \list
-    \o ListView.Beginning - position item at the top (or left for horizontal orientation) of the view.
-    \o ListView.Center - position item in the center of the view.
-    \o ListView.End - position item at bottom (or right for horizontal orientation) of the view.
-    \o ListView.Visible - if any part of the item is visible then take no action, otherwise
+    \li ListView.Beginning - position item at the top (or left for horizontal orientation) of the view.
+    \li ListView.Center - position item in the center of the view.
+    \li ListView.End - position item at bottom (or right for horizontal orientation) of the view.
+    \li ListView.Visible - if any part of the item is visible then take no action, otherwise
     bring the item into view.
-    \o ListView.Contain - ensure the entire item is visible.  If the item is larger than
+    \li ListView.Contain - ensure the entire item is visible.  If the item is larger than
     the view the item is positioned at the top (or left for horizontal orientation) of the view.
     \endlist
 
@@ -2901,7 +3043,7 @@ void QQuickListViewPrivate::translateAndTransitionItemsAfter(int afterModelIndex
     the actual start of the view can vary based on the size of the delegates.
     The correct way to bring an item into view is with \c positionViewAtIndex.
 
-    \bold Note: methods should only be called after the Component has completed.  To position
+    \b Note: methods should only be called after the Component has completed.  To position
     the view at startup, this method should be called by Component.onCompleted.  For
     example, to position the view at the end:
 
@@ -2921,7 +3063,7 @@ void QQuickListViewPrivate::translateAndTransitionItemsAfter(int afterModelIndex
     of the list does not cause all other items to be repositioned, and because
     the actual start of the view can vary based on the size of the delegates.
 
-    \bold Note: methods should only be called after the Component has completed.  To position
+    \b Note: methods should only be called after the Component has completed.  To position
     the view at startup, this method should be called by Component.onCompleted.  For
     example, to position the view at the end on startup:
 
@@ -2940,7 +3082,7 @@ void QQuickListViewPrivate::translateAndTransitionItemsAfter(int afterModelIndex
     If the item is outside the visible area, -1 is returned, regardless of
     whether an item will exist at that point when scrolled into view.
 
-    \bold Note: methods should only be called after the Component has completed.
+    \b Note: methods should only be called after the Component has completed.
 */
 
 /*!
@@ -2953,7 +3095,7 @@ void QQuickListViewPrivate::translateAndTransitionItemsAfter(int afterModelIndex
     If the item is outside the visible area, null is returned, regardless of
     whether an item will exist at that point when scrolled into view.
 
-    \bold Note: methods should only be called after the Component has completed.
+    \b Note: methods should only be called after the Component has completed.
 */
 
 QQuickListViewAttached *QQuickListView::qmlAttachedProperties(QObject *obj)