src/gui/itemviews/qtreeview.cpp
changeset 0 1918ee327afb
child 3 41300fa6a67c
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/gui/itemviews/qtreeview.cpp	Mon Jan 11 14:00:40 2010 +0000
@@ -0,0 +1,3856 @@
+/****************************************************************************
+**
+** 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 "qtreeview.h"
+
+#ifndef QT_NO_TREEVIEW
+#include <qheaderview.h>
+#include <qitemdelegate.h>
+#include <qapplication.h>
+#include <qscrollbar.h>
+#include <qpainter.h>
+#include <qstack.h>
+#include <qstyle.h>
+#include <qstyleoption.h>
+#include <qevent.h>
+#include <qpen.h>
+#include <qdebug.h>
+#ifndef QT_NO_ACCESSIBILITY
+#include <qaccessible.h>
+#endif
+
+#include <private/qtreeview_p.h>
+
+QT_BEGIN_NAMESPACE
+
+/*!
+    \class QTreeView
+    \brief The QTreeView class provides a default model/view implementation of a tree view.
+
+    \ingroup model-view
+    \ingroup advanced
+
+
+    A QTreeView implements a tree representation of items from a
+    model. This class is used to provide standard hierarchical lists that
+    were previously provided by the \c QListView class, but using the more
+    flexible approach provided by Qt's model/view architecture.
+
+    The QTreeView class is one of the \l{Model/View Classes} and is part of
+    Qt's \l{Model/View Programming}{model/view framework}.
+
+    QTreeView implements the interfaces defined by the
+    QAbstractItemView class to allow it to display data provided by
+    models derived from the QAbstractItemModel class.
+
+    It is simple to construct a tree view displaying data from a
+    model. In the following example, the contents of a directory are
+    supplied by a QDirModel and displayed as a tree:
+
+    \snippet doc/src/snippets/shareddirmodel/main.cpp 3
+    \snippet doc/src/snippets/shareddirmodel/main.cpp 6
+
+    The model/view architecture ensures that the contents of the tree view
+    are updated as the model changes.
+
+    Items that have children can be in an expanded (children are
+    visible) or collapsed (children are hidden) state. When this state
+    changes a collapsed() or expanded() signal is emitted with the
+    model index of the relevant item.
+
+    The amount of indentation used to indicate levels of hierarchy is
+    controlled by the \l indentation property.
+
+    Headers in tree views are constructed using the QHeaderView class and can
+    be hidden using \c{header()->hide()}. Note that each header is configured
+    with its \l{QHeaderView::}{stretchLastSection} property set to true,
+    ensuring that the view does not waste any of the space assigned to it for
+    its header. If this value is set to true, this property will override the
+    resize mode set on the last section in the header.
+
+
+    \section1 Key Bindings
+
+    QTreeView supports a set of key bindings that enable the user to
+    navigate in the view and interact with the contents of items:
+
+    \table
+    \header \o Key \o Action
+    \row \o Up   \o Moves the cursor to the item in the same column on
+         the previous row. If the parent of the current item has no more rows to
+         navigate to, the cursor moves to the relevant item in the last row
+         of the sibling that precedes the parent.
+    \row \o Down \o Moves the cursor to the item in the same column on
+         the next row. If the parent of the current item has no more rows to
+         navigate to, the cursor moves to the relevant item in the first row
+         of the sibling that follows the parent.
+    \row \o Left  \o Hides the children of the current item (if present)
+         by collapsing a branch.
+    \row \o Minus  \o Same as LeftArrow.
+    \row \o Right \o Reveals the children of the current item (if present)
+         by expanding a branch.
+    \row \o Plus  \o Same as RightArrow.
+    \row \o Asterisk  \o Expands all children of the current item (if present).
+    \row \o PageUp   \o Moves the cursor up one page.
+    \row \o PageDown \o Moves the cursor down one page.
+    \row \o Home \o Moves the cursor to an item in the same column of the first
+         row of the first top-level item in the model.
+    \row \o End  \o Moves the cursor to an item in the same column of the last
+         row of the last top-level item in the model.
+    \row \o F2   \o In editable models, this opens the current item for editing.
+         The Escape key can be used to cancel the editing process and revert
+         any changes to the data displayed.
+    \endtable
+
+    \omit
+    Describe the expanding/collapsing concept if not covered elsewhere.
+    \endomit
+
+    \table 100%
+    \row \o \inlineimage windowsxp-treeview.png Screenshot of a Windows XP style tree view
+         \o \inlineimage macintosh-treeview.png Screenshot of a Macintosh style tree view
+         \o \inlineimage plastique-treeview.png Screenshot of a Plastique style tree view
+    \row \o A \l{Windows XP Style Widget Gallery}{Windows XP style} tree view.
+         \o A \l{Macintosh Style Widget Gallery}{Macintosh style} tree view.
+         \o A \l{Plastique Style Widget Gallery}{Plastique style} tree 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 heights
+    is to set the \l uniformRowHeights property to true.
+
+    \sa QListView, QTreeWidget, {View Classes}, QAbstractItemModel, QAbstractItemView,
+        {Dir View Example}
+*/
+
+
+/*!
+  \fn void QTreeView::expanded(const QModelIndex &index)
+
+  This signal is emitted when the item specified by \a index is expanded.
+*/
+
+
+/*!
+  \fn void QTreeView::collapsed(const QModelIndex &index)
+
+  This signal is emitted when the item specified by \a index is collapsed.
+*/
+
+/*!
+    Constructs a table view with a \a parent to represent a model's
+    data. Use setModel() to set the model.
+
+    \sa QAbstractItemModel
+*/
+QTreeView::QTreeView(QWidget *parent)
+    : QAbstractItemView(*new QTreeViewPrivate, parent)
+{
+    Q_D(QTreeView);
+    d->initialize();
+}
+
+/*!
+  \internal
+*/
+QTreeView::QTreeView(QTreeViewPrivate &dd, QWidget *parent)
+    : QAbstractItemView(dd, parent)
+{
+    Q_D(QTreeView);
+    d->initialize();
+}
+
+/*!
+  Destroys the tree view.
+*/
+QTreeView::~QTreeView()
+{
+}
+
+/*!
+  \reimp
+*/
+void QTreeView::setModel(QAbstractItemModel *model)
+{
+    Q_D(QTreeView);
+    if (model == d->model)
+        return;
+    if (d->selectionModel) { // support row editing
+        disconnect(d->selectionModel, SIGNAL(currentRowChanged(QModelIndex,QModelIndex)),
+                   d->model, SLOT(submit()));
+        disconnect(d->model, SIGNAL(rowsRemoved(QModelIndex,int,int)),
+                   this, SLOT(rowsRemoved(QModelIndex,int,int)));
+        disconnect(d->model, SIGNAL(modelAboutToBeReset()), this, SLOT(_q_modelAboutToBeReset()));
+    }
+    d->viewItems.clear();
+    d->expandedIndexes.clear();
+    d->hiddenIndexes.clear();
+    d->header->setModel(model);
+    QAbstractItemView::setModel(model);
+
+    // QAbstractItemView connects to a private slot
+    disconnect(d->model, SIGNAL(rowsRemoved(QModelIndex,int,int)),
+               this, SLOT(_q_rowsRemoved(QModelIndex,int,int)));
+    // do header layout after the tree
+    disconnect(d->model, SIGNAL(layoutChanged()),
+               d->header, SLOT(_q_layoutChanged()));
+    // QTreeView has a public slot for this
+    connect(d->model, SIGNAL(rowsRemoved(QModelIndex,int,int)),
+            this, SLOT(rowsRemoved(QModelIndex,int,int)));
+
+    connect(d->model, SIGNAL(modelAboutToBeReset()), SLOT(_q_modelAboutToBeReset()));
+
+    if (d->sortingEnabled)
+        d->_q_sortIndicatorChanged(header()->sortIndicatorSection(), header()->sortIndicatorOrder());
+}
+
+/*!
+  \reimp
+*/
+void QTreeView::setRootIndex(const QModelIndex &index)
+{
+    Q_D(QTreeView);
+    d->header->setRootIndex(index);
+    QAbstractItemView::setRootIndex(index);
+}
+
+/*!
+  \reimp
+*/
+void QTreeView::setSelectionModel(QItemSelectionModel *selectionModel)
+{
+    Q_D(QTreeView);
+    Q_ASSERT(selectionModel);
+    if (d->selectionModel) {
+        // support row editing
+        disconnect(d->selectionModel, SIGNAL(currentRowChanged(QModelIndex,QModelIndex)),
+                   d->model, SLOT(submit()));
+    }
+
+    d->header->setSelectionModel(selectionModel);
+    QAbstractItemView::setSelectionModel(selectionModel);
+
+    if (d->selectionModel) {
+        // support row editing
+        connect(d->selectionModel, SIGNAL(currentRowChanged(QModelIndex,QModelIndex)),
+                d->model, SLOT(submit()));
+    }
+}
+
+/*!
+  Returns the header for the tree view.
+
+  \sa QAbstractItemModel::headerData()
+*/
+QHeaderView *QTreeView::header() const
+{
+    Q_D(const QTreeView);
+    return d->header;
+}
+
+/*!
+    Sets the header for the tree view, to the given \a header.
+
+    The view takes ownership over the given \a header and deletes it
+    when a new header is set.
+
+    \sa QAbstractItemModel::headerData()
+*/
+void QTreeView::setHeader(QHeaderView *header)
+{
+    Q_D(QTreeView);
+    if (header == d->header || !header)
+        return;
+    if (d->header && d->header->parent() == this)
+        delete d->header;
+    d->header = header;
+    d->header->setParent(this);
+
+    if (!d->header->model()) {
+        d->header->setModel(d->model);
+        if (d->selectionModel)
+            d->header->setSelectionModel(d->selectionModel);
+    }
+
+    connect(d->header, SIGNAL(sectionResized(int,int,int)),
+            this, SLOT(columnResized(int,int,int)));
+    connect(d->header, SIGNAL(sectionMoved(int,int,int)),
+            this, SLOT(columnMoved()));
+    connect(d->header, SIGNAL(sectionCountChanged(int,int)),
+            this, SLOT(columnCountChanged(int,int)));
+    connect(d->header, SIGNAL(sectionHandleDoubleClicked(int)),
+            this, SLOT(resizeColumnToContents(int)));
+    connect(d->header, SIGNAL(geometriesChanged()),
+            this, SLOT(updateGeometries()));
+
+    setSortingEnabled(d->sortingEnabled);
+}
+
+/*!
+  \property QTreeView::autoExpandDelay
+  \brief The delay time before items in a tree are opened during a drag and drop operation.
+  \since 4.3
+
+  This property holds the amount of time in milliseconds that the user must wait over
+  a node before that node will automatically open or close.  If the time is
+  set to less then 0 then it will not be activated.
+
+  By default, this property has a value of -1, meaning that auto-expansion is disabled.
+*/
+int QTreeView::autoExpandDelay() const
+{
+    Q_D(const QTreeView);
+    return d->autoExpandDelay;
+}
+
+void QTreeView::setAutoExpandDelay(int delay)
+{
+    Q_D(QTreeView);
+    d->autoExpandDelay = delay;
+}
+
+/*!
+  \property QTreeView::indentation
+  \brief indentation of the items in the tree view.
+
+  This property holds the indentation measured in pixels of the items for each
+  level in the tree view. For top-level items, the indentation specifies the
+  horizontal distance from the viewport edge to the items in the first column;
+  for child items, it specifies their indentation from their parent items.
+
+  By default, this property has a value of 20.
+*/
+int QTreeView::indentation() const
+{
+    Q_D(const QTreeView);
+    return d->indent;
+}
+
+void QTreeView::setIndentation(int i)
+{
+    Q_D(QTreeView);
+    if (i != d->indent) {
+        d->indent = i;
+        d->viewport->update();
+    }
+}
+
+/*!
+  \property QTreeView::rootIsDecorated
+  \brief whether to show controls for expanding and collapsing top-level items
+
+  Items with children are typically shown with controls to expand and collapse
+  them, allowing their children to be shown or hidden. If this property is
+  false, these controls are not shown for top-level items. This can be used to
+  make a single level tree structure appear like a simple list of items.
+
+  By default, this property is true.
+*/
+bool QTreeView::rootIsDecorated() const
+{
+    Q_D(const QTreeView);
+    return d->rootDecoration;
+}
+
+void QTreeView::setRootIsDecorated(bool show)
+{
+    Q_D(QTreeView);
+    if (show != d->rootDecoration) {
+        d->rootDecoration = show;
+        d->viewport->update();
+    }
+}
+
+/*!
+  \property QTreeView::uniformRowHeights
+  \brief whether all items in the treeview have the same height
+
+  This property should only be set to true if it is guaranteed that all items
+  in the view has the same height. This enables the view to do some
+  optimizations.
+
+  The height is obtained from the first item in the view.  It is updated
+  when the data changes on that item.
+
+  By default, this property is false.
+*/
+bool QTreeView::uniformRowHeights() const
+{
+    Q_D(const QTreeView);
+    return d->uniformRowHeights;
+}
+
+void QTreeView::setUniformRowHeights(bool uniform)
+{
+    Q_D(QTreeView);
+    d->uniformRowHeights = uniform;
+}
+
+/*!
+  \property QTreeView::itemsExpandable
+  \brief whether the items are expandable by the user.
+
+  This property holds whether the user can expand and collapse items
+  interactively.
+
+  By default, this property is true.
+
+*/
+bool QTreeView::itemsExpandable() const
+{
+    Q_D(const QTreeView);
+    return d->itemsExpandable;
+}
+
+void QTreeView::setItemsExpandable(bool enable)
+{
+    Q_D(QTreeView);
+    d->itemsExpandable = enable;
+}
+
+/*!
+  \property QTreeView::expandsOnDoubleClick
+  \since 4.4
+  \brief whether the items can be expanded by double-clicking.
+
+  This property holds whether the user can expand and collapse items
+  by double-clicking. The default value is true.
+
+  \sa itemsExpandable
+*/
+bool QTreeView::expandsOnDoubleClick() const
+{
+    Q_D(const QTreeView);
+    return d->expandsOnDoubleClick;
+}
+
+void QTreeView::setExpandsOnDoubleClick(bool enable)
+{
+    Q_D(QTreeView);
+    d->expandsOnDoubleClick = enable;
+}
+
+/*!
+  Returns the horizontal position of the \a column in the viewport.
+*/
+int QTreeView::columnViewportPosition(int column) const
+{
+    Q_D(const QTreeView);
+    return d->header->sectionViewportPosition(column);
+}
+
+/*!
+  Returns the width of the \a column.
+
+  \sa resizeColumnToContents(), setColumnWidth()
+*/
+int QTreeView::columnWidth(int column) const
+{
+    Q_D(const QTreeView);
+    return d->header->sectionSize(column);
+}
+
+/*!
+  \since 4.2
+
+  Sets the width of the given \a column to the \a width specified.
+
+  \sa columnWidth(), resizeColumnToContents()
+*/
+void QTreeView::setColumnWidth(int column, int width)
+{
+    Q_D(QTreeView);
+    d->header->resizeSection(column, width);
+}
+
+/*!
+  Returns the column in the tree view whose header covers the \a x
+  coordinate given.
+*/
+int QTreeView::columnAt(int x) const
+{
+    Q_D(const QTreeView);
+    return d->header->logicalIndexAt(x);
+}
+
+/*!
+    Returns true if the \a column is hidden; otherwise returns false.
+
+    \sa hideColumn(), isRowHidden()
+*/
+bool QTreeView::isColumnHidden(int column) const
+{
+    Q_D(const QTreeView);
+    return d->header->isSectionHidden(column);
+}
+
+/*!
+  If \a hide is true the \a column is hidden, otherwise the \a column is shown.
+
+  \sa hideColumn(), setRowHidden()
+*/
+void QTreeView::setColumnHidden(int column, bool hide)
+{
+    Q_D(QTreeView);
+    if (column < 0 || column >= d->header->count())
+        return;
+    d->header->setSectionHidden(column, hide);
+}
+
+/*!
+  \property QTreeView::headerHidden
+  \brief whether the header is shown or not.
+  \since 4.4
+
+  If this property is true, the header is not shown otherwise it is.
+  The default value is false.
+
+  \sa header()
+*/
+bool QTreeView::isHeaderHidden() const
+{
+    Q_D(const QTreeView);
+    return d->header->isHidden();
+}
+
+void QTreeView::setHeaderHidden(bool hide)
+{
+    Q_D(QTreeView);
+    d->header->setHidden(hide);
+}
+
+/*!
+    Returns true if the item in the given \a row of the \a parent is hidden;
+    otherwise returns false.
+
+    \sa setRowHidden(), isColumnHidden()
+*/
+bool QTreeView::isRowHidden(int row, const QModelIndex &parent) const
+{
+    Q_D(const QTreeView);
+    if (!d->model)
+        return false;
+    return d->isRowHidden(d->model->index(row, 0, parent));
+}
+
+/*!
+  If \a hide is true the \a row with the given \a parent is hidden, otherwise the \a row is shown.
+
+  \sa isRowHidden(), setColumnHidden()
+*/
+void QTreeView::setRowHidden(int row, const QModelIndex &parent, bool hide)
+{
+    Q_D(QTreeView);
+    if (!d->model)
+        return;
+    QModelIndex index = d->model->index(row, 0, parent);
+    if (!index.isValid())
+        return;
+
+    if (hide) {
+        d->hiddenIndexes.insert(index);
+    } else if(d->isPersistent(index)) { //if the index is not persistent, it cannot be in the set
+        d->hiddenIndexes.remove(index);
+    }
+
+    d->doDelayedItemsLayout();
+}
+
+/*!
+  \since 4.3
+
+  Returns true if the item in first column in the given \a row
+  of the \a parent is spanning all the columns; otherwise returns false.
+
+  \sa setFirstColumnSpanned()
+*/
+bool QTreeView::isFirstColumnSpanned(int row, const QModelIndex &parent) const
+{
+    Q_D(const QTreeView);
+    if (d->spanningIndexes.isEmpty() || !d->model)
+        return false;
+    QModelIndex index = d->model->index(row, 0, parent);
+    for (int i = 0; i < d->spanningIndexes.count(); ++i)
+        if (d->spanningIndexes.at(i) == index)
+            return true;
+    return false;
+}
+
+/*!
+  \since 4.3
+
+  If \a span is true the item in the first column in the \a row
+  with the given \a parent is set to span all columns, otherwise all items
+  on the \a row are shown.
+
+  \sa isFirstColumnSpanned()
+*/
+void QTreeView::setFirstColumnSpanned(int row, const QModelIndex &parent, bool span)
+{
+    Q_D(QTreeView);
+    if (!d->model)
+        return;
+    QModelIndex index = d->model->index(row, 0, parent);
+    if (!index.isValid())
+        return;
+
+    if (span) {
+        QPersistentModelIndex persistent(index);
+        if (!d->spanningIndexes.contains(persistent))
+            d->spanningIndexes.append(persistent);
+    } else {
+        QPersistentModelIndex persistent(index);
+        int i = d->spanningIndexes.indexOf(persistent);
+        if (i >= 0)
+            d->spanningIndexes.remove(i);
+    }
+
+    d->executePostedLayout();
+    int i = d->viewIndex(index);
+    if (i >= 0)
+        d->viewItems[i].spanning = span;
+
+    d->viewport->update();
+}
+
+/*!
+  \reimp
+*/
+void QTreeView::dataChanged(const QModelIndex &topLeft, const QModelIndex &bottomRight)
+{
+    Q_D(QTreeView);
+
+    // if we are going to do a complete relayout anyway, there is no need to update
+    if (d->delayedPendingLayout)
+        return;
+
+    // refresh the height cache here; we don't really lose anything by getting the size hint,
+    // since QAbstractItemView::dataChanged() will get the visualRect for the items anyway
+
+    int topViewIndex = d->viewIndex(topLeft);
+    if (topViewIndex == 0)
+        d->defaultItemHeight = indexRowSizeHint(topLeft);
+    bool sizeChanged = false;
+    if (topViewIndex != -1) {
+        if (topLeft == bottomRight) {
+            int oldHeight = d->itemHeight(topViewIndex);
+            d->invalidateHeightCache(topViewIndex);
+            sizeChanged = (oldHeight != d->itemHeight(topViewIndex));
+        } else {
+            int bottomViewIndex = d->viewIndex(bottomRight);
+            for (int i = topViewIndex; i <= bottomViewIndex; ++i) {
+                int oldHeight = d->itemHeight(i);
+                d->invalidateHeightCache(i);
+                sizeChanged |= (oldHeight != d->itemHeight(i));
+            }
+        }
+    }
+
+    if (sizeChanged) {
+        d->updateScrollBars();
+        d->viewport->update();
+    }
+    QAbstractItemView::dataChanged(topLeft, bottomRight);
+}
+
+/*!
+  Hides the \a column given.
+
+  \note This function should only be called after the model has been
+  initialized, as the view needs to know the number of columns in order to
+  hide \a column.
+
+  \sa showColumn(), setColumnHidden()
+*/
+void QTreeView::hideColumn(int column)
+{
+    Q_D(QTreeView);
+    d->header->hideSection(column);
+}
+
+/*!
+  Shows the given \a column in the tree view.
+
+  \sa hideColumn(), setColumnHidden()
+*/
+void QTreeView::showColumn(int column)
+{
+    Q_D(QTreeView);
+    d->header->showSection(column);
+}
+
+/*!
+  \fn void QTreeView::expand(const QModelIndex &index)
+
+  Expands the model item specified by the \a index.
+
+  \sa expanded()
+*/
+void QTreeView::expand(const QModelIndex &index)
+{
+    Q_D(QTreeView);
+    if (!d->isIndexValid(index))
+        return;
+    if (d->delayedPendingLayout) {
+        //A complete relayout is going to be performed, just store the expanded index, no need to layout.
+        if (d->storeExpanded(index))
+            emit expanded(index);
+        return;
+    }
+
+    int i = d->viewIndex(index);
+    if (i != -1) { // is visible
+        d->expand(i, true);
+        if (!d->isAnimating()) {
+            updateGeometries();
+            d->viewport->update();
+        }
+    } else if (d->storeExpanded(index)) {
+        emit expanded(index);
+    }
+}
+
+/*!
+  \fn void QTreeView::collapse(const QModelIndex &index)
+
+  Collapses the model item specified by the \a index.
+
+  \sa collapsed()
+*/
+void QTreeView::collapse(const QModelIndex &index)
+{
+    Q_D(QTreeView);
+    if (!d->isIndexValid(index))
+        return;
+    //if the current item is now invisible, the autoscroll will expand the tree to see it, so disable the autoscroll
+    d->delayedAutoScroll.stop();
+
+    if (d->delayedPendingLayout) {
+        //A complete relayout is going to be performed, just un-store the expanded index, no need to layout.
+        if (d->isPersistent(index) && d->expandedIndexes.remove(index))
+            emit collapsed(index);
+        return;
+    }
+    int i = d->viewIndex(index);
+    if (i != -1) { // is visible
+        d->collapse(i, true);
+        if (!d->isAnimating()) {
+            updateGeometries();
+            viewport()->update();
+        }
+    } else {
+        if (d->isPersistent(index) && d->expandedIndexes.remove(index))
+            emit collapsed(index);
+    }
+}
+
+/*!
+  \fn bool QTreeView::isExpanded(const QModelIndex &index) const
+
+  Returns true if the model item \a index is expanded; otherwise returns
+  false.
+
+  \sa expand(), expanded(), setExpanded()
+*/
+bool QTreeView::isExpanded(const QModelIndex &index) const
+{
+    Q_D(const QTreeView);
+    return d->isIndexExpanded(index);
+}
+
+/*!
+  Sets the item referred to by \a index to either collapse or expanded,
+  depending on the value of \a expanded.
+
+  \sa expanded(), expand(), isExpanded()
+*/
+void QTreeView::setExpanded(const QModelIndex &index, bool expanded)
+{
+    if (expanded)
+        this->expand(index);
+    else
+        this->collapse(index);
+}
+
+/*!
+    \since 4.2
+    \property QTreeView::sortingEnabled
+    \brief whether sorting is enabled
+
+    If this property is true, sorting is enabled for the tree; if the property
+    is false, sorting is not enabled. The default value is false.
+
+    \note In order to avoid performance issues, it is recommended that
+    sorting is enabled \e after inserting the items into the tree.
+    Alternatively, you could also insert the items into a list before inserting
+    the items into the tree.
+
+    \sa sortByColumn()
+*/
+
+void QTreeView::setSortingEnabled(bool enable)
+{
+    Q_D(QTreeView);
+    header()->setSortIndicatorShown(enable);
+    header()->setClickable(enable);
+    if (enable) {
+        //sortByColumn has to be called before we connect or set the sortingEnabled flag
+        // because otherwise it will not call sort on the model.
+        sortByColumn(header()->sortIndicatorSection(), header()->sortIndicatorOrder());
+        connect(header(), SIGNAL(sortIndicatorChanged(int,Qt::SortOrder)),
+                this, SLOT(_q_sortIndicatorChanged(int, Qt::SortOrder)), Qt::UniqueConnection);
+    } else {
+        disconnect(header(), SIGNAL(sortIndicatorChanged(int,Qt::SortOrder)),
+                   this, SLOT(_q_sortIndicatorChanged(int, Qt::SortOrder)));
+    }
+    d->sortingEnabled = enable;
+}
+
+bool QTreeView::isSortingEnabled() const
+{
+    Q_D(const QTreeView);
+    return d->sortingEnabled;
+}
+
+/*!
+    \since 4.2
+    \property QTreeView::animated
+    \brief whether animations are enabled
+
+    If this property is true the treeview will animate expandsion
+    and collasping of branches. If this property is false, the treeview
+    will expand or collapse branches immediately without showing
+    the animation.
+
+    By default, this property is false.
+*/
+
+void QTreeView::setAnimated(bool animate)
+{
+    Q_D(QTreeView);
+    d->animationsEnabled = animate;
+}
+
+bool QTreeView::isAnimated() const
+{
+    Q_D(const QTreeView);
+    return d->animationsEnabled;
+}
+
+/*!
+    \since 4.2
+    \property QTreeView::allColumnsShowFocus
+    \brief whether items should show keyboard focus using all columns
+
+    If this property is true all columns will show focus, otherwise only
+    one column will show focus.
+
+    The default is false.
+*/
+
+void QTreeView::setAllColumnsShowFocus(bool enable)
+{
+    Q_D(QTreeView);
+    if (d->allColumnsShowFocus == enable)
+        return;
+    d->allColumnsShowFocus = enable;
+    d->viewport->update();
+}
+
+bool QTreeView::allColumnsShowFocus() const
+{
+    Q_D(const QTreeView);
+    return d->allColumnsShowFocus;
+}
+
+/*!
+    \property QTreeView::wordWrap
+    \brief the item text word-wrapping policy
+    \since 4.3
+
+    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.
+
+    Note that even if wrapping is enabled, the cell will not be
+    expanded to fit all text. Ellipsis will be inserted according to
+    the current \l{QAbstractItemView::}{textElideMode}.
+*/
+void QTreeView::setWordWrap(bool on)
+{
+    Q_D(QTreeView);
+    if (d->wrapItemText == on)
+        return;
+    d->wrapItemText = on;
+    d->doDelayedItemsLayout();
+}
+
+bool QTreeView::wordWrap() const
+{
+    Q_D(const QTreeView);
+    return d->wrapItemText;
+}
+
+
+/*!
+  \reimp
+ */
+void QTreeView::keyboardSearch(const QString &search)
+{
+    Q_D(QTreeView);
+    if (!d->model->rowCount(d->root) || !d->model->columnCount(d->root))
+        return;
+
+    QModelIndex start;
+    if (currentIndex().isValid())
+        start = currentIndex();
+    else
+        start = d->model->index(0, 0, d->root);
+
+    QTime now(QTime::currentTime());
+    bool skipRow = false;
+    if (search.isEmpty()
+        || (d->keyboardInputTime.msecsTo(now) > QApplication::keyboardInputInterval())) {
+        d->keyboardInput = search;
+        skipRow = true;
+    } else {
+        d->keyboardInput += search;
+    }
+    d->keyboardInputTime = now;
+
+    // special case for searches with same key like 'aaaaa'
+    bool sameKey = false;
+    if (d->keyboardInput.length() > 1) {
+        int c = d->keyboardInput.count(d->keyboardInput.at(d->keyboardInput.length() - 1));
+        sameKey = (c == d->keyboardInput.length());
+        if (sameKey)
+            skipRow = true;
+    }
+
+    // skip if we are searching for the same key or a new search started
+    if (skipRow) {
+        if (indexBelow(start).isValid())
+            start = indexBelow(start);
+        else
+            start = d->model->index(0, start.column(), d->root);
+    }
+
+    d->executePostedLayout();
+    int startIndex = d->viewIndex(start);
+    if (startIndex <= -1)
+        return;
+
+    int previousLevel = -1;
+    int bestAbove = -1;
+    int bestBelow = -1;
+    QString searchString = sameKey ? QString(d->keyboardInput.at(0)) : d->keyboardInput;
+    for (int i = 0; i < d->viewItems.count(); ++i) {
+        if ((int)d->viewItems.at(i).level > previousLevel) {
+            QModelIndex searchFrom = d->viewItems.at(i).index;
+            if (searchFrom.parent() == start.parent())
+                searchFrom = start;
+            QModelIndexList match = d->model->match(searchFrom, Qt::DisplayRole, searchString);
+            if (match.count()) {
+                int hitIndex = d->viewIndex(match.at(0));
+                if (hitIndex >= 0 && hitIndex < startIndex)
+                    bestAbove = bestAbove == -1 ? hitIndex : qMin(hitIndex, bestAbove);
+                else if (hitIndex >= startIndex)
+                    bestBelow = bestBelow == -1 ? hitIndex : qMin(hitIndex, bestBelow);
+            }
+        }
+        previousLevel = d->viewItems.at(i).level;
+    }
+
+    QModelIndex index;
+    if (bestBelow > -1)
+        index = d->viewItems.at(bestBelow).index;
+    else if (bestAbove > -1)
+        index = d->viewItems.at(bestAbove).index;
+
+    if (index.isValid()) {
+        QItemSelectionModel::SelectionFlags flags = (d->selectionMode == SingleSelection
+                                                     ? QItemSelectionModel::SelectionFlags(
+                                                         QItemSelectionModel::ClearAndSelect
+                                                         |d->selectionBehaviorFlags())
+                                                     : QItemSelectionModel::SelectionFlags(
+                                                         QItemSelectionModel::NoUpdate));
+        selectionModel()->setCurrentIndex(index, flags);
+    }
+}
+
+/*!
+  Returns the rectangle on the viewport occupied by the item at \a index.
+  If the index is not visible or explicitly hidden, the returned rectangle is invalid.
+*/
+QRect QTreeView::visualRect(const QModelIndex &index) const
+{
+    Q_D(const QTreeView);
+
+    if (!d->isIndexValid(index) || isIndexHidden(index))
+        return QRect();
+
+    d->executePostedLayout();
+
+    int vi = d->viewIndex(index);
+    if (vi < 0)
+        return QRect();
+
+    bool spanning = d->viewItems.at(vi).spanning;
+
+    // if we have a spanning item, make the selection stretch from left to right
+    int x = (spanning ? 0 : columnViewportPosition(index.column()));
+    int w = (spanning ? d->header->length() : columnWidth(index.column()));
+    // handle indentation
+    if (index.column() == 0) {
+        int i = d->indentationForItem(vi);
+        w -= i;
+        if (!isRightToLeft())
+            x += i;
+    }
+
+    int y = d->coordinateForItem(vi);
+    int h = d->itemHeight(vi);
+
+    return QRect(x, y, w, h);
+}
+
+/*!
+    Scroll the contents of the tree view until the given model item
+    \a index is visible. The \a hint parameter specifies more
+    precisely where the item should be located after the
+    operation.
+    If any of the parents of the model item are collapsed, they will
+    be expanded to ensure that the model item is visible.
+*/
+void QTreeView::scrollTo(const QModelIndex &index, ScrollHint hint)
+{
+    Q_D(QTreeView);
+
+    if (!d->isIndexValid(index))
+        return;
+
+    d->executePostedLayout();
+    d->updateScrollBars();
+
+    // Expand all parents if the parent(s) of the node are not expanded.
+    QModelIndex parent = index.parent();
+    while (parent.isValid() && state() == NoState && d->itemsExpandable) {
+        if (!isExpanded(parent))
+            expand(parent);
+        parent = d->model->parent(parent);
+    }
+
+    int item = d->viewIndex(index);
+    if (item < 0)
+        return;
+
+    QRect area = d->viewport->rect();
+
+    // vertical
+    if (verticalScrollMode() == QAbstractItemView::ScrollPerItem) {
+        int top = verticalScrollBar()->value();
+        int bottom = top + verticalScrollBar()->pageStep();
+        if (hint == EnsureVisible && item >= top && item < bottom) {
+            // nothing to do
+        } else if (hint == PositionAtTop || (hint == EnsureVisible && item < top)) {
+            verticalScrollBar()->setValue(item);
+        } else { // PositionAtBottom or PositionAtCenter
+            const int currentItemHeight = d->itemHeight(item);
+            int y = (hint == PositionAtCenter
+                 //we center on the current item with a preference to the top item (ie. -1)
+                     ? area.height() / 2 + currentItemHeight - 1
+                 //otherwise we simply take the whole space
+                     : area.height());
+            if (y > currentItemHeight) {
+                while (item >= 0) {
+                    y -= d->itemHeight(item);
+                    if (y < 0) { //there is no more space left
+                        item++;
+                        break;
+                    }
+                    item--;
+                }
+            }
+            verticalScrollBar()->setValue(item);
+        }
+    } else { // ScrollPerPixel
+        QRect rect(columnViewportPosition(index.column()),
+                   d->coordinateForItem(item), // ### slow for items outside the view
+                   columnWidth(index.column()),
+                   d->itemHeight(item));
+
+        if (rect.isEmpty()) {
+            // nothing to do
+        } else if (hint == EnsureVisible && area.contains(rect)) {
+            d->viewport->update(rect);
+            // nothing to do
+        } else {
+            bool above = (hint == EnsureVisible
+                        && (rect.top() < area.top()
+                            || area.height() < rect.height()));
+            bool below = (hint == EnsureVisible
+                        && rect.bottom() > area.bottom()
+                        && rect.height() < area.height());
+
+            int verticalValue = verticalScrollBar()->value();
+            if (hint == PositionAtTop || above)
+                verticalValue += rect.top();
+            else if (hint == PositionAtBottom || below)
+                verticalValue += rect.bottom() - area.height();
+            else if (hint == PositionAtCenter)
+                verticalValue += rect.top() - ((area.height() - rect.height()) / 2);
+            verticalScrollBar()->setValue(verticalValue);
+        }
+    }
+    // horizontal
+    int viewportWidth = d->viewport->width();
+    int horizontalOffset = d->header->offset();
+    int horizontalPosition = d->header->sectionPosition(index.column());
+    int cellWidth = d->header->sectionSize(index.column());
+
+    if (hint == PositionAtCenter) {
+        horizontalScrollBar()->setValue(horizontalPosition - ((viewportWidth - cellWidth) / 2));
+    } else {
+        if (horizontalPosition - horizontalOffset < 0 || cellWidth > viewportWidth)
+            horizontalScrollBar()->setValue(horizontalPosition);
+        else if (horizontalPosition - horizontalOffset + cellWidth > viewportWidth)
+            horizontalScrollBar()->setValue(horizontalPosition - viewportWidth + cellWidth);
+    }
+}
+
+/*!
+  \reimp
+*/
+void QTreeView::timerEvent(QTimerEvent *event)
+{
+    Q_D(QTreeView);
+    if (event->timerId() == d->columnResizeTimerID) {
+        updateGeometries();
+        killTimer(d->columnResizeTimerID);
+        d->columnResizeTimerID = 0;
+        QRect rect;
+        int viewportHeight = d->viewport->height();
+        int viewportWidth = d->viewport->width();
+        for (int i = d->columnsToUpdate.size() - 1; i >= 0; --i) {
+            int column = d->columnsToUpdate.at(i);
+            int x = columnViewportPosition(column);
+            if (isRightToLeft())
+                rect |= QRect(0, 0, x + columnWidth(column), viewportHeight);
+            else
+                rect |= QRect(x, 0, viewportWidth - x, viewportHeight);
+        }
+        d->viewport->update(rect.normalized());
+        d->columnsToUpdate.clear();
+    } else if (event->timerId() == d->openTimer.timerId()) {
+        QPoint pos = d->viewport->mapFromGlobal(QCursor::pos());
+        if (state() == QAbstractItemView::DraggingState
+            && d->viewport->rect().contains(pos)) {
+            QModelIndex index = indexAt(pos);
+            setExpanded(index, !isExpanded(index));
+        }
+        d->openTimer.stop();
+    }
+
+    QAbstractItemView::timerEvent(event);
+}
+
+/*!
+  \reimp
+*/
+#ifndef QT_NO_DRAGANDDROP
+void QTreeView::dragMoveEvent(QDragMoveEvent *event)
+{
+    Q_D(QTreeView);
+    if (d->autoExpandDelay >= 0)
+        d->openTimer.start(d->autoExpandDelay, this);
+    QAbstractItemView::dragMoveEvent(event);
+}
+#endif
+
+/*!
+  \reimp
+*/
+bool QTreeView::viewportEvent(QEvent *event)
+{
+    Q_D(QTreeView);
+    switch (event->type()) {
+    case QEvent::HoverEnter:
+    case QEvent::HoverLeave:
+    case QEvent::HoverMove: {
+        QHoverEvent *he = static_cast<QHoverEvent*>(event);
+        int oldBranch = d->hoverBranch;
+        d->hoverBranch = d->itemDecorationAt(he->pos());
+        if (oldBranch != d->hoverBranch) {
+            QModelIndex oldIndex = d->modelIndex(oldBranch),
+                newIndex = d->modelIndex(d->hoverBranch);
+            if (oldIndex != newIndex) {
+                QRect oldRect = visualRect(oldIndex);
+                QRect newRect = visualRect(newIndex);
+                viewport()->update(oldRect.left() - d->indent, oldRect.top(), d->indent, oldRect.height());
+                viewport()->update(newRect.left() - d->indent, newRect.top(), d->indent, newRect.height());
+            }
+        }
+        if (selectionBehavior() == QAbstractItemView::SelectRows) {
+            QModelIndex newHoverIndex = indexAt(he->pos());
+            if (d->hover != newHoverIndex) {
+                QRect oldHoverRect = visualRect(d->hover);
+                QRect newHoverRect = visualRect(newHoverIndex);
+                viewport()->update(QRect(0, newHoverRect.y(), viewport()->width(), newHoverRect.height()));
+                viewport()->update(QRect(0, oldHoverRect.y(), viewport()->width(), oldHoverRect.height()));
+            }
+        }
+        break; }
+    default:
+        break;
+    }
+    return QAbstractItemView::viewportEvent(event);
+}
+
+/*!
+  \reimp
+*/
+void QTreeView::paintEvent(QPaintEvent *event)
+{
+    Q_D(QTreeView);
+    d->executePostedLayout();
+    QPainter painter(viewport());
+#ifndef QT_NO_ANIMATION
+    if (d->isAnimating()) {
+        drawTree(&painter, event->region() - d->animatedOperation.rect());
+        d->drawAnimatedOperation(&painter);
+    } else
+#endif //QT_NO_ANIMATION
+    {
+        drawTree(&painter, event->region());
+#ifndef QT_NO_DRAGANDDROP
+        d->paintDropIndicator(&painter);
+#endif
+    }
+}
+
+void QTreeViewPrivate::paintAlternatingRowColors(QPainter *painter, QStyleOptionViewItemV4 *option, int y, int bottom) const
+{
+    Q_Q(const QTreeView);
+    if (!alternatingColors || !q->style()->styleHint(QStyle::SH_ItemView_PaintAlternatingRowColorsForEmptyArea, option, q))
+        return;
+    int rowHeight = defaultItemHeight;
+    if (rowHeight <= 0) {
+        rowHeight = itemDelegate->sizeHint(*option, QModelIndex()).height();
+        if (rowHeight <= 0)
+            return;
+    }
+    while (y <= bottom) {
+        option->rect.setRect(0, y, viewport->width(), rowHeight);
+        if (current & 1) {
+            option->features |= QStyleOptionViewItemV2::Alternate;
+        } else {
+            option->features &= ~QStyleOptionViewItemV2::Alternate;
+        }
+        ++current;
+        q->style()->drawPrimitive(QStyle::PE_PanelItemViewRow, option, painter, q);
+        y += rowHeight;
+    }
+}
+
+bool QTreeViewPrivate::expandOrCollapseItemAtPos(const QPoint &pos)
+{
+    Q_Q(QTreeView);
+    // we want to handle mousePress in EditingState (persistent editors)
+    if ((state != QAbstractItemView::NoState
+		&& state != QAbstractItemView::EditingState)
+		|| !viewport->rect().contains(pos))
+        return true;
+
+    int i = itemDecorationAt(pos);
+    if ((i != -1) && itemsExpandable && hasVisibleChildren(viewItems.at(i).index)) {
+        if (viewItems.at(i).expanded)
+            collapse(i, true);
+        else
+            expand(i, true);
+        if (!isAnimating()) {
+            q->updateGeometries();
+            viewport->update();
+        }
+        return true;
+    }
+    return false;
+}
+
+void QTreeViewPrivate::_q_modelDestroyed()
+{
+    //we need to clear that list because it contais QModelIndex to 
+    //the model currently being destroyed
+    viewItems.clear();
+    QAbstractItemViewPrivate::_q_modelDestroyed();
+}
+
+/*!
+  \reimp
+
+  We have a QTreeView way of knowing what elements are on the viewport
+*/
+QItemViewPaintPairs QTreeViewPrivate::draggablePaintPairs(const QModelIndexList &indexes, QRect *r) const
+{
+    Q_ASSERT(r);
+    return QAbstractItemViewPrivate::draggablePaintPairs(indexes, r);
+    Q_Q(const QTreeView);
+    QRect &rect = *r;
+    const QRect viewportRect = viewport->rect();
+    int itemOffset = 0;
+    int row = firstVisibleItem(&itemOffset);
+    QPair<int, int> startEnd = startAndEndColumns(viewportRect);
+    QVector<int> columns;
+    for (int i = startEnd.first; i <= startEnd.second; ++i) {
+        int logical = header->logicalIndex(i);
+        if (!header->isSectionHidden(logical))
+            columns += logical;
+    }
+    QSet<QModelIndex> visibleIndexes;
+    for (; itemOffset < viewportRect.bottom() && row < viewItems.count(); ++row) {
+        const QModelIndex &index = viewItems.at(row).index;
+        for (int colIndex = 0; colIndex < columns.count(); ++colIndex)
+            visibleIndexes += index.sibling(index.row(), columns.at(colIndex));
+        itemOffset += itemHeight(row);
+    }
+
+    //now that we have the visible indexes, we can try to find those which are selected
+    QItemViewPaintPairs ret;
+    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;
+}
+
+
+/*!
+  \since 4.2
+  Draws the part of the tree intersecting the given \a region using the specified
+  \a painter.
+
+  \sa paintEvent()
+*/
+void QTreeView::drawTree(QPainter *painter, const QRegion &region) const
+{
+    Q_D(const QTreeView);
+    const QVector<QTreeViewItem> viewItems = d->viewItems;
+
+    QStyleOptionViewItemV4 option = d->viewOptionsV4();
+    const QStyle::State state = option.state;
+    d->current = 0;
+
+    if (viewItems.count() == 0 || d->header->count() == 0 || !d->itemDelegate) {
+        d->paintAlternatingRowColors(painter, &option, 0, region.boundingRect().bottom()+1);
+        return;
+    }
+
+    int firstVisibleItemOffset = 0;
+    const int firstVisibleItem = d->firstVisibleItem(&firstVisibleItemOffset);
+    if (firstVisibleItem < 0) {
+        d->paintAlternatingRowColors(painter, &option, 0, region.boundingRect().bottom()+1);
+        return;
+    }
+
+    const int viewportWidth = d->viewport->width();
+
+    QVector<QRect> rects = region.rects();
+    QVector<int> drawn;
+    bool multipleRects = (rects.size() > 1);
+    for (int a = 0; a < rects.size(); ++a) {
+        const QRect area = (multipleRects
+                            ? QRect(0, rects.at(a).y(), viewportWidth, rects.at(a).height())
+                            : rects.at(a));
+        d->leftAndRight = d->startAndEndColumns(area);
+
+        int i = firstVisibleItem; // the first item at the top of the viewport
+        int y = firstVisibleItemOffset; // we may only see part of the first item
+
+        // start at the top of the viewport  and iterate down to the update area
+        for (; i < viewItems.count(); ++i) {
+            const int itemHeight = d->itemHeight(i);
+            if (y + itemHeight > area.top())
+                break;
+            y += itemHeight;
+        }
+
+        // paint the visible rows
+        for (; i < viewItems.count() && y <= area.bottom(); ++i) {
+            const int itemHeight = d->itemHeight(i);
+            option.rect.setRect(0, y, viewportWidth, itemHeight);
+            option.state = state | (viewItems.at(i).expanded
+                                    ? QStyle::State_Open : QStyle::State_None);
+            d->current = i;
+            d->spanning = viewItems.at(i).spanning;
+            if (!multipleRects || !drawn.contains(i)) {
+                drawRow(painter, option, viewItems.at(i).index);
+                if (multipleRects)   // even if the rect only intersects the item,
+                    drawn.append(i); // the entire item will be painted
+            }
+            y += itemHeight;
+        }
+
+        if (y <= area.bottom()) {
+            d->current = i;
+            d->paintAlternatingRowColors(painter, &option, y, area.bottom());
+        }
+    }
+}
+
+/// ### move to QObject :)
+static inline bool ancestorOf(QObject *widget, QObject *other)
+{
+    for (QObject *parent = other; parent != 0; parent = parent->parent()) {
+        if (parent == widget)
+            return true;
+    }
+    return false;
+}
+
+/*!
+    Draws the row in the tree view that contains the model item \a index,
+    using the \a painter given. The \a option control how the item is
+    displayed.
+
+    \sa setAlternatingRowColors()
+*/
+void QTreeView::drawRow(QPainter *painter, const QStyleOptionViewItem &option,
+                        const QModelIndex &index) const
+{
+    Q_D(const QTreeView);
+    QStyleOptionViewItemV4 opt = option;
+    const QPoint offset = d->scrollDelayOffset;
+    const int y = option.rect.y() + offset.y();
+    const QModelIndex parent = index.parent();
+    const QHeaderView *header = d->header;
+    const QModelIndex current = currentIndex();
+    const QModelIndex hover = d->hover;
+    const bool reverse = isRightToLeft();
+    const QStyle::State state = opt.state;
+    const bool spanning = d->spanning;
+    const int left = (spanning ? header->visualIndex(0) : d->leftAndRight.first);
+    const int right = (spanning ? header->visualIndex(0) : d->leftAndRight.second);
+    const bool alternate = d->alternatingColors;
+    const bool enabled = (state & QStyle::State_Enabled) != 0;
+    const bool allColumnsShowFocus = d->allColumnsShowFocus;
+
+
+    // when the row contains an index widget which has focus,
+    // we want to paint the entire row as active
+    bool indexWidgetHasFocus = false;
+    if ((current.row() == index.row()) && !d->editors.isEmpty()) {
+        const int r = index.row();
+        QWidget *fw = QApplication::focusWidget();
+        for (int c = 0; c < header->count(); ++c) {
+            QModelIndex idx = d->model->index(r, c, parent);
+            if (QWidget *editor = indexWidget(idx)) {
+                if (ancestorOf(editor, fw)) {
+                    indexWidgetHasFocus = true;
+                    break;
+                }
+            }
+        }
+    }
+
+    const bool widgetHasFocus = hasFocus();
+    bool currentRowHasFocus = false;
+    if (allColumnsShowFocus && widgetHasFocus && current.isValid()) {
+        // check if the focus index is before or after the visible columns
+        const int r = index.row();
+        for (int c = 0; c < left && !currentRowHasFocus; ++c) {
+            QModelIndex idx = d->model->index(r, c, parent);
+            currentRowHasFocus = (idx == current);
+        }
+        QModelIndex parent = d->model->parent(index);
+        for (int c = right; c < header->count() && !currentRowHasFocus; ++c) {
+            currentRowHasFocus = (d->model->index(r, c, parent) == current);
+        }
+    }
+
+    // ### special case: treeviews with multiple columns draw
+    // the selections differently than with only one column
+    opt.showDecorationSelected = (d->selectionBehavior & SelectRows)
+                                 || option.showDecorationSelected;
+
+    int width, height = option.rect.height();
+    int position;
+    QModelIndex modelIndex;
+    int columnCount = header->count();
+    const bool hoverRow = selectionBehavior() == QAbstractItemView::SelectRows
+                  && index.parent() == hover.parent()
+                  && index.row() == hover.row();
+
+    /* 'left' and 'right' are the left-most and right-most visible visual indices.
+       Compute the first visible logical indices before and after the left and right.
+       We will use these values to determine the QStyleOptionViewItemV4::viewItemPosition. */
+    int logicalIndexBeforeLeft = -1, logicalIndexAfterRight = -1;
+    for (int visualIndex = left - 1; visualIndex >= 0; --visualIndex) {
+        int logicalIndex = header->logicalIndex(visualIndex);
+        if (!header->isSectionHidden(logicalIndex)) {
+            logicalIndexBeforeLeft = logicalIndex;
+            break;
+        }
+    }
+    QVector<int> logicalIndices; // vector of currently visibly logical indices
+    for (int visualIndex = left; visualIndex < columnCount; ++visualIndex) {
+        int logicalIndex = header->logicalIndex(visualIndex);
+        if (!header->isSectionHidden(logicalIndex)) {
+            if (visualIndex > right) {
+                logicalIndexAfterRight = logicalIndex;
+                break;
+            }
+            logicalIndices.append(logicalIndex);
+        }
+    }
+
+    for (int currentLogicalSection = 0; currentLogicalSection < logicalIndices.count(); ++currentLogicalSection) {
+        int headerSection = logicalIndices.at(currentLogicalSection);
+        position = columnViewportPosition(headerSection) + offset.x();
+        width = header->sectionSize(headerSection);
+
+        if (spanning) {
+            int lastSection = header->logicalIndex(header->count() - 1);
+            if (!reverse) {
+                width = columnViewportPosition(lastSection) + header->sectionSize(lastSection) - position;
+            } else {
+                width += position - columnViewportPosition(lastSection);
+                position = columnViewportPosition(lastSection);
+            }
+        }
+
+        modelIndex = d->model->index(index.row(), headerSection, parent);
+        if (!modelIndex.isValid())
+            continue;
+        opt.state = state;
+
+        // determine the viewItemPosition depending on the position of column 0
+        int nextLogicalSection = currentLogicalSection + 1 >= logicalIndices.count()
+                                 ? logicalIndexAfterRight
+                                 : logicalIndices.at(currentLogicalSection + 1);
+        int prevLogicalSection = currentLogicalSection - 1 < 0
+                                 ? logicalIndexBeforeLeft
+                                 : logicalIndices.at(currentLogicalSection - 1);
+        if (columnCount == 1 || (nextLogicalSection == 0 && prevLogicalSection == -1)
+            || (headerSection == 0 && nextLogicalSection == -1) || spanning)
+            opt.viewItemPosition = QStyleOptionViewItemV4::OnlyOne;
+        else if (headerSection == 0 || (nextLogicalSection != 0 && prevLogicalSection == -1))
+            opt.viewItemPosition = QStyleOptionViewItemV4::Beginning;
+        else if (nextLogicalSection == 0 || nextLogicalSection == -1)
+            opt.viewItemPosition = QStyleOptionViewItemV4::End;
+        else
+            opt.viewItemPosition = QStyleOptionViewItemV4::Middle;
+
+        // fake activeness when row editor has focus
+        if (indexWidgetHasFocus)
+            opt.state |= QStyle::State_Active;
+
+        if (d->selectionModel->isSelected(modelIndex))
+            opt.state |= QStyle::State_Selected;
+        if (widgetHasFocus && (current == modelIndex)) {
+            if (allColumnsShowFocus)
+                currentRowHasFocus = true;
+            else
+                opt.state |= QStyle::State_HasFocus;
+        }
+        if ((hoverRow || modelIndex == hover)
+            && (option.showDecorationSelected || (d->hoverBranch == -1)))
+            opt.state |= QStyle::State_MouseOver;
+        else
+            opt.state &= ~QStyle::State_MouseOver;
+
+        if (enabled) {
+            QPalette::ColorGroup cg;
+            if ((d->model->flags(modelIndex) & Qt::ItemIsEnabled) == 0) {
+                opt.state &= ~QStyle::State_Enabled;
+                cg = QPalette::Disabled;
+            } else if (opt.state & QStyle::State_Active) {
+                cg = QPalette::Active;
+            } else {
+                cg = QPalette::Inactive;
+            }
+            opt.palette.setCurrentColorGroup(cg);
+        }
+
+        if (alternate) {
+            if (d->current & 1) {
+                opt.features |= QStyleOptionViewItemV2::Alternate;
+            } else {
+                opt.features &= ~QStyleOptionViewItemV2::Alternate;
+            }
+        }
+
+        /* Prior to Qt 4.3, the background of the branch (in selected state and
+           alternate row color was provided by the view. For backward compatibility,
+           this is now delegated to the style using PE_PanelViewItemRow which
+           does the appropriate fill */
+        if (headerSection == 0) {
+            const int i = d->indentationForItem(d->current);
+            QRect branches(reverse ? position + width - i : position, y, i, height);
+            const bool setClipRect = branches.width() > width;
+            if (setClipRect) {
+                painter->save();
+                painter->setClipRect(QRect(position, y, width, height));
+            }
+            // draw background for the branch (selection + alternate row)
+            opt.rect = branches;
+            style()->drawPrimitive(QStyle::PE_PanelItemViewRow, &opt, painter, this);
+
+            // draw background of the item (only alternate row). rest of the background
+            // is provided by the delegate
+            QStyle::State oldState = opt.state;
+            opt.state &= ~QStyle::State_Selected;
+            opt.rect.setRect(reverse ? position : i + position, y, width - i, height);
+            style()->drawPrimitive(QStyle::PE_PanelItemViewRow, &opt, painter, this);
+            opt.state = oldState;
+
+            drawBranches(painter, branches, index);
+            if (setClipRect)
+                painter->restore();
+        } else {
+            QStyle::State oldState = opt.state;
+            opt.state &= ~QStyle::State_Selected;
+            opt.rect.setRect(position, y, width, height);
+            style()->drawPrimitive(QStyle::PE_PanelItemViewRow, &opt, painter, this);
+            opt.state = oldState;
+        }
+
+        if (const QWidget *widget = d->editorForIndex(modelIndex).editor) {
+            painter->save();
+            painter->setClipRect(widget->geometry());
+            d->delegateForIndex(modelIndex)->paint(painter, opt, modelIndex);
+            painter->restore();
+        } else {
+            d->delegateForIndex(modelIndex)->paint(painter, opt, modelIndex);
+        }
+    }
+
+    if (currentRowHasFocus) {
+        QStyleOptionFocusRect o;
+        o.QStyleOption::operator=(option);
+        o.state |= QStyle::State_KeyboardFocusChange;
+        QPalette::ColorGroup cg = (option.state & QStyle::State_Enabled)
+                                  ? QPalette::Normal : QPalette::Disabled;
+        o.backgroundColor = option.palette.color(cg, d->selectionModel->isSelected(index)
+                                                 ? QPalette::Highlight : QPalette::Background);
+        int x = 0;
+        if (!option.showDecorationSelected)
+            x = header->sectionPosition(0) + d->indentationForItem(d->current);
+	QRect focusRect(x - header->offset(), y, header->length() - x, height);
+        o.rect = style()->visualRect(layoutDirection(), d->viewport->rect(), focusRect);
+        style()->drawPrimitive(QStyle::PE_FrameFocusRect, &o, painter);
+        // if we show focus on all columns and the first section is moved,
+        // we have to split the focus rect into two rects
+        if (allColumnsShowFocus && !option.showDecorationSelected
+            && header->sectionsMoved() && (header->visualIndex(0) != 0)) {
+	    QRect sectionRect(0, y, header->sectionPosition(0), height); 
+            o.rect = style()->visualRect(layoutDirection(), d->viewport->rect(), sectionRect);
+            style()->drawPrimitive(QStyle::PE_FrameFocusRect, &o, painter);
+        }
+    }
+}
+
+/*!
+  Draws the branches in the tree view on the same row as the model item
+  \a index, using the \a painter given. The branches are drawn in the
+  rectangle specified by \a rect.
+*/
+void QTreeView::drawBranches(QPainter *painter, const QRect &rect,
+                             const QModelIndex &index) const
+{
+    Q_D(const QTreeView);
+    const bool reverse = isRightToLeft();
+    const int indent = d->indent;
+    const int outer = d->rootDecoration ? 0 : 1;
+    const int item = d->current;
+    const QTreeViewItem &viewItem = d->viewItems.at(item);
+    int level = viewItem.level;
+    QRect primitive(reverse ? rect.left() : rect.right() + 1, rect.top(), indent, rect.height());
+
+    QModelIndex parent = index.parent();
+    QModelIndex current = parent;
+    QModelIndex ancestor = current.parent();
+
+    QStyleOptionViewItemV2 opt = viewOptions();
+    QStyle::State extraFlags = QStyle::State_None;
+    if (isEnabled())
+        extraFlags |= QStyle::State_Enabled;
+    if (window()->isActiveWindow())
+        extraFlags |= QStyle::State_Active;
+    QPoint oldBO = painter->brushOrigin();
+    if (verticalScrollMode() == QAbstractItemView::ScrollPerPixel)
+        painter->setBrushOrigin(QPoint(0, verticalOffset()));
+
+    if (d->alternatingColors) {
+        if (d->current & 1) {
+            opt.features |= QStyleOptionViewItemV2::Alternate;
+        } else {
+            opt.features &= ~QStyleOptionViewItemV2::Alternate;
+        }
+    }
+
+    // When hovering over a row, pass State_Hover for painting the branch
+    // indicators if it has the decoration (aka branch) selected.
+    bool hoverRow = selectionBehavior() == QAbstractItemView::SelectRows
+                    && opt.showDecorationSelected
+                    && index.parent() == d->hover.parent()
+                    && index.row() == d->hover.row();
+
+    if (d->selectionModel->isSelected(index))
+        extraFlags |= QStyle::State_Selected;
+
+    if (level >= outer) {
+        // start with the innermost branch
+        primitive.moveLeft(reverse ? primitive.left() : primitive.left() - indent);
+        opt.rect = primitive;
+
+        const bool expanded = viewItem.expanded;
+        const bool children = (((expanded && viewItem.total > 0)) // already laid out and has children
+                                || d->hasVisibleChildren(index)); // not laid out yet, so we don't know
+        bool moreSiblings = false;
+        if (d->hiddenIndexes.isEmpty())
+            moreSiblings = (d->model->rowCount(parent) - 1 > index.row());
+        else
+            moreSiblings = ((d->viewItems.size() > item +1)
+                            && (d->viewItems.at(item + 1).index.parent() == parent));
+
+        opt.state = QStyle::State_Item | extraFlags
+                    | (moreSiblings ? QStyle::State_Sibling : QStyle::State_None)
+                    | (children ? QStyle::State_Children : QStyle::State_None)
+                    | (expanded ? QStyle::State_Open : QStyle::State_None);
+        if (hoverRow || item == d->hoverBranch)
+            opt.state |= QStyle::State_MouseOver;
+        else
+            opt.state &= ~QStyle::State_MouseOver;
+        style()->drawPrimitive(QStyle::PE_IndicatorBranch, &opt, painter, this);
+    }
+    // then go out level by level
+    for (--level; level >= outer; --level) { // we have already drawn the innermost branch
+        primitive.moveLeft(reverse ? primitive.left() + indent : primitive.left() - indent);
+        opt.rect = primitive;
+        opt.state = extraFlags;
+        bool moreSiblings = false;
+        if (d->hiddenIndexes.isEmpty()) {
+            moreSiblings = (d->model->rowCount(ancestor) - 1 > current.row());
+        } else {
+            int successor = item + viewItem.total + 1;
+            while (successor < d->viewItems.size()
+                   && d->viewItems.at(successor).level >= uint(level)) {
+                const QTreeViewItem &successorItem = d->viewItems.at(successor);
+                if (successorItem.level == uint(level)) {
+                    moreSiblings = true;
+                    break;
+                }
+                successor += successorItem.total + 1;
+            }
+        }
+        if (moreSiblings)
+            opt.state |= QStyle::State_Sibling;
+        if (hoverRow || item == d->hoverBranch)
+            opt.state |= QStyle::State_MouseOver;
+        else
+            opt.state &= ~QStyle::State_MouseOver;
+        style()->drawPrimitive(QStyle::PE_IndicatorBranch, &opt, painter, this);
+        current = ancestor;
+        ancestor = current.parent();
+    }
+    painter->setBrushOrigin(oldBO);
+}
+
+/*!
+  \reimp
+*/
+void QTreeView::mousePressEvent(QMouseEvent *event)
+{
+	Q_D(QTreeView);
+    bool handled = false;
+    if (style()->styleHint(QStyle::SH_Q3ListViewExpand_SelectMouseType, 0, this) == QEvent::MouseButtonPress)
+        handled = d->expandOrCollapseItemAtPos(event->pos());
+	if (!handled && d->itemDecorationAt(event->pos()) == -1)
+        QAbstractItemView::mousePressEvent(event);
+}
+
+/*!
+  \reimp
+*/
+void QTreeView::mouseReleaseEvent(QMouseEvent *event)
+{
+    Q_D(QTreeView);
+    if (d->itemDecorationAt(event->pos()) == -1) {
+        QAbstractItemView::mouseReleaseEvent(event);
+    } else {
+        if (state() == QAbstractItemView::DragSelectingState)
+            setState(QAbstractItemView::NoState);
+        if (style()->styleHint(QStyle::SH_Q3ListViewExpand_SelectMouseType, 0, this) == QEvent::MouseButtonRelease)
+            d->expandOrCollapseItemAtPos(event->pos());
+    }
+}
+
+/*!
+  \reimp
+*/
+void QTreeView::mouseDoubleClickEvent(QMouseEvent *event)
+{
+    Q_D(QTreeView);
+    if (state() != NoState || !d->viewport->rect().contains(event->pos()))
+        return;
+
+    int i = d->itemDecorationAt(event->pos());
+    if (i == -1) {
+        i = d->itemAtCoordinate(event->y());
+        if (i == -1)
+            return; // user clicked outside the items
+
+        const QPersistentModelIndex firstColumnIndex = d->viewItems.at(i).index;
+
+        int column = d->header->logicalIndexAt(event->x());
+        QPersistentModelIndex persistent = firstColumnIndex.sibling(firstColumnIndex.row(), column);
+
+        if (d->pressedIndex != persistent) {
+            mousePressEvent(event);
+            return;
+        }
+
+        // signal handlers may change the model
+        emit doubleClicked(persistent);
+
+        if (!persistent.isValid())
+            return;
+
+        if (edit(persistent, DoubleClicked, event) || state() != NoState)
+            return; // the double click triggered editing
+
+        if (!style()->styleHint(QStyle::SH_ItemView_ActivateItemOnSingleClick, 0, this))
+            emit activated(persistent);
+
+        d->executePostedLayout(); // we need to make sure viewItems is updated
+        if (d->itemsExpandable
+            && d->expandsOnDoubleClick
+            && d->hasVisibleChildren(persistent)) {
+            if (!((i < d->viewItems.count()) && (d->viewItems.at(i).index == firstColumnIndex))) {
+                // find the new index of the item
+                for (i = 0; i < d->viewItems.count(); ++i) {
+                    if (d->viewItems.at(i).index == firstColumnIndex)
+                        break;
+                }
+                if (i == d->viewItems.count())
+                    return;
+            }
+            if (d->viewItems.at(i).expanded)
+                d->collapse(i, true);
+            else
+                d->expand(i, true);
+            updateGeometries();
+            viewport()->update();
+        }
+    }
+}
+
+/*!
+  \reimp
+*/
+void QTreeView::mouseMoveEvent(QMouseEvent *event)
+{
+    Q_D(QTreeView);
+    if (d->itemDecorationAt(event->pos()) == -1) // ### what about expanding/collapsing state ?
+        QAbstractItemView::mouseMoveEvent(event);
+}
+
+/*!
+  \reimp
+*/
+void QTreeView::keyPressEvent(QKeyEvent *event)
+{
+    Q_D(QTreeView);
+    QModelIndex current = currentIndex();
+    //this is the management of the expansion
+    if (d->isIndexValid(current) && d->model && d->itemsExpandable) {
+        switch (event->key()) {
+        case Qt::Key_Asterisk: {
+            QStack<QModelIndex> parents;
+            parents.push(current);
+                while (!parents.isEmpty()) {
+                    QModelIndex parent = parents.pop();
+                    for (int row = 0; row < d->model->rowCount(parent); ++row) {
+                        QModelIndex child = d->model->index(row, 0, parent);
+                        if (!d->isIndexValid(child))
+                            break;
+                        parents.push(child);
+                        expand(child);
+                    }
+                }
+                expand(current);
+            break; }
+        case Qt::Key_Plus:
+            expand(current);
+            break;
+        case Qt::Key_Minus:
+            collapse(current);
+            break;
+        }
+    }
+
+    QAbstractItemView::keyPressEvent(event);
+}
+
+/*!
+  \reimp
+*/
+QModelIndex QTreeView::indexAt(const QPoint &point) const
+{
+    Q_D(const QTreeView);
+    d->executePostedLayout();
+
+    int visualIndex = d->itemAtCoordinate(point.y());
+    QModelIndex idx = d->modelIndex(visualIndex);
+    if (!idx.isValid())
+        return QModelIndex();
+
+    if (d->viewItems.at(visualIndex).spanning)
+        return idx;
+
+    int column = d->columnAt(point.x());
+    if (column == idx.column())
+        return idx;
+    if (column < 0)
+        return QModelIndex();
+    return idx.sibling(idx.row(), column);
+}
+
+/*!
+  Returns the model index of the item above \a index.
+*/
+QModelIndex QTreeView::indexAbove(const QModelIndex &index) const
+{
+    Q_D(const QTreeView);
+    if (!d->isIndexValid(index))
+        return QModelIndex();
+    d->executePostedLayout();
+    int i = d->viewIndex(index);
+    if (--i < 0)
+        return QModelIndex();
+    return d->viewItems.at(i).index;
+}
+
+/*!
+  Returns the model index of the item below \a index.
+*/
+QModelIndex QTreeView::indexBelow(const QModelIndex &index) const
+{
+    Q_D(const QTreeView);
+    if (!d->isIndexValid(index))
+        return QModelIndex();
+    d->executePostedLayout();
+    int i = d->viewIndex(index);
+    if (++i >= d->viewItems.count())
+        return QModelIndex();
+    return d->viewItems.at(i).index;
+}
+
+/*!
+    \internal
+
+    Lays out the items in the tree view.
+*/
+void QTreeView::doItemsLayout()
+{
+    Q_D(QTreeView);
+    d->viewItems.clear(); // prepare for new layout
+    QModelIndex parent = d->root;
+    if (d->model->hasChildren(parent)) {
+        d->layout(-1);
+    }
+    QAbstractItemView::doItemsLayout();
+    d->header->doItemsLayout();
+}
+
+/*!
+  \reimp
+*/
+void QTreeView::reset()
+{
+    Q_D(QTreeView);
+    d->expandedIndexes.clear();
+    d->hiddenIndexes.clear();
+    d->spanningIndexes.clear();
+    d->viewItems.clear();
+    QAbstractItemView::reset();
+}
+
+/*!
+  Returns the horizontal offset of the items in the treeview.
+
+  Note that the tree view uses the horizontal header section
+  positions to determine the positions of columns in the view.
+
+  \sa verticalOffset()
+*/
+int QTreeView::horizontalOffset() const
+{
+    Q_D(const QTreeView);
+    return d->header->offset();
+}
+
+/*!
+  Returns the vertical offset of the items in the tree view.
+
+  \sa horizontalOffset()
+*/
+int QTreeView::verticalOffset() const
+{
+    Q_D(const QTreeView);
+    if (d->verticalScrollMode == QAbstractItemView::ScrollPerItem) {
+        if (d->uniformRowHeights)
+            return verticalScrollBar()->value() * d->defaultItemHeight;
+        // If we are scrolling per item and have non-uniform row heights,
+        // finding the vertical offset in pixels is going to be relatively slow.
+        // ### find a faster way to do this
+        d->executePostedLayout();
+        int offset = 0;
+        for (int i = 0; i < d->viewItems.count(); ++i) {
+            if (i == verticalScrollBar()->value())
+                return offset;
+            offset += d->itemHeight(i);
+        }
+        return 0;
+    }
+    // scroll per pixel
+    return verticalScrollBar()->value();
+}
+
+/*!
+    Move the cursor in the way described by \a cursorAction, using the
+    information provided by the button \a modifiers.
+*/
+QModelIndex QTreeView::moveCursor(CursorAction cursorAction, Qt::KeyboardModifiers modifiers)
+{
+    Q_D(QTreeView);
+    Q_UNUSED(modifiers);
+
+    d->executePostedLayout();
+
+    QModelIndex current = currentIndex();
+    if (!current.isValid()) {
+        int i = d->below(-1);
+        int c = 0;
+        while (c < d->header->count() && d->header->isSectionHidden(c))
+            ++c;
+        if (i < d->viewItems.count() && c < d->header->count()) {
+            return d->modelIndex(i, c);
+        }
+        return QModelIndex();
+    }
+    int vi = -1;
+#if defined(Q_WS_MAC) && !defined(QT_NO_STYLE_MAC)
+    // Selection behavior is slightly different on the Mac.
+    if (d->selectionMode == QAbstractItemView::ExtendedSelection
+        && d->selectionModel
+        && d->selectionModel->hasSelection()) {
+
+        const bool moveUpDown = (cursorAction == MoveUp || cursorAction == MoveDown);
+        const bool moveNextPrev = (cursorAction == MoveNext || cursorAction == MovePrevious);
+        const bool contiguousSelection = moveUpDown && (modifiers & Qt::ShiftModifier);
+
+        // Use the outermost index in the selection as the current index
+        if (!contiguousSelection && (moveUpDown || moveNextPrev)) {
+
+            // Find outermost index.
+            const bool useTopIndex = (cursorAction == MoveUp || cursorAction == MovePrevious);
+            int index = useTopIndex ? INT_MAX : INT_MIN;
+            const QItemSelection selection = d->selectionModel->selection();
+            for (int i = 0; i < selection.count(); ++i) {
+                const QItemSelectionRange &range = selection.at(i);
+                int candidate = d->viewIndex(useTopIndex ? range.topLeft() : range.bottomRight());
+                if (candidate >= 0)
+                    index = useTopIndex ? qMin(index, candidate) : qMax(index, candidate);
+            }
+
+            if (index >= 0 && index < INT_MAX)
+                vi = index;
+        }
+    }
+#endif
+    if (vi < 0)
+        vi = qMax(0, d->viewIndex(current));
+
+    switch (cursorAction) {
+    case MoveNext:
+    case MoveDown:
+#ifdef QT_KEYPAD_NAVIGATION
+        if (vi == d->viewItems.count()-1 && QApplication::keypadNavigationEnabled())
+            return d->model->index(0, current.column(), d->root);
+#endif
+        return d->modelIndex(d->below(vi), current.column());
+    case MovePrevious:
+    case MoveUp:
+#ifdef QT_KEYPAD_NAVIGATION
+        if (vi == 0 && QApplication::keypadNavigationEnabled())
+            return d->modelIndex(d->viewItems.count() - 1, current.column());
+#endif
+        return d->modelIndex(d->above(vi), current.column());
+    case MoveLeft: {
+        QScrollBar *sb = horizontalScrollBar();
+        if (vi < d->viewItems.count() && d->viewItems.at(vi).expanded && d->itemsExpandable && sb->value() == sb->minimum())
+            d->collapse(vi, true);
+        else {
+            bool descend = style()->styleHint(QStyle::SH_ItemView_ArrowKeysNavigateIntoChildren, 0, this);
+            if (descend) {
+                QModelIndex par = current.parent();
+                if (par.isValid() && par != rootIndex())
+                    return par;
+                else
+                    descend = false;
+            }
+            if (!descend) {
+                if (d->selectionBehavior == SelectItems || d->selectionBehavior == SelectColumns) {
+                    int visualColumn = d->header->visualIndex(current.column()) - 1;
+                    while (visualColumn >= 0 && isColumnHidden(d->header->logicalIndex(visualColumn)))
+                        visualColumn--;
+                    int newColumn = d->header->logicalIndex(visualColumn);
+                    QModelIndex next = current.sibling(current.row(), newColumn);
+                    if (next.isValid())
+                        return next;
+                }
+
+                sb->setValue(sb->value() - sb->singleStep());
+            }
+
+        }
+        updateGeometries();
+        viewport()->update();
+        break;
+    }
+    case MoveRight:
+        if (vi < d->viewItems.count() && !d->viewItems.at(vi).expanded && d->itemsExpandable
+            && d->hasVisibleChildren(d->viewItems.at(vi).index)) {
+            d->expand(vi, true);
+        } else {
+            bool descend = style()->styleHint(QStyle::SH_ItemView_ArrowKeysNavigateIntoChildren, 0, this);
+            if (descend) {
+                QModelIndex idx = d->modelIndex(d->below(vi));
+                if (idx.parent() == current)
+                    return idx;
+                else
+                    descend = false;
+            }
+            if (!descend) {
+                if (d->selectionBehavior == SelectItems || d->selectionBehavior == SelectColumns) {
+                    int visualColumn = d->header->visualIndex(current.column()) + 1;
+                    while (visualColumn < d->model->columnCount(current.parent()) && isColumnHidden(d->header->logicalIndex(visualColumn)))
+                        visualColumn++;
+
+                    QModelIndex next = current.sibling(current.row(), visualColumn);
+                    if (next.isValid())
+                        return next;
+                }
+
+                //last restort: we change the scrollbar value
+                QScrollBar *sb = horizontalScrollBar();
+                sb->setValue(sb->value() + sb->singleStep());
+            }
+        }
+        updateGeometries();
+        viewport()->update();
+        break;
+    case MovePageUp:
+        return d->modelIndex(d->pageUp(vi), current.column());
+    case MovePageDown:
+        return d->modelIndex(d->pageDown(vi), current.column());
+    case MoveHome:
+        return d->model->index(0, current.column(), d->root);
+    case MoveEnd:
+        return d->modelIndex(d->viewItems.count() - 1, current.column());
+    }
+    return current;
+}
+
+/*!
+  Applies the selection \a command to the items in or touched by the
+  rectangle, \a rect.
+
+  \sa selectionCommand()
+*/
+void QTreeView::setSelection(const QRect &rect, QItemSelectionModel::SelectionFlags command)
+{
+    Q_D(QTreeView);
+    if (!selectionModel() || rect.isNull())
+        return;
+
+    d->executePostedLayout();
+    QPoint tl(isRightToLeft() ? qMax(rect.left(), rect.right())
+              : qMin(rect.left(), rect.right()), qMin(rect.top(), rect.bottom()));
+    QPoint br(isRightToLeft() ? qMin(rect.left(), rect.right()) :
+              qMax(rect.left(), rect.right()), qMax(rect.top(), rect.bottom()));
+    QModelIndex topLeft = indexAt(tl);
+    QModelIndex bottomRight = indexAt(br);
+    if (!topLeft.isValid() && !bottomRight.isValid()) {
+        if (command & QItemSelectionModel::Clear)
+            selectionModel()->clear();
+        return;
+    }
+    if (!topLeft.isValid() && !d->viewItems.isEmpty())
+        topLeft = d->viewItems.first().index;
+    if (!bottomRight.isValid() && !d->viewItems.isEmpty()) {
+        const int column = d->header->logicalIndex(d->header->count() - 1);
+        const QModelIndex index = d->viewItems.last().index;
+        bottomRight = index.sibling(index.row(), column);
+    }
+
+    if (!d->isIndexEnabled(topLeft) || !d->isIndexEnabled(bottomRight))
+        return;
+
+    d->select(topLeft, bottomRight, command);
+}
+
+/*!
+  Returns the rectangle from the viewport of the items in the given
+  \a selection.
+*/
+QRegion QTreeView::visualRegionForSelection(const QItemSelection &selection) const
+{
+    Q_D(const QTreeView);
+    if (selection.isEmpty())
+        return QRegion();
+
+    QRegion selectionRegion;
+    for (int i = 0; i < selection.count(); ++i) {
+        QItemSelectionRange range = selection.at(i);
+        if (!range.isValid())
+            continue;
+        QModelIndex parent = range.parent();
+        QModelIndex leftIndex = range.topLeft();
+        int columnCount = d->model->columnCount(parent);
+        while (leftIndex.isValid() && isIndexHidden(leftIndex)) {
+            if (leftIndex.column() + 1 < columnCount)
+                leftIndex = d->model->index(leftIndex.row(), leftIndex.column() + 1, parent);
+            else
+                leftIndex = QModelIndex();
+        }
+        if (!leftIndex.isValid())
+            continue;
+        const QRect leftRect = visualRect(leftIndex);
+        int top = leftRect.top();
+        QModelIndex rightIndex = range.bottomRight();
+        while (rightIndex.isValid() && isIndexHidden(rightIndex)) {
+            if (rightIndex.column() - 1 >= 0)
+                rightIndex = d->model->index(rightIndex.row(), rightIndex.column() - 1, parent);
+            else
+                rightIndex = QModelIndex();
+        }
+        if (!rightIndex.isValid())
+            continue;
+        const QRect rightRect = visualRect(rightIndex);
+        int bottom = rightRect.bottom();
+        if (top > bottom)
+            qSwap<int>(top, bottom);
+        int height = bottom - top + 1;
+        if (d->header->sectionsMoved()) {
+            for (int c = range.left(); c <= range.right(); ++c)
+                selectionRegion += QRegion(QRect(columnViewportPosition(c), top,
+                                                 columnWidth(c), height));
+        } else {
+            QRect combined = leftRect|rightRect;
+            combined.setX(columnViewportPosition(isRightToLeft() ? range.right() : range.left()));
+            selectionRegion += combined;
+        }
+    }
+    return selectionRegion;
+}
+
+/*!
+  \reimp
+*/
+QModelIndexList QTreeView::selectedIndexes() const
+{
+    QModelIndexList viewSelected;
+    QModelIndexList modelSelected;
+    if (selectionModel())
+        modelSelected = selectionModel()->selectedIndexes();
+    for (int i = 0; i < modelSelected.count(); ++i) {
+        // check that neither the parents nor the index is hidden before we add
+        QModelIndex index = modelSelected.at(i);
+        while (index.isValid() && !isIndexHidden(index))
+            index = index.parent();
+        if (index.isValid())
+            continue;
+        viewSelected.append(modelSelected.at(i));
+    }
+    return viewSelected;
+}
+
+/*!
+  Scrolls the contents of the tree view by (\a dx, \a dy).
+*/
+void QTreeView::scrollContentsBy(int dx, int dy)
+{
+    Q_D(QTreeView);
+
+    d->delayedAutoScroll.stop(); // auto scroll was canceled by the user scrolling
+
+    dx = isRightToLeft() ? -dx : dx;
+    if (dx) {
+        if (horizontalScrollMode() == QAbstractItemView::ScrollPerItem) {
+            int oldOffset = d->header->offset();
+            if (horizontalScrollBar()->value() == horizontalScrollBar()->maximum())
+                d->header->setOffsetToLastSection();
+            else
+                d->header->setOffsetToSectionPosition(horizontalScrollBar()->value());
+            int newOffset = d->header->offset();
+            dx = isRightToLeft() ? newOffset - oldOffset : oldOffset - newOffset;
+        } else {
+            d->header->setOffset(horizontalScrollBar()->value());
+        }
+    }
+
+    const int itemHeight = d->defaultItemHeight <= 0 ? sizeHintForRow(0) : d->defaultItemHeight;
+    if (d->viewItems.isEmpty() || itemHeight == 0)
+        return;
+
+    // guestimate the number of items in the viewport
+    int viewCount = d->viewport->height() / itemHeight;
+    int maxDeltaY = qMin(d->viewItems.count(), viewCount);
+    // no need to do a lot of work if we are going to redraw the whole thing anyway
+    if (qAbs(dy) > qAbs(maxDeltaY) && d->editors.isEmpty()) {
+        verticalScrollBar()->update();
+        d->viewport->update();
+        return;
+    }
+
+    if (dy && verticalScrollMode() == QAbstractItemView::ScrollPerItem) {
+        int currentScrollbarValue = verticalScrollBar()->value();
+        int previousScrollbarValue = currentScrollbarValue + dy; // -(-dy)
+        int currentViewIndex = currentScrollbarValue; // the first visible item
+        int previousViewIndex = previousScrollbarValue;
+        const QVector<QTreeViewItem> viewItems = d->viewItems;
+        dy = 0;
+        if (previousViewIndex < currentViewIndex) { // scrolling down
+            for (int i = previousViewIndex; i < currentViewIndex; ++i) {
+                if (i < d->viewItems.count())
+                    dy -= d->itemHeight(i);
+            }
+        } else if (previousViewIndex > currentViewIndex) { // scrolling up
+            for (int i = previousViewIndex - 1; i >= currentViewIndex; --i) {
+                if (i < d->viewItems.count())
+                    dy += d->itemHeight(i);
+            }
+        }
+    }
+
+    d->scrollContentsBy(dx, dy);
+}
+
+/*!
+  This slot is called whenever a column has been moved.
+*/
+void QTreeView::columnMoved()
+{
+    Q_D(QTreeView);
+    updateEditorGeometries();
+    d->viewport->update();
+}
+
+/*!
+  \internal
+*/
+void QTreeView::reexpand()
+{
+    // do nothing
+}
+
+/*!
+  \internal
+*/
+static bool treeViewItemLessThan(const QTreeViewItem &left,
+                                 const QTreeViewItem &right)
+{
+    if (left.level != right.level) {
+        Q_ASSERT(left.level > right.level);
+        QModelIndex leftParent = left.index.parent();
+        QModelIndex rightParent = right.index.parent();
+        // computer parent, don't get
+        while (leftParent.isValid() && leftParent.parent() != rightParent)
+            leftParent = leftParent.parent();
+        return (leftParent.row() < right.index.row());
+    }
+    return (left.index.row() < right.index.row());
+}
+
+/*!
+  Informs the view that the rows from the \a start row to the \a end row
+  inclusive have been inserted into the \a parent model item.
+*/
+void QTreeView::rowsInserted(const QModelIndex &parent, int start, int end)
+{
+    Q_D(QTreeView);
+    // if we are going to do a complete relayout anyway, there is no need to update
+    if (d->delayedPendingLayout) {
+        QAbstractItemView::rowsInserted(parent, start, end);
+        return;
+    }
+
+    //don't add a hierarchy on a column != 0
+    if (parent.column() != 0 && parent.isValid()) {
+        QAbstractItemView::rowsInserted(parent, start, end);
+        return;
+    }
+
+    if (parent != d->root && !d->isIndexExpanded(parent) && d->model->rowCount(parent) > (end - start) + 1) {
+        QAbstractItemView::rowsInserted(parent, start, end);
+        return;
+    }
+
+    const int parentItem = d->viewIndex(parent);
+    if (((parentItem != -1) && d->viewItems.at(parentItem).expanded && updatesEnabled())
+        || (parent == d->root)) {
+        const uint childLevel = (parentItem == -1)
+                                ? uint(0) : d->viewItems.at(parentItem).level + 1;
+        const int firstChildItem = parentItem + 1;
+        const int lastChildItem = firstChildItem + ((parentItem == -1)
+                                                    ? d->viewItems.count()
+                                                    : d->viewItems.at(parentItem).total) - 1;
+
+        const int delta = end - start + 1;
+        QVector<QTreeViewItem> insertedItems(delta);
+        for (int i = 0; i < delta; ++i) {
+            insertedItems[i].index = d->model->index(i + start, 0, parent);
+            insertedItems[i].level = childLevel;
+        }
+        if (d->viewItems.isEmpty())
+            d->defaultItemHeight = indexRowSizeHint(insertedItems[0].index);
+
+        int insertPos;
+        if (lastChildItem < firstChildItem) { // no children
+            insertPos = firstChildItem;
+        } else {
+            // do a binary search to figure out where to insert
+            QVector<QTreeViewItem>::iterator it;
+            it = qLowerBound(d->viewItems.begin() + firstChildItem,
+                             d->viewItems.begin() + lastChildItem + 1,
+                             insertedItems.at(0), treeViewItemLessThan);
+            insertPos = it - d->viewItems.begin();
+
+            // update stale model indexes of siblings
+            for (int item = insertPos; item <= lastChildItem; ) {
+                Q_ASSERT(d->viewItems.at(item).level == childLevel);
+                const QModelIndex modelIndex = d->viewItems.at(item).index;
+                //Q_ASSERT(modelIndex.parent() == parent);
+                d->viewItems[item].index = d->model->index(
+                    modelIndex.row() + delta, modelIndex.column(), parent);
+
+                if (!d->viewItems[item].index.isValid()) {
+                    // Something really bad is happening, a bad model is
+                    // often the cause.  We can't optimize in this case :(
+                    qWarning() << "QTreeView::rowsInserted internal representation of the model has been corrupted, resetting.";
+                    doItemsLayout();
+                    return;
+                }
+
+                item += d->viewItems.at(item).total + 1;
+            }
+        }
+
+        d->viewItems.insert(insertPos, delta, insertedItems.at(0));
+        if (delta > 1) {
+            qCopy(insertedItems.begin() + 1, insertedItems.end(),
+                  d->viewItems.begin() + insertPos + 1);
+        }
+
+        d->updateChildCount(parentItem, delta);
+        updateGeometries();
+        viewport()->update();
+    } else if ((parentItem != -1) && d->viewItems.at(parentItem).expanded) {
+        d->doDelayedItemsLayout();
+    } else if (parentItem != -1 && (d->model->rowCount(parent) == end - start + 1)) {
+        // the parent just went from 0 children to having some update to re-paint the decoration
+        viewport()->update();
+    }
+    QAbstractItemView::rowsInserted(parent, start, end);
+}
+
+/*!
+  Informs the view that the rows from the \a start row to the \a end row
+  inclusive are about to removed from the given \a parent model item.
+*/
+void QTreeView::rowsAboutToBeRemoved(const QModelIndex &parent, int start, int end)
+{
+    Q_D(QTreeView);
+    d->rowsRemoved(parent, start, end, false);
+    QAbstractItemView::rowsAboutToBeRemoved(parent, start, end);
+}
+
+/*!
+    \since 4.1
+
+    Informs the view that the rows from the \a start row to the \a end row
+    inclusive have been removed from the given \a parent model item.
+*/
+void QTreeView::rowsRemoved(const QModelIndex &parent, int start, int end)
+{
+    Q_D(QTreeView);
+    d->rowsRemoved(parent, start, end, true);
+}
+
+/*!
+  Informs the tree view that the number of columns in the tree view has
+  changed from \a oldCount to \a newCount.
+*/
+void QTreeView::columnCountChanged(int oldCount, int newCount)
+{
+    Q_D(QTreeView);
+    if (oldCount == 0 && newCount > 0) {
+        //if the first column has just been added we need to relayout.
+        d->doDelayedItemsLayout();
+    }
+
+    if (isVisible())
+        updateGeometries();
+	viewport()->update();
+}
+
+/*!
+  Resizes the \a column given to the size of its contents.
+
+  \sa columnWidth(), setColumnWidth()
+*/
+void QTreeView::resizeColumnToContents(int column)
+{
+    Q_D(QTreeView);
+    d->executePostedLayout();
+    if (column < 0 || column >= d->header->count())
+        return;
+    int contents = sizeHintForColumn(column);
+    int header = d->header->isHidden() ? 0 : d->header->sectionSizeHint(column);
+    d->header->resizeSection(column, qMax(contents, header));
+}
+
+/*!
+  \obsolete
+  \overload
+
+  Sorts the model by the values in the given \a column.
+*/
+void QTreeView::sortByColumn(int column)
+{
+    Q_D(QTreeView);
+    sortByColumn(column, d->header->sortIndicatorOrder());
+}
+
+/*!
+  \since 4.2
+
+  Sets the model up for sorting by the values in the given \a column and \a order.
+
+  \a column may be -1, in which case no sort indicator will be shown
+  and the model will return to its natural, unsorted order. Note that not
+  all models support this and may even crash in this case.
+
+  \sa sortingEnabled
+*/
+void QTreeView::sortByColumn(int column, Qt::SortOrder order)
+{
+    Q_D(QTreeView);
+
+    //If sorting is enabled  will emit a signal connected to _q_sortIndicatorChanged, which then actually sorts
+    d->header->setSortIndicator(column, order);
+    //If sorting is not enabled, force to sort now.
+    if (!d->sortingEnabled)
+        d->model->sort(column, order);
+}
+
+/*!
+  \reimp
+*/
+void QTreeView::selectAll()
+{
+    Q_D(QTreeView);
+    if (!selectionModel())
+        return;
+    SelectionMode mode = d->selectionMode;
+    d->executePostedLayout(); //make sure we lay out the items
+    if (mode != SingleSelection && !d->viewItems.isEmpty())
+        d->select(d->viewItems.first().index, d->viewItems.last().index,
+                  QItemSelectionModel::ClearAndSelect
+                  |QItemSelectionModel::Rows);
+}
+
+/*!
+  \since 4.2
+  Expands all expandable items.
+
+  Warning: if the model contains a large number of items,
+  this function will take some time to execute.
+
+  \sa collapseAll() expand()  collapse() setExpanded()
+*/
+void QTreeView::expandAll()
+{
+    Q_D(QTreeView);
+    d->viewItems.clear();
+    d->expandedIndexes.clear();
+    d->interruptDelayedItemsLayout();
+    d->layout(-1);
+    for (int i = 0; i < d->viewItems.count(); ++i) {
+        if (d->viewItems[i].expanded)
+            continue;
+        d->viewItems[i].expanded = true;
+        d->layout(i);
+        QModelIndex idx = d->viewItems.at(i).index;
+        d->expandedIndexes.insert(idx);
+    }
+    updateGeometries();
+    d->viewport->update();
+}
+
+/*!
+  \since 4.2
+
+  Collapses all expanded items.
+
+  \sa expandAll() expand()  collapse() setExpanded()
+*/
+void QTreeView::collapseAll()
+{
+    Q_D(QTreeView);
+    d->expandedIndexes.clear();
+    doItemsLayout();
+}
+
+/*!
+  \since 4.3
+  Expands all expandable items to the given \a depth.
+
+  \sa expandAll() collapseAll() expand()  collapse() setExpanded()
+*/
+void QTreeView::expandToDepth(int depth)
+{
+    Q_D(QTreeView);
+    d->viewItems.clear();
+    d->expandedIndexes.clear();
+    d->interruptDelayedItemsLayout();
+    d->layout(-1);
+    for (int i = 0; i < d->viewItems.count(); ++i) {
+        if (d->viewItems.at(i).level <= (uint)depth) {
+            d->viewItems[i].expanded = true;
+            d->layout(i);
+            d->storeExpanded(d->viewItems.at(i).index);
+        }
+    }
+    updateGeometries();
+    d->viewport->update();
+}
+
+/*!
+    This function is called whenever \a{column}'s size is changed in
+    the header. \a oldSize and \a newSize give the previous size and
+    the new size in pixels.
+
+    \sa setColumnWidth()
+*/
+void QTreeView::columnResized(int column, int /* oldSize */, int /* newSize */)
+{
+    Q_D(QTreeView);
+    d->columnsToUpdate.append(column);
+    if (d->columnResizeTimerID == 0)
+        d->columnResizeTimerID = startTimer(0);
+}
+
+/*!
+  \reimp
+*/
+void QTreeView::updateGeometries()
+{
+    Q_D(QTreeView);
+    if (d->header) {
+        if (d->geometryRecursionBlock)
+            return;
+        d->geometryRecursionBlock = true;
+        QSize hint = d->header->isHidden() ? QSize(0, 0) : d->header->sizeHint();
+        setViewportMargins(0, hint.height(), 0, 0);
+        QRect vg = d->viewport->geometry();
+        QRect geometryRect(vg.left(), vg.top() - hint.height(), vg.width(), hint.height());
+        d->header->setGeometry(geometryRect);
+        //d->header->setOffset(horizontalScrollBar()->value()); // ### bug ???
+        QMetaObject::invokeMethod(d->header, "updateGeometries");
+        d->updateScrollBars();
+        d->geometryRecursionBlock = false;
+    }
+    QAbstractItemView::updateGeometries();
+}
+
+/*!
+  Returns the size hint for the \a column's width or -1 if there is no
+  model.
+
+  If you need to set the width of a given column to a fixed value, call
+  QHeaderView::resizeSection() on the view's header.
+
+  If you reimplement this function in a subclass, note that the value you
+  return is only used when resizeColumnToContents() is called. In that case,
+  if a larger column width is required by either the view's header or
+  the item delegate, that width will be used instead.
+
+  \sa QWidget::sizeHint, header()
+*/
+int QTreeView::sizeHintForColumn(int column) const
+{
+    Q_D(const QTreeView);
+    d->executePostedLayout();
+    if (d->viewItems.isEmpty())
+        return -1;
+    int w = 0;
+    QStyleOptionViewItemV4 option = d->viewOptionsV4();
+    const QVector<QTreeViewItem> viewItems = d->viewItems;
+
+    int start = 0;
+    int end = viewItems.count();
+    if(end > 1000) { //if we have too many item this function would be too slow.
+        //we get a good approximation by only iterate over 1000 items.
+        start = qMax(0, d->firstVisibleItem() - 100);
+        end = qMin(end, start + 900);
+    }
+
+    for (int i = start; i < end; ++i) {
+        if (viewItems.at(i).spanning)
+            continue; // we have no good size hint
+        QModelIndex index = viewItems.at(i).index;
+        index = index.sibling(index.row(), column);
+        QWidget *editor = d->editorForIndex(index).editor;
+        if (editor && d->persistent.contains(editor)) {
+            w = qMax(w, editor->sizeHint().width());
+            int min = editor->minimumSize().width();
+            int max = editor->maximumSize().width();
+            w = qBound(min, w, max);
+        }
+        int hint = d->delegateForIndex(index)->sizeHint(option, index).width();
+        w = qMax(w, hint + (column == 0 ? d->indentationForItem(i) : 0));
+    }
+    return w;
+}
+
+/*!
+  Returns the size hint for the row indicated by \a index.
+
+  \sa sizeHintForColumn(), uniformRowHeights()
+*/
+int QTreeView::indexRowSizeHint(const QModelIndex &index) const
+{
+    Q_D(const QTreeView);
+    if (!d->isIndexValid(index) || !d->itemDelegate)
+        return 0;
+
+    int start = -1;
+    int end = -1;
+    int count = d->header->count();
+    bool emptyHeader = (count == 0);
+    QModelIndex parent = index.parent();
+
+    if (count && isVisible()) {
+        // If the sections have moved, we end up checking too many or too few
+        start = d->header->visualIndexAt(0);
+    } else {
+        // If the header has not been laid out yet, we use the model directly
+        count = d->model->columnCount(parent);
+    }
+
+    if (isRightToLeft()) {
+        start = (start == -1 ? count - 1 : start);
+        end = 0;
+    } else {
+        start = (start == -1 ? 0 : start);
+        end = count - 1;
+    }
+
+    if (end < start)
+        qSwap(end, start);
+
+    int height = -1;
+    QStyleOptionViewItemV4 option = d->viewOptionsV4();
+    // ### If we want word wrapping in the items,
+    // ### we need to go through all the columns
+    // ### and set the width of the column
+
+    // Hack to speed up the function
+    option.rect.setWidth(-1);
+
+    for (int column = start; column <= end; ++column) {
+        int logicalColumn = emptyHeader ? column : d->header->logicalIndex(column);
+        if (d->header->isSectionHidden(logicalColumn))
+            continue;
+        QModelIndex idx = d->model->index(index.row(), logicalColumn, parent);
+        if (idx.isValid()) {
+            QWidget *editor = d->editorForIndex(idx).editor;
+            if (editor && d->persistent.contains(editor)) {
+                height = qMax(height, editor->sizeHint().height());
+                int min = editor->minimumSize().height();
+                int max = editor->maximumSize().height();
+                height = qBound(min, height, max);
+            }
+            int hint = d->delegateForIndex(idx)->sizeHint(option, idx).height();
+            height = qMax(height, hint);
+        }
+    }
+
+    return height;
+}
+
+/*!
+    \since 4.3
+    Returns the height of the row indicated by the given \a index.
+    \sa indexRowSizeHint()
+*/
+int QTreeView::rowHeight(const QModelIndex &index) const
+{
+    Q_D(const QTreeView);
+    d->executePostedLayout();
+    int i = d->viewIndex(index);
+    if (i == -1)
+        return 0;
+    return d->itemHeight(i);
+}
+
+/*!
+  \internal
+*/
+void QTreeView::horizontalScrollbarAction(int action)
+{
+    QAbstractItemView::horizontalScrollbarAction(action);
+}
+
+/*!
+  \reimp
+*/
+bool QTreeView::isIndexHidden(const QModelIndex &index) const
+{
+    return (isColumnHidden(index.column()) || isRowHidden(index.row(), index.parent()));
+}
+
+/*
+  private implementation
+*/
+void QTreeViewPrivate::initialize()
+{
+    Q_Q(QTreeView);
+    updateStyledFrameWidths();
+    q->setSelectionBehavior(QAbstractItemView::SelectRows);
+    q->setSelectionMode(QAbstractItemView::SingleSelection);
+    q->setHorizontalScrollMode(QAbstractItemView::ScrollPerPixel);
+    q->setAttribute(Qt::WA_MacShowFocusRect);
+
+    QHeaderView *header = new QHeaderView(Qt::Horizontal, q);
+    header->setMovable(true);
+    header->setStretchLastSection(true);
+    header->setDefaultAlignment(Qt::AlignLeft|Qt::AlignVCenter);
+    q->setHeader(header);
+#ifndef QT_NO_ANIMATION
+    QObject::connect(&animatedOperation, SIGNAL(finished()), q, SLOT(_q_endAnimatedOperation()));
+#endif //QT_NO_ANIMATION
+}
+
+void QTreeViewPrivate::expand(int item, bool emitSignal)
+{
+    Q_Q(QTreeView);
+
+    if (item == -1 || viewItems.at(item).expanded)
+        return;
+
+#ifndef QT_NO_ANIMATION
+    if (emitSignal && animationsEnabled)
+        prepareAnimatedOperation(item, QVariantAnimation::Forward);
+#endif //QT_NO_ANIMATION
+    QAbstractItemView::State oldState = state;
+    q->setState(QAbstractItemView::ExpandingState);
+    const QModelIndex index = viewItems.at(item).index;
+    storeExpanded(index);
+    viewItems[item].expanded = true;
+    layout(item);
+    q->setState(oldState);
+
+    if (model->canFetchMore(index))
+        model->fetchMore(index);
+    if (emitSignal) {
+        emit q->expanded(index);
+#ifndef QT_NO_ANIMATION
+        if (animationsEnabled)
+            beginAnimatedOperation();
+#endif //QT_NO_ANIMATION
+    }
+}
+
+void QTreeViewPrivate::collapse(int item, bool emitSignal)
+{
+    Q_Q(QTreeView);
+
+    if (item == -1 || expandedIndexes.isEmpty())
+        return;
+
+    //if the current item is now invisible, the autoscroll will expand the tree to see it, so disable the autoscroll
+    delayedAutoScroll.stop();
+
+    int total = viewItems.at(item).total;
+    const QModelIndex &modelIndex = viewItems.at(item).index;
+    if (!isPersistent(modelIndex))
+        return; // if the index is not persistent, no chances it is expanded
+    QSet<QPersistentModelIndex>::iterator it = expandedIndexes.find(modelIndex);
+    if (it == expandedIndexes.end() || viewItems.at(item).expanded == false)
+        return; // nothing to do
+
+#ifndef QT_NO_ANIMATION
+    if (emitSignal && animationsEnabled)
+        prepareAnimatedOperation(item, QVariantAnimation::Backward);
+#endif //QT_NO_ANIMATION
+
+    QAbstractItemView::State oldState = state;
+    q->setState(QAbstractItemView::CollapsingState);
+    expandedIndexes.erase(it);
+    viewItems[item].expanded = false;
+    int index = item;
+    QModelIndex parent = modelIndex;
+    while (parent.isValid() && parent != root) {
+        Q_ASSERT(index > -1);
+        viewItems[index].total -= total;
+        parent = parent.parent();
+        index = viewIndex(parent);
+    }
+    viewItems.remove(item + 1, total); // collapse
+    q->setState(oldState);
+
+    if (emitSignal) {
+        emit q->collapsed(modelIndex);
+#ifndef QT_NO_ANIMATION
+        if (animationsEnabled)
+            beginAnimatedOperation();
+#endif //QT_NO_ANIMATION
+    }
+}
+
+#ifndef QT_NO_ANIMATION
+void QTreeViewPrivate::prepareAnimatedOperation(int item, QVariantAnimation::Direction direction)
+{
+    animatedOperation.item = item;
+    animatedOperation.viewport = viewport;
+    animatedOperation.setDirection(direction);
+
+    int top = coordinateForItem(item) + itemHeight(item);
+    QRect rect = viewport->rect();
+    rect.setTop(top);
+    if (direction == QVariantAnimation::Backward) {
+        const int limit = rect.height() * 2;
+        int h = 0;
+        int c = item + viewItems.at(item).total + 1;
+        for (int i = item + 1; i < c && h < limit; ++i)
+            h += itemHeight(i);
+        rect.setHeight(h);
+        animatedOperation.setEndValue(top + h);
+    }
+    animatedOperation.setStartValue(top);
+    animatedOperation.before = renderTreeToPixmapForAnimation(rect);
+}
+
+void QTreeViewPrivate::beginAnimatedOperation()
+{
+    Q_Q(QTreeView);
+
+    QRect rect = viewport->rect();
+    rect.setTop(animatedOperation.top());
+    if (animatedOperation.direction() == QVariantAnimation::Forward) {
+        const int limit = rect.height() * 2;
+        int h = 0;
+        int c = animatedOperation.item + viewItems.at(animatedOperation.item).total + 1;
+        for (int i = animatedOperation.item + 1; i < c && h < limit; ++i)
+            h += itemHeight(i);
+        rect.setHeight(h);
+        animatedOperation.setEndValue(animatedOperation.top() + h);
+    }
+
+    if (!rect.isEmpty()) {
+        animatedOperation.after = renderTreeToPixmapForAnimation(rect);
+
+        q->setState(QAbstractItemView::AnimatingState);
+        animatedOperation.start(); //let's start the animation
+    }
+}
+
+void QTreeViewPrivate::drawAnimatedOperation(QPainter *painter) const
+{
+    const int start = animatedOperation.startValue().toInt(),
+        end = animatedOperation.endValue().toInt(),
+        current = animatedOperation.currentValue().toInt();
+    bool collapsing = animatedOperation.direction() == QVariantAnimation::Backward;
+    const QPixmap top = collapsing ? animatedOperation.before : animatedOperation.after;
+    painter->drawPixmap(0, start, top, 0, end - current - 1, top.width(), top.height());
+    const QPixmap bottom = collapsing ? animatedOperation.after : animatedOperation.before;
+    painter->drawPixmap(0, current, bottom);
+}
+
+QPixmap QTreeViewPrivate::renderTreeToPixmapForAnimation(const QRect &rect) const
+{
+    Q_Q(const QTreeView);
+    QPixmap pixmap(rect.size());
+    pixmap.fill(Qt::transparent); //the base might not be opaque, and we don't want uninitialized pixels.
+    QPainter painter(&pixmap);
+    painter.fillRect(QRect(QPoint(0,0), rect.size()), q->palette().base());
+    painter.translate(0, -rect.top());
+    q->drawTree(&painter, QRegion(rect));
+    painter.end();
+
+    //and now let's render the editors the editors
+    QStyleOptionViewItemV4 option = viewOptionsV4();
+    for (QList<QEditorInfo>::const_iterator it = editors.constBegin(); it != editors.constEnd(); ++it) {
+        QWidget *editor = it->editor;
+        QModelIndex index = it->index;
+        option.rect = q->visualRect(index);
+        if (option.rect.isValid()) {
+
+            if (QAbstractItemDelegate *delegate = delegateForIndex(index))
+                delegate->updateEditorGeometry(editor, option, index);
+
+            const QPoint pos = editor->pos();
+            if (rect.contains(pos)) {
+                editor->render(&pixmap, pos - rect.topLeft());
+                //the animation uses pixmap to display the treeview's content
+                //the editor is rendered on this pixmap and thus can (should) be hidden
+                editor->hide();
+            }
+        }
+    }
+
+
+    return pixmap;
+}
+
+void QTreeViewPrivate::_q_endAnimatedOperation()
+{
+    Q_Q(QTreeView);
+    q->setState(QAbstractItemView::NoState);
+    q->updateGeometries();
+    viewport->update();
+}
+#endif //QT_NO_ANIMATION
+
+void QTreeViewPrivate::_q_modelAboutToBeReset()
+{
+    viewItems.clear();
+}
+
+void QTreeViewPrivate::_q_columnsAboutToBeRemoved(const QModelIndex &parent, int start, int end)
+{
+    if (start <= 0 && 0 <= end)
+        viewItems.clear();
+    QAbstractItemViewPrivate::_q_columnsAboutToBeRemoved(parent, start, end);
+}
+
+void QTreeViewPrivate::_q_columnsRemoved(const QModelIndex &parent, int start, int end)
+{
+    if (start <= 0 && 0 <= end)
+        doDelayedItemsLayout();
+    QAbstractItemViewPrivate::_q_columnsRemoved(parent, start, end);
+}
+
+void QTreeViewPrivate::layout(int i)
+{
+    Q_Q(QTreeView);
+    QModelIndex current;
+    QModelIndex parent = (i < 0) ? (QModelIndex)root : modelIndex(i);
+
+    if (i>=0 && !parent.isValid()) {
+        //modelIndex() should never return something invalid for the real items.
+        //This can happen if columncount has been set to 0.
+        //To avoid infinite loop we stop here.
+        return;
+    }
+
+    int count = 0;
+    if (model->hasChildren(parent)) {
+        if (model->canFetchMore(parent))
+            model->fetchMore(parent);
+        count = model->rowCount(parent);
+    }
+
+    bool expanding = true;
+    if (i == -1) {
+        if (uniformRowHeights) {
+            QModelIndex index = model->index(0, 0, parent);
+            defaultItemHeight = q->indexRowSizeHint(index);
+        }
+        viewItems.resize(count);
+    } else if (viewItems[i].total != (uint)count) {
+            viewItems.insert(i + 1, count, QTreeViewItem()); // expand
+    } else {
+        expanding = false;
+    }
+
+    int first = i + 1;
+    int level = (i >= 0 ? viewItems.at(i).level + 1 : 0);
+    int hidden = 0;
+    int last = 0;
+    int children = 0;
+
+    for (int j = first; j < first + count; ++j) {
+        current = model->index(j - first, 0, parent);
+        if (isRowHidden(current)) {
+            ++hidden;
+            last = j - hidden + children;
+        } else {
+            last = j - hidden + children;
+            viewItems[last].index = current;
+            viewItems[last].level = level;
+            viewItems[last].height = 0;
+            viewItems[last].spanning = q->isFirstColumnSpanned(current.row(), parent);
+            viewItems[last].expanded = false;
+            viewItems[last].total = 0;
+            if (isIndexExpanded(current)) {
+                viewItems[last].expanded = true;
+                layout(last);
+                children += viewItems[last].total;
+                last = j - hidden + children;
+            }
+        }
+    }
+
+    // remove hidden items
+    if (hidden > 0)
+        viewItems.remove(last + 1, hidden); // collapse
+
+    if (!expanding)
+        return; // nothing changed
+
+    while (parent != root) {
+        Q_ASSERT(i > -1);
+        viewItems[i].total += count - hidden;
+        parent = parent.parent();
+        i = viewIndex(parent);
+    }
+}
+
+int QTreeViewPrivate::pageUp(int i) const
+{
+    int index = itemAtCoordinate(coordinateForItem(i) - viewport->height());
+    return index == -1 ? 0 : index;
+}
+
+int QTreeViewPrivate::pageDown(int i) const
+{
+    int index = itemAtCoordinate(coordinateForItem(i) + viewport->height());
+    return index == -1 ? viewItems.count() - 1 : index;
+}
+
+int QTreeViewPrivate::indentationForItem(int item) const
+{
+    if (item < 0 || item >= viewItems.count())
+        return 0;
+    int level = viewItems.at(item).level;
+    if (rootDecoration)
+        ++level;
+    return level * indent;
+}
+
+int QTreeViewPrivate::itemHeight(int item) const
+{
+    if (uniformRowHeights)
+        return defaultItemHeight;
+    if (viewItems.isEmpty())
+        return 0;
+    const QModelIndex &index = viewItems.at(item).index;
+    int height = viewItems.at(item).height;
+    if (height <= 0 && index.isValid()) {
+        height = q_func()->indexRowSizeHint(index);
+        viewItems[item].height = height;
+    }
+    if (!index.isValid() || height < 0)
+        return 0;
+    return height;
+}
+
+
+/*!
+  \internal
+  Returns the viewport y coordinate for \a item.
+*/
+int QTreeViewPrivate::coordinateForItem(int item) const
+{
+    if (verticalScrollMode == QAbstractItemView::ScrollPerPixel) {
+        if (uniformRowHeights)
+            return (item * defaultItemHeight) - vbar->value();
+        // ### optimize (spans or caching)
+        int y = 0;
+        for (int i = 0; i < viewItems.count(); ++i) {
+            if (i == item)
+                return y - vbar->value();
+            y += itemHeight(i);
+        }
+    } else { // ScrollPerItem
+        int topViewItemIndex = vbar->value();
+        if (uniformRowHeights)
+            return defaultItemHeight * (item - topViewItemIndex);
+        if (item >= topViewItemIndex) {
+            // search in the visible area first and continue down
+            // ### slow if the item is not visible
+            int viewItemCoordinate = 0;
+            int viewItemIndex = topViewItemIndex;
+            while (viewItemIndex < viewItems.count()) {
+                if (viewItemIndex == item)
+                    return viewItemCoordinate;
+                viewItemCoordinate += itemHeight(viewItemIndex);
+                ++viewItemIndex;
+            }
+            // below the last item in the view
+            Q_ASSERT(false);
+            return viewItemCoordinate;
+        } else {
+            // search the area above the viewport (used for editor widgets)
+            int viewItemCoordinate = 0;
+            for (int viewItemIndex = topViewItemIndex; viewItemIndex > 0; --viewItemIndex) {
+                if (viewItemIndex == item)
+                    return viewItemCoordinate;
+                viewItemCoordinate -= itemHeight(viewItemIndex - 1);
+            }
+            return viewItemCoordinate;
+        }
+    }
+    return 0;
+}
+
+/*!
+  \internal
+  Returns the index of the view item at the
+  given viewport \a coordinate.
+
+  \sa modelIndex()
+*/
+int QTreeViewPrivate::itemAtCoordinate(int coordinate) const
+{
+    const int itemCount = viewItems.count();
+    if (itemCount == 0)
+        return -1;
+    if (uniformRowHeights && defaultItemHeight <= 0)
+        return -1;
+    if (verticalScrollMode == QAbstractItemView::ScrollPerPixel) {
+        if (uniformRowHeights) {
+            const int viewItemIndex = (coordinate + vbar->value()) / defaultItemHeight;
+            return ((viewItemIndex >= itemCount || viewItemIndex < 0) ? -1 : viewItemIndex);
+        }
+        // ### optimize
+        int viewItemCoordinate = 0;
+        const int contentsCoordinate = coordinate + vbar->value();
+        for (int viewItemIndex = 0; viewItemIndex < viewItems.count(); ++viewItemIndex) {
+            viewItemCoordinate += itemHeight(viewItemIndex);
+            if (viewItemCoordinate >= contentsCoordinate)
+                return (viewItemIndex >= itemCount ? -1 : viewItemIndex);
+        }
+    } else { // ScrollPerItem
+        int topViewItemIndex = vbar->value();
+        if (uniformRowHeights) {
+            if (coordinate < 0)
+                coordinate -= defaultItemHeight - 1;
+            const int viewItemIndex = topViewItemIndex + (coordinate / defaultItemHeight);
+            return ((viewItemIndex >= itemCount || viewItemIndex < 0) ? -1 : viewItemIndex);
+        }
+        if (coordinate >= 0) {
+            // the coordinate is in or below the viewport
+            int viewItemCoordinate = 0;
+            for (int viewItemIndex = topViewItemIndex; viewItemIndex < viewItems.count(); ++viewItemIndex) {
+                viewItemCoordinate += itemHeight(viewItemIndex);
+                if (viewItemCoordinate > coordinate)
+                    return (viewItemIndex >= itemCount ? -1 : viewItemIndex);
+            }
+        } else {
+            // the coordinate is above the viewport
+            int viewItemCoordinate = 0;
+            for (int viewItemIndex = topViewItemIndex; viewItemIndex >= 0; --viewItemIndex) {
+                if (viewItemCoordinate <= coordinate)
+                    return (viewItemIndex >= itemCount ? -1 : viewItemIndex);
+                viewItemCoordinate -= itemHeight(viewItemIndex);
+            }
+        }
+    }
+    return -1;
+}
+
+int QTreeViewPrivate::viewIndex(const QModelIndex &_index) const
+{
+    if (!_index.isValid() || viewItems.isEmpty())
+        return -1;
+
+    const int totalCount = viewItems.count();
+    const QModelIndex index = _index.sibling(_index.row(), 0);
+
+
+    // A quick check near the last item to see if we are just incrementing
+    const int start = lastViewedItem > 2 ? lastViewedItem - 2 : 0;
+    const int end = lastViewedItem < totalCount - 2 ? lastViewedItem + 2 : totalCount;
+    int row = index.row();
+    for (int i = start; i < end; ++i) {
+        const QModelIndex &idx = viewItems.at(i).index;
+        if (idx.row() == row) {
+            if (idx.internalId() == index.internalId()) {
+                lastViewedItem = i;
+                return i;
+            }
+        }
+    }
+
+    // NOTE: this function is slow if the item is outside the visible area
+    // search in visible items first and below
+    int t = firstVisibleItem();
+    t = t > 100 ? t - 100 : 0; // start 100 items above the visible area
+
+    for (int i = t; i < totalCount; ++i) {
+        const QModelIndex &idx = viewItems.at(i).index;
+        if (idx.row() == row) {
+            if (idx.internalId() == index.internalId()) {
+                lastViewedItem = i;
+                return i;
+            }
+        }
+    }
+    // search from top to first visible
+    for (int j = 0; j < t; ++j) {
+        const QModelIndex &idx = viewItems.at(j).index;
+        if (idx.row() == row) {
+            if (idx.internalId() == index.internalId()) {
+                lastViewedItem = j;
+                return j;
+            }
+        }
+    }
+    // nothing found
+    return -1;
+}
+
+QModelIndex QTreeViewPrivate::modelIndex(int i, int column) const
+{
+    if (i < 0 || i >= viewItems.count())
+        return QModelIndex();
+
+    QModelIndex ret = viewItems.at(i).index;
+    if (column)
+        ret = ret.sibling(ret.row(), column);
+    return ret;
+}
+
+int QTreeViewPrivate::firstVisibleItem(int *offset) const
+{
+    const int value = vbar->value();
+    if (verticalScrollMode == QAbstractItemView::ScrollPerItem) {
+        if (offset)
+            *offset = 0;
+        return (value < 0 || value >= viewItems.count()) ? -1 : value;
+    }
+    // ScrollMode == ScrollPerPixel
+    if (uniformRowHeights) {
+        if (!defaultItemHeight)
+            return -1;
+
+        if (offset)
+            *offset = -(value % defaultItemHeight);
+        return value / defaultItemHeight;
+    }
+    int y = 0; // ### optimize (use spans ?)
+    for (int i = 0; i < viewItems.count(); ++i) {
+        y += itemHeight(i); // the height value is cached
+        if (y > value) {
+            if (offset)
+                *offset = y - value - itemHeight(i);
+            return i;
+        }
+    }
+    return -1;
+}
+
+int QTreeViewPrivate::columnAt(int x) const
+{
+    return header->logicalIndexAt(x);
+}
+
+void QTreeViewPrivate::relayout(const QModelIndex &parent)
+{
+    Q_Q(QTreeView);
+    // do a local relayout of the items
+    if (parent.isValid()) {
+        int parentViewIndex = viewIndex(parent);
+        if (parentViewIndex > -1 && viewItems.at(parentViewIndex).expanded) {
+            collapse(parentViewIndex, false); // remove the current layout
+            expand(parentViewIndex, false); // do the relayout
+            q->updateGeometries();
+            viewport->update();
+        }
+    } else {
+        viewItems.clear();
+        q->doItemsLayout();
+    }
+}
+
+
+void QTreeViewPrivate::updateScrollBars()
+{
+    Q_Q(QTreeView);
+    QSize viewportSize = viewport->size();
+    if (!viewportSize.isValid())
+        viewportSize = QSize(0, 0);
+
+    int itemsInViewport = 0;
+    if (uniformRowHeights) {
+        if (defaultItemHeight <= 0)
+            itemsInViewport = viewItems.count();
+        else
+            itemsInViewport = viewportSize.height() / defaultItemHeight;
+    } else {
+        const int itemsCount = viewItems.count();
+        const int viewportHeight = viewportSize.height();
+        for (int height = 0, item = itemsCount - 1; item >= 0; --item) {
+            height += itemHeight(item);
+            if (height > viewportHeight)
+                break;
+            ++itemsInViewport;
+        }
+    }
+    if (verticalScrollMode == QAbstractItemView::ScrollPerItem) {
+        if (!viewItems.isEmpty())
+            itemsInViewport = qMax(1, itemsInViewport);
+        vbar->setRange(0, viewItems.count() - itemsInViewport);
+        vbar->setPageStep(itemsInViewport);
+        vbar->setSingleStep(1);
+    } else { // scroll per pixel
+        int contentsHeight = 0;
+        if (uniformRowHeights) {
+            contentsHeight = defaultItemHeight * viewItems.count();
+        } else { // ### optimize (spans or caching)
+            for (int i = 0; i < viewItems.count(); ++i)
+                contentsHeight += itemHeight(i);
+        }
+        vbar->setRange(0, contentsHeight - viewportSize.height());
+        vbar->setPageStep(viewportSize.height());
+        vbar->setSingleStep(qMax(viewportSize.height() / (itemsInViewport + 1), 2));
+    }
+
+    const int columnCount = header->count();
+    const int viewportWidth = viewportSize.width();
+    int columnsInViewport = 0;
+    for (int width = 0, column = columnCount - 1; column >= 0; --column) {
+        int logical = header->logicalIndex(column);
+        width += header->sectionSize(logical);
+        if (width > viewportWidth)
+            break;
+        ++columnsInViewport;
+    }
+    if (columnCount > 0)
+        columnsInViewport = qMax(1, columnsInViewport);
+    if (horizontalScrollMode == QAbstractItemView::ScrollPerItem) {
+        hbar->setRange(0, columnCount - columnsInViewport);
+        hbar->setPageStep(columnsInViewport);
+        hbar->setSingleStep(1);
+    } else { // scroll per pixel
+        const int horizontalLength = header->length();
+        const QSize maxSize = q->maximumViewportSize();
+        if (maxSize.width() >= horizontalLength && vbar->maximum() <= 0)
+            viewportSize = maxSize;
+        hbar->setPageStep(viewportSize.width());
+        hbar->setRange(0, qMax(horizontalLength - viewportSize.width(), 0));
+        hbar->setSingleStep(qMax(viewportSize.width() / (columnsInViewport + 1), 2));
+    }
+}
+
+int QTreeViewPrivate::itemDecorationAt(const QPoint &pos) const
+{
+    executePostedLayout();
+    int x = pos.x();
+    int column = header->logicalIndexAt(x);
+    if (column != 0)
+        return -1; // no logical index at x
+
+    int viewItemIndex = itemAtCoordinate(pos.y());
+    QRect returning = itemDecorationRect(modelIndex(viewItemIndex));
+    if (!returning.contains(pos))
+        return -1;
+
+    return viewItemIndex;
+}
+
+QRect QTreeViewPrivate::itemDecorationRect(const QModelIndex &index) const
+{
+    Q_Q(const QTreeView);
+    if (!rootDecoration && index.parent() == root)
+        return QRect(); // no decoration at root
+
+    int viewItemIndex = viewIndex(index);
+    if (viewItemIndex < 0 || !hasVisibleChildren(viewItems.at(viewItemIndex).index))
+        return QRect();
+
+    int itemIndentation = indentationForItem(viewItemIndex);
+    int position = header->sectionViewportPosition(0);
+    int size = header->sectionSize(0);
+
+    QRect rect;
+    if (q->isRightToLeft())
+        rect = QRect(position + size - itemIndentation, coordinateForItem(viewItemIndex),
+                     indent, itemHeight(viewItemIndex));
+    else
+        rect = QRect(position + itemIndentation - indent, coordinateForItem(viewItemIndex),
+                     indent, itemHeight(viewItemIndex));
+    QStyleOption opt;
+    opt.initFrom(q);
+    opt.rect = rect;
+    return q->style()->subElementRect(QStyle::SE_TreeViewDisclosureItem, &opt, q);
+}
+
+QList<QPair<int, int> > QTreeViewPrivate::columnRanges(const QModelIndex &topIndex,
+                                                          const QModelIndex &bottomIndex) const
+{
+    const int topVisual = header->visualIndex(topIndex.column()),
+        bottomVisual = header->visualIndex(bottomIndex.column());
+
+    const int start = qMin(topVisual, bottomVisual);
+    const int end = qMax(topVisual, bottomVisual);
+
+    QList<int> logicalIndexes;
+
+    //we iterate over the visual indexes to get the logical indexes
+    for (int c = start; c <= end; c++) {
+        const int logical = header->logicalIndex(c);
+        if (!header->isSectionHidden(logical)) {
+            logicalIndexes << logical;
+        }
+    }
+    //let's sort the list
+    qSort(logicalIndexes.begin(), logicalIndexes.end());
+
+    QList<QPair<int, int> > ret;
+    QPair<int, int> current;
+    current.first = -2; // -1 is not enough because -1+1 = 0
+    current.second = -2;
+    for(int i = 0; i < logicalIndexes.count(); ++i) {
+        const int logicalColumn = logicalIndexes.at(i);
+        if (current.second + 1 != logicalColumn) {
+            if (current.first != -2) {
+                //let's save the current one
+                ret += current;
+            }
+            //let's start a new one
+            current.first = current.second = logicalColumn;
+        } else {
+            current.second++;
+        }
+    }
+
+    //let's get the last range
+    if (current.first != -2) {
+        ret += current;
+    }
+
+    return ret;
+}
+
+void QTreeViewPrivate::select(const QModelIndex &topIndex, const QModelIndex &bottomIndex,
+                              QItemSelectionModel::SelectionFlags command)
+{
+    Q_Q(QTreeView);
+    QItemSelection selection;
+    const int top = viewIndex(topIndex),
+        bottom = viewIndex(bottomIndex);
+
+    const QList< QPair<int, int> > colRanges = columnRanges(topIndex, bottomIndex);
+    QList< QPair<int, int> >::const_iterator it;
+    for (it = colRanges.begin(); it != colRanges.end(); ++it) {
+        const int left = (*it).first,
+            right = (*it).second;
+
+        QModelIndex previous;
+        QItemSelectionRange currentRange;
+        QStack<QItemSelectionRange> rangeStack;
+        for (int i = top; i <= bottom; ++i) {
+            QModelIndex index = modelIndex(i);
+            QModelIndex parent = index.parent();
+            QModelIndex previousParent = previous.parent();
+            if (previous.isValid() && parent == previousParent) {
+                // same parent
+                if (qAbs(previous.row() - index.row()) > 1) {
+                    //a hole (hidden index inside a range) has been detected
+                    if (currentRange.isValid()) {
+                        selection.append(currentRange);
+                    }
+                    //let's start a new range
+                    currentRange = QItemSelectionRange(index.sibling(index.row(), left), index.sibling(index.row(), right));
+                } else {
+                    QModelIndex tl = model->index(currentRange.top(), currentRange.left(),
+                        currentRange.parent());
+                    currentRange = QItemSelectionRange(tl, index.sibling(index.row(), right));
+                }
+            } else if (previous.isValid() && parent == model->index(previous.row(), 0, previousParent)) {
+                // item is child of previous
+                rangeStack.push(currentRange);
+                currentRange = QItemSelectionRange(index.sibling(index.row(), left), index.sibling(index.row(), right));
+            } else {
+                if (currentRange.isValid())
+                    selection.append(currentRange);
+                if (rangeStack.isEmpty()) {
+                    currentRange = QItemSelectionRange(index.sibling(index.row(), left), index.sibling(index.row(), right));
+                } else {
+                    currentRange = rangeStack.pop();
+                    index = currentRange.bottomRight(); //let's resume the range
+                    --i; //we process again the current item
+                }
+            }
+            previous = index;
+        }
+        if (currentRange.isValid())
+            selection.append(currentRange);
+        for (int i = 0; i < rangeStack.count(); ++i)
+            selection.append(rangeStack.at(i));
+    }
+    q->selectionModel()->select(selection, command);
+}
+
+QPair<int,int> QTreeViewPrivate::startAndEndColumns(const QRect &rect) const
+{
+    Q_Q(const QTreeView);
+    int start = header->visualIndexAt(rect.left());
+    int end = header->visualIndexAt(rect.right());
+    if (q->isRightToLeft()) {
+        start = (start == -1 ? header->count() - 1 : start);
+        end = (end == -1 ? 0 : end);
+    } else {
+        start = (start == -1 ? 0 : start);
+        end = (end == -1 ? header->count() - 1 : end);
+    }
+    return qMakePair<int,int>(qMin(start, end), qMax(start, end));
+}
+
+bool QTreeViewPrivate::hasVisibleChildren(const QModelIndex& parent) const
+{
+    Q_Q(const QTreeView);
+    if (model->hasChildren(parent)) {
+        if (hiddenIndexes.isEmpty())
+            return true;
+        if (q->isIndexHidden(parent))
+            return false;
+        int rowCount = model->rowCount(parent);
+        for (int i = 0; i < rowCount; ++i) {
+            if (!q->isRowHidden(i, parent))
+                return true;
+        }
+        if (rowCount == 0)
+            return true;
+    }
+    return false;
+}
+
+void QTreeViewPrivate::rowsRemoved(const QModelIndex &parent,
+                                   int start, int end, bool after)
+{
+    Q_Q(QTreeView);
+    // if we are going to do a complete relayout anyway, there is no need to update
+    if (delayedPendingLayout) {
+        _q_rowsRemoved(parent, start, end);
+        return;
+    }
+
+    const int parentItem = viewIndex(parent);
+    if ((parentItem != -1) || (parent == root)) {
+
+        const uint childLevel = (parentItem == -1)
+                                ? uint(0) : viewItems.at(parentItem).level + 1;
+        Q_UNUSED(childLevel); // unused in release mode, used in assert below
+
+        const int firstChildItem = parentItem + 1;
+        int lastChildItem = firstChildItem + ((parentItem == -1)
+                                              ? viewItems.count()
+                                              : viewItems.at(parentItem).total) - 1;
+
+        const int delta = end - start + 1;
+
+        int removedCount = 0;
+        for (int item = firstChildItem; item <= lastChildItem; ) {
+            Q_ASSERT(viewItems.at(item).level == childLevel);
+            const QModelIndex modelIndex = viewItems.at(item).index;
+            //Q_ASSERT(modelIndex.parent() == parent);
+            const int count = viewItems.at(item).total + 1;
+            if (modelIndex.row() < start) {
+                // not affected by the removal
+                item += count;
+            } else if (modelIndex.row() <= end) {
+                // removed
+                viewItems.remove(item, count);
+                removedCount += count;
+                lastChildItem -= count;
+            } else {
+                if (after) {
+                    // moved; update the model index
+                    viewItems[item].index = model->index(
+                        modelIndex.row() - delta, modelIndex.column(), parent);
+                }
+                item += count;
+            }
+        }
+
+        updateChildCount(parentItem, -removedCount);
+        if (after) {
+            q->updateGeometries();
+            viewport->update();
+        } else {
+            //we have removed items: we should at least update the scroll bar values.
+            // They are used to determine the item geometry.
+            updateScrollBars();
+        }
+    } else {
+        // If an ancestor of root is removed then relayout
+        QModelIndex idx = root;
+        while (idx.isValid()) {
+            idx = idx.parent();
+            if (idx == parent) {
+                doDelayedItemsLayout();
+                break;
+            }
+        }
+    }
+    _q_rowsRemoved(parent, start, end);
+
+    QSet<QPersistentModelIndex>::iterator it = expandedIndexes.begin();
+    while (it != expandedIndexes.constEnd()) {
+        if (!it->isValid())
+            it = expandedIndexes.erase(it);
+        else
+            ++it;
+    }
+    it = hiddenIndexes.begin();
+    while (it != hiddenIndexes.constEnd()) {
+        if (!it->isValid())
+            it = hiddenIndexes.erase(it);
+        else
+            ++it;
+    }
+}
+
+void QTreeViewPrivate::updateChildCount(const int parentItem, const int delta)
+{
+    if ((parentItem != -1) && delta) {
+        int level = viewItems.at(parentItem).level;
+        int item = parentItem;
+        do {
+            Q_ASSERT(item >= 0);
+            for ( ; int(viewItems.at(item).level) != level; --item) ;
+            viewItems[item].total += delta;
+            --level;
+        } while (level >= 0);
+    }
+}
+
+
+void QTreeViewPrivate::_q_sortIndicatorChanged(int column, Qt::SortOrder order)
+{
+    model->sort(column, order);
+}
+
+/*!
+  \reimp
+ */
+void QTreeView::currentChanged(const QModelIndex &current, const QModelIndex &previous)
+{
+#ifndef QT_NO_ACCESSIBILITY
+    if (QAccessible::isActive()) {
+        int entry = visualIndex(current) + 1;
+        if (header())
+            ++entry;
+        QAccessible::updateAccessibility(viewport(), entry, QAccessible::Focus);
+    }
+#endif
+    QAbstractItemView::currentChanged(current, previous);
+
+    if (allColumnsShowFocus()) {
+        if (previous.isValid()) {
+            QRect previousRect = visualRect(previous);
+            previousRect.setX(0);
+            previousRect.setWidth(viewport()->width());
+            viewport()->update(previousRect);
+        }
+        if (current.isValid()) {
+            QRect currentRect = visualRect(current);
+            currentRect.setX(0);
+            currentRect.setWidth(viewport()->width());
+            viewport()->update(currentRect);
+        }
+    }
+}
+
+/*!
+  \reimp
+ */
+void QTreeView::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;
+            if (header())
+                ++entry;
+            QAccessible::updateAccessibility(viewport(), entry, QAccessible::Selection);
+        }
+        QModelIndex desel = deselected.indexes().value(0);
+        if (desel.isValid()) {
+            int entry = visualIndex(desel) + 1;
+            if (header())
+                ++entry;
+            QAccessible::updateAccessibility(viewport(), entry, QAccessible::SelectionRemove);
+        }
+    }
+#endif
+    QAbstractItemView::selectionChanged(selected, deselected);
+}
+
+int QTreeView::visualIndex(const QModelIndex &index) const
+{
+    Q_D(const QTreeView);
+    d->executePostedLayout();
+    return d->viewIndex(index);
+}
+
+QT_END_NAMESPACE
+
+#include "moc_qtreeview.cpp"
+
+#endif // QT_NO_TREEVIEW