src/gui/itemviews/qlistview.cpp
changeset 0 1918ee327afb
child 3 41300fa6a67c
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/gui/itemviews/qlistview.cpp	Mon Jan 11 14:00:40 2010 +0000
@@ -0,0 +1,2993 @@
+/****************************************************************************
+**
+** Copyright (C) 2009 Nokia Corporation and/or its subsidiary(-ies).
+** All rights reserved.
+** Contact: Nokia Corporation (qt-info@nokia.com)
+**
+** This file is part of the QtGui module of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL$
+** No Commercial Usage
+** This file contains pre-release code and may not be distributed.
+** You may use this file in accordance with the terms and conditions
+** contained in the Technology Preview License Agreement accompanying
+** this package.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 2.1 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPL included in the
+** packaging of this file.  Please review the following information to
+** ensure the GNU Lesser General Public License version 2.1 requirements
+** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
+**
+** In addition, as a special exception, Nokia gives you certain additional
+** rights.  These rights are described in the Nokia Qt LGPL Exception
+** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
+**
+** If you have questions regarding the use of this file, please contact
+** Nokia at qt-info@nokia.com.
+**
+**
+**
+**
+**
+**
+**
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#include "qlistview.h"
+
+#ifndef QT_NO_LISTVIEW
+#include <qabstractitemdelegate.h>
+#include <qapplication.h>
+#include <qpainter.h>
+#include <qbitmap.h>
+#include <qvector.h>
+#include <qstyle.h>
+#include <qevent.h>
+#include <qscrollbar.h>
+#include <qrubberband.h>
+#include <private/qlistview_p.h>
+#include <qdebug.h>
+#ifndef QT_NO_ACCESSIBILITY
+#include <qaccessible.h>
+#endif
+
+QT_BEGIN_NAMESPACE
+
+/*!
+    \class QListView
+
+    \brief The QListView class provides a list or icon view onto a model.
+
+    \ingroup model-view
+    \ingroup advanced
+
+
+    A QListView presents items stored in a model, either as a simple
+    non-hierarchical list, or as a collection of icons. This class is used
+    to provide lists and icon views that were previously provided by the
+    \c QListBox and \c QIconView classes, but using the more flexible
+    approach provided by Qt's model/view architecture.
+
+    The QListView class is one of the \l{Model/View Classes}
+    and is part of Qt's \l{Model/View Programming}{model/view framework}.
+
+    This view does not display horizontal or vertical headers; to display
+    a list of items with a horizontal header, use QTreeView instead.
+
+    QListView implements the interfaces defined by the
+    QAbstractItemView class to allow it to display data provided by
+    models derived from the QAbstractItemModel class.
+
+    Items in a list view can be displayed using one of two view modes:
+    In \l ListMode, the items are displayed in the form of a simple list;
+    in \l IconMode, the list view takes the form of an \e{icon view} in
+    which the items are displayed with icons like files in a file manager.
+    By default, the list view is in \l ListMode. To change the view mode,
+    use the setViewMode() function, and to determine the current view mode,
+    use viewMode().
+
+    Items in these views are laid out in the direction specified by the
+    flow() of the list view. The items may be fixed in place, or allowed
+    to move, depending on the view's movement() state.
+
+    If the items in the model cannot be completely laid out in the
+    direction of flow, they can be wrapped at the boundary of the view
+    widget; this depends on isWrapping(). This property is useful when the
+    items are being represented by an icon view.
+
+    The resizeMode() and layoutMode() govern how and when the items are
+    laid out. Items are spaced according to their spacing(), and can exist
+    within a notional grid of size specified by gridSize(). The items can
+    be rendered as large or small icons depending on their iconSize().
+
+    \table 100%
+    \row \o \inlineimage windowsxp-listview.png Screenshot of a Windows XP style list view
+         \o \inlineimage macintosh-listview.png Screenshot of a Macintosh style table view
+         \o \inlineimage plastique-listview.png Screenshot of a Plastique style table view
+    \row \o A \l{Windows XP Style Widget Gallery}{Windows XP style} list view.
+         \o A \l{Macintosh Style Widget Gallery}{Macintosh style} list view.
+         \o A \l{Plastique Style Widget Gallery}{Plastique style} list view.
+    \endtable
+
+    \section1 Improving Performance
+
+    It is possible to give the view hints about the data it is handling in order
+    to improve its performance when displaying large numbers of items. One approach
+    that can be taken for views that are intended to display items with equal sizes
+    is to set the \l uniformItemSizes property to true.
+
+    \sa {View Classes}, QTreeView, QTableView, QListWidget
+*/
+
+/*!
+    \enum QListView::ViewMode
+
+    \value ListMode The items are laid out using TopToBottom flow, with Small size and Static movement
+    \value IconMode The items are laid out using LeftToRight flow, with Large size and Free movement
+*/
+
+/*!
+  \enum QListView::Movement
+
+  \value Static The items cannot be moved by the user.
+  \value Free The items can be moved freely by the user.
+  \value Snap The items snap to the specified grid when moved; see
+  setGridSize().
+*/
+
+/*!
+  \enum QListView::Flow
+
+  \value LeftToRight The items are laid out in the view from the left
+  to the right.
+  \value TopToBottom The items are laid out in the view from the top
+  to the bottom.
+*/
+
+/*!
+  \enum QListView::ResizeMode
+
+  \value Fixed The items will only be laid out the first time the view is shown.
+  \value Adjust The items will be laid out every time the view is resized.
+*/
+
+/*!
+  \enum QListView::LayoutMode
+
+  \value SinglePass The items are laid out all at once.
+  \value Batched The items are laid out in batches of \l batchSize items.
+  \sa batchSize
+*/
+
+/*!
+  \since 4.2
+  \fn void QListView::indexesMoved(const QModelIndexList &indexes)
+
+  This signal is emitted when the specified \a indexes are moved in the view.
+*/
+
+/*!
+    Creates a new QListView with the given \a parent to view a model.
+    Use setModel() to set the model.
+*/
+QListView::QListView(QWidget *parent)
+    : QAbstractItemView(*new QListViewPrivate, parent)
+{
+    setViewMode(ListMode);
+    setSelectionMode(SingleSelection);
+    setAttribute(Qt::WA_MacShowFocusRect);
+    Q_D(QListView);               // We rely on a qobject_cast for PM_DefaultFrameWidth to change
+    d->updateStyledFrameWidths(); // hence we have to force an update now that the object has been constructed
+}
+
+/*!
+  \internal
+*/
+QListView::QListView(QListViewPrivate &dd, QWidget *parent)
+    : QAbstractItemView(dd, parent)
+{
+    setViewMode(ListMode);
+    setSelectionMode(SingleSelection);
+    setAttribute(Qt::WA_MacShowFocusRect);
+    Q_D(QListView);               // We rely on a qobject_cast for PM_DefaultFrameWidth to change
+    d->updateStyledFrameWidths(); // hence we have to force an update now that the object has been constructed
+}
+
+/*!
+  Destroys the view.
+*/
+QListView::~QListView()
+{
+}
+
+/*!
+    \property QListView::movement
+    \brief whether the items can be moved freely, are snapped to a
+    grid, or cannot be moved at all.
+
+    This property determines how the user can move the items in the
+    view. \l Static means that the items can't be moved the user. \l
+    Free means that the user can drag and drop the items to any
+    position in the view. \l Snap means that the user can drag and
+    drop the items, but only to the positions in a notional grid
+    signified by the gridSize property.
+
+    Setting this property when the view is visible will cause the
+    items to be laid out again.
+
+    By default, this property is set to \l Static.
+
+    \sa gridSize, resizeMode, viewMode
+*/
+void QListView::setMovement(Movement movement)
+{
+    Q_D(QListView);
+    d->modeProperties |= uint(QListViewPrivate::Movement);
+    d->movement = movement;
+
+#ifndef QT_NO_DRAGANDDROP
+    bool movable = (movement != Static);
+    setDragEnabled(movable);
+    d->viewport->setAcceptDrops(movable);
+#endif
+    d->doDelayedItemsLayout();
+}
+
+QListView::Movement QListView::movement() const
+{
+    Q_D(const QListView);
+    return d->movement;
+}
+
+/*!
+    \property QListView::flow
+    \brief which direction the items layout should flow.
+
+    If this property is \l LeftToRight, the items will be laid out left
+    to right. If the \l isWrapping property is true, the layout will wrap
+    when it reaches the right side of the visible area. If this
+    property is \l TopToBottom, the items will be laid out from the top
+    of the visible area, wrapping when it reaches the bottom.
+
+    Setting this property when the view is visible will cause the
+    items to be laid out again.
+
+    By default, this property is set to \l TopToBottom.
+
+    \sa viewMode
+*/
+void QListView::setFlow(Flow flow)
+{
+    Q_D(QListView);
+    d->modeProperties |= uint(QListViewPrivate::Flow);
+    d->flow = flow;
+    d->doDelayedItemsLayout();
+}
+
+QListView::Flow QListView::flow() const
+{
+    Q_D(const QListView);
+    return d->flow;
+}
+
+/*!
+    \property QListView::isWrapping
+    \brief whether the items layout should wrap.
+
+    This property holds whether the layout should wrap when there is
+    no more space in the visible area. The point at which the layout wraps
+    depends on the \l flow property.
+
+    Setting this property when the view is visible will cause the
+    items to be laid out again.
+
+    By default, this property is false.
+
+    \sa viewMode
+*/
+void QListView::setWrapping(bool enable)
+{
+    Q_D(QListView);
+    d->modeProperties |= uint(QListViewPrivate::Wrap);
+    d->setWrapping(enable);
+    d->doDelayedItemsLayout();
+}
+
+bool QListView::isWrapping() const
+{
+    Q_D(const QListView);
+    return d->isWrapping();
+}
+
+/*!
+    \property QListView::resizeMode
+    \brief whether the items are laid out again when the view is resized.
+
+    If this property is \l Adjust, the items will be laid out again
+    when the view is resized. If the value is \l Fixed, the items will
+    not be laid out when the view is resized.
+
+    By default, this property is set to \l Fixed.
+
+    \sa movement, gridSize, viewMode
+*/
+void QListView::setResizeMode(ResizeMode mode)
+{
+    Q_D(QListView);
+    d->modeProperties |= uint(QListViewPrivate::ResizeMode);
+    d->resizeMode = mode;
+}
+
+QListView::ResizeMode QListView::resizeMode() const
+{
+    Q_D(const QListView);
+    return d->resizeMode;
+}
+
+/*!
+    \property QListView::layoutMode
+    \brief determines whether the layout of items should happen immediately or be delayed.
+
+    This property holds the layout mode for the items. When the mode
+    is \l SinglePass (the default), the items are laid out all in one go.
+    When the mode is \l Batched, the items are laid out in batches of \l batchSize
+    items, while processing events. This makes it possible to
+    instantly view and interact with the visible items while the rest
+    are being laid out.
+
+    \sa viewMode
+*/
+void QListView::setLayoutMode(LayoutMode mode)
+{
+    Q_D(QListView);
+    d->layoutMode = mode;
+}
+
+QListView::LayoutMode QListView::layoutMode() const
+{
+    Q_D(const QListView);
+    return d->layoutMode;
+}
+
+/*!
+    \property QListView::spacing
+    \brief the space between items in the layout
+
+    This property is the size of the empty space that is padded around
+    an item in the layout.
+
+    Setting this property when the view is visible will cause the
+    items to be laid out again.
+
+    By default, this property contains a value of 0.
+
+    \sa viewMode
+*/
+// ### Qt5: Use same semantic as layouts (spacing is the size of space
+// *between* items)
+void QListView::setSpacing(int space)
+{
+    Q_D(QListView);
+    d->modeProperties |= uint(QListViewPrivate::Spacing);
+    d->setSpacing(space);
+    d->doDelayedItemsLayout();
+}
+
+int QListView::spacing() const
+{
+    Q_D(const QListView);
+    return d->spacing();
+}
+
+/*!
+    \property QListView::batchSize
+    \brief the number of items laid out in each batch if \l layoutMode is
+    set to \l Batched
+
+    The default value is 100.
+
+    \since 4.2
+*/
+
+void QListView::setBatchSize(int batchSize)
+{
+    Q_D(QListView);
+    if (batchSize <= 0) {
+        qWarning("Invalid batchSize (%d)", batchSize);
+        return;
+    }
+    d->batchSize = batchSize;
+}
+
+int QListView::batchSize() const
+{
+    Q_D(const QListView);
+    return d->batchSize;
+}
+
+/*!
+    \property QListView::gridSize
+    \brief the size of the layout grid
+
+    This property is the size of the grid in which the items are laid
+    out. The default is an empty size which means that there is no
+    grid and the layout is not done in a grid. Setting this property
+    to a non-empty size switches on the grid layout. (When a grid
+    layout is in force the \l spacing property is ignored.)
+
+    Setting this property when the view is visible will cause the
+    items to be laid out again.
+
+    \sa viewMode
+*/
+void QListView::setGridSize(const QSize &size)
+{
+    Q_D(QListView);
+    d->modeProperties |= uint(QListViewPrivate::GridSize);
+    d->setGridSize(size);
+    d->doDelayedItemsLayout();
+}
+
+QSize QListView::gridSize() const
+{
+    Q_D(const QListView);
+    return d->gridSize();
+}
+
+/*!
+    \property QListView::viewMode
+    \brief the view mode of the QListView.
+
+    This property will change the other unset properties to conform
+    with the set view mode. QListView-specific properties that have already been set
+    will not be changed, unless clearPropertyFlags() has been called.
+
+    Setting the view mode will enable or disable drag and drop based on the
+    selected movement. For ListMode, the default movement is \l Static
+    (drag and drop disabled); for IconMode, the default movement is
+    \l Free (drag and drop enabled).
+
+    \sa isWrapping, spacing, gridSize, flow, movement, resizeMode
+*/
+void QListView::setViewMode(ViewMode mode)
+{
+    Q_D(QListView);
+    if (d->commonListView && d->viewMode == mode)
+        return;
+    d->viewMode = mode;
+
+    delete d->commonListView;
+    if (mode == ListMode) {
+        d->commonListView = new QListModeViewBase(this, d);
+        if (!(d->modeProperties & QListViewPrivate::Wrap))
+            d->setWrapping(false);
+        if (!(d->modeProperties & QListViewPrivate::Spacing))
+            d->setSpacing(0);
+        if (!(d->modeProperties & QListViewPrivate::GridSize))
+            d->setGridSize(QSize());
+        if (!(d->modeProperties & QListViewPrivate::Flow))
+            d->flow = TopToBottom;
+        if (!(d->modeProperties & QListViewPrivate::Movement))
+            d->movement = Static;
+        if (!(d->modeProperties & QListViewPrivate::ResizeMode))
+            d->resizeMode = Fixed;
+        if (!(d->modeProperties & QListViewPrivate::SelectionRectVisible))
+            d->showElasticBand = false;
+    } else {
+        d->commonListView = new QIconModeViewBase(this, d);
+        if (!(d->modeProperties & QListViewPrivate::Wrap))
+            d->setWrapping(true);
+        if (!(d->modeProperties & QListViewPrivate::Spacing))
+            d->setSpacing(0);
+        if (!(d->modeProperties & QListViewPrivate::GridSize))
+            d->setGridSize(QSize());
+        if (!(d->modeProperties & QListViewPrivate::Flow))
+            d->flow = LeftToRight;
+        if (!(d->modeProperties & QListViewPrivate::Movement))
+            d->movement = Free;
+        if (!(d->modeProperties & QListViewPrivate::ResizeMode))
+            d->resizeMode = Fixed;
+        if (!(d->modeProperties & QListViewPrivate::SelectionRectVisible))
+            d->showElasticBand = true;
+    }
+
+#ifndef QT_NO_DRAGANDDROP
+    bool movable = (d->movement != Static);
+    setDragEnabled(movable);
+    setAcceptDrops(movable);
+#endif
+    d->clear();
+    d->doDelayedItemsLayout();
+}
+
+QListView::ViewMode QListView::viewMode() const
+{
+    Q_D(const QListView);
+    return d->viewMode;
+}
+
+/*!
+    Clears the QListView-specific property flags. See \l{viewMode}.
+
+    Properties inherited from QAbstractItemView are not covered by the
+    property flags. Specifically, \l{QAbstractItemView::dragEnabled}
+    {dragEnabled} and \l{QAbstractItemView::acceptDrops}
+    {acceptsDrops} are computed by QListView when calling
+    setMovement() or setViewMode().
+*/
+void QListView::clearPropertyFlags()
+{
+    Q_D(QListView);
+    d->modeProperties = 0;
+}
+
+/*!
+    Returns true if the \a row is hidden; otherwise returns false.
+*/
+bool QListView::isRowHidden(int row) const
+{
+    Q_D(const QListView);
+    return d->isHidden(row);
+}
+
+/*!
+    If \a hide is true, the given \a row will be hidden; otherwise
+    the \a row will be shown.
+*/
+void QListView::setRowHidden(int row, bool hide)
+{
+    Q_D(QListView);
+    const bool hidden = d->isHidden(row);
+    if (hide && !hidden)
+        d->commonListView->appendHiddenRow(row);
+    else if (!hide && hidden)
+        d->commonListView->removeHiddenRow(row);
+    d->doDelayedItemsLayout();
+    d->viewport->update();
+}
+
+/*!
+  \reimp
+*/
+QRect QListView::visualRect(const QModelIndex &index) const
+{
+    Q_D(const QListView);
+    return d->mapToViewport(rectForIndex(index));
+}
+
+/*!
+  \reimp
+*/
+void QListView::scrollTo(const QModelIndex &index, ScrollHint hint)
+{
+    Q_D(QListView);
+
+    if (index.parent() != d->root || index.column() != d->column)
+        return;
+
+    const QRect rect = visualRect(index);
+    if (hint == EnsureVisible && d->viewport->rect().contains(rect)) {
+        d->viewport->update(rect);
+        return;
+    }
+
+    if (d->flow == QListView::TopToBottom || d->isWrapping()) // vertical
+        verticalScrollBar()->setValue(d->verticalScrollToValue(index, rect, hint));
+
+    if (d->flow == QListView::LeftToRight || d->isWrapping()) // horizontal
+        horizontalScrollBar()->setValue(d->horizontalScrollToValue(index, rect, hint));
+}
+
+int QListViewPrivate::horizontalScrollToValue(const QModelIndex &index, const QRect &rect,
+                                              QListView::ScrollHint hint) const
+{
+    Q_Q(const QListView);
+    const QRect area = viewport->rect();
+    const bool leftOf = q->isRightToLeft()
+                        ? (rect.left() < area.left()) && (rect.right() < area.right())
+                        : rect.left() < area.left();
+    const bool rightOf = q->isRightToLeft()
+                         ? rect.right() > area.right()
+                         : (rect.right() > area.right()) && (rect.left() > area.left());
+    return commonListView->horizontalScrollToValue(q->visualIndex(index), hint, leftOf, rightOf, area, rect);
+}
+
+int QListViewPrivate::verticalScrollToValue(const QModelIndex &index, const QRect &rect,
+                                            QListView::ScrollHint hint) const
+{
+    Q_Q(const QListView);
+    const QRect area = viewport->rect();
+    const bool above = (hint == QListView::EnsureVisible && rect.top() < area.top());
+    const bool below = (hint == QListView::EnsureVisible && rect.bottom() > area.bottom());
+    return commonListView->verticalScrollToValue(q->visualIndex(index), hint, above, below, area, rect);
+}
+
+void QListViewPrivate::selectAll(QItemSelectionModel::SelectionFlags command)
+{
+    if (!selectionModel)
+        return;
+
+    QItemSelection selection;
+    QModelIndex topLeft;
+    int row = 0;
+    const int colCount = model->columnCount(root);
+    for(; row < model->rowCount(root); ++row) {
+        if (isHidden(row)) {
+            //it might be the end of a selection range
+            if (topLeft.isValid()) {
+                QModelIndex bottomRight = model->index(row - 1, colCount - 1, root);
+                selection.append(QItemSelectionRange(topLeft, bottomRight));
+                topLeft = QModelIndex();
+            }
+            continue;
+        }
+
+        if (!topLeft.isValid()) //start of a new selection range
+            topLeft = model->index(row, 0, root);
+    }
+
+    if (topLeft.isValid()) {
+        //last selected range
+        QModelIndex bottomRight = model->index(row - 1, colCount - 1, root);
+        selection.append(QItemSelectionRange(topLeft, bottomRight));
+    }
+
+    if (!selection.isEmpty())
+        selectionModel->select(selection, command);
+}
+
+/*!
+  \reimp
+
+  We have a QListView way of knowing what elements are on the viewport
+  through the intersectingSet function
+*/
+QItemViewPaintPairs QListViewPrivate::draggablePaintPairs(const QModelIndexList &indexes, QRect *r) const
+{
+    Q_ASSERT(r);
+    Q_Q(const QListView);
+    QRect &rect = *r;
+    const QRect viewportRect = viewport->rect();
+    QItemViewPaintPairs ret;
+    const QSet<QModelIndex> visibleIndexes = intersectingSet(viewportRect).toList().toSet();
+    for (int i = 0; i < indexes.count(); ++i) {
+        const QModelIndex &index = indexes.at(i);
+        if (visibleIndexes.contains(index)) {
+            const QRect current = q->visualRect(index);
+            ret += qMakePair(current, index);
+            rect |= current;
+        }
+    }
+    rect &= viewportRect;
+    return ret;
+}
+
+/*!
+  \internal
+*/
+void QListView::reset()
+{
+    Q_D(QListView);
+    d->clear();
+    d->hiddenRows.clear();
+    QAbstractItemView::reset();
+}
+
+/*!
+  \internal
+*/
+void QListView::setRootIndex(const QModelIndex &index)
+{
+    Q_D(QListView);
+    d->column = qBound(0, d->column, d->model->columnCount(index) - 1);
+    QAbstractItemView::setRootIndex(index);
+    // sometimes we get an update before reset() is called
+    d->clear();
+    d->hiddenRows.clear();
+}
+
+/*!
+    \internal
+
+    Scroll the view contents by \a dx and \a dy.
+*/
+
+void QListView::scrollContentsBy(int dx, int dy)
+{
+    Q_D(QListView);
+    d->delayedAutoScroll.stop(); // auto scroll was canceled by the user scrolling
+    d->commonListView->scrollContentsBy(dx, dy, d->state == QListView::DragSelectingState);
+}
+
+/*!
+    \internal
+
+    Resize the internal contents to \a width and \a height and set the
+    scroll bar ranges accordingly.
+*/
+void QListView::resizeContents(int width, int height)
+{
+    Q_D(QListView);
+    d->setContentsSize(width, height);
+}
+
+/*!
+    \internal
+*/
+QSize QListView::contentsSize() const
+{
+    Q_D(const QListView);
+    return d->contentsSize();
+}
+
+/*!
+  \reimp
+*/
+void QListView::dataChanged(const QModelIndex &topLeft, const QModelIndex &bottomRight)
+{
+    d_func()->commonListView->dataChanged(topLeft, bottomRight);
+    QAbstractItemView::dataChanged(topLeft, bottomRight);
+}
+
+/*!
+  \reimp
+*/
+void QListView::rowsInserted(const QModelIndex &parent, int start, int end)
+{
+    Q_D(QListView);
+    // ### be smarter about inserted items
+    d->clear();
+    d->doDelayedItemsLayout();
+    QAbstractItemView::rowsInserted(parent, start, end);
+}
+
+/*!
+  \reimp
+*/
+void QListView::rowsAboutToBeRemoved(const QModelIndex &parent, int start, int end)
+{
+    Q_D(QListView);
+    // if the parent is above d->root in the tree, nothing will happen
+    QAbstractItemView::rowsAboutToBeRemoved(parent, start, end);
+    if (parent == d->root) {
+        for (int i = d->hiddenRows.count() - 1; i >= 0; --i) {
+            int hiddenRow = d->hiddenRows.at(i).row();
+            if (hiddenRow >= start && hiddenRow <= end) {
+                d->hiddenRows.remove(i);
+            }
+        }
+    }
+    d->clear();
+    d->doDelayedItemsLayout();
+}
+
+/*!
+  \reimp
+*/
+void QListView::mouseMoveEvent(QMouseEvent *e)
+{
+    if (!isVisible())
+	return;
+    Q_D(QListView);
+    QAbstractItemView::mouseMoveEvent(e);
+    if (state() == DragSelectingState
+        && d->showElasticBand
+        && d->selectionMode != SingleSelection
+        && d->selectionMode != NoSelection) {
+        QRect rect(d->pressedPosition, e->pos() + QPoint(horizontalOffset(), verticalOffset()));
+        rect = rect.normalized();
+        d->viewport->update(d->mapToViewport(rect.united(d->elasticBand)));
+        d->elasticBand = rect;
+    }
+}
+
+/*!
+  \reimp
+*/
+void QListView::mouseReleaseEvent(QMouseEvent *e)
+{
+    Q_D(QListView);
+    QAbstractItemView::mouseReleaseEvent(e);
+    // #### move this implementation into a dynamic class
+    if (d->showElasticBand && d->elasticBand.isValid()) {
+        d->viewport->update(d->mapToViewport(d->elasticBand));
+        d->elasticBand = QRect();
+    }
+}
+
+/*!
+  \reimp
+*/
+void QListView::timerEvent(QTimerEvent *e)
+{
+    Q_D(QListView);
+    if (e->timerId() == d->batchLayoutTimer.timerId()) {
+        if (d->doItemsLayout(d->batchSize)) { // layout is done
+            d->batchLayoutTimer.stop();
+            updateGeometries();
+            d->viewport->update();
+        }
+    }
+    QAbstractItemView::timerEvent(e);
+}
+
+/*!
+  \reimp
+*/
+void QListView::resizeEvent(QResizeEvent *e)
+{
+    Q_D(QListView);
+    if (d->delayedPendingLayout)
+        return;
+
+    QSize delta = e->size() - e->oldSize();
+
+    if (delta.isNull())
+      return;
+
+    bool listWrap = (d->viewMode == ListMode) && d->wrapItemText;
+    bool flowDimensionChanged = (d->flow == LeftToRight && delta.width() != 0) 
+				|| (d->flow == TopToBottom && delta.height() != 0);
+
+    // We post a delayed relayout in the following cases :
+    // - we're wrapping
+    // - the state is NoState, we're adjusting and the size has changed in the flowing direction
+    if (listWrap 
+        || (state() == NoState && d->resizeMode == Adjust && flowDimensionChanged)) {
+	d->doDelayedItemsLayout(100); // wait 1/10 sec before starting the layout
+    } else {	
+        QAbstractItemView::resizeEvent(e);
+    }
+}
+
+#ifndef QT_NO_DRAGANDDROP
+
+/*!
+  \reimp
+*/
+void QListView::dragMoveEvent(QDragMoveEvent *e)
+{
+    if (!d_func()->commonListView->filterDragMoveEvent(e))
+        QAbstractItemView::dragMoveEvent(e);
+}
+
+
+/*!
+  \reimp
+*/
+void QListView::dragLeaveEvent(QDragLeaveEvent *e)
+{
+    if (!d_func()->commonListView->filterDragLeaveEvent(e))
+        QAbstractItemView::dragLeaveEvent(e);
+}
+
+/*!
+  \reimp
+*/
+void QListView::dropEvent(QDropEvent *e)
+{
+    if (!d_func()->commonListView->filterDropEvent(e))
+        QAbstractItemView::dropEvent(e);
+}
+
+/*!
+  \reimp
+*/
+void QListView::startDrag(Qt::DropActions supportedActions)
+{
+    if (!d_func()->commonListView->filterStartDrag(supportedActions))
+        QAbstractItemView::startDrag(supportedActions);
+}
+
+/*!
+    \internal
+
+    Called whenever items from the view is dropped on the viewport.
+    The \a event provides additional information.
+*/
+void QListView::internalDrop(QDropEvent *event)
+{
+    // ### Qt5: remove that function
+    Q_UNUSED(event);
+}
+
+/*!
+    \internal
+
+    Called whenever the user starts dragging items and the items are movable,
+    enabling internal dragging and dropping of items.
+*/
+void QListView::internalDrag(Qt::DropActions supportedActions)
+{
+    // ### Qt5: remove that function
+    Q_UNUSED(supportedActions);
+}
+
+#endif // QT_NO_DRAGANDDROP
+
+/*!
+  \reimp
+*/
+QStyleOptionViewItem QListView::viewOptions() const
+{
+    Q_D(const QListView);
+    QStyleOptionViewItem option = QAbstractItemView::viewOptions();
+    if (!d->iconSize.isValid()) { // otherwise it was already set in abstractitemview
+        int pm = (d->viewMode == ListMode
+                  ? style()->pixelMetric(QStyle::PM_ListViewIconSize, 0, this)
+                  : style()->pixelMetric(QStyle::PM_IconViewIconSize, 0, this));
+        option.decorationSize = QSize(pm, pm);
+    }
+    if (d->viewMode == IconMode) {
+        option.showDecorationSelected = false;
+        option.decorationPosition = QStyleOptionViewItem::Top;
+        option.displayAlignment = Qt::AlignCenter;
+    } else {
+        option.decorationPosition = QStyleOptionViewItem::Left;
+    }
+    return option;
+}
+
+
+/*!
+  \reimp
+*/
+void QListView::paintEvent(QPaintEvent *e)
+{
+    Q_D(QListView);
+    if (!d->itemDelegate)
+        return;
+    QStyleOptionViewItemV4 option = d->viewOptionsV4();
+    QPainter painter(d->viewport);
+
+    const QVector<QModelIndex> toBeRendered = d->intersectingSet(e->rect().translated(horizontalOffset(), verticalOffset()), false);
+
+    const QModelIndex current = currentIndex();
+    const QModelIndex hover = d->hover;
+    const QAbstractItemModel *itemModel = d->model;
+    const QItemSelectionModel *selections = d->selectionModel;
+    const bool focus = (hasFocus() || d->viewport->hasFocus()) && current.isValid();
+    const bool alternate = d->alternatingColors;
+    const QStyle::State state = option.state;
+    const QAbstractItemView::State viewState = this->state();
+    const bool enabled = (state & QStyle::State_Enabled) != 0;
+
+    bool alternateBase = false;
+    int previousRow = -2; // trigger the alternateBase adjustment on first pass
+
+    QVector<QModelIndex>::const_iterator end = toBeRendered.constEnd();
+    for (QVector<QModelIndex>::const_iterator it = toBeRendered.constBegin(); it != end; ++it) {
+        Q_ASSERT((*it).isValid());
+        option.rect = visualRect(*it);
+
+        if (flow() == TopToBottom)
+            option.rect.setWidth(qMin(viewport()->size().width(), option.rect.width()));
+        else
+            option.rect.setHeight(qMin(viewport()->size().height(), option.rect.height()));
+
+        option.state = state;
+        if (selections && selections->isSelected(*it))
+            option.state |= QStyle::State_Selected;
+        if (enabled) {
+            QPalette::ColorGroup cg;
+            if ((itemModel->flags(*it) & Qt::ItemIsEnabled) == 0) {
+                option.state &= ~QStyle::State_Enabled;
+                cg = QPalette::Disabled;
+            } else {
+                cg = QPalette::Normal;
+            }
+            option.palette.setCurrentColorGroup(cg);
+        }
+        if (focus && current == *it) {
+            option.state |= QStyle::State_HasFocus;
+            if (viewState == EditingState)
+                option.state |= QStyle::State_Editing;
+        }
+        if (*it == hover)
+            option.state |= QStyle::State_MouseOver;
+        else
+            option.state &= ~QStyle::State_MouseOver;
+
+        if (alternate) {
+            int row = (*it).row();
+            if (row != previousRow + 1) {
+                // adjust alternateBase according to rows in the "gap"
+                if (!d->hiddenRows.isEmpty()) {
+                    for (int r = qMax(previousRow + 1, 0); r < row; ++r) {
+                        if (!d->isHidden(r))
+                            alternateBase = !alternateBase;
+                    }
+                } else {
+                    alternateBase = (row & 1) != 0;
+                }
+            }
+            if (alternateBase) {
+                option.features |= QStyleOptionViewItemV2::Alternate;
+            } else {
+                option.features &= ~QStyleOptionViewItemV2::Alternate;
+            }
+
+            // draw background of the item (only alternate row). rest of the background
+            // is provided by the delegate
+            QStyle::State oldState = option.state;
+            option.state &= ~QStyle::State_Selected;
+            style()->drawPrimitive(QStyle::PE_PanelItemViewRow, &option, &painter, this);
+            option.state = oldState;
+
+            alternateBase = !alternateBase;
+            previousRow = row;
+        }
+
+        if (const QWidget *widget = d->editorForIndex(*it).editor) {
+            QRegion itemGeometry(option.rect);
+            QRegion widgetGeometry(widget->geometry());
+            painter.save();
+            painter.setClipRegion(itemGeometry.subtracted(widgetGeometry));
+            d->delegateForIndex(*it)->paint(&painter, option, *it);
+            painter.restore();
+        } else {
+            d->delegateForIndex(*it)->paint(&painter, option, *it);
+        }
+    }
+
+#ifndef QT_NO_DRAGANDDROP
+    d->commonListView->paintDragDrop(&painter);
+#endif
+
+#ifndef QT_NO_RUBBERBAND
+    // #### move this implementation into a dynamic class
+    if (d->showElasticBand && d->elasticBand.isValid()) {
+        QStyleOptionRubberBand opt;
+        opt.initFrom(this);
+        opt.shape = QRubberBand::Rectangle;
+        opt.opaque = false;
+        opt.rect = d->mapToViewport(d->elasticBand, false).intersected(
+            d->viewport->rect().adjusted(-16, -16, 16, 16));
+        painter.save();
+        style()->drawControl(QStyle::CE_RubberBand, &opt, &painter);
+        painter.restore();
+    }
+#endif
+}
+
+/*!
+  \reimp
+*/
+QModelIndex QListView::indexAt(const QPoint &p) const
+{
+    Q_D(const QListView);
+    QRect rect(p.x() + horizontalOffset(), p.y() + verticalOffset(), 1, 1);
+    const QVector<QModelIndex> intersectVector = d->intersectingSet(rect);
+    QModelIndex index = intersectVector.count() > 0
+                        ? intersectVector.last() : QModelIndex();
+    if (index.isValid() && visualRect(index).contains(p))
+        return index;
+    return QModelIndex();
+}
+
+/*!
+  \reimp
+*/
+int QListView::horizontalOffset() const
+{
+    return d_func()->commonListView->horizontalOffset();
+}
+
+/*!
+  \reimp
+*/
+int QListView::verticalOffset() const
+{
+    return d_func()->commonListView->verticalOffset();
+}
+
+/*!
+  \reimp
+*/
+QModelIndex QListView::moveCursor(CursorAction cursorAction, Qt::KeyboardModifiers modifiers)
+{
+    Q_D(QListView);
+    Q_UNUSED(modifiers);
+
+    QModelIndex current = currentIndex();
+    if (!current.isValid()) {
+        int rowCount = d->model->rowCount(d->root);
+        if (!rowCount)
+            return QModelIndex();
+        int row = 0;
+        while (row < rowCount && d->isHiddenOrDisabled(row))
+            ++row;
+        if (row >= rowCount)
+            return QModelIndex();
+        return d->model->index(row, d->column, d->root);
+    }
+
+    const QRect initialRect = rectForIndex(current);
+    QRect rect = initialRect;
+    if (rect.isEmpty()) {
+        return d->model->index(0, d->column, d->root);
+    }
+    if (d->gridSize().isValid()) rect.setSize(d->gridSize());
+
+    QSize contents = d->contentsSize();
+    QVector<QModelIndex> intersectVector;
+
+    switch (cursorAction) {
+    case MoveLeft:
+        while (intersectVector.isEmpty()) {
+            rect.translate(-rect.width(), 0);
+            if (rect.right() <= 0)
+                return current;
+            if (rect.left() < 0)
+                rect.setLeft(0);
+            intersectVector = d->intersectingSet(rect);
+            d->removeCurrentAndDisabled(&intersectVector, current);
+        }
+        return d->closestIndex(initialRect, intersectVector);
+    case MoveRight:
+        while (intersectVector.isEmpty()) {
+            rect.translate(rect.width(), 0);
+            if (rect.left() >= contents.width())
+                return current;
+            if (rect.right() > contents.width())
+                rect.setRight(contents.width());
+            intersectVector = d->intersectingSet(rect);
+            d->removeCurrentAndDisabled(&intersectVector, current);
+        }
+        return d->closestIndex(initialRect, intersectVector);
+    case MovePageUp:
+        rect.moveTop(rect.top() - d->viewport->height());
+        if (rect.top() < rect.height())
+            rect.moveTop(rect.height());
+    case MovePrevious:
+    case MoveUp:
+        while (intersectVector.isEmpty()) {
+            rect.translate(0, -rect.height());
+            if (rect.bottom() <= 0) {
+#ifdef QT_KEYPAD_NAVIGATION
+                if (QApplication::keypadNavigationEnabled()) {
+                    int row = d->batchStartRow() - 1;
+                    while (row >= 0 && d->isHiddenOrDisabled(row))
+                        --row;
+                    if (row >= 0)
+                        return d->model->index(row, d->column, d->root);
+                }
+#endif
+                return current;
+            }
+            if (rect.top() < 0)
+                rect.setTop(0);
+            intersectVector = d->intersectingSet(rect);
+            d->removeCurrentAndDisabled(&intersectVector, current);
+        }
+        return d->closestIndex(initialRect, intersectVector);
+    case MovePageDown:
+        rect.moveTop(rect.top() + d->viewport->height());
+        if (rect.bottom() > contents.height() - rect.height())
+            rect.moveBottom(contents.height() - rect.height());
+    case MoveNext:
+    case MoveDown:
+        while (intersectVector.isEmpty()) {
+            rect.translate(0, rect.height());
+            if (rect.top() >= contents.height()) {
+#ifdef QT_KEYPAD_NAVIGATION
+                if (QApplication::keypadNavigationEnabled()) {
+                    int rowCount = d->model->rowCount(d->root);
+                    int row = 0;
+                    while (row < rowCount && d->isHiddenOrDisabled(row))
+                        ++row;
+                    if (row < rowCount)
+                        return d->model->index(row, d->column, d->root);
+                }
+#endif
+                return current;
+            }
+            if (rect.bottom() > contents.height())
+                rect.setBottom(contents.height());
+            intersectVector = d->intersectingSet(rect);
+            d->removeCurrentAndDisabled(&intersectVector, current);
+        }
+        return d->closestIndex(initialRect, intersectVector);
+    case MoveHome:
+        return d->model->index(0, d->column, d->root);
+    case MoveEnd:
+        return d->model->index(d->batchStartRow() - 1, d->column, d->root);}
+
+    return current;
+}
+
+/*!
+    Returns the rectangle of the item at position \a index in the
+    model. The rectangle is in contents coordinates.
+
+    \sa visualRect()
+*/
+QRect QListView::rectForIndex(const QModelIndex &index) const
+{
+    return d_func()->rectForIndex(index);
+}
+
+/*!
+    \since 4.1
+
+    Sets the contents position of the item at \a index in the model to the given
+    \a position.
+    If the list view's movement mode is Static or its view mode is ListView,
+    this function will have no effect.
+*/
+void QListView::setPositionForIndex(const QPoint &position, const QModelIndex &index)
+{
+    Q_D(QListView);
+    if (d->movement == Static
+        || !d->isIndexValid(index)
+        || index.parent() != d->root
+        || index.column() != d->column)
+        return;
+
+    d->executePostedLayout();
+    d->commonListView->setPositionForIndex(position, index);
+}
+
+/*!
+  \reimp
+*/
+void QListView::setSelection(const QRect &rect, QItemSelectionModel::SelectionFlags command)
+{
+    Q_D(QListView);
+    if (!d->selectionModel)
+        return;
+
+    // if we are wrapping, we can only selecte inside the contents rectangle
+    int w = qMax(d->contentsSize().width(), d->viewport->width());
+    int h = qMax(d->contentsSize().height(), d->viewport->height());
+    if (d->wrap && !QRect(0, 0, w, h).intersects(rect))
+        return;
+
+    QItemSelection selection;
+
+    if (rect.width() == 1 && rect.height() == 1) {
+        const QVector<QModelIndex> intersectVector = d->intersectingSet(rect.translated(horizontalOffset(), verticalOffset()));
+        QModelIndex tl;
+        if (!intersectVector.isEmpty())
+            tl = intersectVector.last(); // special case for mouse press; only select the top item
+        if (tl.isValid() && d->isIndexEnabled(tl))
+            selection.select(tl, tl);
+    } else {
+        if (state() == DragSelectingState) { // visual selection mode (rubberband selection)
+            selection = d->selection(rect.translated(horizontalOffset(), verticalOffset()));
+        } else { // logical selection mode (key and mouse click selection)
+            QModelIndex tl, br;
+            // get the first item
+            const QRect topLeft(rect.left() + horizontalOffset(), rect.top() + verticalOffset(), 1, 1);
+            QVector<QModelIndex> intersectVector = d->intersectingSet(topLeft);
+            if (!intersectVector.isEmpty())
+                tl = intersectVector.last();
+            // get the last item
+            const QRect bottomRight(rect.right() + horizontalOffset(), rect.bottom() + verticalOffset(), 1, 1);
+            intersectVector = d->intersectingSet(bottomRight);
+            if (!intersectVector.isEmpty())
+                br = intersectVector.last();
+
+            // get the ranges
+            if (tl.isValid() && br.isValid()
+                && d->isIndexEnabled(tl)
+                && d->isIndexEnabled(br)) {
+                QRect first = rectForIndex(tl);
+                QRect last = rectForIndex(br);
+                QRect middle;
+                if (d->flow == LeftToRight) {
+                    QRect &top = first;
+                    QRect &bottom = last;
+                    // if bottom is above top, swap them
+                    if (top.center().y() > bottom.center().y()) {
+                        QRect tmp = top;
+                        top = bottom;
+                        bottom = tmp;
+                    }
+                    // if the rect are on differnet lines, expand
+                    if (top.top() != bottom.top()) {
+                        // top rectangle
+                        if (isRightToLeft())
+                            top.setLeft(0);
+                        else
+                            top.setRight(contentsSize().width());
+                        // bottom rectangle
+                        if (isRightToLeft())
+                            bottom.setRight(contentsSize().width());
+                        else
+                            bottom.setLeft(0);
+                    } else if (top.left() > bottom.right()) {
+                        if (isRightToLeft())
+                            bottom.setLeft(top.right());
+                        else
+                            bottom.setRight(top.left());
+                    } else {
+                        if (isRightToLeft())
+                            top.setLeft(bottom.right());
+                        else
+                            top.setRight(bottom.left());
+                    }
+                    // middle rectangle
+                    if (top.bottom() < bottom.top()) {
+                        if (gridSize().isValid() && !gridSize().isNull())
+                            middle.setTop(top.top() + gridSize().height());
+                        else
+                            middle.setTop(top.bottom() + 1);
+                        middle.setLeft(qMin(top.left(), bottom.left()));
+                        middle.setBottom(bottom.top() - 1);
+                        middle.setRight(qMax(top.right(), bottom.right()));
+                    }
+                } else {    // TopToBottom
+                    QRect &left = first;
+                    QRect &right = last;
+                    if (left.center().x() > right.center().x())
+                        qSwap(left, right);
+
+                    int ch = contentsSize().height();
+                    if (left.left() != right.left()) {
+                        // left rectangle
+                        if (isRightToLeft())
+                            left.setTop(0);
+                        else
+                            left.setBottom(ch);
+
+                        // top rectangle
+                        if (isRightToLeft())
+                            right.setBottom(ch);
+                        else
+                            right.setTop(0);
+                        // only set middle if the
+                        middle.setTop(0);
+                        middle.setBottom(ch);
+                        if (gridSize().isValid() && !gridSize().isNull())
+                            middle.setLeft(left.left() + gridSize().width());
+                        else
+                            middle.setLeft(left.right() + 1);
+                        middle.setRight(right.left() - 1);
+                    } else if (left.bottom() < right.top()) {
+                        left.setBottom(right.top() - 1);
+                    } else {
+                        right.setBottom(left.top() - 1);
+                    }
+                }
+
+                // do the selections
+                QItemSelection topSelection = d->selection(first);
+                QItemSelection middleSelection = d->selection(middle);
+                QItemSelection bottomSelection = d->selection(last);
+                // merge
+                selection.merge(topSelection, QItemSelectionModel::Select);
+                selection.merge(middleSelection, QItemSelectionModel::Select);
+                selection.merge(bottomSelection, QItemSelectionModel::Select);
+            }
+        }
+    }
+
+    d->selectionModel->select(selection, command);
+}
+
+/*!
+  \reimp
+*/
+QRegion QListView::visualRegionForSelection(const QItemSelection &selection) const
+{
+    Q_D(const QListView);
+    // ### NOTE: this is a potential bottleneck in non-static mode
+    int c = d->column;
+    QRegion selectionRegion;
+    for (int i = 0; i < selection.count(); ++i) {
+        if (!selection.at(i).isValid())
+            continue;
+        QModelIndex parent = selection.at(i).topLeft().parent();
+        //we only display the children of the root in a listview
+        //we're not interested in the other model indexes
+        if (parent != d->root)
+            continue;
+        int t = selection.at(i).topLeft().row();
+        int b = selection.at(i).bottomRight().row();
+        if (d->viewMode == IconMode || d->isWrapping()) { // in non-static mode, we have to go through all selected items
+            for (int r = t; r <= b; ++r)
+                selectionRegion += QRegion(visualRect(d->model->index(r, c, parent)));
+        } else { // in static mode, we can optimize a bit
+            while (t <= b && d->isHidden(t)) ++t;
+            while (b >= t && d->isHidden(b)) --b;
+            const QModelIndex top = d->model->index(t, c, parent);
+            const QModelIndex bottom = d->model->index(b, c, parent);
+            QRect rect(visualRect(top).topLeft(),
+                       visualRect(bottom).bottomRight());
+            selectionRegion += QRegion(rect);
+        }
+    }
+
+    return selectionRegion;
+}
+
+/*!
+  \reimp
+*/
+QModelIndexList QListView::selectedIndexes() const
+{
+    Q_D(const QListView);
+    if (!d->selectionModel)
+        return QModelIndexList();
+
+    QModelIndexList viewSelected = d->selectionModel->selectedIndexes();
+    for (int i = 0; i < viewSelected.count(); ++i) {
+        const QModelIndex &index = viewSelected.at(i);
+        if (!isIndexHidden(index) && index.parent() == d->root && index.column() == d->column)
+            ++i;
+        else
+            viewSelected.removeAt(i);
+    }
+    return viewSelected;
+}
+
+/*!
+    \internal
+
+    Layout the items according to the flow and wrapping properties.
+*/
+void QListView::doItemsLayout()
+{
+    Q_D(QListView);
+    // showing the scroll bars will trigger a resize event,
+    // so we set the state to expanding to avoid
+    // triggering another layout
+    QAbstractItemView::State oldState = state();
+    setState(ExpandingState); 
+    if (d->model->columnCount(d->root) > 0) { // no columns means no contents
+        d->resetBatchStartRow();
+        if (layoutMode() == SinglePass)
+            d->doItemsLayout(d->model->rowCount(d->root)); // layout everything
+        else if (!d->batchLayoutTimer.isActive()) {
+            if (!d->doItemsLayout(d->batchSize)) // layout is done
+                d->batchLayoutTimer.start(0, this); // do a new batch as fast as possible
+        }
+    }
+    QAbstractItemView::doItemsLayout();
+    setState(oldState);        // restoring the oldState
+}
+
+/*!
+  \reimp
+*/
+void QListView::updateGeometries()
+{
+    Q_D(QListView);
+    if (d->model->rowCount(d->root) <= 0 || d->model->columnCount(d->root) <= 0) {
+        horizontalScrollBar()->setRange(0, 0);
+        verticalScrollBar()->setRange(0, 0);
+    } else {
+        QModelIndex index = d->model->index(0, d->column, d->root);
+        QStyleOptionViewItemV4 option = d->viewOptionsV4();
+        QSize step = d->itemSize(option, index);
+        d->commonListView->updateHorizontalScrollBar(step);
+        d->commonListView->updateVerticalScrollBar(step);
+    }
+
+    QAbstractItemView::updateGeometries();
+
+    // if the scroll bars are turned off, we resize the contents to the viewport
+    if (d->movement == Static && !d->isWrapping()) {
+        d->layoutChildren(); // we need the viewport size to be updated
+        if (d->flow == TopToBottom) {
+            if (horizontalScrollBarPolicy() == Qt::ScrollBarAlwaysOff) {
+                d->setContentsSize(viewport()->width(), contentsSize().height());
+                horizontalScrollBar()->setRange(0, 0); // we see all the contents anyway
+            }
+        } else { // LeftToRight
+            if (verticalScrollBarPolicy() == Qt::ScrollBarAlwaysOff) {
+                d->setContentsSize(contentsSize().width(), viewport()->height());
+                verticalScrollBar()->setRange(0, 0); // we see all the contents anyway
+            }
+        }
+    }
+}
+
+/*!
+  \reimp
+*/
+bool QListView::isIndexHidden(const QModelIndex &index) const
+{
+    Q_D(const QListView);
+    return (d->isHidden(index.row())
+            && (index.parent() == d->root)
+            && index.column() == d->column);
+}
+
+/*!
+    \property QListView::modelColumn
+    \brief the column in the model that is visible
+
+    By default, this property contains 0, indicating that the first
+    column in the model will be shown.
+*/
+void QListView::setModelColumn(int column)
+{
+    Q_D(QListView);
+    if (column < 0 || column >= d->model->columnCount(d->root))
+        return;
+    d->column = column;
+    d->doDelayedItemsLayout();
+}
+
+int QListView::modelColumn() const
+{
+    Q_D(const QListView);
+    return d->column;
+}
+
+/*!
+    \property QListView::uniformItemSizes
+    \brief whether all items in the listview have the same size
+    \since 4.1
+
+    This property should only be set to true if it is guaranteed that all items
+    in the view have the same size. This enables the view to do some
+    optimizations for performance purposes.
+
+    By default, this property is false.
+*/
+void QListView::setUniformItemSizes(bool enable)
+{
+    Q_D(QListView);
+    d->uniformItemSizes = enable;
+}
+
+bool QListView::uniformItemSizes() const
+{
+    Q_D(const QListView);
+    return d->uniformItemSizes;
+}
+
+/*!
+    \property QListView::wordWrap
+    \brief the item text word-wrapping policy
+    \since 4.2
+
+    If this property is true then the item text is wrapped where
+    necessary at word-breaks; otherwise it is not wrapped at all.
+    This property is false by default.
+
+    Please note that even if wrapping is enabled, the cell will not be
+    expanded to make room for the text. It will print ellipsis for
+    text that cannot be shown, according to the view's
+    \l{QAbstractItemView::}{textElideMode}.
+*/
+void QListView::setWordWrap(bool on)
+{
+    Q_D(QListView);
+    if (d->wrapItemText == on)
+        return;
+    d->wrapItemText = on;
+    d->doDelayedItemsLayout();
+}
+
+bool QListView::wordWrap() const
+{
+    Q_D(const QListView);
+    return d->wrapItemText;
+}
+
+/*!
+    \property QListView::selectionRectVisible
+    \brief if the selection rectangle should be visible
+    \since 4.3
+
+    If this property is true then the selection rectangle is visible;
+    otherwise it will be hidden.
+
+    \note The selection rectangle will only be visible if the selection mode
+    is in a mode where more than one item can be selected; i.e., it will not
+    draw a selection rectangle if the selection mode is
+    QAbstractItemView::SingleSelection.
+
+    By default, this property is false.
+*/
+void QListView::setSelectionRectVisible(bool show)
+{
+    Q_D(QListView);
+    d->modeProperties |= uint(QListViewPrivate::SelectionRectVisible);
+    d->setSelectionRectVisible(show);
+}
+
+bool QListView::isSelectionRectVisible() const
+{
+    Q_D(const QListView);
+    return d->isSelectionRectVisible();
+}
+
+/*!
+    \reimp
+*/
+bool QListView::event(QEvent *e)
+{
+    return QAbstractItemView::event(e);
+}
+
+/*
+ * private object implementation
+ */
+
+QListViewPrivate::QListViewPrivate()
+    : QAbstractItemViewPrivate(),
+      commonListView(0),
+      wrap(false),
+      space(0),
+      flow(QListView::TopToBottom),
+      movement(QListView::Static),
+      resizeMode(QListView::Fixed),
+      layoutMode(QListView::SinglePass),
+      viewMode(QListView::ListMode),
+      modeProperties(0),
+      column(0),
+      uniformItemSizes(false),
+      batchSize(100),
+      showElasticBand(false)
+{
+}
+
+QListViewPrivate::~QListViewPrivate()
+{
+    delete commonListView;
+}
+
+void QListViewPrivate::clear()
+{
+    // initialization of data structs
+    cachedItemSize = QSize();
+    commonListView->clear();
+}
+
+void QListViewPrivate::prepareItemsLayout()
+{
+    Q_Q(QListView);
+    clear();
+
+    //take the size as if there were scrollbar in order to prevent scrollbar to blink
+    layoutBounds = QRect(QPoint(), q->maximumViewportSize());
+
+    int frameAroundContents = 0;
+    if (q->style()->styleHint(QStyle::SH_ScrollView_FrameOnlyAroundContents))
+        frameAroundContents = q->style()->pixelMetric(QStyle::PM_DefaultFrameWidth) * 2;
+
+    // maximumViewportSize() already takes scrollbar into account if policy is
+    // Qt::ScrollBarAlwaysOn but scrollbar extent must be deduced if policy
+    // is Qt::ScrollBarAsNeeded
+    int verticalMargin = vbarpolicy==Qt::ScrollBarAsNeeded
+        ? q->style()->pixelMetric(QStyle::PM_ScrollBarExtent, 0, vbar) + frameAroundContents
+        : 0;
+    int horizontalMargin =  hbarpolicy==Qt::ScrollBarAsNeeded
+        ? q->style()->pixelMetric(QStyle::PM_ScrollBarExtent, 0, hbar) + frameAroundContents
+        : 0;
+
+    layoutBounds.adjust(0, 0, -verticalMargin, -horizontalMargin);
+
+    int rowCount = model->columnCount(root) <= 0 ? 0 : model->rowCount(root);
+    commonListView->setRowCount(rowCount);
+}
+
+/*!
+  \internal
+*/
+bool QListViewPrivate::doItemsLayout(int delta)
+{
+    int max = model->rowCount(root) - 1;
+    int first = batchStartRow();
+    int last = qMin(first + delta - 1, max);
+
+    if (first == 0) {
+        layoutChildren(); // make sure the viewport has the right size
+        prepareItemsLayout();
+    }
+
+    if (max < 0 || last < first) {
+        return true; // nothing to do
+    }
+
+    QListViewLayoutInfo info;
+    info.bounds = layoutBounds;
+    info.grid = gridSize();
+    info.spacing = (info.grid.isValid() ? 0 : spacing());
+    info.first = first;
+    info.last = last;
+    info.wrap = isWrapping();
+    info.flow = flow;
+    info.max = max;
+
+    return commonListView->doBatchedItemLayout(info, max);
+}
+
+QListViewItem QListViewPrivate::indexToListViewItem(const QModelIndex &index) const
+{
+    if (!index.isValid() || isHidden(index.row()))
+        return QListViewItem();
+
+    return commonListView->indexToListViewItem(index);
+}
+
+QRect QListViewPrivate::mapToViewport(const QRect &rect, bool extend) const
+{
+    Q_Q(const QListView);
+    if (!rect.isValid())
+        return rect;
+
+    QRect result = extend ? commonListView->mapToViewport(rect) : rect;
+    int dx = -q->horizontalOffset();
+    int dy = -q->verticalOffset();
+    return result.adjusted(dx, dy, dx, dy);
+}
+
+QModelIndex QListViewPrivate::closestIndex(const QRect &target,
+                                           const QVector<QModelIndex> &candidates) const
+{
+    int distance = 0;
+    int shortest = INT_MAX;
+    QModelIndex closest;
+    QVector<QModelIndex>::const_iterator it = candidates.begin();
+
+    for (; it != candidates.end(); ++it) {
+        if (!(*it).isValid())
+            continue;
+
+        const QRect indexRect = indexToListViewItem(*it).rect();
+
+        //if the center x (or y) position of an item is included in the rect of the other item,
+        //we define the distance between them as the difference in x (or y) of their respective center.
+        // Otherwise, we use the nahattan  length between the 2 items
+        if ((target.center().x() >= indexRect.x() && target.center().x() < indexRect.right())
+            || (indexRect.center().x() >= target.x() && indexRect.center().x() < target.right())) {
+                //one item's center is at the vertical of the other
+                distance = qAbs(indexRect.center().y() - target.center().y());
+        } else if ((target.center().y() >= indexRect.y() && target.center().y() < indexRect.bottom())
+            || (indexRect.center().y() >= target.y() && indexRect.center().y() < target.bottom())) {
+                //one item's center is at the vertical of the other
+                distance = qAbs(indexRect.center().x() - target.center().x());
+        } else {
+            distance = (indexRect.center() - target.center()).manhattanLength();
+        }
+        if (distance < shortest) {
+            shortest = distance;
+            closest = *it;
+        }
+    }
+    return closest;
+}
+
+QSize QListViewPrivate::itemSize(const QStyleOptionViewItem &option, const QModelIndex &index) const
+{
+    if (!uniformItemSizes) {
+        const QAbstractItemDelegate *delegate = delegateForIndex(index);
+        return delegate ? delegate->sizeHint(option, index) : QSize();
+    }
+    if (!cachedItemSize.isValid()) { // the last item is probaly the largest, so we use its size
+        int row = model->rowCount(root) - 1;
+        QModelIndex sample = model->index(row, column, root);
+        const QAbstractItemDelegate *delegate = delegateForIndex(sample);
+        cachedItemSize = delegate ? delegate->sizeHint(option, sample) : QSize();
+    }
+    return cachedItemSize;
+}
+
+QItemSelection QListViewPrivate::selection(const QRect &rect) const
+{
+    QItemSelection selection;
+    QModelIndex tl, br;
+    const QVector<QModelIndex> intersectVector = intersectingSet(rect);
+    QVector<QModelIndex>::const_iterator it = intersectVector.begin();
+    for (; it != intersectVector.end(); ++it) {
+        if (!tl.isValid() && !br.isValid()) {
+            tl = br = *it;
+        } else if ((*it).row() == (tl.row() - 1)) {
+            tl = *it; // expand current range
+        } else if ((*it).row() == (br.row() + 1)) {
+            br = (*it); // expand current range
+        } else {
+            selection.select(tl, br); // select current range
+            tl = br = *it; // start new range
+        }
+    }
+
+    if (tl.isValid() && br.isValid())
+        selection.select(tl, br);
+    else if (tl.isValid())
+        selection.select(tl, tl);
+    else if (br.isValid())
+        selection.select(br, br);
+
+    return selection;
+}
+
+/*
+ * Common ListView Implementation
+*/
+
+void QCommonListViewBase::appendHiddenRow(int row)
+{
+    dd->hiddenRows.append(dd->model->index(row, 0, qq->rootIndex()));
+}
+
+void QCommonListViewBase::removeHiddenRow(int row)
+{
+    dd->hiddenRows.remove(dd->hiddenRows.indexOf(dd->model->index(row, 0, qq->rootIndex())));
+}
+
+void QCommonListViewBase::updateHorizontalScrollBar(const QSize &step)
+{
+    horizontalScrollBar()->setSingleStep(step.width() + spacing());
+    horizontalScrollBar()->setPageStep(viewport()->width());
+    horizontalScrollBar()->setRange(0, contentsSize.width() - viewport()->width());
+}
+
+void QCommonListViewBase::updateVerticalScrollBar(const QSize &step)
+{
+    verticalScrollBar()->setSingleStep(step.height() + spacing());
+    verticalScrollBar()->setPageStep(viewport()->height());
+    verticalScrollBar()->setRange(0, contentsSize.height() - viewport()->height());
+}
+
+void QCommonListViewBase::scrollContentsBy(int dx, int dy, bool /*scrollElasticBand*/)
+{
+    dd->scrollContentsBy(isRightToLeft() ? -dx : dx, dy);
+}
+
+int QCommonListViewBase::verticalScrollToValue(int /*index*/, QListView::ScrollHint hint,
+                                          bool above, bool below, const QRect &area, const QRect &rect) const
+{
+    int verticalValue = verticalScrollBar()->value();
+    QRect adjusted = rect.adjusted(-spacing(), -spacing(), spacing(), spacing());
+    if (hint == QListView::PositionAtTop || above)
+        verticalValue += adjusted.top();
+    else if (hint == QListView::PositionAtBottom || below)
+        verticalValue += qMin(adjusted.top(), adjusted.bottom() - area.height() + 1);
+    else if (hint == QListView::PositionAtCenter)
+        verticalValue += adjusted.top() - ((area.height() - adjusted.height()) / 2);
+    return verticalValue;
+}
+
+int QCommonListViewBase::horizontalOffset() const
+{
+    return (isRightToLeft() ? horizontalScrollBar()->maximum() - horizontalScrollBar()->value() : horizontalScrollBar()->value());
+}
+
+int QCommonListViewBase::horizontalScrollToValue(const int /*index*/, QListView::ScrollHint hint,
+                                            bool leftOf, bool rightOf, const QRect &area, const QRect &rect) const
+{
+    int horizontalValue = horizontalScrollBar()->value();
+    if (isRightToLeft()) {
+        if (hint == QListView::PositionAtCenter) {
+            horizontalValue += ((area.width() - rect.width()) / 2) - rect.left();
+        } else {
+            if (leftOf)
+                horizontalValue -= rect.left();
+            else if (rightOf)
+                horizontalValue += qMin(rect.left(), area.width() - rect.right());
+        }
+    } else {
+        if (hint == QListView::PositionAtCenter) {
+            horizontalValue += rect.left() - ((area.width()- rect.width()) / 2);
+        } else {
+            if (leftOf)
+                horizontalValue += rect.left();
+            else if (rightOf)
+                horizontalValue += qMin(rect.left(), rect.right() - area.width());
+        }
+    }
+    return horizontalValue;
+}
+
+/*
+ * ListMode ListView Implementation
+*/
+
+#ifndef QT_NO_DRAGANDDROP
+void QListModeViewBase::paintDragDrop(QPainter *painter)
+{
+    // FIXME: Until the we can provide a proper drop indicator
+    // in IconMode, it makes no sense to show it
+    dd->paintDropIndicator(painter);
+}
+#endif //QT_NO_DRAGANDDROP
+
+void QListModeViewBase::updateVerticalScrollBar(const QSize &step)
+{
+    if (verticalScrollMode() == QAbstractItemView::ScrollPerItem
+        && ((flow() == QListView::TopToBottom && !isWrapping())
+        || (flow() == QListView::LeftToRight && isWrapping()))) {
+            const int steps = (flow() == QListView::TopToBottom ? scrollValueMap : segmentPositions).count() - 1;
+            if (steps > 0) {
+                const int pageSteps = perItemScrollingPageSteps(viewport()->height(), contentsSize.height(), isWrapping());
+                verticalScrollBar()->setSingleStep(1);
+                verticalScrollBar()->setPageStep(pageSteps);
+                verticalScrollBar()->setRange(0, steps - pageSteps);
+            } else {
+                verticalScrollBar()->setRange(0, 0);
+            }
+            // } else if (vertical && d->isWrapping() && d->movement == Static) {
+            // ### wrapped scrolling in flow direction
+    } else {
+        QCommonListViewBase::updateVerticalScrollBar(step);
+    }
+}
+
+void QListModeViewBase::updateHorizontalScrollBar(const QSize &step)
+{
+    if (horizontalScrollMode() == QAbstractItemView::ScrollPerItem
+        && ((flow() == QListView::TopToBottom && isWrapping())
+        || (flow() == QListView::LeftToRight && !isWrapping()))) {
+            int steps = (flow() == QListView::TopToBottom ? segmentPositions : scrollValueMap).count() - 1;
+            if (steps > 0) {
+                const int pageSteps = perItemScrollingPageSteps(viewport()->width(), contentsSize.width(), isWrapping());
+                horizontalScrollBar()->setSingleStep(1);
+                horizontalScrollBar()->setPageStep(pageSteps);
+                horizontalScrollBar()->setRange(0, steps - pageSteps);
+            } else {
+                horizontalScrollBar()->setRange(0, 0);
+            }
+    } else {
+        QCommonListViewBase::updateHorizontalScrollBar(step);
+    }
+}
+
+int QListModeViewBase::verticalScrollToValue(int index, QListView::ScrollHint hint,
+                                          bool above, bool below, const QRect &area, const QRect &rect) const
+{
+    if (verticalScrollMode() == QAbstractItemView::ScrollPerItem) {
+        int value;
+        if (scrollValueMap.isEmpty())
+            value = 0;
+        else
+            value = qBound(0, scrollValueMap.at(verticalScrollBar()->value()), flowPositions.count() - 1);
+        if (above)
+            hint = QListView::PositionAtTop;
+        else if (below)
+            hint = QListView::PositionAtBottom;
+        if (hint == QListView::EnsureVisible)
+            return value;
+
+        return perItemScrollToValue(index, value, area.height(), hint, Qt::Vertical, isWrapping(), rect.height());
+    }
+
+    return QCommonListViewBase::verticalScrollToValue(index, hint, above, below, area, rect);
+}
+
+int QListModeViewBase::horizontalOffset() const
+{
+    if (horizontalScrollMode() == QAbstractItemView::ScrollPerItem) {
+        if (isWrapping()) {
+            if (flow() == QListView::TopToBottom && !segmentPositions.isEmpty()) {
+                const int max = segmentPositions.count() - 1;
+                int currentValue = qBound(0, horizontalScrollBar()->value(), max);
+                int position = segmentPositions.at(currentValue);
+                int maximumValue = qBound(0, horizontalScrollBar()->maximum(), max);
+                int maximum = segmentPositions.at(maximumValue);
+                return (isRightToLeft() ? maximum - position : position);
+            }
+        } else if (flow() == QListView::LeftToRight && !flowPositions.isEmpty()) {
+            int position = flowPositions.at(scrollValueMap.at(horizontalScrollBar()->value()));
+            int maximum = flowPositions.at(scrollValueMap.at(horizontalScrollBar()->maximum()));
+            return (isRightToLeft() ? maximum - position : position);
+        }
+    }
+    return QCommonListViewBase::horizontalOffset();
+}
+
+int QListModeViewBase::verticalOffset() const
+{
+    if (verticalScrollMode() == QAbstractItemView::ScrollPerItem) {
+        if (isWrapping()) {
+            if (flow() == QListView::LeftToRight && !segmentPositions.isEmpty()) {
+                int value = verticalScrollBar()->value();
+                if (value >= segmentPositions.count())
+                    return 0;
+                return segmentPositions.at(value);
+            }
+        } else if (flow() == QListView::TopToBottom && !flowPositions.isEmpty()) {
+            int value = verticalScrollBar()->value();
+            if (value > scrollValueMap.count())
+                return 0;
+            return flowPositions.at(scrollValueMap.at(value)) - spacing();
+        }
+    }
+    return QCommonListViewBase::verticalOffset();
+}
+
+int QListModeViewBase::horizontalScrollToValue(int index, QListView::ScrollHint hint,
+                                            bool leftOf, bool rightOf, const QRect &area, const QRect &rect) const
+{
+    if (horizontalScrollMode() != QAbstractItemView::ScrollPerItem)
+        return QCommonListViewBase::horizontalScrollToValue(index, hint, leftOf, rightOf, area, rect);
+
+    int value;
+    if (scrollValueMap.isEmpty())
+        value = 0;
+    else
+        value = qBound(0, scrollValueMap.at(horizontalScrollBar()->value()), flowPositions.count() - 1);
+    if (leftOf)
+        hint = QListView::PositionAtTop;
+    else if (rightOf)
+        hint = QListView::PositionAtBottom;
+    if (hint == QListView::EnsureVisible)
+        return value;
+
+    return perItemScrollToValue(index, value, area.width(), hint, Qt::Horizontal, isWrapping(), rect.width());
+}
+
+void QListModeViewBase::scrollContentsBy(int dx, int dy, bool scrollElasticBand)
+{
+    // ### reorder this logic
+    const int verticalValue = verticalScrollBar()->value();
+    const int horizontalValue = horizontalScrollBar()->value();
+    const bool vertical = (verticalScrollMode() == QAbstractItemView::ScrollPerItem);
+    const bool horizontal = (horizontalScrollMode() == QAbstractItemView::ScrollPerItem);
+
+    if (isWrapping()) {
+        if (segmentPositions.isEmpty())
+            return;
+        const int max = segmentPositions.count() - 1;
+        if (horizontal && flow() == QListView::TopToBottom && dx != 0) {
+            int currentValue = qBound(0, horizontalValue, max);
+            int previousValue = qBound(0, currentValue + dx, max);
+            int currentCoordinate = segmentPositions.at(currentValue);
+            int previousCoordinate = segmentPositions.at(previousValue);
+            dx = previousCoordinate - currentCoordinate;
+        } else if (vertical && flow() == QListView::LeftToRight && dy != 0) {
+            int currentValue = qBound(0, verticalValue, max);
+            int previousValue = qBound(0, currentValue + dy, max);
+            int currentCoordinate = segmentPositions.at(currentValue);
+            int previousCoordinate = segmentPositions.at(previousValue);
+            dy = previousCoordinate - currentCoordinate;
+        }
+    } else {
+        if (flowPositions.isEmpty())
+            return;
+        const int max = flowPositions.count() - 1;
+        if (vertical && flow() == QListView::TopToBottom && dy != 0) {
+            int currentValue = qBound(0, verticalValue, max);
+            int previousValue = qBound(0, currentValue + dy, max);
+            int currentCoordinate = flowPositions.at(scrollValueMap.at(currentValue));
+            int previousCoordinate = flowPositions.at(scrollValueMap.at(previousValue));
+            dy = previousCoordinate - currentCoordinate;
+        } else if (horizontal && flow() == QListView::LeftToRight && dx != 0) {
+            int currentValue = qBound(0, horizontalValue, max);
+            int previousValue = qBound(0, currentValue + dx, max);
+            int currentCoordinate = flowPositions.at(scrollValueMap.at(currentValue));
+            int previousCoordinate = flowPositions.at(scrollValueMap.at(previousValue));
+            dx = previousCoordinate - currentCoordinate;
+        }
+    }
+    QCommonListViewBase::scrollContentsBy(dx, dy, scrollElasticBand);
+}
+
+bool QListModeViewBase::doBatchedItemLayout(const QListViewLayoutInfo &info, int max)
+{
+    doStaticLayout(info);
+    if (batchStartRow > max) { // stop items layout
+        flowPositions.resize(flowPositions.count());
+        segmentPositions.resize(segmentPositions.count());
+        segmentStartRows.resize(segmentStartRows.count());
+        return true; // done
+    }
+    return false; // not done
+}
+
+QListViewItem QListModeViewBase::indexToListViewItem(const QModelIndex &index) const
+{
+    if (flowPositions.isEmpty()
+        || segmentPositions.isEmpty()
+        || index.row() >= flowPositions.count())
+        return QListViewItem();
+
+    const int segment = qBinarySearch<int>(segmentStartRows, index.row(),
+                                           0, segmentStartRows.count() - 1);
+
+
+    QStyleOptionViewItemV4 options = viewOptions();
+    options.rect.setSize(contentsSize);
+    QSize size = (uniformItemSizes() && cachedItemSize().isValid())
+                 ? cachedItemSize() : itemSize(options, index);
+
+    QPoint pos;
+    if (flow() == QListView::LeftToRight) {
+        pos.setX(flowPositions.at(index.row()));
+        pos.setY(segmentPositions.at(segment));
+    } else { // TopToBottom
+        pos.setY(flowPositions.at(index.row()));
+        pos.setX(segmentPositions.at(segment));
+        if (isWrapping()) { // make the items as wide as the segment
+            int right = (segment + 1 >= segmentPositions.count()
+                     ? contentsSize.width()
+                     : segmentPositions.at(segment + 1));
+            size.setWidth(right - pos.x());
+        } else { // make the items as wide as the viewport
+            size.setWidth(qMax(size.width(), viewport()->width()));
+        }
+    }
+
+    return QListViewItem(QRect(pos, size), index.row());
+}
+
+QPoint QListModeViewBase::initStaticLayout(const QListViewLayoutInfo &info)
+{
+    int x, y;
+    if (info.first == 0) {
+        flowPositions.clear();
+        segmentPositions.clear();
+        segmentStartRows.clear();
+        segmentExtents.clear();
+        scrollValueMap.clear();
+        x = info.bounds.left() + info.spacing;
+        y = info.bounds.top() + info.spacing;
+        segmentPositions.append(info.flow == QListView::LeftToRight ? y : x);
+        segmentStartRows.append(0);
+    } else if (info.wrap) {
+        if (info.flow == QListView::LeftToRight) {
+            x = batchSavedPosition;
+            y = segmentPositions.last();
+        } else { // flow == QListView::TopToBottom
+            x = segmentPositions.last();
+            y = batchSavedPosition;
+        }
+    } else { // not first and not wrap
+        if (info.flow == QListView::LeftToRight) {
+            x = batchSavedPosition;
+            y = info.bounds.top() + info.spacing;
+        } else { // flow == QListView::TopToBottom
+            x = info.bounds.left() + info.spacing;
+            y = batchSavedPosition;
+        }
+    }
+    return QPoint(x, y);
+}
+
+/*!
+  \internal
+*/
+void QListModeViewBase::doStaticLayout(const QListViewLayoutInfo &info)
+{
+    const bool useItemSize = !info.grid.isValid();
+    const QPoint topLeft = initStaticLayout(info);
+    QStyleOptionViewItemV4 option = viewOptions();
+    option.rect = info.bounds;
+
+    // The static layout data structures are as follows:
+    // One vector contains the coordinate in the direction of layout flow.
+    // Another vector contains the coordinates of the segments.
+    // A third vector contains the index (model row) of the first item
+    // of each segment.
+
+    int segStartPosition;
+    int segEndPosition;
+    int deltaFlowPosition;
+    int deltaSegPosition;
+    int deltaSegHint;
+    int flowPosition;
+    int segPosition;
+
+    if (info.flow == QListView::LeftToRight) {
+        segStartPosition = info.bounds.left();
+        segEndPosition = info.bounds.width();
+        flowPosition = topLeft.x();
+        segPosition = topLeft.y();
+        deltaFlowPosition = info.grid.width(); // dx
+        deltaSegPosition = useItemSize ? batchSavedDeltaSeg : info.grid.height(); // dy
+        deltaSegHint = info.grid.height();
+    } else { // flow == QListView::TopToBottom
+        segStartPosition = info.bounds.top();
+        segEndPosition = info.bounds.height();
+        flowPosition = topLeft.y();
+        segPosition = topLeft.x();
+        deltaFlowPosition = info.grid.height(); // dy
+        deltaSegPosition = useItemSize ? batchSavedDeltaSeg : info.grid.width(); // dx
+        deltaSegHint = info.grid.width();
+    }
+
+    for (int row = info.first; row <= info.last; ++row) {
+        if (isHidden(row)) { // ###
+            flowPositions.append(flowPosition);
+        } else {
+            // if we are not using a grid, we need to find the deltas
+            if (useItemSize) {
+                QSize hint = itemSize(option, modelIndex(row));
+                if (info.flow == QListView::LeftToRight) {
+                    deltaFlowPosition = hint.width() + info.spacing;
+                    deltaSegHint = hint.height() + info.spacing;
+                } else { // TopToBottom
+                    deltaFlowPosition = hint.height() + info.spacing;
+                    deltaSegHint = hint.width() + info.spacing;
+                }
+            }
+            // create new segment
+            if (info.wrap && (flowPosition + deltaFlowPosition >= segEndPosition)) {
+                segmentExtents.append(flowPosition);
+                flowPosition = info.spacing + segStartPosition;
+                segPosition += deltaSegPosition;
+                segmentPositions.append(segPosition);
+                segmentStartRows.append(row);
+                deltaSegPosition = 0;
+            }
+            // save the flow position of this item
+            scrollValueMap.append(flowPositions.count());
+            flowPositions.append(flowPosition);
+            // prepare for the next item
+            deltaSegPosition = qMax(deltaSegHint, deltaSegPosition);
+            flowPosition += info.spacing + deltaFlowPosition;
+        }
+    }
+    // used when laying out next batch
+    batchSavedPosition = flowPosition;
+    batchSavedDeltaSeg = deltaSegPosition;
+    batchStartRow = info.last + 1;
+    if (info.last == info.max)
+        flowPosition -= info.spacing; // remove extra spacing
+    // set the contents size
+    QRect rect = info.bounds;
+    if (info.flow == QListView::LeftToRight) {
+        rect.setRight(segmentPositions.count() == 1 ? flowPosition : info.bounds.right());
+        rect.setBottom(segPosition + deltaSegPosition);
+    } else { // TopToBottom
+        rect.setRight(segPosition + deltaSegPosition);
+        rect.setBottom(segmentPositions.count() == 1 ? flowPosition : info.bounds.bottom());
+    }
+    contentsSize = QSize(rect.right(), rect.bottom());
+    // if it is the last batch, save the end of the segments
+    if (info.last == info.max) {
+        segmentExtents.append(flowPosition);
+        scrollValueMap.append(flowPositions.count());
+        flowPositions.append(flowPosition);
+        segmentPositions.append(info.wrap ? segPosition + deltaSegPosition : INT_MAX);
+    }
+    // if the new items are visble, update the viewport
+    QRect changedRect(topLeft, rect.bottomRight());
+    if (clipRect().intersects(changedRect))
+        viewport()->update();
+}
+
+/*!
+  \internal
+  Finds the set of items intersecting with \a area.
+  In this function, itemsize is counted from topleft to the start of the next item.
+*/
+QVector<QModelIndex> QListModeViewBase::intersectingSet(const QRect &area) const
+{
+    QVector<QModelIndex> ret;
+    int segStartPosition;
+    int segEndPosition;
+    int flowStartPosition;
+    int flowEndPosition;
+    if (flow() == QListView::LeftToRight) {
+        segStartPosition = area.top();
+        segEndPosition = area.bottom();
+        flowStartPosition = area.left();
+        flowEndPosition = area.right();
+    } else {
+        segStartPosition = area.left();
+        segEndPosition = area.right();
+        flowStartPosition = area.top();
+        flowEndPosition = area.bottom();
+    }
+    if (segmentPositions.count() < 2 || flowPositions.isEmpty())
+        return ret;
+    // the last segment position is actually the edge of the last segment
+    const int segLast = segmentPositions.count() - 2;
+    int seg = qBinarySearch<int>(segmentPositions, segStartPosition, 0, segLast + 1);
+    for (; seg <= segLast && segmentPositions.at(seg) <= segEndPosition; ++seg) {
+        int first = segmentStartRows.at(seg);
+        int last = (seg < segLast ? segmentStartRows.at(seg + 1) : batchStartRow) - 1;
+        if (segmentExtents.at(seg) < flowStartPosition)
+            continue;
+        int row = qBinarySearch<int>(flowPositions, flowStartPosition, first, last);
+        for (; row <= last && flowPositions.at(row) <= flowEndPosition; ++row) {
+            if (isHidden(row))
+                continue;
+            QModelIndex index = modelIndex(row);
+            if (index.isValid())
+                ret += index;
+#if 0 // for debugging
+            else
+                qWarning("intersectingSet: row %d was invalid", row);
+#endif
+        }
+    }
+    return ret;
+}
+
+QRect QListModeViewBase::mapToViewport(const QRect &rect) const
+{
+    if (isWrapping())
+        return rect;
+    // If the listview is in "listbox-mode", the items are as wide as the view.
+    // But we don't shrink the items.
+    QRect result = rect;
+    if (flow() == QListView::TopToBottom) {
+        result.setLeft(spacing());
+        result.setWidth(qMax(rect.width(), qMax(contentsSize.width(), viewport()->width()) - 2 * spacing()));
+    } else { // LeftToRight
+        result.setTop(spacing());
+        result.setHeight(qMax(rect.height(), qMax(contentsSize.height(), viewport()->height()) - 2 * spacing()));
+    }
+    return result;
+}
+
+int QListModeViewBase::perItemScrollingPageSteps(int length, int bounds, bool wrap) const
+{
+    QVector<int> positions;
+    if (wrap)
+        positions = segmentPositions;
+    else if (!flowPositions.isEmpty()) {
+        positions.reserve(scrollValueMap.size());
+        foreach (int itemShown, scrollValueMap)
+            positions.append(flowPositions.at(itemShown));
+    }
+    if (positions.isEmpty() || bounds <= length)
+        return positions.count();
+    if (uniformItemSizes()) {
+        for (int i = 1; i < positions.count(); ++i)
+            if (positions.at(i) > 0)
+                return length / positions.at(i);
+        return 0; // all items had height 0
+    }
+    int pageSteps = 0;
+    int steps = positions.count() - 1;
+    int max = qMax(length, bounds);
+    int min = qMin(length, bounds);
+    int pos = min - (max - positions.last());
+
+    while (pos >= 0 && steps > 0) {
+        pos -= (positions.at(steps) - positions.at(steps - 1));
+        if (pos >= 0) //this item should be visible
+            ++pageSteps;
+        --steps;
+    }
+
+    // at this point we know that positions has at least one entry
+    return qMax(pageSteps, 1);
+}
+
+int QListModeViewBase::perItemScrollToValue(int index, int scrollValue, int viewportSize,
+                                                 QAbstractItemView::ScrollHint hint,
+                                                 Qt::Orientation orientation, bool wrap, int itemExtent) const
+{
+    if (index < 0)
+        return scrollValue;
+    if (!wrap) {
+        int topIndex = index;
+        const int bottomIndex = topIndex;
+        const int bottomCoordinate = flowPositions.at(index);
+
+        while (topIndex > 0 &&
+            (bottomCoordinate - flowPositions.at(topIndex-1) + itemExtent) <= (viewportSize)) {
+            topIndex--;
+        }
+
+        const int itemCount = bottomIndex - topIndex + 1;
+        switch (hint) {
+        case QAbstractItemView::PositionAtTop:
+            return index;
+        case QAbstractItemView::PositionAtBottom:
+            return index - itemCount + 1;
+        case QAbstractItemView::PositionAtCenter:
+            return index - (itemCount / 2);
+        default:
+            break;
+        }
+    } else { // wrapping
+        Qt::Orientation flowOrientation = (flow() == QListView::LeftToRight
+                                           ? Qt::Horizontal : Qt::Vertical);
+        if (flowOrientation == orientation) { // scrolling in the "flow" direction
+            // ### wrapped scrolling in the flow direction
+            return flowPositions.at(index); // ### always pixel based for now
+        } else if (!segmentStartRows.isEmpty()) { // we are scrolling in the "segment" direction
+            int segment = qBinarySearch<int>(segmentStartRows, index, 0, segmentStartRows.count() - 1);
+            int leftSegment = segment;
+            const int rightSegment = leftSegment;
+            const int bottomCoordinate = segmentPositions.at(segment);
+
+            while (leftSegment > scrollValue &&
+                (bottomCoordinate - segmentPositions.at(leftSegment-1) + itemExtent) <= (viewportSize)) {
+                    leftSegment--;
+            }
+
+            const int segmentCount = rightSegment - leftSegment + 1;
+            switch (hint) {
+            case QAbstractItemView::PositionAtTop:
+                return segment;
+            case QAbstractItemView::PositionAtBottom:
+                return segment - segmentCount + 1;
+            case QAbstractItemView::PositionAtCenter:
+                return segment - (segmentCount / 2);
+            default:
+                break;
+            }
+        }
+    }
+    return scrollValue;
+}
+
+void QListModeViewBase::clear()
+{
+    flowPositions.clear();
+    segmentPositions.clear();
+    segmentStartRows.clear();
+    segmentExtents.clear();
+    batchSavedPosition = 0;
+    batchStartRow = 0;
+    batchSavedDeltaSeg = 0;
+}
+
+/*
+ * IconMode ListView Implementation
+*/
+
+void QIconModeViewBase::setPositionForIndex(const QPoint &position, const QModelIndex &index)
+{
+    if (index.row() >= items.count())
+        return;
+    const QSize oldContents = contentsSize;
+    qq->update(index); // update old position
+    moveItem(index.row(), position);
+    qq->update(index); // update new position
+
+    if (contentsSize != oldContents)
+        dd->viewUpdateGeometries(); // update the scroll bars
+}
+
+void QIconModeViewBase::appendHiddenRow(int row)
+{
+    if (row >= 0 && row < items.count()) //remove item
+        tree.removeLeaf(items.at(row).rect(), row);
+    QCommonListViewBase::appendHiddenRow(row);
+}
+
+void QIconModeViewBase::removeHiddenRow(int row)
+{
+    QCommonListViewBase::removeHiddenRow(row);
+    if (row >= 0 && row < items.count()) //insert item
+        tree.insertLeaf(items.at(row).rect(), row);
+}
+
+#ifndef QT_NO_DRAGANDDROP
+void QIconModeViewBase::paintDragDrop(QPainter *painter)
+{
+    if (!draggedItems.isEmpty() && viewport()->rect().contains(draggedItemsPos)) {
+        //we need to draw the items that arre dragged
+        painter->translate(draggedItemsDelta());
+        QStyleOptionViewItemV4 option = viewOptions();
+        option.state &= ~QStyle::State_MouseOver;
+        QVector<QModelIndex>::const_iterator it = draggedItems.begin();
+        QListViewItem item = indexToListViewItem(*it);
+        for (; it != draggedItems.end(); ++it) {
+            item = indexToListViewItem(*it);
+            option.rect = viewItemRect(item);
+            delegate(*it)->paint(painter, option, *it);
+        }
+    }
+}
+
+bool QIconModeViewBase::filterStartDrag(Qt::DropActions supportedActions)
+{
+    // This function does the same thing as in QAbstractItemView::startDrag(),
+    // plus adding viewitems to the draggedItems list.
+    // We need these items to draw the drag items
+    QModelIndexList indexes = dd->selectionModel->selectedIndexes();
+    if (indexes.count() > 0 ) {
+        if (viewport()->acceptDrops()) {
+            QModelIndexList::ConstIterator it = indexes.constBegin();
+            for (; it != indexes.constEnd(); ++it)
+                if (dd->model->flags(*it) & Qt::ItemIsDragEnabled
+                    && (*it).column() == dd->column)
+                    draggedItems.push_back(*it);
+        }
+        QDrag *drag = new QDrag(qq);
+        drag->setMimeData(dd->model->mimeData(indexes));
+        Qt::DropAction action = drag->exec(supportedActions, Qt::CopyAction);
+        draggedItems.clear();
+        if (action == Qt::MoveAction)
+            dd->clearOrRemove();
+    }
+    return true;
+}
+
+bool QIconModeViewBase::filterDropEvent(QDropEvent *e)
+{
+    if (e->source() != qq)
+        return false;
+
+    const QSize contents = contentsSize;
+    QPoint offset(horizontalOffset(), verticalOffset());
+    QPoint end = e->pos() + offset;
+    QPoint start = dd->pressedPosition;
+    QPoint delta = (dd->movement == QListView::Snap ? snapToGrid(end) - snapToGrid(start) : end - start);
+    QList<QModelIndex> indexes = dd->selectionModel->selectedIndexes();
+    for (int i = 0; i < indexes.count(); ++i) {
+        QModelIndex index = indexes.at(i);
+        QRect rect = dd->rectForIndex(index);
+        viewport()->update(dd->mapToViewport(rect, false));
+        QPoint dest = rect.topLeft() + delta;
+        if (qq->isRightToLeft())
+            dest.setX(dd->flipX(dest.x()) - rect.width());
+        moveItem(index.row(), dest);
+        qq->update(index);
+    }
+    dd->stopAutoScroll();
+    draggedItems.clear();
+    dd->emitIndexesMoved(indexes);
+    e->accept(); // we have handled the event
+    // if the size has not grown, we need to check if it has shrinked
+    if (contentsSize != contents) {
+        if ((contentsSize.width() <= contents.width()
+            || contentsSize.height() <= contents.height())) {
+                updateContentsSize();
+        }
+        dd->viewUpdateGeometries();
+    }
+    return true;
+}
+
+bool QIconModeViewBase::filterDragLeaveEvent(QDragLeaveEvent *e)
+{
+    viewport()->update(draggedItemsRect()); // erase the area
+    draggedItemsPos = QPoint(-1, -1); // don't draw the dragged items
+    return QCommonListViewBase::filterDragLeaveEvent(e);
+}
+
+bool QIconModeViewBase::filterDragMoveEvent(QDragMoveEvent *e)
+{
+    if (e->source() != qq || !dd->canDecode(e))
+        return false;
+
+    // ignore by default
+    e->ignore();
+    // get old dragged items rect
+    QRect itemsRect = this->itemsRect(draggedItems);
+    viewport()->update(itemsRect.translated(draggedItemsDelta()));
+    // update position
+    draggedItemsPos = e->pos();
+    // get new items rect
+    viewport()->update(itemsRect.translated(draggedItemsDelta()));
+    // set the item under the cursor to current
+    QModelIndex index;
+    if (movement() == QListView::Snap) {
+        QRect rect(snapToGrid(e->pos() + offset()), gridSize());
+        const QVector<QModelIndex> intersectVector = intersectingSet(rect);
+        index = intersectVector.count() > 0 ? intersectVector.last() : QModelIndex();
+    } else {
+        index = qq->indexAt(e->pos());
+    }
+    // check if we allow drops here
+    if (draggedItems.contains(index))
+        e->accept(); // allow changing item position
+    else if (dd->model->flags(index) & Qt::ItemIsDropEnabled)
+        e->accept(); // allow dropping on dropenabled items
+    else if (!index.isValid())
+        e->accept(); // allow dropping in empty areas
+
+    // the event was treated. do autoscrolling
+    if (dd->shouldAutoScroll(e->pos()))
+        dd->startAutoScroll();
+    return true;
+}
+#endif // QT_NO_DRAGANDDROP
+
+void QIconModeViewBase::setRowCount(int rowCount)
+{
+    tree.create(qMax(rowCount - hiddenCount(), 0));
+}
+
+void QIconModeViewBase::scrollContentsBy(int dx, int dy, bool scrollElasticBand)
+{
+    if (scrollElasticBand)
+        dd->scrollElasticBandBy(isRightToLeft() ? -dx : dx, dy);
+
+    QCommonListViewBase::scrollContentsBy(dx, dy, scrollElasticBand);
+    if (!draggedItems.isEmpty())
+        viewport()->update(draggedItemsRect().translated(dx, dy));
+}
+
+void QIconModeViewBase::dataChanged(const QModelIndex &topLeft, const QModelIndex &bottomRight)
+{
+    if (column() >= topLeft.column() && column() <= bottomRight.column())  {
+        QStyleOptionViewItemV4 option = viewOptions();
+        int bottom = qMin(items.count(), bottomRight.row() + 1);
+        for (int row = topLeft.row(); row < bottom; ++row)
+            items[row].resize(itemSize(option, modelIndex(row)));
+    }
+}
+
+bool QIconModeViewBase::doBatchedItemLayout(const QListViewLayoutInfo &info, int max)
+{
+    if (info.last >= items.count()) {
+        //first we create the items
+        QStyleOptionViewItemV4 option = viewOptions();
+        for (int row = items.count(); row <= info.last; ++row) {
+            QSize size = itemSize(option, modelIndex(row));
+            QListViewItem item(QRect(0, 0, size.width(), size.height()), row); // default pos
+            items.append(item);
+        }
+        doDynamicLayout(info);
+    }
+    return (batchStartRow > max); // done
+}
+
+QListViewItem QIconModeViewBase::indexToListViewItem(const QModelIndex &index) const
+{
+    if (index.isValid() && index.row() < items.count())
+        return items.at(index.row());
+    return QListViewItem();
+}
+
+void QIconModeViewBase::initBspTree(const QSize &contents)
+{
+    // remove all items from the tree
+    int leafCount = tree.leafCount();
+    for (int l = 0; l < leafCount; ++l)
+        tree.leaf(l).clear();
+    // we have to get the bounding rect of the items before we can initialize the tree
+    QBspTree::Node::Type type = QBspTree::Node::Both; // 2D
+    // simple heuristics to get better bsp
+    if (contents.height() / contents.width() >= 3)
+        type = QBspTree::Node::HorizontalPlane;
+    else if (contents.width() / contents.height() >= 3)
+        type = QBspTree::Node::VerticalPlane;
+    // build tree for the bounding rect (not just the contents rect)
+    tree.init(QRect(0, 0, contents.width(), contents.height()), type);
+}
+
+QPoint QIconModeViewBase::initDynamicLayout(const QListViewLayoutInfo &info)
+{
+    int x, y;
+    if (info.first == 0) {
+        x = info.bounds.x() + info.spacing;
+        y = info.bounds.y() + info.spacing;
+        items.reserve(rowCount() - hiddenCount());
+    } else {
+        const QListViewItem item = items.at(info.first - 1);
+        x = item.x;
+        y = item.y;
+        if (info.flow == QListView::LeftToRight)
+            x += (info.grid.isValid() ? info.grid.width() : item.w) + info.spacing;
+        else
+            y += (info.grid.isValid() ? info.grid.height() : item.h) + info.spacing;
+    }
+    return QPoint(x, y);
+}
+
+/*!
+  \internal
+*/
+void QIconModeViewBase::doDynamicLayout(const QListViewLayoutInfo &info)
+{
+    const bool useItemSize = !info.grid.isValid();
+    const QPoint topLeft = initDynamicLayout(info);
+
+    int segStartPosition;
+    int segEndPosition;
+    int deltaFlowPosition;
+    int deltaSegPosition;
+    int deltaSegHint;
+    int flowPosition;
+    int segPosition;
+
+    if (info.flow == QListView::LeftToRight) {
+        segStartPosition = info.bounds.left() + info.spacing;
+        segEndPosition = info.bounds.right();
+        deltaFlowPosition = info.grid.width(); // dx
+        deltaSegPosition = (useItemSize ? batchSavedDeltaSeg : info.grid.height()); // dy
+        deltaSegHint = info.grid.height();
+        flowPosition = topLeft.x();
+        segPosition = topLeft.y();
+    } else { // flow == QListView::TopToBottom
+        segStartPosition = info.bounds.top() + info.spacing;
+        segEndPosition = info.bounds.bottom();
+        deltaFlowPosition = info.grid.height(); // dy
+        deltaSegPosition = (useItemSize ? batchSavedDeltaSeg : info.grid.width()); // dx
+        deltaSegHint = info.grid.width();
+        flowPosition = topLeft.y();
+        segPosition = topLeft.x();
+    }
+
+    if (moved.count() != items.count())
+        moved.resize(items.count());
+
+    QRect rect(QPoint(), topLeft);
+    QListViewItem *item = 0;
+    for (int row = info.first; row <= info.last; ++row) {
+        item = &items[row];
+        if (isHidden(row)) {
+            item->invalidate();
+        } else {
+            // if we are not using a grid, we need to find the deltas
+            if (useItemSize) {
+                if (info.flow == QListView::LeftToRight)
+                    deltaFlowPosition = item->w + info.spacing;
+                else
+                    deltaFlowPosition = item->h + info.spacing;
+            } else {
+                item->w = qMin<int>(info.grid.width(), item->w);
+                item->h = qMin<int>(info.grid.height(), item->h);
+            }
+
+            // create new segment
+            if (info.wrap
+                && flowPosition + deltaFlowPosition > segEndPosition
+                && flowPosition > segStartPosition) {
+                flowPosition = segStartPosition;
+                segPosition += deltaSegPosition;
+                if (useItemSize)
+                    deltaSegPosition = 0;
+            }
+            // We must delay calculation of the seg adjustment, as this item
+            // may have caused a wrap to occur
+            if (useItemSize) {
+                if (info.flow == QListView::LeftToRight)
+                    deltaSegHint = item->h + info.spacing;
+                else
+                    deltaSegHint = item->w + info.spacing;
+                deltaSegPosition = qMax(deltaSegPosition, deltaSegHint);
+            }
+
+            // set the position of the item
+            // ### idealy we should have some sort of alignment hint for the item
+            // ### (normally that would be a point between the icon and the text)
+            if (!moved.testBit(row)) {
+                if (info.flow == QListView::LeftToRight) {
+                    if (useItemSize) {
+                        item->x = flowPosition;
+                        item->y = segPosition;
+                    } else { // use grid
+                        item->x = flowPosition + ((deltaFlowPosition - item->w) / 2);
+                        item->y = segPosition;
+                    }
+                } else { // TopToBottom
+                    if (useItemSize) {
+                        item->y = flowPosition;
+                        item->x = segPosition;
+                    } else { // use grid
+                        item->y = flowPosition + ((deltaFlowPosition - item->h) / 2);
+                        item->x = segPosition;
+                    }
+                }
+            }
+
+            // let the contents contain the new item
+            if (useItemSize)
+                rect |= item->rect();
+            else if (info.flow == QListView::LeftToRight)
+                rect |= QRect(flowPosition, segPosition, deltaFlowPosition, deltaSegPosition);
+            else // flow == TopToBottom
+                rect |= QRect(segPosition, flowPosition, deltaSegPosition, deltaFlowPosition);
+
+            // prepare for next item
+            flowPosition += deltaFlowPosition; // current position + item width + gap
+        }
+    }
+    batchSavedDeltaSeg = deltaSegPosition;
+    batchStartRow = info.last + 1;
+    bool done = (info.last >= rowCount() - 1);
+    // resize the content area
+    if (done || !info.bounds.contains(item->rect()))
+        contentsSize = QSize(rect.width(), rect.height());
+    // resize tree
+    int insertFrom = info.first;
+    if (done || info.first == 0) {
+        initBspTree(rect.size());
+        insertFrom = 0;
+    }
+    // insert items in tree
+    for (int row = insertFrom; row <= info.last; ++row)
+        tree.insertLeaf(items.at(row).rect(), row);
+    // if the new items are visble, update the viewport
+    QRect changedRect(topLeft, rect.bottomRight());
+    if (clipRect().intersects(changedRect))
+        viewport()->update();
+}
+
+QVector<QModelIndex> QIconModeViewBase::intersectingSet(const QRect &area) const
+{
+    QIconModeViewBase *that = const_cast<QIconModeViewBase*>(this);
+    QBspTree::Data data(static_cast<void*>(that));
+    QVector<QModelIndex> res;
+    that->interSectingVector = &res;
+    that->tree.climbTree(area, &QIconModeViewBase::addLeaf, data);
+    that->interSectingVector = 0;
+    return res;
+}
+
+QRect QIconModeViewBase::itemsRect(const QVector<QModelIndex> &indexes) const
+{
+    QVector<QModelIndex>::const_iterator it = indexes.begin();
+    QListViewItem item = indexToListViewItem(*it);
+    QRect rect(item.x, item.y, item.w, item.h);
+    for (; it != indexes.end(); ++it) {
+        item = indexToListViewItem(*it);
+        rect |= viewItemRect(item);
+    }
+    return rect;
+}
+
+int QIconModeViewBase::itemIndex(const QListViewItem &item) const
+{
+    if (!item.isValid())
+        return -1;
+    int i = item.indexHint;
+    if (i < items.count()) {
+        if (items.at(i) == item)
+            return i;
+    } else {
+        i = items.count() - 1;
+    }
+
+    int j = i;
+    int c = items.count();
+    bool a = true;
+    bool b = true;
+
+    while (a || b) {
+        if (a) {
+            if (items.at(i) == item) {
+                items.at(i).indexHint = i;
+                return i;
+            }
+            a = ++i < c;
+        }
+        if (b) {
+            if (items.at(j) == item) {
+                items.at(j).indexHint = j;
+                return j;
+            }
+            b = --j > -1;
+        }
+    }
+    return -1;
+}
+
+void QIconModeViewBase::addLeaf(QVector<int> &leaf, const QRect &area,
+                                   uint visited, QBspTree::Data data)
+{
+    QListViewItem *vi;
+    QIconModeViewBase *_this = static_cast<QIconModeViewBase *>(data.ptr);
+    for (int i = 0; i < leaf.count(); ++i) {
+        int idx = leaf.at(i);
+        if (idx < 0 || idx >= _this->items.count())
+            continue;
+        vi = &_this->items[idx];
+        Q_ASSERT(vi);
+        if (vi->isValid() && vi->rect().intersects(area) && vi->visited != visited) {
+            QModelIndex index  = _this->dd->listViewItemToIndex(*vi);
+            Q_ASSERT(index.isValid());
+            _this->interSectingVector->append(index);
+            vi->visited = visited;
+        }
+    }
+}
+
+void QIconModeViewBase::moveItem(int index, const QPoint &dest)
+{
+    // does not impact on the bintree itself or the contents rect
+    QListViewItem *item = &items[index];
+    QRect rect = item->rect();
+
+    // move the item without removing it from the tree
+    tree.removeLeaf(rect, index);
+    item->move(dest);
+    tree.insertLeaf(QRect(dest, rect.size()), index);
+
+    // resize the contents area
+    contentsSize = (QRect(QPoint(0, 0), contentsSize)|QRect(dest, rect.size())).size();
+
+    // mark the item as moved
+    if (moved.count() != items.count())
+        moved.resize(items.count());
+    moved.setBit(index, true);
+}
+
+QPoint QIconModeViewBase::snapToGrid(const QPoint &pos) const
+{
+    int x = pos.x() - (pos.x() % gridSize().width());
+    int y = pos.y() - (pos.y() % gridSize().height());
+    return QPoint(x, y);
+}
+
+QPoint QIconModeViewBase::draggedItemsDelta() const
+{
+    if (movement() == QListView::Snap) {
+        QPoint snapdelta = QPoint((offset().x() % gridSize().width()),
+                                  (offset().y() % gridSize().height()));
+        return snapToGrid(draggedItemsPos + snapdelta) - snapToGrid(pressedPosition()) - snapdelta;
+    }
+    return draggedItemsPos - pressedPosition();
+}
+
+QRect QIconModeViewBase::draggedItemsRect() const
+{
+    QRect rect = itemsRect(draggedItems);
+    rect.translate(draggedItemsDelta());
+    return rect;
+}
+
+void QListViewPrivate::scrollElasticBandBy(int dx, int dy)
+{
+    if (dx > 0) // right
+        elasticBand.moveRight(elasticBand.right() + dx);
+    else if (dx < 0) // left
+        elasticBand.moveLeft(elasticBand.left() - dx);
+    if (dy > 0) // down
+        elasticBand.moveBottom(elasticBand.bottom() + dy);
+    else if (dy < 0) // up
+        elasticBand.moveTop(elasticBand.top() - dy);
+}
+
+void QIconModeViewBase::clear()
+{
+    tree.destroy();
+    items.clear();
+    moved.clear();
+    batchStartRow = 0;
+    batchSavedDeltaSeg = 0;
+}
+
+void QIconModeViewBase::updateContentsSize()
+{
+    QRect bounding;
+    for (int i = 0; i < items.count(); ++i)
+        bounding |= items.at(i).rect();
+    contentsSize = bounding.size();
+}
+
+/*!
+  \reimp
+*/
+void QListView::currentChanged(const QModelIndex &current, const QModelIndex &previous)
+{
+#ifndef QT_NO_ACCESSIBILITY
+    if (QAccessible::isActive()) {
+        if (current.isValid()) {
+            int entry = visualIndex(current) + 1;
+            QAccessible::updateAccessibility(viewport(), entry, QAccessible::Focus);
+        }
+    }
+#endif
+    QAbstractItemView::currentChanged(current, previous);
+}
+
+/*!
+  \reimp
+*/
+void QListView::selectionChanged(const QItemSelection &selected,
+                                 const QItemSelection &deselected)
+{
+#ifndef QT_NO_ACCESSIBILITY
+    if (QAccessible::isActive()) {
+        // ### does not work properly for selection ranges.
+        QModelIndex sel = selected.indexes().value(0);
+        if (sel.isValid()) {
+            int entry = visualIndex(sel) + 1;
+            QAccessible::updateAccessibility(viewport(), entry, QAccessible::Selection);
+        }
+        QModelIndex desel = deselected.indexes().value(0);
+        if (desel.isValid()) {
+            int entry = visualIndex(desel) + 1;
+            QAccessible::updateAccessibility(viewport(), entry, QAccessible::SelectionRemove);
+        }
+    }
+#endif
+    QAbstractItemView::selectionChanged(selected, deselected);
+}
+
+int QListView::visualIndex(const QModelIndex &index) const
+{
+    Q_D(const QListView);
+    d->executePostedLayout();
+    QListViewItem itm = d->indexToListViewItem(index);
+    return d->commonListView->itemIndex(itm);
+}
+
+QT_END_NAMESPACE
+
+#endif // QT_NO_LISTVIEW