util/src/gui/itemviews/qtreeview.cpp
changeset 7 f7bc934e204c
equal deleted inserted replaced
3:41300fa6a67c 7:f7bc934e204c
       
     1 /****************************************************************************
       
     2 **
       
     3 ** Copyright (C) 2010 Nokia Corporation and/or its subsidiary(-ies).
       
     4 ** All rights reserved.
       
     5 ** Contact: Nokia Corporation (qt-info@nokia.com)
       
     6 **
       
     7 ** This file is part of the QtGui module of the Qt Toolkit.
       
     8 **
       
     9 ** $QT_BEGIN_LICENSE:LGPL$
       
    10 ** No Commercial Usage
       
    11 ** This file contains pre-release code and may not be distributed.
       
    12 ** You may use this file in accordance with the terms and conditions
       
    13 ** contained in the Technology Preview License Agreement accompanying
       
    14 ** this package.
       
    15 **
       
    16 ** GNU Lesser General Public License Usage
       
    17 ** Alternatively, this file may be used under the terms of the GNU Lesser
       
    18 ** General Public License version 2.1 as published by the Free Software
       
    19 ** Foundation and appearing in the file LICENSE.LGPL included in the
       
    20 ** packaging of this file.  Please review the following information to
       
    21 ** ensure the GNU Lesser General Public License version 2.1 requirements
       
    22 ** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
       
    23 **
       
    24 ** In addition, as a special exception, Nokia gives you certain additional
       
    25 ** rights.  These rights are described in the Nokia Qt LGPL Exception
       
    26 ** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
       
    27 **
       
    28 ** If you have questions regarding the use of this file, please contact
       
    29 ** Nokia at qt-info@nokia.com.
       
    30 **
       
    31 **
       
    32 **
       
    33 **
       
    34 **
       
    35 **
       
    36 **
       
    37 **
       
    38 ** $QT_END_LICENSE$
       
    39 **
       
    40 ****************************************************************************/
       
    41 #include "qtreeview.h"
       
    42 
       
    43 #ifndef QT_NO_TREEVIEW
       
    44 #include <qheaderview.h>
       
    45 #include <qitemdelegate.h>
       
    46 #include <qapplication.h>
       
    47 #include <qscrollbar.h>
       
    48 #include <qpainter.h>
       
    49 #include <qstack.h>
       
    50 #include <qstyle.h>
       
    51 #include <qstyleoption.h>
       
    52 #include <qevent.h>
       
    53 #include <qpen.h>
       
    54 #include <qdebug.h>
       
    55 #ifndef QT_NO_ACCESSIBILITY
       
    56 #include <qaccessible.h>
       
    57 #endif
       
    58 
       
    59 #include <private/qtreeview_p.h>
       
    60 
       
    61 QT_BEGIN_NAMESPACE
       
    62 
       
    63 /*!
       
    64     \class QTreeView
       
    65     \brief The QTreeView class provides a default model/view implementation of a tree view.
       
    66 
       
    67     \ingroup model-view
       
    68     \ingroup advanced
       
    69 
       
    70 
       
    71     A QTreeView implements a tree representation of items from a
       
    72     model. This class is used to provide standard hierarchical lists that
       
    73     were previously provided by the \c QListView class, but using the more
       
    74     flexible approach provided by Qt's model/view architecture.
       
    75 
       
    76     The QTreeView class is one of the \l{Model/View Classes} and is part of
       
    77     Qt's \l{Model/View Programming}{model/view framework}.
       
    78 
       
    79     QTreeView implements the interfaces defined by the
       
    80     QAbstractItemView class to allow it to display data provided by
       
    81     models derived from the QAbstractItemModel class.
       
    82 
       
    83     It is simple to construct a tree view displaying data from a
       
    84     model. In the following example, the contents of a directory are
       
    85     supplied by a QDirModel and displayed as a tree:
       
    86 
       
    87     \snippet doc/src/snippets/shareddirmodel/main.cpp 3
       
    88     \snippet doc/src/snippets/shareddirmodel/main.cpp 6
       
    89 
       
    90     The model/view architecture ensures that the contents of the tree view
       
    91     are updated as the model changes.
       
    92 
       
    93     Items that have children can be in an expanded (children are
       
    94     visible) or collapsed (children are hidden) state. When this state
       
    95     changes a collapsed() or expanded() signal is emitted with the
       
    96     model index of the relevant item.
       
    97 
       
    98     The amount of indentation used to indicate levels of hierarchy is
       
    99     controlled by the \l indentation property.
       
   100 
       
   101     Headers in tree views are constructed using the QHeaderView class and can
       
   102     be hidden using \c{header()->hide()}. Note that each header is configured
       
   103     with its \l{QHeaderView::}{stretchLastSection} property set to true,
       
   104     ensuring that the view does not waste any of the space assigned to it for
       
   105     its header. If this value is set to true, this property will override the
       
   106     resize mode set on the last section in the header.
       
   107 
       
   108 
       
   109     \section1 Key Bindings
       
   110 
       
   111     QTreeView supports a set of key bindings that enable the user to
       
   112     navigate in the view and interact with the contents of items:
       
   113 
       
   114     \table
       
   115     \header \o Key \o Action
       
   116     \row \o Up   \o Moves the cursor to the item in the same column on
       
   117          the previous row. If the parent of the current item has no more rows to
       
   118          navigate to, the cursor moves to the relevant item in the last row
       
   119          of the sibling that precedes the parent.
       
   120     \row \o Down \o Moves the cursor to the item in the same column on
       
   121          the next row. If the parent of the current item has no more rows to
       
   122          navigate to, the cursor moves to the relevant item in the first row
       
   123          of the sibling that follows the parent.
       
   124     \row \o Left  \o Hides the children of the current item (if present)
       
   125          by collapsing a branch.
       
   126     \row \o Minus  \o Same as LeftArrow.
       
   127     \row \o Right \o Reveals the children of the current item (if present)
       
   128          by expanding a branch.
       
   129     \row \o Plus  \o Same as RightArrow.
       
   130     \row \o Asterisk  \o Expands all children of the current item (if present).
       
   131     \row \o PageUp   \o Moves the cursor up one page.
       
   132     \row \o PageDown \o Moves the cursor down one page.
       
   133     \row \o Home \o Moves the cursor to an item in the same column of the first
       
   134          row of the first top-level item in the model.
       
   135     \row \o End  \o Moves the cursor to an item in the same column of the last
       
   136          row of the last top-level item in the model.
       
   137     \row \o F2   \o In editable models, this opens the current item for editing.
       
   138          The Escape key can be used to cancel the editing process and revert
       
   139          any changes to the data displayed.
       
   140     \endtable
       
   141 
       
   142     \omit
       
   143     Describe the expanding/collapsing concept if not covered elsewhere.
       
   144     \endomit
       
   145 
       
   146     \table 100%
       
   147     \row \o \inlineimage windowsxp-treeview.png Screenshot of a Windows XP style tree view
       
   148          \o \inlineimage macintosh-treeview.png Screenshot of a Macintosh style tree view
       
   149          \o \inlineimage plastique-treeview.png Screenshot of a Plastique style tree view
       
   150     \row \o A \l{Windows XP Style Widget Gallery}{Windows XP style} tree view.
       
   151          \o A \l{Macintosh Style Widget Gallery}{Macintosh style} tree view.
       
   152          \o A \l{Plastique Style Widget Gallery}{Plastique style} tree view.
       
   153     \endtable
       
   154 
       
   155     \section1 Improving Performance
       
   156 
       
   157     It is possible to give the view hints about the data it is handling in order
       
   158     to improve its performance when displaying large numbers of items. One approach
       
   159     that can be taken for views that are intended to display items with equal heights
       
   160     is to set the \l uniformRowHeights property to true.
       
   161 
       
   162     \sa QListView, QTreeWidget, {View Classes}, QAbstractItemModel, QAbstractItemView,
       
   163         {Dir View Example}
       
   164 */
       
   165 
       
   166 
       
   167 /*!
       
   168   \fn void QTreeView::expanded(const QModelIndex &index)
       
   169 
       
   170   This signal is emitted when the item specified by \a index is expanded.
       
   171 */
       
   172 
       
   173 
       
   174 /*!
       
   175   \fn void QTreeView::collapsed(const QModelIndex &index)
       
   176 
       
   177   This signal is emitted when the item specified by \a index is collapsed.
       
   178 */
       
   179 
       
   180 /*!
       
   181     Constructs a tree view with a \a parent to represent a model's
       
   182     data. Use setModel() to set the model.
       
   183 
       
   184     \sa QAbstractItemModel
       
   185 */
       
   186 QTreeView::QTreeView(QWidget *parent)
       
   187     : QAbstractItemView(*new QTreeViewPrivate, parent)
       
   188 {
       
   189     Q_D(QTreeView);
       
   190     d->initialize();
       
   191 }
       
   192 
       
   193 /*!
       
   194   \internal
       
   195 */
       
   196 QTreeView::QTreeView(QTreeViewPrivate &dd, QWidget *parent)
       
   197     : QAbstractItemView(dd, parent)
       
   198 {
       
   199     Q_D(QTreeView);
       
   200     d->initialize();
       
   201 }
       
   202 
       
   203 /*!
       
   204   Destroys the tree view.
       
   205 */
       
   206 QTreeView::~QTreeView()
       
   207 {
       
   208 }
       
   209 
       
   210 /*!
       
   211   \reimp
       
   212 */
       
   213 void QTreeView::setModel(QAbstractItemModel *model)
       
   214 {
       
   215     Q_D(QTreeView);
       
   216     if (model == d->model)
       
   217         return;
       
   218     if (d->model && d->model != QAbstractItemModelPrivate::staticEmptyModel()) {
       
   219         disconnect(d->model, SIGNAL(rowsRemoved(QModelIndex,int,int)),
       
   220                 this, SLOT(rowsRemoved(QModelIndex,int,int)));
       
   221 
       
   222         disconnect(d->model, SIGNAL(modelAboutToBeReset()), this, SLOT(_q_modelAboutToBeReset()));
       
   223     }
       
   224 
       
   225     if (d->selectionModel) { // support row editing
       
   226         disconnect(d->selectionModel, SIGNAL(currentRowChanged(QModelIndex,QModelIndex)),
       
   227                    d->model, SLOT(submit()));
       
   228         disconnect(d->model, SIGNAL(rowsRemoved(QModelIndex,int,int)),
       
   229                    this, SLOT(rowsRemoved(QModelIndex,int,int)));
       
   230         disconnect(d->model, SIGNAL(modelAboutToBeReset()), this, SLOT(_q_modelAboutToBeReset()));
       
   231     }
       
   232     d->viewItems.clear();
       
   233     d->expandedIndexes.clear();
       
   234     d->hiddenIndexes.clear();
       
   235     d->header->setModel(model);
       
   236     QAbstractItemView::setModel(model);
       
   237 
       
   238     // QAbstractItemView connects to a private slot
       
   239     disconnect(d->model, SIGNAL(rowsRemoved(QModelIndex,int,int)),
       
   240                this, SLOT(_q_rowsRemoved(QModelIndex,int,int)));
       
   241     // do header layout after the tree
       
   242     disconnect(d->model, SIGNAL(layoutChanged()),
       
   243                d->header, SLOT(_q_layoutChanged()));
       
   244     // QTreeView has a public slot for this
       
   245     connect(d->model, SIGNAL(rowsRemoved(QModelIndex,int,int)),
       
   246             this, SLOT(rowsRemoved(QModelIndex,int,int)));
       
   247 
       
   248     connect(d->model, SIGNAL(modelAboutToBeReset()), SLOT(_q_modelAboutToBeReset()));
       
   249 
       
   250     if (d->sortingEnabled)
       
   251         d->_q_sortIndicatorChanged(header()->sortIndicatorSection(), header()->sortIndicatorOrder());
       
   252 }
       
   253 
       
   254 /*!
       
   255   \reimp
       
   256 */
       
   257 void QTreeView::setRootIndex(const QModelIndex &index)
       
   258 {
       
   259     Q_D(QTreeView);
       
   260     d->header->setRootIndex(index);
       
   261     QAbstractItemView::setRootIndex(index);
       
   262 }
       
   263 
       
   264 /*!
       
   265   \reimp
       
   266 */
       
   267 void QTreeView::setSelectionModel(QItemSelectionModel *selectionModel)
       
   268 {
       
   269     Q_D(QTreeView);
       
   270     Q_ASSERT(selectionModel);
       
   271     if (d->selectionModel) {
       
   272         // support row editing
       
   273         disconnect(d->selectionModel, SIGNAL(currentRowChanged(QModelIndex,QModelIndex)),
       
   274                    d->model, SLOT(submit()));
       
   275     }
       
   276 
       
   277     d->header->setSelectionModel(selectionModel);
       
   278     QAbstractItemView::setSelectionModel(selectionModel);
       
   279 
       
   280     if (d->selectionModel) {
       
   281         // support row editing
       
   282         connect(d->selectionModel, SIGNAL(currentRowChanged(QModelIndex,QModelIndex)),
       
   283                 d->model, SLOT(submit()));
       
   284     }
       
   285 }
       
   286 
       
   287 /*!
       
   288   Returns the header for the tree view.
       
   289 
       
   290   \sa QAbstractItemModel::headerData()
       
   291 */
       
   292 QHeaderView *QTreeView::header() const
       
   293 {
       
   294     Q_D(const QTreeView);
       
   295     return d->header;
       
   296 }
       
   297 
       
   298 /*!
       
   299     Sets the header for the tree view, to the given \a header.
       
   300 
       
   301     The view takes ownership over the given \a header and deletes it
       
   302     when a new header is set.
       
   303 
       
   304     \sa QAbstractItemModel::headerData()
       
   305 */
       
   306 void QTreeView::setHeader(QHeaderView *header)
       
   307 {
       
   308     Q_D(QTreeView);
       
   309     if (header == d->header || !header)
       
   310         return;
       
   311     if (d->header && d->header->parent() == this)
       
   312         delete d->header;
       
   313     d->header = header;
       
   314     d->header->setParent(this);
       
   315 
       
   316     if (!d->header->model()) {
       
   317         d->header->setModel(d->model);
       
   318         if (d->selectionModel)
       
   319             d->header->setSelectionModel(d->selectionModel);
       
   320     }
       
   321 
       
   322     connect(d->header, SIGNAL(sectionResized(int,int,int)),
       
   323             this, SLOT(columnResized(int,int,int)));
       
   324     connect(d->header, SIGNAL(sectionMoved(int,int,int)),
       
   325             this, SLOT(columnMoved()));
       
   326     connect(d->header, SIGNAL(sectionCountChanged(int,int)),
       
   327             this, SLOT(columnCountChanged(int,int)));
       
   328     connect(d->header, SIGNAL(sectionHandleDoubleClicked(int)),
       
   329             this, SLOT(resizeColumnToContents(int)));
       
   330     connect(d->header, SIGNAL(geometriesChanged()),
       
   331             this, SLOT(updateGeometries()));
       
   332 
       
   333     setSortingEnabled(d->sortingEnabled);
       
   334 }
       
   335 
       
   336 /*!
       
   337   \property QTreeView::autoExpandDelay
       
   338   \brief The delay time before items in a tree are opened during a drag and drop operation.
       
   339   \since 4.3
       
   340 
       
   341   This property holds the amount of time in milliseconds that the user must wait over
       
   342   a node before that node will automatically open or close.  If the time is
       
   343   set to less then 0 then it will not be activated.
       
   344 
       
   345   By default, this property has a value of -1, meaning that auto-expansion is disabled.
       
   346 */
       
   347 int QTreeView::autoExpandDelay() const
       
   348 {
       
   349     Q_D(const QTreeView);
       
   350     return d->autoExpandDelay;
       
   351 }
       
   352 
       
   353 void QTreeView::setAutoExpandDelay(int delay)
       
   354 {
       
   355     Q_D(QTreeView);
       
   356     d->autoExpandDelay = delay;
       
   357 }
       
   358 
       
   359 /*!
       
   360   \property QTreeView::indentation
       
   361   \brief indentation of the items in the tree view.
       
   362 
       
   363   This property holds the indentation measured in pixels of the items for each
       
   364   level in the tree view. For top-level items, the indentation specifies the
       
   365   horizontal distance from the viewport edge to the items in the first column;
       
   366   for child items, it specifies their indentation from their parent items.
       
   367 
       
   368   By default, this property has a value of 20.
       
   369 */
       
   370 int QTreeView::indentation() const
       
   371 {
       
   372     Q_D(const QTreeView);
       
   373     return d->indent;
       
   374 }
       
   375 
       
   376 void QTreeView::setIndentation(int i)
       
   377 {
       
   378     Q_D(QTreeView);
       
   379     if (i != d->indent) {
       
   380         d->indent = i;
       
   381         d->viewport->update();
       
   382     }
       
   383 }
       
   384 
       
   385 /*!
       
   386   \property QTreeView::rootIsDecorated
       
   387   \brief whether to show controls for expanding and collapsing top-level items
       
   388 
       
   389   Items with children are typically shown with controls to expand and collapse
       
   390   them, allowing their children to be shown or hidden. If this property is
       
   391   false, these controls are not shown for top-level items. This can be used to
       
   392   make a single level tree structure appear like a simple list of items.
       
   393 
       
   394   By default, this property is true.
       
   395 */
       
   396 bool QTreeView::rootIsDecorated() const
       
   397 {
       
   398     Q_D(const QTreeView);
       
   399     return d->rootDecoration;
       
   400 }
       
   401 
       
   402 void QTreeView::setRootIsDecorated(bool show)
       
   403 {
       
   404     Q_D(QTreeView);
       
   405     if (show != d->rootDecoration) {
       
   406         d->rootDecoration = show;
       
   407         d->viewport->update();
       
   408     }
       
   409 }
       
   410 
       
   411 /*!
       
   412   \property QTreeView::uniformRowHeights
       
   413   \brief whether all items in the treeview have the same height
       
   414 
       
   415   This property should only be set to true if it is guaranteed that all items
       
   416   in the view has the same height. This enables the view to do some
       
   417   optimizations.
       
   418 
       
   419   The height is obtained from the first item in the view.  It is updated
       
   420   when the data changes on that item.
       
   421 
       
   422   By default, this property is false.
       
   423 */
       
   424 bool QTreeView::uniformRowHeights() const
       
   425 {
       
   426     Q_D(const QTreeView);
       
   427     return d->uniformRowHeights;
       
   428 }
       
   429 
       
   430 void QTreeView::setUniformRowHeights(bool uniform)
       
   431 {
       
   432     Q_D(QTreeView);
       
   433     d->uniformRowHeights = uniform;
       
   434 }
       
   435 
       
   436 /*!
       
   437   \property QTreeView::itemsExpandable
       
   438   \brief whether the items are expandable by the user.
       
   439 
       
   440   This property holds whether the user can expand and collapse items
       
   441   interactively.
       
   442 
       
   443   By default, this property is true.
       
   444 
       
   445 */
       
   446 bool QTreeView::itemsExpandable() const
       
   447 {
       
   448     Q_D(const QTreeView);
       
   449     return d->itemsExpandable;
       
   450 }
       
   451 
       
   452 void QTreeView::setItemsExpandable(bool enable)
       
   453 {
       
   454     Q_D(QTreeView);
       
   455     d->itemsExpandable = enable;
       
   456 }
       
   457 
       
   458 /*!
       
   459   \property QTreeView::expandsOnDoubleClick
       
   460   \since 4.4
       
   461   \brief whether the items can be expanded by double-clicking.
       
   462 
       
   463   This property holds whether the user can expand and collapse items
       
   464   by double-clicking. The default value is true.
       
   465 
       
   466   \sa itemsExpandable
       
   467 */
       
   468 bool QTreeView::expandsOnDoubleClick() const
       
   469 {
       
   470     Q_D(const QTreeView);
       
   471     return d->expandsOnDoubleClick;
       
   472 }
       
   473 
       
   474 void QTreeView::setExpandsOnDoubleClick(bool enable)
       
   475 {
       
   476     Q_D(QTreeView);
       
   477     d->expandsOnDoubleClick = enable;
       
   478 }
       
   479 
       
   480 /*!
       
   481   Returns the horizontal position of the \a column in the viewport.
       
   482 */
       
   483 int QTreeView::columnViewportPosition(int column) const
       
   484 {
       
   485     Q_D(const QTreeView);
       
   486     return d->header->sectionViewportPosition(column);
       
   487 }
       
   488 
       
   489 /*!
       
   490   Returns the width of the \a column.
       
   491 
       
   492   \sa resizeColumnToContents(), setColumnWidth()
       
   493 */
       
   494 int QTreeView::columnWidth(int column) const
       
   495 {
       
   496     Q_D(const QTreeView);
       
   497     return d->header->sectionSize(column);
       
   498 }
       
   499 
       
   500 /*!
       
   501   \since 4.2
       
   502 
       
   503   Sets the width of the given \a column to the \a width specified.
       
   504 
       
   505   \sa columnWidth(), resizeColumnToContents()
       
   506 */
       
   507 void QTreeView::setColumnWidth(int column, int width)
       
   508 {
       
   509     Q_D(QTreeView);
       
   510     d->header->resizeSection(column, width);
       
   511 }
       
   512 
       
   513 /*!
       
   514   Returns the column in the tree view whose header covers the \a x
       
   515   coordinate given.
       
   516 */
       
   517 int QTreeView::columnAt(int x) const
       
   518 {
       
   519     Q_D(const QTreeView);
       
   520     return d->header->logicalIndexAt(x);
       
   521 }
       
   522 
       
   523 /*!
       
   524     Returns true if the \a column is hidden; otherwise returns false.
       
   525 
       
   526     \sa hideColumn(), isRowHidden()
       
   527 */
       
   528 bool QTreeView::isColumnHidden(int column) const
       
   529 {
       
   530     Q_D(const QTreeView);
       
   531     return d->header->isSectionHidden(column);
       
   532 }
       
   533 
       
   534 /*!
       
   535   If \a hide is true the \a column is hidden, otherwise the \a column is shown.
       
   536 
       
   537   \sa hideColumn(), setRowHidden()
       
   538 */
       
   539 void QTreeView::setColumnHidden(int column, bool hide)
       
   540 {
       
   541     Q_D(QTreeView);
       
   542     if (column < 0 || column >= d->header->count())
       
   543         return;
       
   544     d->header->setSectionHidden(column, hide);
       
   545 }
       
   546 
       
   547 /*!
       
   548   \property QTreeView::headerHidden
       
   549   \brief whether the header is shown or not.
       
   550   \since 4.4
       
   551 
       
   552   If this property is true, the header is not shown otherwise it is.
       
   553   The default value is false.
       
   554 
       
   555   \sa header()
       
   556 */
       
   557 bool QTreeView::isHeaderHidden() const
       
   558 {
       
   559     Q_D(const QTreeView);
       
   560     return d->header->isHidden();
       
   561 }
       
   562 
       
   563 void QTreeView::setHeaderHidden(bool hide)
       
   564 {
       
   565     Q_D(QTreeView);
       
   566     d->header->setHidden(hide);
       
   567 }
       
   568 
       
   569 /*!
       
   570     Returns true if the item in the given \a row of the \a parent is hidden;
       
   571     otherwise returns false.
       
   572 
       
   573     \sa setRowHidden(), isColumnHidden()
       
   574 */
       
   575 bool QTreeView::isRowHidden(int row, const QModelIndex &parent) const
       
   576 {
       
   577     Q_D(const QTreeView);
       
   578     if (!d->model)
       
   579         return false;
       
   580     return d->isRowHidden(d->model->index(row, 0, parent));
       
   581 }
       
   582 
       
   583 /*!
       
   584   If \a hide is true the \a row with the given \a parent is hidden, otherwise the \a row is shown.
       
   585 
       
   586   \sa isRowHidden(), setColumnHidden()
       
   587 */
       
   588 void QTreeView::setRowHidden(int row, const QModelIndex &parent, bool hide)
       
   589 {
       
   590     Q_D(QTreeView);
       
   591     if (!d->model)
       
   592         return;
       
   593     QModelIndex index = d->model->index(row, 0, parent);
       
   594     if (!index.isValid())
       
   595         return;
       
   596 
       
   597     if (hide) {
       
   598         d->hiddenIndexes.insert(index);
       
   599     } else if(d->isPersistent(index)) { //if the index is not persistent, it cannot be in the set
       
   600         d->hiddenIndexes.remove(index);
       
   601     }
       
   602 
       
   603     d->doDelayedItemsLayout();
       
   604 }
       
   605 
       
   606 /*!
       
   607   \since 4.3
       
   608 
       
   609   Returns true if the item in first column in the given \a row
       
   610   of the \a parent is spanning all the columns; otherwise returns false.
       
   611 
       
   612   \sa setFirstColumnSpanned()
       
   613 */
       
   614 bool QTreeView::isFirstColumnSpanned(int row, const QModelIndex &parent) const
       
   615 {
       
   616     Q_D(const QTreeView);
       
   617     if (d->spanningIndexes.isEmpty() || !d->model)
       
   618         return false;
       
   619     QModelIndex index = d->model->index(row, 0, parent);
       
   620     for (int i = 0; i < d->spanningIndexes.count(); ++i)
       
   621         if (d->spanningIndexes.at(i) == index)
       
   622             return true;
       
   623     return false;
       
   624 }
       
   625 
       
   626 /*!
       
   627   \since 4.3
       
   628 
       
   629   If \a span is true the item in the first column in the \a row
       
   630   with the given \a parent is set to span all columns, otherwise all items
       
   631   on the \a row are shown.
       
   632 
       
   633   \sa isFirstColumnSpanned()
       
   634 */
       
   635 void QTreeView::setFirstColumnSpanned(int row, const QModelIndex &parent, bool span)
       
   636 {
       
   637     Q_D(QTreeView);
       
   638     if (!d->model)
       
   639         return;
       
   640     QModelIndex index = d->model->index(row, 0, parent);
       
   641     if (!index.isValid())
       
   642         return;
       
   643 
       
   644     if (span) {
       
   645         QPersistentModelIndex persistent(index);
       
   646         if (!d->spanningIndexes.contains(persistent))
       
   647             d->spanningIndexes.append(persistent);
       
   648     } else {
       
   649         QPersistentModelIndex persistent(index);
       
   650         int i = d->spanningIndexes.indexOf(persistent);
       
   651         if (i >= 0)
       
   652             d->spanningIndexes.remove(i);
       
   653     }
       
   654 
       
   655     d->executePostedLayout();
       
   656     int i = d->viewIndex(index);
       
   657     if (i >= 0)
       
   658         d->viewItems[i].spanning = span;
       
   659 
       
   660     d->viewport->update();
       
   661 }
       
   662 
       
   663 /*!
       
   664   \reimp
       
   665 */
       
   666 void QTreeView::dataChanged(const QModelIndex &topLeft, const QModelIndex &bottomRight)
       
   667 {
       
   668     Q_D(QTreeView);
       
   669 
       
   670     // if we are going to do a complete relayout anyway, there is no need to update
       
   671     if (d->delayedPendingLayout)
       
   672         return;
       
   673 
       
   674     // refresh the height cache here; we don't really lose anything by getting the size hint,
       
   675     // since QAbstractItemView::dataChanged() will get the visualRect for the items anyway
       
   676 
       
   677     int topViewIndex = d->viewIndex(topLeft);
       
   678     if (topViewIndex == 0)
       
   679         d->defaultItemHeight = indexRowSizeHint(topLeft);
       
   680     bool sizeChanged = false;
       
   681     if (topViewIndex != -1) {
       
   682         if (topLeft == bottomRight) {
       
   683             int oldHeight = d->itemHeight(topViewIndex);
       
   684             d->invalidateHeightCache(topViewIndex);
       
   685             sizeChanged = (oldHeight != d->itemHeight(topViewIndex));
       
   686         } else {
       
   687             int bottomViewIndex = d->viewIndex(bottomRight);
       
   688             for (int i = topViewIndex; i <= bottomViewIndex; ++i) {
       
   689                 int oldHeight = d->itemHeight(i);
       
   690                 d->invalidateHeightCache(i);
       
   691                 sizeChanged |= (oldHeight != d->itemHeight(i));
       
   692             }
       
   693         }
       
   694     }
       
   695 
       
   696     if (sizeChanged) {
       
   697         d->updateScrollBars();
       
   698         d->viewport->update();
       
   699     }
       
   700     QAbstractItemView::dataChanged(topLeft, bottomRight);
       
   701 }
       
   702 
       
   703 /*!
       
   704   Hides the \a column given.
       
   705 
       
   706   \note This function should only be called after the model has been
       
   707   initialized, as the view needs to know the number of columns in order to
       
   708   hide \a column.
       
   709 
       
   710   \sa showColumn(), setColumnHidden()
       
   711 */
       
   712 void QTreeView::hideColumn(int column)
       
   713 {
       
   714     Q_D(QTreeView);
       
   715     d->header->hideSection(column);
       
   716 }
       
   717 
       
   718 /*!
       
   719   Shows the given \a column in the tree view.
       
   720 
       
   721   \sa hideColumn(), setColumnHidden()
       
   722 */
       
   723 void QTreeView::showColumn(int column)
       
   724 {
       
   725     Q_D(QTreeView);
       
   726     d->header->showSection(column);
       
   727 }
       
   728 
       
   729 /*!
       
   730   \fn void QTreeView::expand(const QModelIndex &index)
       
   731 
       
   732   Expands the model item specified by the \a index.
       
   733 
       
   734   \sa expanded()
       
   735 */
       
   736 void QTreeView::expand(const QModelIndex &index)
       
   737 {
       
   738     Q_D(QTreeView);
       
   739     if (!d->isIndexValid(index))
       
   740         return;
       
   741     if (d->delayedPendingLayout) {
       
   742         //A complete relayout is going to be performed, just store the expanded index, no need to layout.
       
   743         if (d->storeExpanded(index))
       
   744             emit expanded(index);
       
   745         return;
       
   746     }
       
   747 
       
   748     int i = d->viewIndex(index);
       
   749     if (i != -1) { // is visible
       
   750         d->expand(i, true);
       
   751         if (!d->isAnimating()) {
       
   752             updateGeometries();
       
   753             d->viewport->update();
       
   754         }
       
   755     } else if (d->storeExpanded(index)) {
       
   756         emit expanded(index);
       
   757     }
       
   758 }
       
   759 
       
   760 /*!
       
   761   \fn void QTreeView::collapse(const QModelIndex &index)
       
   762 
       
   763   Collapses the model item specified by the \a index.
       
   764 
       
   765   \sa collapsed()
       
   766 */
       
   767 void QTreeView::collapse(const QModelIndex &index)
       
   768 {
       
   769     Q_D(QTreeView);
       
   770     if (!d->isIndexValid(index))
       
   771         return;
       
   772     //if the current item is now invisible, the autoscroll will expand the tree to see it, so disable the autoscroll
       
   773     d->delayedAutoScroll.stop();
       
   774 
       
   775     if (d->delayedPendingLayout) {
       
   776         //A complete relayout is going to be performed, just un-store the expanded index, no need to layout.
       
   777         if (d->isPersistent(index) && d->expandedIndexes.remove(index))
       
   778             emit collapsed(index);
       
   779         return;
       
   780     }
       
   781     int i = d->viewIndex(index);
       
   782     if (i != -1) { // is visible
       
   783         d->collapse(i, true);
       
   784         if (!d->isAnimating()) {
       
   785             updateGeometries();
       
   786             viewport()->update();
       
   787         }
       
   788     } else {
       
   789         if (d->isPersistent(index) && d->expandedIndexes.remove(index))
       
   790             emit collapsed(index);
       
   791     }
       
   792 }
       
   793 
       
   794 /*!
       
   795   \fn bool QTreeView::isExpanded(const QModelIndex &index) const
       
   796 
       
   797   Returns true if the model item \a index is expanded; otherwise returns
       
   798   false.
       
   799 
       
   800   \sa expand(), expanded(), setExpanded()
       
   801 */
       
   802 bool QTreeView::isExpanded(const QModelIndex &index) const
       
   803 {
       
   804     Q_D(const QTreeView);
       
   805     return d->isIndexExpanded(index);
       
   806 }
       
   807 
       
   808 /*!
       
   809   Sets the item referred to by \a index to either collapse or expanded,
       
   810   depending on the value of \a expanded.
       
   811 
       
   812   \sa expanded(), expand(), isExpanded()
       
   813 */
       
   814 void QTreeView::setExpanded(const QModelIndex &index, bool expanded)
       
   815 {
       
   816     if (expanded)
       
   817         this->expand(index);
       
   818     else
       
   819         this->collapse(index);
       
   820 }
       
   821 
       
   822 /*!
       
   823     \since 4.2
       
   824     \property QTreeView::sortingEnabled
       
   825     \brief whether sorting is enabled
       
   826 
       
   827     If this property is true, sorting is enabled for the tree; if the property
       
   828     is false, sorting is not enabled. The default value is false.
       
   829 
       
   830     \note In order to avoid performance issues, it is recommended that
       
   831     sorting is enabled \e after inserting the items into the tree.
       
   832     Alternatively, you could also insert the items into a list before inserting
       
   833     the items into the tree.
       
   834 
       
   835     \sa sortByColumn()
       
   836 */
       
   837 
       
   838 void QTreeView::setSortingEnabled(bool enable)
       
   839 {
       
   840     Q_D(QTreeView);
       
   841     header()->setSortIndicatorShown(enable);
       
   842     header()->setClickable(enable);
       
   843     if (enable) {
       
   844         //sortByColumn has to be called before we connect or set the sortingEnabled flag
       
   845         // because otherwise it will not call sort on the model.
       
   846         sortByColumn(header()->sortIndicatorSection(), header()->sortIndicatorOrder());
       
   847         connect(header(), SIGNAL(sortIndicatorChanged(int,Qt::SortOrder)),
       
   848                 this, SLOT(_q_sortIndicatorChanged(int,Qt::SortOrder)), Qt::UniqueConnection);
       
   849     } else {
       
   850         disconnect(header(), SIGNAL(sortIndicatorChanged(int,Qt::SortOrder)),
       
   851                    this, SLOT(_q_sortIndicatorChanged(int,Qt::SortOrder)));
       
   852     }
       
   853     d->sortingEnabled = enable;
       
   854 }
       
   855 
       
   856 bool QTreeView::isSortingEnabled() const
       
   857 {
       
   858     Q_D(const QTreeView);
       
   859     return d->sortingEnabled;
       
   860 }
       
   861 
       
   862 /*!
       
   863     \since 4.2
       
   864     \property QTreeView::animated
       
   865     \brief whether animations are enabled
       
   866 
       
   867     If this property is true the treeview will animate expandsion
       
   868     and collasping of branches. If this property is false, the treeview
       
   869     will expand or collapse branches immediately without showing
       
   870     the animation.
       
   871 
       
   872     By default, this property is false.
       
   873 */
       
   874 
       
   875 void QTreeView::setAnimated(bool animate)
       
   876 {
       
   877     Q_D(QTreeView);
       
   878     d->animationsEnabled = animate;
       
   879 }
       
   880 
       
   881 bool QTreeView::isAnimated() const
       
   882 {
       
   883     Q_D(const QTreeView);
       
   884     return d->animationsEnabled;
       
   885 }
       
   886 
       
   887 /*!
       
   888     \since 4.2
       
   889     \property QTreeView::allColumnsShowFocus
       
   890     \brief whether items should show keyboard focus using all columns
       
   891 
       
   892     If this property is true all columns will show focus, otherwise only
       
   893     one column will show focus.
       
   894 
       
   895     The default is false.
       
   896 */
       
   897 
       
   898 void QTreeView::setAllColumnsShowFocus(bool enable)
       
   899 {
       
   900     Q_D(QTreeView);
       
   901     if (d->allColumnsShowFocus == enable)
       
   902         return;
       
   903     d->allColumnsShowFocus = enable;
       
   904     d->viewport->update();
       
   905 }
       
   906 
       
   907 bool QTreeView::allColumnsShowFocus() const
       
   908 {
       
   909     Q_D(const QTreeView);
       
   910     return d->allColumnsShowFocus;
       
   911 }
       
   912 
       
   913 /*!
       
   914     \property QTreeView::wordWrap
       
   915     \brief the item text word-wrapping policy
       
   916     \since 4.3
       
   917 
       
   918     If this property is true then the item text is wrapped where
       
   919     necessary at word-breaks; otherwise it is not wrapped at all.
       
   920     This property is false by default.
       
   921 
       
   922     Note that even if wrapping is enabled, the cell will not be
       
   923     expanded to fit all text. Ellipsis will be inserted according to
       
   924     the current \l{QAbstractItemView::}{textElideMode}.
       
   925 */
       
   926 void QTreeView::setWordWrap(bool on)
       
   927 {
       
   928     Q_D(QTreeView);
       
   929     if (d->wrapItemText == on)
       
   930         return;
       
   931     d->wrapItemText = on;
       
   932     d->doDelayedItemsLayout();
       
   933 }
       
   934 
       
   935 bool QTreeView::wordWrap() const
       
   936 {
       
   937     Q_D(const QTreeView);
       
   938     return d->wrapItemText;
       
   939 }
       
   940 
       
   941 
       
   942 /*!
       
   943   \reimp
       
   944  */
       
   945 void QTreeView::keyboardSearch(const QString &search)
       
   946 {
       
   947     Q_D(QTreeView);
       
   948     if (!d->model->rowCount(d->root) || !d->model->columnCount(d->root))
       
   949         return;
       
   950 
       
   951     QModelIndex start;
       
   952     if (currentIndex().isValid())
       
   953         start = currentIndex();
       
   954     else
       
   955         start = d->model->index(0, 0, d->root);
       
   956 
       
   957     QTime now(QTime::currentTime());
       
   958     bool skipRow = false;
       
   959     if (search.isEmpty()
       
   960         || (d->keyboardInputTime.msecsTo(now) > QApplication::keyboardInputInterval())) {
       
   961         d->keyboardInput = search;
       
   962         skipRow = true;
       
   963     } else {
       
   964         d->keyboardInput += search;
       
   965     }
       
   966     d->keyboardInputTime = now;
       
   967 
       
   968     // special case for searches with same key like 'aaaaa'
       
   969     bool sameKey = false;
       
   970     if (d->keyboardInput.length() > 1) {
       
   971         int c = d->keyboardInput.count(d->keyboardInput.at(d->keyboardInput.length() - 1));
       
   972         sameKey = (c == d->keyboardInput.length());
       
   973         if (sameKey)
       
   974             skipRow = true;
       
   975     }
       
   976 
       
   977     // skip if we are searching for the same key or a new search started
       
   978     if (skipRow) {
       
   979         if (indexBelow(start).isValid())
       
   980             start = indexBelow(start);
       
   981         else
       
   982             start = d->model->index(0, start.column(), d->root);
       
   983     }
       
   984 
       
   985     d->executePostedLayout();
       
   986     int startIndex = d->viewIndex(start);
       
   987     if (startIndex <= -1)
       
   988         return;
       
   989 
       
   990     int previousLevel = -1;
       
   991     int bestAbove = -1;
       
   992     int bestBelow = -1;
       
   993     QString searchString = sameKey ? QString(d->keyboardInput.at(0)) : d->keyboardInput;
       
   994     for (int i = 0; i < d->viewItems.count(); ++i) {
       
   995         if ((int)d->viewItems.at(i).level > previousLevel) {
       
   996             QModelIndex searchFrom = d->viewItems.at(i).index;
       
   997             if (searchFrom.parent() == start.parent())
       
   998                 searchFrom = start;
       
   999             QModelIndexList match = d->model->match(searchFrom, Qt::DisplayRole, searchString);
       
  1000             if (match.count()) {
       
  1001                 int hitIndex = d->viewIndex(match.at(0));
       
  1002                 if (hitIndex >= 0 && hitIndex < startIndex)
       
  1003                     bestAbove = bestAbove == -1 ? hitIndex : qMin(hitIndex, bestAbove);
       
  1004                 else if (hitIndex >= startIndex)
       
  1005                     bestBelow = bestBelow == -1 ? hitIndex : qMin(hitIndex, bestBelow);
       
  1006             }
       
  1007         }
       
  1008         previousLevel = d->viewItems.at(i).level;
       
  1009     }
       
  1010 
       
  1011     QModelIndex index;
       
  1012     if (bestBelow > -1)
       
  1013         index = d->viewItems.at(bestBelow).index;
       
  1014     else if (bestAbove > -1)
       
  1015         index = d->viewItems.at(bestAbove).index;
       
  1016 
       
  1017     if (index.isValid()) {
       
  1018         QItemSelectionModel::SelectionFlags flags = (d->selectionMode == SingleSelection
       
  1019                                                      ? QItemSelectionModel::SelectionFlags(
       
  1020                                                          QItemSelectionModel::ClearAndSelect
       
  1021                                                          |d->selectionBehaviorFlags())
       
  1022                                                      : QItemSelectionModel::SelectionFlags(
       
  1023                                                          QItemSelectionModel::NoUpdate));
       
  1024         selectionModel()->setCurrentIndex(index, flags);
       
  1025     }
       
  1026 }
       
  1027 
       
  1028 /*!
       
  1029   Returns the rectangle on the viewport occupied by the item at \a index.
       
  1030   If the index is not visible or explicitly hidden, the returned rectangle is invalid.
       
  1031 */
       
  1032 QRect QTreeView::visualRect(const QModelIndex &index) const
       
  1033 {
       
  1034     Q_D(const QTreeView);
       
  1035 
       
  1036     if (!d->isIndexValid(index) || isIndexHidden(index))
       
  1037         return QRect();
       
  1038 
       
  1039     d->executePostedLayout();
       
  1040 
       
  1041     int vi = d->viewIndex(index);
       
  1042     if (vi < 0)
       
  1043         return QRect();
       
  1044 
       
  1045     bool spanning = d->viewItems.at(vi).spanning;
       
  1046 
       
  1047     // if we have a spanning item, make the selection stretch from left to right
       
  1048     int x = (spanning ? 0 : columnViewportPosition(index.column()));
       
  1049     int w = (spanning ? d->header->length() : columnWidth(index.column()));
       
  1050     // handle indentation
       
  1051     if (index.column() == 0) {
       
  1052         int i = d->indentationForItem(vi);
       
  1053         w -= i;
       
  1054         if (!isRightToLeft())
       
  1055             x += i;
       
  1056     }
       
  1057 
       
  1058     int y = d->coordinateForItem(vi);
       
  1059     int h = d->itemHeight(vi);
       
  1060 
       
  1061     return QRect(x, y, w, h);
       
  1062 }
       
  1063 
       
  1064 /*!
       
  1065     Scroll the contents of the tree view until the given model item
       
  1066     \a index is visible. The \a hint parameter specifies more
       
  1067     precisely where the item should be located after the
       
  1068     operation.
       
  1069     If any of the parents of the model item are collapsed, they will
       
  1070     be expanded to ensure that the model item is visible.
       
  1071 */
       
  1072 void QTreeView::scrollTo(const QModelIndex &index, ScrollHint hint)
       
  1073 {
       
  1074     Q_D(QTreeView);
       
  1075 
       
  1076     if (!d->isIndexValid(index))
       
  1077         return;
       
  1078 
       
  1079     d->executePostedLayout();
       
  1080     d->updateScrollBars();
       
  1081 
       
  1082     // Expand all parents if the parent(s) of the node are not expanded.
       
  1083     QModelIndex parent = index.parent();
       
  1084     while (parent.isValid() && state() == NoState && d->itemsExpandable) {
       
  1085         if (!isExpanded(parent))
       
  1086             expand(parent);
       
  1087         parent = d->model->parent(parent);
       
  1088     }
       
  1089 
       
  1090     int item = d->viewIndex(index);
       
  1091     if (item < 0)
       
  1092         return;
       
  1093 
       
  1094     QRect area = d->viewport->rect();
       
  1095 
       
  1096     // vertical
       
  1097     if (verticalScrollMode() == QAbstractItemView::ScrollPerItem) {
       
  1098         int top = verticalScrollBar()->value();
       
  1099         int bottom = top + verticalScrollBar()->pageStep();
       
  1100         if (hint == EnsureVisible && item >= top && item < bottom) {
       
  1101             // nothing to do
       
  1102         } else if (hint == PositionAtTop || (hint == EnsureVisible && item < top)) {
       
  1103             verticalScrollBar()->setValue(item);
       
  1104         } else { // PositionAtBottom or PositionAtCenter
       
  1105             const int currentItemHeight = d->itemHeight(item);
       
  1106             int y = (hint == PositionAtCenter
       
  1107                  //we center on the current item with a preference to the top item (ie. -1)
       
  1108                      ? area.height() / 2 + currentItemHeight - 1
       
  1109                  //otherwise we simply take the whole space
       
  1110                      : area.height());
       
  1111             if (y > currentItemHeight) {
       
  1112                 while (item >= 0) {
       
  1113                     y -= d->itemHeight(item);
       
  1114                     if (y < 0) { //there is no more space left
       
  1115                         item++;
       
  1116                         break;
       
  1117                     }
       
  1118                     item--;
       
  1119                 }
       
  1120             }
       
  1121             verticalScrollBar()->setValue(item);
       
  1122         }
       
  1123     } else { // ScrollPerPixel
       
  1124         QRect rect(columnViewportPosition(index.column()),
       
  1125                    d->coordinateForItem(item), // ### slow for items outside the view
       
  1126                    columnWidth(index.column()),
       
  1127                    d->itemHeight(item));
       
  1128 
       
  1129         if (rect.isEmpty()) {
       
  1130             // nothing to do
       
  1131         } else if (hint == EnsureVisible && area.contains(rect)) {
       
  1132             d->viewport->update(rect);
       
  1133             // nothing to do
       
  1134         } else {
       
  1135             bool above = (hint == EnsureVisible
       
  1136                         && (rect.top() < area.top()
       
  1137                             || area.height() < rect.height()));
       
  1138             bool below = (hint == EnsureVisible
       
  1139                         && rect.bottom() > area.bottom()
       
  1140                         && rect.height() < area.height());
       
  1141 
       
  1142             int verticalValue = verticalScrollBar()->value();
       
  1143             if (hint == PositionAtTop || above)
       
  1144                 verticalValue += rect.top();
       
  1145             else if (hint == PositionAtBottom || below)
       
  1146                 verticalValue += rect.bottom() - area.height();
       
  1147             else if (hint == PositionAtCenter)
       
  1148                 verticalValue += rect.top() - ((area.height() - rect.height()) / 2);
       
  1149             verticalScrollBar()->setValue(verticalValue);
       
  1150         }
       
  1151     }
       
  1152     // horizontal
       
  1153     int viewportWidth = d->viewport->width();
       
  1154     int horizontalOffset = d->header->offset();
       
  1155     int horizontalPosition = d->header->sectionPosition(index.column());
       
  1156     int cellWidth = d->header->sectionSize(index.column());
       
  1157 
       
  1158     if (hint == PositionAtCenter) {
       
  1159         horizontalScrollBar()->setValue(horizontalPosition - ((viewportWidth - cellWidth) / 2));
       
  1160     } else {
       
  1161         if (horizontalPosition - horizontalOffset < 0 || cellWidth > viewportWidth)
       
  1162             horizontalScrollBar()->setValue(horizontalPosition);
       
  1163         else if (horizontalPosition - horizontalOffset + cellWidth > viewportWidth)
       
  1164             horizontalScrollBar()->setValue(horizontalPosition - viewportWidth + cellWidth);
       
  1165     }
       
  1166 }
       
  1167 
       
  1168 /*!
       
  1169   \reimp
       
  1170 */
       
  1171 void QTreeView::timerEvent(QTimerEvent *event)
       
  1172 {
       
  1173     Q_D(QTreeView);
       
  1174     if (event->timerId() == d->columnResizeTimerID) {
       
  1175         updateGeometries();
       
  1176         killTimer(d->columnResizeTimerID);
       
  1177         d->columnResizeTimerID = 0;
       
  1178         QRect rect;
       
  1179         int viewportHeight = d->viewport->height();
       
  1180         int viewportWidth = d->viewport->width();
       
  1181         for (int i = d->columnsToUpdate.size() - 1; i >= 0; --i) {
       
  1182             int column = d->columnsToUpdate.at(i);
       
  1183             int x = columnViewportPosition(column);
       
  1184             if (isRightToLeft())
       
  1185                 rect |= QRect(0, 0, x + columnWidth(column), viewportHeight);
       
  1186             else
       
  1187                 rect |= QRect(x, 0, viewportWidth - x, viewportHeight);
       
  1188         }
       
  1189         d->viewport->update(rect.normalized());
       
  1190         d->columnsToUpdate.clear();
       
  1191     } else if (event->timerId() == d->openTimer.timerId()) {
       
  1192         QPoint pos = d->viewport->mapFromGlobal(QCursor::pos());
       
  1193         if (state() == QAbstractItemView::DraggingState
       
  1194             && d->viewport->rect().contains(pos)) {
       
  1195             QModelIndex index = indexAt(pos);
       
  1196             setExpanded(index, !isExpanded(index));
       
  1197         }
       
  1198         d->openTimer.stop();
       
  1199     }
       
  1200 
       
  1201     QAbstractItemView::timerEvent(event);
       
  1202 }
       
  1203 
       
  1204 /*!
       
  1205   \reimp
       
  1206 */
       
  1207 #ifndef QT_NO_DRAGANDDROP
       
  1208 void QTreeView::dragMoveEvent(QDragMoveEvent *event)
       
  1209 {
       
  1210     Q_D(QTreeView);
       
  1211     if (d->autoExpandDelay >= 0)
       
  1212         d->openTimer.start(d->autoExpandDelay, this);
       
  1213     QAbstractItemView::dragMoveEvent(event);
       
  1214 }
       
  1215 #endif
       
  1216 
       
  1217 /*!
       
  1218   \reimp
       
  1219 */
       
  1220 bool QTreeView::viewportEvent(QEvent *event)
       
  1221 {
       
  1222     Q_D(QTreeView);
       
  1223     switch (event->type()) {
       
  1224     case QEvent::HoverEnter:
       
  1225     case QEvent::HoverLeave:
       
  1226     case QEvent::HoverMove: {
       
  1227         QHoverEvent *he = static_cast<QHoverEvent*>(event);
       
  1228         int oldBranch = d->hoverBranch;
       
  1229         d->hoverBranch = d->itemDecorationAt(he->pos());
       
  1230         if (oldBranch != d->hoverBranch) {
       
  1231             QModelIndex oldIndex = d->modelIndex(oldBranch),
       
  1232                 newIndex = d->modelIndex(d->hoverBranch);
       
  1233             if (oldIndex != newIndex) {
       
  1234                 QRect oldRect = visualRect(oldIndex);
       
  1235                 QRect newRect = visualRect(newIndex);
       
  1236                 oldRect.setLeft(oldRect.left() - d->indent);
       
  1237                 newRect.setLeft(newRect.left() - d->indent);
       
  1238                 //we need to paint the whole items (including the decoration) so that when the user
       
  1239                 //moves the mouse over those elements they are updated
       
  1240                 viewport()->update(oldRect);
       
  1241                 viewport()->update(newRect);
       
  1242             }
       
  1243         }
       
  1244         break; }
       
  1245     default:
       
  1246         break;
       
  1247     }
       
  1248     return QAbstractItemView::viewportEvent(event);
       
  1249 }
       
  1250 
       
  1251 /*!
       
  1252   \reimp
       
  1253 */
       
  1254 void QTreeView::paintEvent(QPaintEvent *event)
       
  1255 {
       
  1256     Q_D(QTreeView);
       
  1257     d->executePostedLayout();
       
  1258     QPainter painter(viewport());
       
  1259 #ifndef QT_NO_ANIMATION
       
  1260     if (d->isAnimating()) {
       
  1261         drawTree(&painter, event->region() - d->animatedOperation.rect());
       
  1262         d->drawAnimatedOperation(&painter);
       
  1263     } else
       
  1264 #endif //QT_NO_ANIMATION
       
  1265     {
       
  1266         drawTree(&painter, event->region());
       
  1267 #ifndef QT_NO_DRAGANDDROP
       
  1268         d->paintDropIndicator(&painter);
       
  1269 #endif
       
  1270     }
       
  1271 }
       
  1272 
       
  1273 void QTreeViewPrivate::paintAlternatingRowColors(QPainter *painter, QStyleOptionViewItemV4 *option, int y, int bottom) const
       
  1274 {
       
  1275     Q_Q(const QTreeView);
       
  1276     if (!alternatingColors || !q->style()->styleHint(QStyle::SH_ItemView_PaintAlternatingRowColorsForEmptyArea, option, q))
       
  1277         return;
       
  1278     int rowHeight = defaultItemHeight;
       
  1279     if (rowHeight <= 0) {
       
  1280         rowHeight = itemDelegate->sizeHint(*option, QModelIndex()).height();
       
  1281         if (rowHeight <= 0)
       
  1282             return;
       
  1283     }
       
  1284     while (y <= bottom) {
       
  1285         option->rect.setRect(0, y, viewport->width(), rowHeight);
       
  1286         if (current & 1) {
       
  1287             option->features |= QStyleOptionViewItemV2::Alternate;
       
  1288         } else {
       
  1289             option->features &= ~QStyleOptionViewItemV2::Alternate;
       
  1290         }
       
  1291         ++current;
       
  1292         q->style()->drawPrimitive(QStyle::PE_PanelItemViewRow, option, painter, q);
       
  1293         y += rowHeight;
       
  1294     }
       
  1295 }
       
  1296 
       
  1297 bool QTreeViewPrivate::expandOrCollapseItemAtPos(const QPoint &pos)
       
  1298 {
       
  1299     Q_Q(QTreeView);
       
  1300     // we want to handle mousePress in EditingState (persistent editors)
       
  1301     if ((state != QAbstractItemView::NoState
       
  1302 		&& state != QAbstractItemView::EditingState)
       
  1303 		|| !viewport->rect().contains(pos))
       
  1304         return true;
       
  1305 
       
  1306     int i = itemDecorationAt(pos);
       
  1307     if ((i != -1) && itemsExpandable && hasVisibleChildren(viewItems.at(i).index)) {
       
  1308         if (viewItems.at(i).expanded)
       
  1309             collapse(i, true);
       
  1310         else
       
  1311             expand(i, true);
       
  1312         if (!isAnimating()) {
       
  1313             q->updateGeometries();
       
  1314             viewport->update();
       
  1315         }
       
  1316         return true;
       
  1317     }
       
  1318     return false;
       
  1319 }
       
  1320 
       
  1321 void QTreeViewPrivate::_q_modelDestroyed()
       
  1322 {
       
  1323     //we need to clear that list because it contais QModelIndex to 
       
  1324     //the model currently being destroyed
       
  1325     viewItems.clear();
       
  1326     QAbstractItemViewPrivate::_q_modelDestroyed();
       
  1327 }
       
  1328 
       
  1329 /*!
       
  1330   \reimp
       
  1331 
       
  1332   We have a QTreeView way of knowing what elements are on the viewport
       
  1333 */
       
  1334 QItemViewPaintPairs QTreeViewPrivate::draggablePaintPairs(const QModelIndexList &indexes, QRect *r) const
       
  1335 {
       
  1336     Q_ASSERT(r);
       
  1337     return QAbstractItemViewPrivate::draggablePaintPairs(indexes, r);
       
  1338     Q_Q(const QTreeView);
       
  1339     QRect &rect = *r;
       
  1340     const QRect viewportRect = viewport->rect();
       
  1341     int itemOffset = 0;
       
  1342     int row = firstVisibleItem(&itemOffset);
       
  1343     QPair<int, int> startEnd = startAndEndColumns(viewportRect);
       
  1344     QVector<int> columns;
       
  1345     for (int i = startEnd.first; i <= startEnd.second; ++i) {
       
  1346         int logical = header->logicalIndex(i);
       
  1347         if (!header->isSectionHidden(logical))
       
  1348             columns += logical;
       
  1349     }
       
  1350     QSet<QModelIndex> visibleIndexes;
       
  1351     for (; itemOffset < viewportRect.bottom() && row < viewItems.count(); ++row) {
       
  1352         const QModelIndex &index = viewItems.at(row).index;
       
  1353         for (int colIndex = 0; colIndex < columns.count(); ++colIndex)
       
  1354             visibleIndexes += index.sibling(index.row(), columns.at(colIndex));
       
  1355         itemOffset += itemHeight(row);
       
  1356     }
       
  1357 
       
  1358     //now that we have the visible indexes, we can try to find those which are selected
       
  1359     QItemViewPaintPairs ret;
       
  1360     for (int i = 0; i < indexes.count(); ++i) {
       
  1361         const QModelIndex &index = indexes.at(i);
       
  1362         if (visibleIndexes.contains(index)) {
       
  1363             const QRect current = q->visualRect(index);
       
  1364             ret += qMakePair(current, index);
       
  1365             rect |= current;
       
  1366         }
       
  1367     }
       
  1368     rect &= viewportRect;
       
  1369     return ret;
       
  1370 }
       
  1371 
       
  1372 
       
  1373 /*!
       
  1374   \since 4.2
       
  1375   Draws the part of the tree intersecting the given \a region using the specified
       
  1376   \a painter.
       
  1377 
       
  1378   \sa paintEvent()
       
  1379 */
       
  1380 void QTreeView::drawTree(QPainter *painter, const QRegion &region) const
       
  1381 {
       
  1382     Q_D(const QTreeView);
       
  1383     const QVector<QTreeViewItem> viewItems = d->viewItems;
       
  1384 
       
  1385     QStyleOptionViewItemV4 option = d->viewOptionsV4();
       
  1386     const QStyle::State state = option.state;
       
  1387     d->current = 0;
       
  1388 
       
  1389     if (viewItems.count() == 0 || d->header->count() == 0 || !d->itemDelegate) {
       
  1390         d->paintAlternatingRowColors(painter, &option, 0, region.boundingRect().bottom()+1);
       
  1391         return;
       
  1392     }
       
  1393 
       
  1394     int firstVisibleItemOffset = 0;
       
  1395     const int firstVisibleItem = d->firstVisibleItem(&firstVisibleItemOffset);
       
  1396     if (firstVisibleItem < 0) {
       
  1397         d->paintAlternatingRowColors(painter, &option, 0, region.boundingRect().bottom()+1);
       
  1398         return;
       
  1399     }
       
  1400 
       
  1401     const int viewportWidth = d->viewport->width();
       
  1402 
       
  1403     QVector<QRect> rects = region.rects();
       
  1404     QVector<int> drawn;
       
  1405     bool multipleRects = (rects.size() > 1);
       
  1406     for (int a = 0; a < rects.size(); ++a) {
       
  1407         const QRect area = (multipleRects
       
  1408                             ? QRect(0, rects.at(a).y(), viewportWidth, rects.at(a).height())
       
  1409                             : rects.at(a));
       
  1410         d->leftAndRight = d->startAndEndColumns(area);
       
  1411 
       
  1412         int i = firstVisibleItem; // the first item at the top of the viewport
       
  1413         int y = firstVisibleItemOffset; // we may only see part of the first item
       
  1414 
       
  1415         // start at the top of the viewport  and iterate down to the update area
       
  1416         for (; i < viewItems.count(); ++i) {
       
  1417             const int itemHeight = d->itemHeight(i);
       
  1418             if (y + itemHeight > area.top())
       
  1419                 break;
       
  1420             y += itemHeight;
       
  1421         }
       
  1422 
       
  1423         // paint the visible rows
       
  1424         for (; i < viewItems.count() && y <= area.bottom(); ++i) {
       
  1425             const int itemHeight = d->itemHeight(i);
       
  1426             option.rect.setRect(0, y, viewportWidth, itemHeight);
       
  1427             option.state = state | (viewItems.at(i).expanded ? QStyle::State_Open : QStyle::State_None)
       
  1428                                  | (viewItems.at(i).hasChildren ? QStyle::State_Children : QStyle::State_None)
       
  1429                                  | (viewItems.at(i).hasMoreSiblings ? QStyle::State_Sibling : QStyle::State_None);
       
  1430             d->current = i;
       
  1431             d->spanning = viewItems.at(i).spanning;
       
  1432             if (!multipleRects || !drawn.contains(i)) {
       
  1433                 drawRow(painter, option, viewItems.at(i).index);
       
  1434                 if (multipleRects)   // even if the rect only intersects the item,
       
  1435                     drawn.append(i); // the entire item will be painted
       
  1436             }
       
  1437             y += itemHeight;
       
  1438         }
       
  1439 
       
  1440         if (y <= area.bottom()) {
       
  1441             d->current = i;
       
  1442             d->paintAlternatingRowColors(painter, &option, y, area.bottom());
       
  1443         }
       
  1444     }
       
  1445 }
       
  1446 
       
  1447 /// ### move to QObject :)
       
  1448 static inline bool ancestorOf(QObject *widget, QObject *other)
       
  1449 {
       
  1450     for (QObject *parent = other; parent != 0; parent = parent->parent()) {
       
  1451         if (parent == widget)
       
  1452             return true;
       
  1453     }
       
  1454     return false;
       
  1455 }
       
  1456 
       
  1457 /*!
       
  1458     Draws the row in the tree view that contains the model item \a index,
       
  1459     using the \a painter given. The \a option control how the item is
       
  1460     displayed.
       
  1461 
       
  1462     \sa setAlternatingRowColors()
       
  1463 */
       
  1464 void QTreeView::drawRow(QPainter *painter, const QStyleOptionViewItem &option,
       
  1465                         const QModelIndex &index) const
       
  1466 {
       
  1467     Q_D(const QTreeView);
       
  1468     QStyleOptionViewItemV4 opt = option;
       
  1469     const QPoint offset = d->scrollDelayOffset;
       
  1470     const int y = option.rect.y() + offset.y();
       
  1471     const QModelIndex parent = index.parent();
       
  1472     const QHeaderView *header = d->header;
       
  1473     const QModelIndex current = currentIndex();
       
  1474     const QModelIndex hover = d->hover;
       
  1475     const bool reverse = isRightToLeft();
       
  1476     const QStyle::State state = opt.state;
       
  1477     const bool spanning = d->spanning;
       
  1478     const int left = (spanning ? header->visualIndex(0) : d->leftAndRight.first);
       
  1479     const int right = (spanning ? header->visualIndex(0) : d->leftAndRight.second);
       
  1480     const bool alternate = d->alternatingColors;
       
  1481     const bool enabled = (state & QStyle::State_Enabled) != 0;
       
  1482     const bool allColumnsShowFocus = d->allColumnsShowFocus;
       
  1483 
       
  1484 
       
  1485     // when the row contains an index widget which has focus,
       
  1486     // we want to paint the entire row as active
       
  1487     bool indexWidgetHasFocus = false;
       
  1488     if ((current.row() == index.row()) && !d->editors.isEmpty()) {
       
  1489         const int r = index.row();
       
  1490         QWidget *fw = QApplication::focusWidget();
       
  1491         for (int c = 0; c < header->count(); ++c) {
       
  1492             QModelIndex idx = d->model->index(r, c, parent);
       
  1493             if (QWidget *editor = indexWidget(idx)) {
       
  1494                 if (ancestorOf(editor, fw)) {
       
  1495                     indexWidgetHasFocus = true;
       
  1496                     break;
       
  1497                 }
       
  1498             }
       
  1499         }
       
  1500     }
       
  1501 
       
  1502     const bool widgetHasFocus = hasFocus();
       
  1503     bool currentRowHasFocus = false;
       
  1504     if (allColumnsShowFocus && widgetHasFocus && current.isValid()) {
       
  1505         // check if the focus index is before or after the visible columns
       
  1506         const int r = index.row();
       
  1507         for (int c = 0; c < left && !currentRowHasFocus; ++c) {
       
  1508             QModelIndex idx = d->model->index(r, c, parent);
       
  1509             currentRowHasFocus = (idx == current);
       
  1510         }
       
  1511         QModelIndex parent = d->model->parent(index);
       
  1512         for (int c = right; c < header->count() && !currentRowHasFocus; ++c) {
       
  1513             currentRowHasFocus = (d->model->index(r, c, parent) == current);
       
  1514         }
       
  1515     }
       
  1516 
       
  1517     // ### special case: treeviews with multiple columns draw
       
  1518     // the selections differently than with only one column
       
  1519     opt.showDecorationSelected = (d->selectionBehavior & SelectRows)
       
  1520                                  || option.showDecorationSelected;
       
  1521 
       
  1522     int width, height = option.rect.height();
       
  1523     int position;
       
  1524     QModelIndex modelIndex;
       
  1525     int columnCount = header->count();
       
  1526     const bool hoverRow = selectionBehavior() == QAbstractItemView::SelectRows
       
  1527                   && index.parent() == hover.parent()
       
  1528                   && index.row() == hover.row();
       
  1529 
       
  1530     /* 'left' and 'right' are the left-most and right-most visible visual indices.
       
  1531        Compute the first visible logical indices before and after the left and right.
       
  1532        We will use these values to determine the QStyleOptionViewItemV4::viewItemPosition. */
       
  1533     int logicalIndexBeforeLeft = -1, logicalIndexAfterRight = -1;
       
  1534     for (int visualIndex = left - 1; visualIndex >= 0; --visualIndex) {
       
  1535         int logicalIndex = header->logicalIndex(visualIndex);
       
  1536         if (!header->isSectionHidden(logicalIndex)) {
       
  1537             logicalIndexBeforeLeft = logicalIndex;
       
  1538             break;
       
  1539         }
       
  1540     }
       
  1541     QVector<int> logicalIndices; // vector of currently visibly logical indices
       
  1542     for (int visualIndex = left; visualIndex < columnCount; ++visualIndex) {
       
  1543         int logicalIndex = header->logicalIndex(visualIndex);
       
  1544         if (!header->isSectionHidden(logicalIndex)) {
       
  1545             if (visualIndex > right) {
       
  1546                 logicalIndexAfterRight = logicalIndex;
       
  1547                 break;
       
  1548             }
       
  1549             logicalIndices.append(logicalIndex);
       
  1550         }
       
  1551     }
       
  1552 
       
  1553     for (int currentLogicalSection = 0; currentLogicalSection < logicalIndices.count(); ++currentLogicalSection) {
       
  1554         int headerSection = logicalIndices.at(currentLogicalSection);
       
  1555         position = columnViewportPosition(headerSection) + offset.x();
       
  1556         width = header->sectionSize(headerSection);
       
  1557 
       
  1558         if (spanning) {
       
  1559             int lastSection = header->logicalIndex(header->count() - 1);
       
  1560             if (!reverse) {
       
  1561                 width = columnViewportPosition(lastSection) + header->sectionSize(lastSection) - position;
       
  1562             } else {
       
  1563                 width += position - columnViewportPosition(lastSection);
       
  1564                 position = columnViewportPosition(lastSection);
       
  1565             }
       
  1566         }
       
  1567 
       
  1568         modelIndex = d->model->index(index.row(), headerSection, parent);
       
  1569         if (!modelIndex.isValid())
       
  1570             continue;
       
  1571         opt.state = state;
       
  1572 
       
  1573         // determine the viewItemPosition depending on the position of column 0
       
  1574         int nextLogicalSection = currentLogicalSection + 1 >= logicalIndices.count()
       
  1575                                  ? logicalIndexAfterRight
       
  1576                                  : logicalIndices.at(currentLogicalSection + 1);
       
  1577         int prevLogicalSection = currentLogicalSection - 1 < 0
       
  1578                                  ? logicalIndexBeforeLeft
       
  1579                                  : logicalIndices.at(currentLogicalSection - 1);
       
  1580         if (columnCount == 1 || (nextLogicalSection == 0 && prevLogicalSection == -1)
       
  1581             || (headerSection == 0 && nextLogicalSection == -1) || spanning)
       
  1582             opt.viewItemPosition = QStyleOptionViewItemV4::OnlyOne;
       
  1583         else if (headerSection == 0 || (nextLogicalSection != 0 && prevLogicalSection == -1))
       
  1584             opt.viewItemPosition = QStyleOptionViewItemV4::Beginning;
       
  1585         else if (nextLogicalSection == 0 || nextLogicalSection == -1)
       
  1586             opt.viewItemPosition = QStyleOptionViewItemV4::End;
       
  1587         else
       
  1588             opt.viewItemPosition = QStyleOptionViewItemV4::Middle;
       
  1589 
       
  1590         // fake activeness when row editor has focus
       
  1591         if (indexWidgetHasFocus)
       
  1592             opt.state |= QStyle::State_Active;
       
  1593 
       
  1594         if (d->selectionModel->isSelected(modelIndex))
       
  1595             opt.state |= QStyle::State_Selected;
       
  1596         if (widgetHasFocus && (current == modelIndex)) {
       
  1597             if (allColumnsShowFocus)
       
  1598                 currentRowHasFocus = true;
       
  1599             else
       
  1600                 opt.state |= QStyle::State_HasFocus;
       
  1601         }
       
  1602         if ((hoverRow || modelIndex == hover)
       
  1603             && (option.showDecorationSelected || (d->hoverBranch == -1)))
       
  1604             opt.state |= QStyle::State_MouseOver;
       
  1605         else
       
  1606             opt.state &= ~QStyle::State_MouseOver;
       
  1607 
       
  1608         if (enabled) {
       
  1609             QPalette::ColorGroup cg;
       
  1610             if ((d->model->flags(modelIndex) & Qt::ItemIsEnabled) == 0) {
       
  1611                 opt.state &= ~QStyle::State_Enabled;
       
  1612                 cg = QPalette::Disabled;
       
  1613             } else if (opt.state & QStyle::State_Active) {
       
  1614                 cg = QPalette::Active;
       
  1615             } else {
       
  1616                 cg = QPalette::Inactive;
       
  1617             }
       
  1618             opt.palette.setCurrentColorGroup(cg);
       
  1619         }
       
  1620 
       
  1621         if (alternate) {
       
  1622             if (d->current & 1) {
       
  1623                 opt.features |= QStyleOptionViewItemV2::Alternate;
       
  1624             } else {
       
  1625                 opt.features &= ~QStyleOptionViewItemV2::Alternate;
       
  1626             }
       
  1627         }
       
  1628 
       
  1629         /* Prior to Qt 4.3, the background of the branch (in selected state and
       
  1630            alternate row color was provided by the view. For backward compatibility,
       
  1631            this is now delegated to the style using PE_PanelViewItemRow which
       
  1632            does the appropriate fill */
       
  1633         if (headerSection == 0) {
       
  1634             const int i = d->indentationForItem(d->current);
       
  1635             QRect branches(reverse ? position + width - i : position, y, i, height);
       
  1636             const bool setClipRect = branches.width() > width;
       
  1637             if (setClipRect) {
       
  1638                 painter->save();
       
  1639                 painter->setClipRect(QRect(position, y, width, height));
       
  1640             }
       
  1641             // draw background for the branch (selection + alternate row)
       
  1642             opt.rect = branches;
       
  1643             style()->drawPrimitive(QStyle::PE_PanelItemViewRow, &opt, painter, this);
       
  1644 
       
  1645             // draw background of the item (only alternate row). rest of the background
       
  1646             // is provided by the delegate
       
  1647             QStyle::State oldState = opt.state;
       
  1648             opt.state &= ~QStyle::State_Selected;
       
  1649             opt.rect.setRect(reverse ? position : i + position, y, width - i, height);
       
  1650             style()->drawPrimitive(QStyle::PE_PanelItemViewRow, &opt, painter, this);
       
  1651             opt.state = oldState;
       
  1652 
       
  1653             drawBranches(painter, branches, index);
       
  1654             if (setClipRect)
       
  1655                 painter->restore();
       
  1656         } else {
       
  1657             QStyle::State oldState = opt.state;
       
  1658             opt.state &= ~QStyle::State_Selected;
       
  1659             opt.rect.setRect(position, y, width, height);
       
  1660             style()->drawPrimitive(QStyle::PE_PanelItemViewRow, &opt, painter, this);
       
  1661             opt.state = oldState;
       
  1662         }
       
  1663 
       
  1664         if (const QWidget *widget = d->editorForIndex(modelIndex).editor) {
       
  1665             painter->save();
       
  1666             painter->setClipRect(widget->geometry());
       
  1667             d->delegateForIndex(modelIndex)->paint(painter, opt, modelIndex);
       
  1668             painter->restore();
       
  1669         } else {
       
  1670             d->delegateForIndex(modelIndex)->paint(painter, opt, modelIndex);
       
  1671         }
       
  1672     }
       
  1673 
       
  1674     if (currentRowHasFocus) {
       
  1675         QStyleOptionFocusRect o;
       
  1676         o.QStyleOption::operator=(option);
       
  1677         o.state |= QStyle::State_KeyboardFocusChange;
       
  1678         QPalette::ColorGroup cg = (option.state & QStyle::State_Enabled)
       
  1679                                   ? QPalette::Normal : QPalette::Disabled;
       
  1680         o.backgroundColor = option.palette.color(cg, d->selectionModel->isSelected(index)
       
  1681                                                  ? QPalette::Highlight : QPalette::Background);
       
  1682         int x = 0;
       
  1683         if (!option.showDecorationSelected)
       
  1684             x = header->sectionPosition(0) + d->indentationForItem(d->current);
       
  1685 	QRect focusRect(x - header->offset(), y, header->length() - x, height);
       
  1686         o.rect = style()->visualRect(layoutDirection(), d->viewport->rect(), focusRect);
       
  1687         style()->drawPrimitive(QStyle::PE_FrameFocusRect, &o, painter);
       
  1688         // if we show focus on all columns and the first section is moved,
       
  1689         // we have to split the focus rect into two rects
       
  1690         if (allColumnsShowFocus && !option.showDecorationSelected
       
  1691             && header->sectionsMoved() && (header->visualIndex(0) != 0)) {
       
  1692 	    QRect sectionRect(0, y, header->sectionPosition(0), height); 
       
  1693             o.rect = style()->visualRect(layoutDirection(), d->viewport->rect(), sectionRect);
       
  1694             style()->drawPrimitive(QStyle::PE_FrameFocusRect, &o, painter);
       
  1695         }
       
  1696     }
       
  1697 }
       
  1698 
       
  1699 /*!
       
  1700   Draws the branches in the tree view on the same row as the model item
       
  1701   \a index, using the \a painter given. The branches are drawn in the
       
  1702   rectangle specified by \a rect.
       
  1703 */
       
  1704 void QTreeView::drawBranches(QPainter *painter, const QRect &rect,
       
  1705                              const QModelIndex &index) const
       
  1706 {
       
  1707     Q_D(const QTreeView);
       
  1708     const bool reverse = isRightToLeft();
       
  1709     const int indent = d->indent;
       
  1710     const int outer = d->rootDecoration ? 0 : 1;
       
  1711     const int item = d->current;
       
  1712     const QTreeViewItem &viewItem = d->viewItems.at(item);
       
  1713     int level = viewItem.level;
       
  1714     QRect primitive(reverse ? rect.left() : rect.right() + 1, rect.top(), indent, rect.height());
       
  1715 
       
  1716     QModelIndex parent = index.parent();
       
  1717     QModelIndex current = parent;
       
  1718     QModelIndex ancestor = current.parent();
       
  1719 
       
  1720     QStyleOptionViewItemV2 opt = viewOptions();
       
  1721     QStyle::State extraFlags = QStyle::State_None;
       
  1722     if (isEnabled())
       
  1723         extraFlags |= QStyle::State_Enabled;
       
  1724     if (window()->isActiveWindow())
       
  1725         extraFlags |= QStyle::State_Active;
       
  1726     QPoint oldBO = painter->brushOrigin();
       
  1727     if (verticalScrollMode() == QAbstractItemView::ScrollPerPixel)
       
  1728         painter->setBrushOrigin(QPoint(0, verticalOffset()));
       
  1729 
       
  1730     if (d->alternatingColors) {
       
  1731         if (d->current & 1) {
       
  1732             opt.features |= QStyleOptionViewItemV2::Alternate;
       
  1733         } else {
       
  1734             opt.features &= ~QStyleOptionViewItemV2::Alternate;
       
  1735         }
       
  1736     }
       
  1737 
       
  1738     // When hovering over a row, pass State_Hover for painting the branch
       
  1739     // indicators if it has the decoration (aka branch) selected.
       
  1740     bool hoverRow = selectionBehavior() == QAbstractItemView::SelectRows
       
  1741                     && opt.showDecorationSelected
       
  1742                     && index.parent() == d->hover.parent()
       
  1743                     && index.row() == d->hover.row();
       
  1744 
       
  1745     if (d->selectionModel->isSelected(index))
       
  1746         extraFlags |= QStyle::State_Selected;
       
  1747 
       
  1748     if (level >= outer) {
       
  1749         // start with the innermost branch
       
  1750         primitive.moveLeft(reverse ? primitive.left() : primitive.left() - indent);
       
  1751         opt.rect = primitive;
       
  1752 
       
  1753         const bool expanded = viewItem.expanded;
       
  1754         const bool children = viewItem.hasChildren;
       
  1755         bool moreSiblings = viewItem.hasMoreSiblings;
       
  1756 
       
  1757         opt.state = QStyle::State_Item | extraFlags
       
  1758                     | (moreSiblings ? QStyle::State_Sibling : QStyle::State_None)
       
  1759                     | (children ? QStyle::State_Children : QStyle::State_None)
       
  1760                     | (expanded ? QStyle::State_Open : QStyle::State_None);
       
  1761         if (hoverRow || item == d->hoverBranch)
       
  1762             opt.state |= QStyle::State_MouseOver;
       
  1763         else
       
  1764             opt.state &= ~QStyle::State_MouseOver;
       
  1765         style()->drawPrimitive(QStyle::PE_IndicatorBranch, &opt, painter, this);
       
  1766     }
       
  1767     // then go out level by level
       
  1768     for (--level; level >= outer; --level) { // we have already drawn the innermost branch
       
  1769         primitive.moveLeft(reverse ? primitive.left() + indent : primitive.left() - indent);
       
  1770         opt.rect = primitive;
       
  1771         opt.state = extraFlags;
       
  1772         bool moreSiblings = false;
       
  1773         if (d->hiddenIndexes.isEmpty()) {
       
  1774             moreSiblings = (d->model->rowCount(ancestor) - 1 > current.row());
       
  1775         } else {
       
  1776             int successor = item + viewItem.total + 1;
       
  1777             while (successor < d->viewItems.size()
       
  1778                    && d->viewItems.at(successor).level >= uint(level)) {
       
  1779                 const QTreeViewItem &successorItem = d->viewItems.at(successor);
       
  1780                 if (successorItem.level == uint(level)) {
       
  1781                     moreSiblings = true;
       
  1782                     break;
       
  1783                 }
       
  1784                 successor += successorItem.total + 1;
       
  1785             }
       
  1786         }
       
  1787         if (moreSiblings)
       
  1788             opt.state |= QStyle::State_Sibling;
       
  1789         if (hoverRow || item == d->hoverBranch)
       
  1790             opt.state |= QStyle::State_MouseOver;
       
  1791         else
       
  1792             opt.state &= ~QStyle::State_MouseOver;
       
  1793         style()->drawPrimitive(QStyle::PE_IndicatorBranch, &opt, painter, this);
       
  1794         current = ancestor;
       
  1795         ancestor = current.parent();
       
  1796     }
       
  1797     painter->setBrushOrigin(oldBO);
       
  1798 }
       
  1799 
       
  1800 /*!
       
  1801   \reimp
       
  1802 */
       
  1803 void QTreeView::mousePressEvent(QMouseEvent *event)
       
  1804 {
       
  1805 	Q_D(QTreeView);
       
  1806     bool handled = false;
       
  1807     if (style()->styleHint(QStyle::SH_Q3ListViewExpand_SelectMouseType, 0, this) == QEvent::MouseButtonPress)
       
  1808         handled = d->expandOrCollapseItemAtPos(event->pos());
       
  1809 	if (!handled && d->itemDecorationAt(event->pos()) == -1)
       
  1810         QAbstractItemView::mousePressEvent(event);
       
  1811 }
       
  1812 
       
  1813 /*!
       
  1814   \reimp
       
  1815 */
       
  1816 void QTreeView::mouseReleaseEvent(QMouseEvent *event)
       
  1817 {
       
  1818     Q_D(QTreeView);
       
  1819     if (d->itemDecorationAt(event->pos()) == -1) {
       
  1820         QAbstractItemView::mouseReleaseEvent(event);
       
  1821     } else {
       
  1822         if (state() == QAbstractItemView::DragSelectingState)
       
  1823             setState(QAbstractItemView::NoState);
       
  1824         if (style()->styleHint(QStyle::SH_Q3ListViewExpand_SelectMouseType, 0, this) == QEvent::MouseButtonRelease)
       
  1825             d->expandOrCollapseItemAtPos(event->pos());
       
  1826     }
       
  1827 }
       
  1828 
       
  1829 /*!
       
  1830   \reimp
       
  1831 */
       
  1832 void QTreeView::mouseDoubleClickEvent(QMouseEvent *event)
       
  1833 {
       
  1834     Q_D(QTreeView);
       
  1835     if (state() != NoState || !d->viewport->rect().contains(event->pos()))
       
  1836         return;
       
  1837 
       
  1838     int i = d->itemDecorationAt(event->pos());
       
  1839     if (i == -1) {
       
  1840         i = d->itemAtCoordinate(event->y());
       
  1841         if (i == -1)
       
  1842             return; // user clicked outside the items
       
  1843 
       
  1844         const QPersistentModelIndex firstColumnIndex = d->viewItems.at(i).index;
       
  1845         const QPersistentModelIndex persistent = indexAt(event->pos());
       
  1846 
       
  1847         if (d->pressedIndex != persistent) {
       
  1848             mousePressEvent(event);
       
  1849             return;
       
  1850         }
       
  1851 
       
  1852         // signal handlers may change the model
       
  1853         emit doubleClicked(persistent);
       
  1854 
       
  1855         if (!persistent.isValid())
       
  1856             return;
       
  1857 
       
  1858         if (edit(persistent, DoubleClicked, event) || state() != NoState)
       
  1859             return; // the double click triggered editing
       
  1860 
       
  1861         if (!style()->styleHint(QStyle::SH_ItemView_ActivateItemOnSingleClick, 0, this))
       
  1862             emit activated(persistent);
       
  1863 
       
  1864         d->executePostedLayout(); // we need to make sure viewItems is updated
       
  1865         if (d->itemsExpandable
       
  1866             && d->expandsOnDoubleClick
       
  1867             && d->hasVisibleChildren(persistent)) {
       
  1868             if (!((i < d->viewItems.count()) && (d->viewItems.at(i).index == firstColumnIndex))) {
       
  1869                 // find the new index of the item
       
  1870                 for (i = 0; i < d->viewItems.count(); ++i) {
       
  1871                     if (d->viewItems.at(i).index == firstColumnIndex)
       
  1872                         break;
       
  1873                 }
       
  1874                 if (i == d->viewItems.count())
       
  1875                     return;
       
  1876             }
       
  1877             if (d->viewItems.at(i).expanded)
       
  1878                 d->collapse(i, true);
       
  1879             else
       
  1880                 d->expand(i, true);
       
  1881             updateGeometries();
       
  1882             viewport()->update();
       
  1883         }
       
  1884     }
       
  1885 }
       
  1886 
       
  1887 /*!
       
  1888   \reimp
       
  1889 */
       
  1890 void QTreeView::mouseMoveEvent(QMouseEvent *event)
       
  1891 {
       
  1892     Q_D(QTreeView);
       
  1893     if (d->itemDecorationAt(event->pos()) == -1) // ### what about expanding/collapsing state ?
       
  1894         QAbstractItemView::mouseMoveEvent(event);
       
  1895 }
       
  1896 
       
  1897 /*!
       
  1898   \reimp
       
  1899 */
       
  1900 void QTreeView::keyPressEvent(QKeyEvent *event)
       
  1901 {
       
  1902     Q_D(QTreeView);
       
  1903     QModelIndex current = currentIndex();
       
  1904     //this is the management of the expansion
       
  1905     if (d->isIndexValid(current) && d->model && d->itemsExpandable) {
       
  1906         switch (event->key()) {
       
  1907         case Qt::Key_Asterisk: {
       
  1908             QStack<QModelIndex> parents;
       
  1909             parents.push(current);
       
  1910                 while (!parents.isEmpty()) {
       
  1911                     QModelIndex parent = parents.pop();
       
  1912                     for (int row = 0; row < d->model->rowCount(parent); ++row) {
       
  1913                         QModelIndex child = d->model->index(row, 0, parent);
       
  1914                         if (!d->isIndexValid(child))
       
  1915                             break;
       
  1916                         parents.push(child);
       
  1917                         expand(child);
       
  1918                     }
       
  1919                 }
       
  1920                 expand(current);
       
  1921             break; }
       
  1922         case Qt::Key_Plus:
       
  1923             expand(current);
       
  1924             break;
       
  1925         case Qt::Key_Minus:
       
  1926             collapse(current);
       
  1927             break;
       
  1928         }
       
  1929     }
       
  1930 
       
  1931     QAbstractItemView::keyPressEvent(event);
       
  1932 }
       
  1933 
       
  1934 /*!
       
  1935   \reimp
       
  1936 */
       
  1937 QModelIndex QTreeView::indexAt(const QPoint &point) const
       
  1938 {
       
  1939     Q_D(const QTreeView);
       
  1940     d->executePostedLayout();
       
  1941 
       
  1942     int visualIndex = d->itemAtCoordinate(point.y());
       
  1943     QModelIndex idx = d->modelIndex(visualIndex);
       
  1944     if (!idx.isValid())
       
  1945         return QModelIndex();
       
  1946 
       
  1947     if (d->viewItems.at(visualIndex).spanning)
       
  1948         return idx;
       
  1949 
       
  1950     int column = d->columnAt(point.x());
       
  1951     if (column == idx.column())
       
  1952         return idx;
       
  1953     if (column < 0)
       
  1954         return QModelIndex();
       
  1955     return idx.sibling(idx.row(), column);
       
  1956 }
       
  1957 
       
  1958 /*!
       
  1959   Returns the model index of the item above \a index.
       
  1960 */
       
  1961 QModelIndex QTreeView::indexAbove(const QModelIndex &index) const
       
  1962 {
       
  1963     Q_D(const QTreeView);
       
  1964     if (!d->isIndexValid(index))
       
  1965         return QModelIndex();
       
  1966     d->executePostedLayout();
       
  1967     int i = d->viewIndex(index);
       
  1968     if (--i < 0)
       
  1969         return QModelIndex();
       
  1970     return d->viewItems.at(i).index;
       
  1971 }
       
  1972 
       
  1973 /*!
       
  1974   Returns the model index of the item below \a index.
       
  1975 */
       
  1976 QModelIndex QTreeView::indexBelow(const QModelIndex &index) const
       
  1977 {
       
  1978     Q_D(const QTreeView);
       
  1979     if (!d->isIndexValid(index))
       
  1980         return QModelIndex();
       
  1981     d->executePostedLayout();
       
  1982     int i = d->viewIndex(index);
       
  1983     if (++i >= d->viewItems.count())
       
  1984         return QModelIndex();
       
  1985     return d->viewItems.at(i).index;
       
  1986 }
       
  1987 
       
  1988 /*!
       
  1989     \internal
       
  1990 
       
  1991     Lays out the items in the tree view.
       
  1992 */
       
  1993 void QTreeView::doItemsLayout()
       
  1994 {
       
  1995     Q_D(QTreeView);
       
  1996     d->viewItems.clear(); // prepare for new layout
       
  1997     QModelIndex parent = d->root;
       
  1998     if (d->model->hasChildren(parent)) {
       
  1999         d->layout(-1);
       
  2000     }
       
  2001     QAbstractItemView::doItemsLayout();
       
  2002     d->header->doItemsLayout();
       
  2003 }
       
  2004 
       
  2005 /*!
       
  2006   \reimp
       
  2007 */
       
  2008 void QTreeView::reset()
       
  2009 {
       
  2010     Q_D(QTreeView);
       
  2011     d->expandedIndexes.clear();
       
  2012     d->hiddenIndexes.clear();
       
  2013     d->spanningIndexes.clear();
       
  2014     d->viewItems.clear();
       
  2015     QAbstractItemView::reset();
       
  2016 }
       
  2017 
       
  2018 /*!
       
  2019   Returns the horizontal offset of the items in the treeview.
       
  2020 
       
  2021   Note that the tree view uses the horizontal header section
       
  2022   positions to determine the positions of columns in the view.
       
  2023 
       
  2024   \sa verticalOffset()
       
  2025 */
       
  2026 int QTreeView::horizontalOffset() const
       
  2027 {
       
  2028     Q_D(const QTreeView);
       
  2029     return d->header->offset();
       
  2030 }
       
  2031 
       
  2032 /*!
       
  2033   Returns the vertical offset of the items in the tree view.
       
  2034 
       
  2035   \sa horizontalOffset()
       
  2036 */
       
  2037 int QTreeView::verticalOffset() const
       
  2038 {
       
  2039     Q_D(const QTreeView);
       
  2040     if (d->verticalScrollMode == QAbstractItemView::ScrollPerItem) {
       
  2041         if (d->uniformRowHeights)
       
  2042             return verticalScrollBar()->value() * d->defaultItemHeight;
       
  2043         // If we are scrolling per item and have non-uniform row heights,
       
  2044         // finding the vertical offset in pixels is going to be relatively slow.
       
  2045         // ### find a faster way to do this
       
  2046         d->executePostedLayout();
       
  2047         int offset = 0;
       
  2048         for (int i = 0; i < d->viewItems.count(); ++i) {
       
  2049             if (i == verticalScrollBar()->value())
       
  2050                 return offset;
       
  2051             offset += d->itemHeight(i);
       
  2052         }
       
  2053         return 0;
       
  2054     }
       
  2055     // scroll per pixel
       
  2056     return verticalScrollBar()->value();
       
  2057 }
       
  2058 
       
  2059 /*!
       
  2060     Move the cursor in the way described by \a cursorAction, using the
       
  2061     information provided by the button \a modifiers.
       
  2062 */
       
  2063 QModelIndex QTreeView::moveCursor(CursorAction cursorAction, Qt::KeyboardModifiers modifiers)
       
  2064 {
       
  2065     Q_D(QTreeView);
       
  2066     Q_UNUSED(modifiers);
       
  2067 
       
  2068     d->executePostedLayout();
       
  2069 
       
  2070     QModelIndex current = currentIndex();
       
  2071     if (!current.isValid()) {
       
  2072         int i = d->below(-1);
       
  2073         int c = 0;
       
  2074         while (c < d->header->count() && d->header->isSectionHidden(c))
       
  2075             ++c;
       
  2076         if (i < d->viewItems.count() && c < d->header->count()) {
       
  2077             return d->modelIndex(i, c);
       
  2078         }
       
  2079         return QModelIndex();
       
  2080     }
       
  2081     int vi = -1;
       
  2082 #if defined(Q_WS_MAC) && !defined(QT_NO_STYLE_MAC)
       
  2083     // Selection behavior is slightly different on the Mac.
       
  2084     if (d->selectionMode == QAbstractItemView::ExtendedSelection
       
  2085         && d->selectionModel
       
  2086         && d->selectionModel->hasSelection()) {
       
  2087 
       
  2088         const bool moveUpDown = (cursorAction == MoveUp || cursorAction == MoveDown);
       
  2089         const bool moveNextPrev = (cursorAction == MoveNext || cursorAction == MovePrevious);
       
  2090         const bool contiguousSelection = moveUpDown && (modifiers & Qt::ShiftModifier);
       
  2091 
       
  2092         // Use the outermost index in the selection as the current index
       
  2093         if (!contiguousSelection && (moveUpDown || moveNextPrev)) {
       
  2094 
       
  2095             // Find outermost index.
       
  2096             const bool useTopIndex = (cursorAction == MoveUp || cursorAction == MovePrevious);
       
  2097             int index = useTopIndex ? INT_MAX : INT_MIN;
       
  2098             const QItemSelection selection = d->selectionModel->selection();
       
  2099             for (int i = 0; i < selection.count(); ++i) {
       
  2100                 const QItemSelectionRange &range = selection.at(i);
       
  2101                 int candidate = d->viewIndex(useTopIndex ? range.topLeft() : range.bottomRight());
       
  2102                 if (candidate >= 0)
       
  2103                     index = useTopIndex ? qMin(index, candidate) : qMax(index, candidate);
       
  2104             }
       
  2105 
       
  2106             if (index >= 0 && index < INT_MAX)
       
  2107                 vi = index;
       
  2108         }
       
  2109     }
       
  2110 #endif
       
  2111     if (vi < 0)
       
  2112         vi = qMax(0, d->viewIndex(current));
       
  2113 
       
  2114     if (isRightToLeft()) {
       
  2115         if (cursorAction == MoveRight)
       
  2116             cursorAction = MoveLeft;
       
  2117         else if (cursorAction == MoveLeft)
       
  2118             cursorAction = MoveRight;
       
  2119     }
       
  2120     switch (cursorAction) {
       
  2121     case MoveNext:
       
  2122     case MoveDown:
       
  2123 #ifdef QT_KEYPAD_NAVIGATION
       
  2124         if (vi == d->viewItems.count()-1 && QApplication::keypadNavigationEnabled())
       
  2125             return d->model->index(0, current.column(), d->root);
       
  2126 #endif
       
  2127         return d->modelIndex(d->below(vi), current.column());
       
  2128     case MovePrevious:
       
  2129     case MoveUp:
       
  2130 #ifdef QT_KEYPAD_NAVIGATION
       
  2131         if (vi == 0 && QApplication::keypadNavigationEnabled())
       
  2132             return d->modelIndex(d->viewItems.count() - 1, current.column());
       
  2133 #endif
       
  2134         return d->modelIndex(d->above(vi), current.column());
       
  2135     case MoveLeft: {
       
  2136         QScrollBar *sb = horizontalScrollBar();
       
  2137         if (vi < d->viewItems.count() && d->viewItems.at(vi).expanded && d->itemsExpandable && sb->value() == sb->minimum())
       
  2138             d->collapse(vi, true);
       
  2139         else {
       
  2140             bool descend = style()->styleHint(QStyle::SH_ItemView_ArrowKeysNavigateIntoChildren, 0, this);
       
  2141             if (descend) {
       
  2142                 QModelIndex par = current.parent();
       
  2143                 if (par.isValid() && par != rootIndex())
       
  2144                     return par;
       
  2145                 else
       
  2146                     descend = false;
       
  2147             }
       
  2148             if (!descend) {
       
  2149                 if (d->selectionBehavior == SelectItems || d->selectionBehavior == SelectColumns) {
       
  2150                     int visualColumn = d->header->visualIndex(current.column()) - 1;
       
  2151                     while (visualColumn >= 0 && isColumnHidden(d->header->logicalIndex(visualColumn)))
       
  2152                         visualColumn--;
       
  2153                     int newColumn = d->header->logicalIndex(visualColumn);
       
  2154                     QModelIndex next = current.sibling(current.row(), newColumn);
       
  2155                     if (next.isValid())
       
  2156                         return next;
       
  2157                 }
       
  2158 
       
  2159                 sb->setValue(sb->value() - sb->singleStep());
       
  2160             }
       
  2161 
       
  2162         }
       
  2163         updateGeometries();
       
  2164         viewport()->update();
       
  2165         break;
       
  2166     }
       
  2167     case MoveRight:
       
  2168         if (vi < d->viewItems.count() && !d->viewItems.at(vi).expanded && d->itemsExpandable
       
  2169             && d->hasVisibleChildren(d->viewItems.at(vi).index)) {
       
  2170             d->expand(vi, true);
       
  2171         } else {
       
  2172             bool descend = style()->styleHint(QStyle::SH_ItemView_ArrowKeysNavigateIntoChildren, 0, this);
       
  2173             if (descend) {
       
  2174                 QModelIndex idx = d->modelIndex(d->below(vi));
       
  2175                 if (idx.parent() == current)
       
  2176                     return idx;
       
  2177                 else
       
  2178                     descend = false;
       
  2179             }
       
  2180             if (!descend) {
       
  2181                 if (d->selectionBehavior == SelectItems || d->selectionBehavior == SelectColumns) {
       
  2182                     int visualColumn = d->header->visualIndex(current.column()) + 1;
       
  2183                     while (visualColumn < d->model->columnCount(current.parent()) && isColumnHidden(d->header->logicalIndex(visualColumn)))
       
  2184                         visualColumn++;
       
  2185 
       
  2186                     QModelIndex next = current.sibling(current.row(), visualColumn);
       
  2187                     if (next.isValid())
       
  2188                         return next;
       
  2189                 }
       
  2190 
       
  2191                 //last restort: we change the scrollbar value
       
  2192                 QScrollBar *sb = horizontalScrollBar();
       
  2193                 sb->setValue(sb->value() + sb->singleStep());
       
  2194             }
       
  2195         }
       
  2196         updateGeometries();
       
  2197         viewport()->update();
       
  2198         break;
       
  2199     case MovePageUp:
       
  2200         return d->modelIndex(d->pageUp(vi), current.column());
       
  2201     case MovePageDown:
       
  2202         return d->modelIndex(d->pageDown(vi), current.column());
       
  2203     case MoveHome:
       
  2204         return d->model->index(0, current.column(), d->root);
       
  2205     case MoveEnd:
       
  2206         return d->modelIndex(d->viewItems.count() - 1, current.column());
       
  2207     }
       
  2208     return current;
       
  2209 }
       
  2210 
       
  2211 /*!
       
  2212   Applies the selection \a command to the items in or touched by the
       
  2213   rectangle, \a rect.
       
  2214 
       
  2215   \sa selectionCommand()
       
  2216 */
       
  2217 void QTreeView::setSelection(const QRect &rect, QItemSelectionModel::SelectionFlags command)
       
  2218 {
       
  2219     Q_D(QTreeView);
       
  2220     if (!selectionModel() || rect.isNull())
       
  2221         return;
       
  2222 
       
  2223     d->executePostedLayout();
       
  2224     QPoint tl(isRightToLeft() ? qMax(rect.left(), rect.right())
       
  2225               : qMin(rect.left(), rect.right()), qMin(rect.top(), rect.bottom()));
       
  2226     QPoint br(isRightToLeft() ? qMin(rect.left(), rect.right()) :
       
  2227               qMax(rect.left(), rect.right()), qMax(rect.top(), rect.bottom()));
       
  2228     QModelIndex topLeft = indexAt(tl);
       
  2229     QModelIndex bottomRight = indexAt(br);
       
  2230     if (!topLeft.isValid() && !bottomRight.isValid()) {
       
  2231         if (command & QItemSelectionModel::Clear)
       
  2232             selectionModel()->clear();
       
  2233         return;
       
  2234     }
       
  2235     if (!topLeft.isValid() && !d->viewItems.isEmpty())
       
  2236         topLeft = d->viewItems.first().index;
       
  2237     if (!bottomRight.isValid() && !d->viewItems.isEmpty()) {
       
  2238         const int column = d->header->logicalIndex(d->header->count() - 1);
       
  2239         const QModelIndex index = d->viewItems.last().index;
       
  2240         bottomRight = index.sibling(index.row(), column);
       
  2241     }
       
  2242 
       
  2243     if (!d->isIndexEnabled(topLeft) || !d->isIndexEnabled(bottomRight))
       
  2244         return;
       
  2245 
       
  2246     d->select(topLeft, bottomRight, command);
       
  2247 }
       
  2248 
       
  2249 /*!
       
  2250   Returns the rectangle from the viewport of the items in the given
       
  2251   \a selection.
       
  2252 */
       
  2253 QRegion QTreeView::visualRegionForSelection(const QItemSelection &selection) const
       
  2254 {
       
  2255     Q_D(const QTreeView);
       
  2256     if (selection.isEmpty())
       
  2257         return QRegion();
       
  2258 
       
  2259     QRegion selectionRegion;
       
  2260     for (int i = 0; i < selection.count(); ++i) {
       
  2261         QItemSelectionRange range = selection.at(i);
       
  2262         if (!range.isValid())
       
  2263             continue;
       
  2264         QModelIndex parent = range.parent();
       
  2265         QModelIndex leftIndex = range.topLeft();
       
  2266         int columnCount = d->model->columnCount(parent);
       
  2267         while (leftIndex.isValid() && isIndexHidden(leftIndex)) {
       
  2268             if (leftIndex.column() + 1 < columnCount)
       
  2269                 leftIndex = d->model->index(leftIndex.row(), leftIndex.column() + 1, parent);
       
  2270             else
       
  2271                 leftIndex = QModelIndex();
       
  2272         }
       
  2273         if (!leftIndex.isValid())
       
  2274             continue;
       
  2275         const QRect leftRect = visualRect(leftIndex);
       
  2276         int top = leftRect.top();
       
  2277         QModelIndex rightIndex = range.bottomRight();
       
  2278         while (rightIndex.isValid() && isIndexHidden(rightIndex)) {
       
  2279             if (rightIndex.column() - 1 >= 0)
       
  2280                 rightIndex = d->model->index(rightIndex.row(), rightIndex.column() - 1, parent);
       
  2281             else
       
  2282                 rightIndex = QModelIndex();
       
  2283         }
       
  2284         if (!rightIndex.isValid())
       
  2285             continue;
       
  2286         const QRect rightRect = visualRect(rightIndex);
       
  2287         int bottom = rightRect.bottom();
       
  2288         if (top > bottom)
       
  2289             qSwap<int>(top, bottom);
       
  2290         int height = bottom - top + 1;
       
  2291         if (d->header->sectionsMoved()) {
       
  2292             for (int c = range.left(); c <= range.right(); ++c)
       
  2293                 selectionRegion += QRegion(QRect(columnViewportPosition(c), top,
       
  2294                                                  columnWidth(c), height));
       
  2295         } else {
       
  2296             QRect combined = leftRect|rightRect;
       
  2297             combined.setX(columnViewportPosition(isRightToLeft() ? range.right() : range.left()));
       
  2298             selectionRegion += combined;
       
  2299         }
       
  2300     }
       
  2301     return selectionRegion;
       
  2302 }
       
  2303 
       
  2304 /*!
       
  2305   \reimp
       
  2306 */
       
  2307 QModelIndexList QTreeView::selectedIndexes() const
       
  2308 {
       
  2309     QModelIndexList viewSelected;
       
  2310     QModelIndexList modelSelected;
       
  2311     if (selectionModel())
       
  2312         modelSelected = selectionModel()->selectedIndexes();
       
  2313     for (int i = 0; i < modelSelected.count(); ++i) {
       
  2314         // check that neither the parents nor the index is hidden before we add
       
  2315         QModelIndex index = modelSelected.at(i);
       
  2316         while (index.isValid() && !isIndexHidden(index))
       
  2317             index = index.parent();
       
  2318         if (index.isValid())
       
  2319             continue;
       
  2320         viewSelected.append(modelSelected.at(i));
       
  2321     }
       
  2322     return viewSelected;
       
  2323 }
       
  2324 
       
  2325 /*!
       
  2326   Scrolls the contents of the tree view by (\a dx, \a dy).
       
  2327 */
       
  2328 void QTreeView::scrollContentsBy(int dx, int dy)
       
  2329 {
       
  2330     Q_D(QTreeView);
       
  2331 
       
  2332     d->delayedAutoScroll.stop(); // auto scroll was canceled by the user scrolling
       
  2333 
       
  2334     dx = isRightToLeft() ? -dx : dx;
       
  2335     if (dx) {
       
  2336         if (horizontalScrollMode() == QAbstractItemView::ScrollPerItem) {
       
  2337             int oldOffset = d->header->offset();
       
  2338             if (horizontalScrollBar()->value() == horizontalScrollBar()->maximum())
       
  2339                 d->header->setOffsetToLastSection();
       
  2340             else
       
  2341                 d->header->setOffsetToSectionPosition(horizontalScrollBar()->value());
       
  2342             int newOffset = d->header->offset();
       
  2343             dx = isRightToLeft() ? newOffset - oldOffset : oldOffset - newOffset;
       
  2344         } else {
       
  2345             d->header->setOffset(horizontalScrollBar()->value());
       
  2346         }
       
  2347     }
       
  2348 
       
  2349     const int itemHeight = d->defaultItemHeight <= 0 ? sizeHintForRow(0) : d->defaultItemHeight;
       
  2350     if (d->viewItems.isEmpty() || itemHeight == 0)
       
  2351         return;
       
  2352 
       
  2353     // guestimate the number of items in the viewport
       
  2354     int viewCount = d->viewport->height() / itemHeight;
       
  2355     int maxDeltaY = qMin(d->viewItems.count(), viewCount);
       
  2356     // no need to do a lot of work if we are going to redraw the whole thing anyway
       
  2357     if (qAbs(dy) > qAbs(maxDeltaY) && d->editors.isEmpty()) {
       
  2358         verticalScrollBar()->update();
       
  2359         d->viewport->update();
       
  2360         return;
       
  2361     }
       
  2362 
       
  2363     if (dy && verticalScrollMode() == QAbstractItemView::ScrollPerItem) {
       
  2364         int currentScrollbarValue = verticalScrollBar()->value();
       
  2365         int previousScrollbarValue = currentScrollbarValue + dy; // -(-dy)
       
  2366         int currentViewIndex = currentScrollbarValue; // the first visible item
       
  2367         int previousViewIndex = previousScrollbarValue;
       
  2368         const QVector<QTreeViewItem> viewItems = d->viewItems;
       
  2369         dy = 0;
       
  2370         if (previousViewIndex < currentViewIndex) { // scrolling down
       
  2371             for (int i = previousViewIndex; i < currentViewIndex; ++i) {
       
  2372                 if (i < d->viewItems.count())
       
  2373                     dy -= d->itemHeight(i);
       
  2374             }
       
  2375         } else if (previousViewIndex > currentViewIndex) { // scrolling up
       
  2376             for (int i = previousViewIndex - 1; i >= currentViewIndex; --i) {
       
  2377                 if (i < d->viewItems.count())
       
  2378                     dy += d->itemHeight(i);
       
  2379             }
       
  2380         }
       
  2381     }
       
  2382 
       
  2383     d->scrollContentsBy(dx, dy);
       
  2384 }
       
  2385 
       
  2386 /*!
       
  2387   This slot is called whenever a column has been moved.
       
  2388 */
       
  2389 void QTreeView::columnMoved()
       
  2390 {
       
  2391     Q_D(QTreeView);
       
  2392     updateEditorGeometries();
       
  2393     d->viewport->update();
       
  2394 }
       
  2395 
       
  2396 /*!
       
  2397   \internal
       
  2398 */
       
  2399 void QTreeView::reexpand()
       
  2400 {
       
  2401     // do nothing
       
  2402 }
       
  2403 
       
  2404 /*!
       
  2405   \internal
       
  2406 */
       
  2407 static bool treeViewItemLessThan(const QTreeViewItem &left,
       
  2408                                  const QTreeViewItem &right)
       
  2409 {
       
  2410     if (left.level != right.level) {
       
  2411         Q_ASSERT(left.level > right.level);
       
  2412         QModelIndex leftParent = left.index.parent();
       
  2413         QModelIndex rightParent = right.index.parent();
       
  2414         // computer parent, don't get
       
  2415         while (leftParent.isValid() && leftParent.parent() != rightParent)
       
  2416             leftParent = leftParent.parent();
       
  2417         return (leftParent.row() < right.index.row());
       
  2418     }
       
  2419     return (left.index.row() < right.index.row());
       
  2420 }
       
  2421 
       
  2422 /*!
       
  2423   Informs the view that the rows from the \a start row to the \a end row
       
  2424   inclusive have been inserted into the \a parent model item.
       
  2425 */
       
  2426 void QTreeView::rowsInserted(const QModelIndex &parent, int start, int end)
       
  2427 {
       
  2428     Q_D(QTreeView);
       
  2429     // if we are going to do a complete relayout anyway, there is no need to update
       
  2430     if (d->delayedPendingLayout) {
       
  2431         QAbstractItemView::rowsInserted(parent, start, end);
       
  2432         return;
       
  2433     }
       
  2434 
       
  2435     //don't add a hierarchy on a column != 0
       
  2436     if (parent.column() != 0 && parent.isValid()) {
       
  2437         QAbstractItemView::rowsInserted(parent, start, end);
       
  2438         return;
       
  2439     }
       
  2440 
       
  2441     const int parentRowCount = d->model->rowCount(parent);
       
  2442     const int delta = end - start + 1;
       
  2443     if (parent != d->root && !d->isIndexExpanded(parent) && parentRowCount > delta) {
       
  2444         QAbstractItemView::rowsInserted(parent, start, end);
       
  2445         return;
       
  2446     }
       
  2447 
       
  2448     const int parentItem = d->viewIndex(parent);
       
  2449     if (((parentItem != -1) && d->viewItems.at(parentItem).expanded && updatesEnabled())
       
  2450         || (parent == d->root)) {
       
  2451         const uint childLevel = (parentItem == -1)
       
  2452                                 ? uint(0) : d->viewItems.at(parentItem).level + 1;
       
  2453         const int firstChildItem = parentItem + 1;
       
  2454         const int lastChildItem = firstChildItem + ((parentItem == -1)
       
  2455                                                     ? d->viewItems.count()
       
  2456                                                     : d->viewItems.at(parentItem).total) - 1;
       
  2457 
       
  2458         if (parentRowCount == end + 1 && start > 0) {
       
  2459             //need to Update hasMoreSiblings
       
  2460             int previousRow = start - 1;
       
  2461             QModelIndex previousSibilingModelIndex = d->model->index(previousRow, 0, parent);
       
  2462             bool isHidden = d->isRowHidden(previousSibilingModelIndex);
       
  2463             while (isHidden && previousRow > 0) {
       
  2464                 previousRow--;
       
  2465                 previousSibilingModelIndex = d->model->index(previousRow, 0, parent);
       
  2466                 isHidden = d->isRowHidden(previousSibilingModelIndex);
       
  2467             }
       
  2468             if (!isHidden) {
       
  2469                 const int previousSibilling = d->viewIndex(previousSibilingModelIndex);
       
  2470                 if(previousSibilling != -1)
       
  2471                     d->viewItems[previousSibilling].hasMoreSiblings = true;
       
  2472             }
       
  2473         }
       
  2474 
       
  2475         QVector<QTreeViewItem> insertedItems(delta);
       
  2476         for (int i = 0; i < delta; ++i) {
       
  2477             QTreeViewItem &item = insertedItems[i];
       
  2478             item.index = d->model->index(i + start, 0, parent);
       
  2479             item.level = childLevel;
       
  2480             item.hasChildren = d->hasVisibleChildren(item.index);
       
  2481             item.hasMoreSiblings = !((i == delta - 1) && (parentRowCount == end +1));
       
  2482         }
       
  2483         if (d->viewItems.isEmpty())
       
  2484             d->defaultItemHeight = indexRowSizeHint(insertedItems[0].index);
       
  2485 
       
  2486         int insertPos;
       
  2487         if (lastChildItem < firstChildItem) { // no children
       
  2488             insertPos = firstChildItem;
       
  2489         } else {
       
  2490             // do a binary search to figure out where to insert
       
  2491             QVector<QTreeViewItem>::iterator it;
       
  2492             it = qLowerBound(d->viewItems.begin() + firstChildItem,
       
  2493                              d->viewItems.begin() + lastChildItem + 1,
       
  2494                              insertedItems.at(0), treeViewItemLessThan);
       
  2495             insertPos = it - d->viewItems.begin();
       
  2496 
       
  2497             // update stale model indexes of siblings
       
  2498             for (int item = insertPos; item <= lastChildItem; ) {
       
  2499                 Q_ASSERT(d->viewItems.at(item).level == childLevel);
       
  2500                 const QModelIndex modelIndex = d->viewItems.at(item).index;
       
  2501                 //Q_ASSERT(modelIndex.parent() == parent);
       
  2502                 d->viewItems[item].index = d->model->index(
       
  2503                     modelIndex.row() + delta, modelIndex.column(), parent);
       
  2504 
       
  2505                 if (!d->viewItems[item].index.isValid()) {
       
  2506                     // Something really bad is happening, a bad model is
       
  2507                     // often the cause.  We can't optimize in this case :(
       
  2508                     qWarning() << "QTreeView::rowsInserted internal representation of the model has been corrupted, resetting.";
       
  2509                     doItemsLayout();
       
  2510                     return;
       
  2511                 }
       
  2512 
       
  2513                 item += d->viewItems.at(item).total + 1;
       
  2514             }
       
  2515         }
       
  2516 
       
  2517         d->viewItems.insert(insertPos, delta, insertedItems.at(0));
       
  2518         if (delta > 1) {
       
  2519             qCopy(insertedItems.begin() + 1, insertedItems.end(),
       
  2520                   d->viewItems.begin() + insertPos + 1);
       
  2521         }
       
  2522 
       
  2523         if (parentItem != -1)
       
  2524             d->viewItems[parentItem].hasChildren = true;
       
  2525         d->updateChildCount(parentItem, delta);
       
  2526 
       
  2527         updateGeometries();
       
  2528         viewport()->update();
       
  2529     } else if ((parentItem != -1) && d->viewItems.at(parentItem).expanded) {
       
  2530         d->doDelayedItemsLayout();
       
  2531     } else if (parentItem != -1 && (d->model->rowCount(parent) == end - start + 1)) {
       
  2532         // the parent just went from 0 children to more. update to re-paint the decoration
       
  2533         d->viewItems[parentItem].hasChildren = true;
       
  2534         viewport()->update();
       
  2535     }
       
  2536     QAbstractItemView::rowsInserted(parent, start, end);
       
  2537 }
       
  2538 
       
  2539 /*!
       
  2540   Informs the view that the rows from the \a start row to the \a end row
       
  2541   inclusive are about to removed from the given \a parent model item.
       
  2542 */
       
  2543 void QTreeView::rowsAboutToBeRemoved(const QModelIndex &parent, int start, int end)
       
  2544 {
       
  2545     Q_D(QTreeView);
       
  2546     d->rowsRemoved(parent, start, end, false);
       
  2547     QAbstractItemView::rowsAboutToBeRemoved(parent, start, end);
       
  2548 }
       
  2549 
       
  2550 /*!
       
  2551     \since 4.1
       
  2552 
       
  2553     Informs the view that the rows from the \a start row to the \a end row
       
  2554     inclusive have been removed from the given \a parent model item.
       
  2555 */
       
  2556 void QTreeView::rowsRemoved(const QModelIndex &parent, int start, int end)
       
  2557 {
       
  2558     Q_D(QTreeView);
       
  2559     d->rowsRemoved(parent, start, end, true);
       
  2560 }
       
  2561 
       
  2562 /*!
       
  2563   Informs the tree view that the number of columns in the tree view has
       
  2564   changed from \a oldCount to \a newCount.
       
  2565 */
       
  2566 void QTreeView::columnCountChanged(int oldCount, int newCount)
       
  2567 {
       
  2568     Q_D(QTreeView);
       
  2569     if (oldCount == 0 && newCount > 0) {
       
  2570         //if the first column has just been added we need to relayout.
       
  2571         d->doDelayedItemsLayout();
       
  2572     }
       
  2573 
       
  2574     if (isVisible())
       
  2575         updateGeometries();
       
  2576 	viewport()->update();
       
  2577 }
       
  2578 
       
  2579 /*!
       
  2580   Resizes the \a column given to the size of its contents.
       
  2581 
       
  2582   \sa columnWidth(), setColumnWidth()
       
  2583 */
       
  2584 void QTreeView::resizeColumnToContents(int column)
       
  2585 {
       
  2586     Q_D(QTreeView);
       
  2587     d->executePostedLayout();
       
  2588     if (column < 0 || column >= d->header->count())
       
  2589         return;
       
  2590     int contents = sizeHintForColumn(column);
       
  2591     int header = d->header->isHidden() ? 0 : d->header->sectionSizeHint(column);
       
  2592     d->header->resizeSection(column, qMax(contents, header));
       
  2593 }
       
  2594 
       
  2595 /*!
       
  2596   \obsolete
       
  2597   \overload
       
  2598 
       
  2599   Sorts the model by the values in the given \a column.
       
  2600 */
       
  2601 void QTreeView::sortByColumn(int column)
       
  2602 {
       
  2603     Q_D(QTreeView);
       
  2604     sortByColumn(column, d->header->sortIndicatorOrder());
       
  2605 }
       
  2606 
       
  2607 /*!
       
  2608   \since 4.2
       
  2609 
       
  2610   Sets the model up for sorting by the values in the given \a column and \a order.
       
  2611 
       
  2612   \a column may be -1, in which case no sort indicator will be shown
       
  2613   and the model will return to its natural, unsorted order. Note that not
       
  2614   all models support this and may even crash in this case.
       
  2615 
       
  2616   \sa sortingEnabled
       
  2617 */
       
  2618 void QTreeView::sortByColumn(int column, Qt::SortOrder order)
       
  2619 {
       
  2620     Q_D(QTreeView);
       
  2621 
       
  2622     //If sorting is enabled  will emit a signal connected to _q_sortIndicatorChanged, which then actually sorts
       
  2623     d->header->setSortIndicator(column, order);
       
  2624     //If sorting is not enabled, force to sort now.
       
  2625     if (!d->sortingEnabled)
       
  2626         d->model->sort(column, order);
       
  2627 }
       
  2628 
       
  2629 /*!
       
  2630   \reimp
       
  2631 */
       
  2632 void QTreeView::selectAll()
       
  2633 {
       
  2634     Q_D(QTreeView);
       
  2635     if (!selectionModel())
       
  2636         return;
       
  2637     SelectionMode mode = d->selectionMode;
       
  2638     d->executePostedLayout(); //make sure we lay out the items
       
  2639     if (mode != SingleSelection && !d->viewItems.isEmpty()) {
       
  2640         const QModelIndex &idx = d->viewItems.last().index;
       
  2641         QModelIndex lastItemIndex = idx.sibling(idx.row(), d->model->columnCount(idx.parent()) - 1);
       
  2642         d->select(d->viewItems.first().index, lastItemIndex,
       
  2643                   QItemSelectionModel::ClearAndSelect
       
  2644                   |QItemSelectionModel::Rows);
       
  2645     }
       
  2646 }
       
  2647 
       
  2648 /*!
       
  2649   \since 4.2
       
  2650   Expands all expandable items.
       
  2651 
       
  2652   Warning: if the model contains a large number of items,
       
  2653   this function will take some time to execute.
       
  2654 
       
  2655   \sa collapseAll() expand()  collapse() setExpanded()
       
  2656 */
       
  2657 void QTreeView::expandAll()
       
  2658 {
       
  2659     Q_D(QTreeView);
       
  2660     d->viewItems.clear();
       
  2661     d->expandedIndexes.clear();
       
  2662     d->interruptDelayedItemsLayout();
       
  2663     d->layout(-1);
       
  2664     for (int i = 0; i < d->viewItems.count(); ++i) {
       
  2665         if (d->viewItems[i].expanded)
       
  2666             continue;
       
  2667         d->viewItems[i].expanded = true;
       
  2668         d->layout(i);
       
  2669         QModelIndex idx = d->viewItems.at(i).index;
       
  2670         d->expandedIndexes.insert(idx);
       
  2671     }
       
  2672     updateGeometries();
       
  2673     d->viewport->update();
       
  2674 }
       
  2675 
       
  2676 /*!
       
  2677   \since 4.2
       
  2678 
       
  2679   Collapses all expanded items.
       
  2680 
       
  2681   \sa expandAll() expand()  collapse() setExpanded()
       
  2682 */
       
  2683 void QTreeView::collapseAll()
       
  2684 {
       
  2685     Q_D(QTreeView);
       
  2686     d->expandedIndexes.clear();
       
  2687     doItemsLayout();
       
  2688 }
       
  2689 
       
  2690 /*!
       
  2691   \since 4.3
       
  2692   Expands all expandable items to the given \a depth.
       
  2693 
       
  2694   \sa expandAll() collapseAll() expand()  collapse() setExpanded()
       
  2695 */
       
  2696 void QTreeView::expandToDepth(int depth)
       
  2697 {
       
  2698     Q_D(QTreeView);
       
  2699     d->viewItems.clear();
       
  2700     d->expandedIndexes.clear();
       
  2701     d->interruptDelayedItemsLayout();
       
  2702     d->layout(-1);
       
  2703     for (int i = 0; i < d->viewItems.count(); ++i) {
       
  2704         if (d->viewItems.at(i).level <= (uint)depth) {
       
  2705             d->viewItems[i].expanded = true;
       
  2706             d->layout(i);
       
  2707             d->storeExpanded(d->viewItems.at(i).index);
       
  2708         }
       
  2709     }
       
  2710     updateGeometries();
       
  2711     d->viewport->update();
       
  2712 }
       
  2713 
       
  2714 /*!
       
  2715     This function is called whenever \a{column}'s size is changed in
       
  2716     the header. \a oldSize and \a newSize give the previous size and
       
  2717     the new size in pixels.
       
  2718 
       
  2719     \sa setColumnWidth()
       
  2720 */
       
  2721 void QTreeView::columnResized(int column, int /* oldSize */, int /* newSize */)
       
  2722 {
       
  2723     Q_D(QTreeView);
       
  2724     d->columnsToUpdate.append(column);
       
  2725     if (d->columnResizeTimerID == 0)
       
  2726         d->columnResizeTimerID = startTimer(0);
       
  2727 }
       
  2728 
       
  2729 /*!
       
  2730   \reimp
       
  2731 */
       
  2732 void QTreeView::updateGeometries()
       
  2733 {
       
  2734     Q_D(QTreeView);
       
  2735     if (d->header) {
       
  2736         if (d->geometryRecursionBlock)
       
  2737             return;
       
  2738         d->geometryRecursionBlock = true;
       
  2739         QSize hint = d->header->isHidden() ? QSize(0, 0) : d->header->sizeHint();
       
  2740         setViewportMargins(0, hint.height(), 0, 0);
       
  2741         QRect vg = d->viewport->geometry();
       
  2742         QRect geometryRect(vg.left(), vg.top() - hint.height(), vg.width(), hint.height());
       
  2743         d->header->setGeometry(geometryRect);
       
  2744         //d->header->setOffset(horizontalScrollBar()->value()); // ### bug ???
       
  2745         QMetaObject::invokeMethod(d->header, "updateGeometries");
       
  2746         d->updateScrollBars();
       
  2747         d->geometryRecursionBlock = false;
       
  2748     }
       
  2749     QAbstractItemView::updateGeometries();
       
  2750 }
       
  2751 
       
  2752 /*!
       
  2753   Returns the size hint for the \a column's width or -1 if there is no
       
  2754   model.
       
  2755 
       
  2756   If you need to set the width of a given column to a fixed value, call
       
  2757   QHeaderView::resizeSection() on the view's header.
       
  2758 
       
  2759   If you reimplement this function in a subclass, note that the value you
       
  2760   return is only used when resizeColumnToContents() is called. In that case,
       
  2761   if a larger column width is required by either the view's header or
       
  2762   the item delegate, that width will be used instead.
       
  2763 
       
  2764   \sa QWidget::sizeHint, header()
       
  2765 */
       
  2766 int QTreeView::sizeHintForColumn(int column) const
       
  2767 {
       
  2768     Q_D(const QTreeView);
       
  2769     d->executePostedLayout();
       
  2770     if (d->viewItems.isEmpty())
       
  2771         return -1;
       
  2772     ensurePolished();
       
  2773     int w = 0;
       
  2774     QStyleOptionViewItemV4 option = d->viewOptionsV4();
       
  2775     const QVector<QTreeViewItem> viewItems = d->viewItems;
       
  2776 
       
  2777     int start = 0;
       
  2778     int end = viewItems.count();
       
  2779     if(end > 1000) { //if we have too many item this function would be too slow.
       
  2780         //we get a good approximation by only iterate over 1000 items.
       
  2781         start = qMax(0, d->firstVisibleItem() - 100);
       
  2782         end = qMin(end, start + 900);
       
  2783     }
       
  2784 
       
  2785     for (int i = start; i < end; ++i) {
       
  2786         if (viewItems.at(i).spanning)
       
  2787             continue; // we have no good size hint
       
  2788         QModelIndex index = viewItems.at(i).index;
       
  2789         index = index.sibling(index.row(), column);
       
  2790         QWidget *editor = d->editorForIndex(index).editor;
       
  2791         if (editor && d->persistent.contains(editor)) {
       
  2792             w = qMax(w, editor->sizeHint().width());
       
  2793             int min = editor->minimumSize().width();
       
  2794             int max = editor->maximumSize().width();
       
  2795             w = qBound(min, w, max);
       
  2796         }
       
  2797         int hint = d->delegateForIndex(index)->sizeHint(option, index).width();
       
  2798         w = qMax(w, hint + (column == 0 ? d->indentationForItem(i) : 0));
       
  2799     }
       
  2800     return w;
       
  2801 }
       
  2802 
       
  2803 /*!
       
  2804   Returns the size hint for the row indicated by \a index.
       
  2805 
       
  2806   \sa sizeHintForColumn(), uniformRowHeights()
       
  2807 */
       
  2808 int QTreeView::indexRowSizeHint(const QModelIndex &index) const
       
  2809 {
       
  2810     Q_D(const QTreeView);
       
  2811     if (!d->isIndexValid(index) || !d->itemDelegate)
       
  2812         return 0;
       
  2813 
       
  2814     int start = -1;
       
  2815     int end = -1;
       
  2816     int count = d->header->count();
       
  2817     bool emptyHeader = (count == 0);
       
  2818     QModelIndex parent = index.parent();
       
  2819 
       
  2820     if (count && isVisible()) {
       
  2821         // If the sections have moved, we end up checking too many or too few
       
  2822         start = d->header->visualIndexAt(0);
       
  2823     } else {
       
  2824         // If the header has not been laid out yet, we use the model directly
       
  2825         count = d->model->columnCount(parent);
       
  2826     }
       
  2827 
       
  2828     if (isRightToLeft()) {
       
  2829         start = (start == -1 ? count - 1 : start);
       
  2830         end = 0;
       
  2831     } else {
       
  2832         start = (start == -1 ? 0 : start);
       
  2833         end = count - 1;
       
  2834     }
       
  2835 
       
  2836     if (end < start)
       
  2837         qSwap(end, start);
       
  2838 
       
  2839     int height = -1;
       
  2840     QStyleOptionViewItemV4 option = d->viewOptionsV4();
       
  2841     // ### If we want word wrapping in the items,
       
  2842     // ### we need to go through all the columns
       
  2843     // ### and set the width of the column
       
  2844 
       
  2845     // Hack to speed up the function
       
  2846     option.rect.setWidth(-1);
       
  2847 
       
  2848     for (int column = start; column <= end; ++column) {
       
  2849         int logicalColumn = emptyHeader ? column : d->header->logicalIndex(column);
       
  2850         if (d->header->isSectionHidden(logicalColumn))
       
  2851             continue;
       
  2852         QModelIndex idx = d->model->index(index.row(), logicalColumn, parent);
       
  2853         if (idx.isValid()) {
       
  2854             QWidget *editor = d->editorForIndex(idx).editor;
       
  2855             if (editor && d->persistent.contains(editor)) {
       
  2856                 height = qMax(height, editor->sizeHint().height());
       
  2857                 int min = editor->minimumSize().height();
       
  2858                 int max = editor->maximumSize().height();
       
  2859                 height = qBound(min, height, max);
       
  2860             }
       
  2861             int hint = d->delegateForIndex(idx)->sizeHint(option, idx).height();
       
  2862             height = qMax(height, hint);
       
  2863         }
       
  2864     }
       
  2865 
       
  2866     return height;
       
  2867 }
       
  2868 
       
  2869 /*!
       
  2870     \since 4.3
       
  2871     Returns the height of the row indicated by the given \a index.
       
  2872     \sa indexRowSizeHint()
       
  2873 */
       
  2874 int QTreeView::rowHeight(const QModelIndex &index) const
       
  2875 {
       
  2876     Q_D(const QTreeView);
       
  2877     d->executePostedLayout();
       
  2878     int i = d->viewIndex(index);
       
  2879     if (i == -1)
       
  2880         return 0;
       
  2881     return d->itemHeight(i);
       
  2882 }
       
  2883 
       
  2884 /*!
       
  2885   \internal
       
  2886 */
       
  2887 void QTreeView::horizontalScrollbarAction(int action)
       
  2888 {
       
  2889     QAbstractItemView::horizontalScrollbarAction(action);
       
  2890 }
       
  2891 
       
  2892 /*!
       
  2893   \reimp
       
  2894 */
       
  2895 bool QTreeView::isIndexHidden(const QModelIndex &index) const
       
  2896 {
       
  2897     return (isColumnHidden(index.column()) || isRowHidden(index.row(), index.parent()));
       
  2898 }
       
  2899 
       
  2900 /*
       
  2901   private implementation
       
  2902 */
       
  2903 void QTreeViewPrivate::initialize()
       
  2904 {
       
  2905     Q_Q(QTreeView);
       
  2906     updateStyledFrameWidths();
       
  2907     q->setSelectionBehavior(QAbstractItemView::SelectRows);
       
  2908     q->setSelectionMode(QAbstractItemView::SingleSelection);
       
  2909     q->setHorizontalScrollMode(QAbstractItemView::ScrollPerPixel);
       
  2910     q->setAttribute(Qt::WA_MacShowFocusRect);
       
  2911 
       
  2912     QHeaderView *header = new QHeaderView(Qt::Horizontal, q);
       
  2913     header->setMovable(true);
       
  2914     header->setStretchLastSection(true);
       
  2915     header->setDefaultAlignment(Qt::AlignLeft|Qt::AlignVCenter);
       
  2916     q->setHeader(header);
       
  2917 #ifndef QT_NO_ANIMATION
       
  2918     QObject::connect(&animatedOperation, SIGNAL(finished()), q, SLOT(_q_endAnimatedOperation()));
       
  2919 #endif //QT_NO_ANIMATION
       
  2920 }
       
  2921 
       
  2922 void QTreeViewPrivate::expand(int item, bool emitSignal)
       
  2923 {
       
  2924     Q_Q(QTreeView);
       
  2925 
       
  2926     if (item == -1 || viewItems.at(item).expanded)
       
  2927         return;
       
  2928 
       
  2929 #ifndef QT_NO_ANIMATION
       
  2930     if (emitSignal && animationsEnabled)
       
  2931         prepareAnimatedOperation(item, QVariantAnimation::Forward);
       
  2932 #endif //QT_NO_ANIMATION
       
  2933     QAbstractItemView::State oldState = state;
       
  2934     q->setState(QAbstractItemView::ExpandingState);
       
  2935     const QModelIndex index = viewItems.at(item).index;
       
  2936     storeExpanded(index);
       
  2937     viewItems[item].expanded = true;
       
  2938     layout(item);
       
  2939     q->setState(oldState);
       
  2940 
       
  2941     if (model->canFetchMore(index))
       
  2942         model->fetchMore(index);
       
  2943     if (emitSignal) {
       
  2944         emit q->expanded(index);
       
  2945 #ifndef QT_NO_ANIMATION
       
  2946         if (animationsEnabled)
       
  2947             beginAnimatedOperation();
       
  2948 #endif //QT_NO_ANIMATION
       
  2949     }
       
  2950 }
       
  2951 
       
  2952 void QTreeViewPrivate::collapse(int item, bool emitSignal)
       
  2953 {
       
  2954     Q_Q(QTreeView);
       
  2955 
       
  2956     if (item == -1 || expandedIndexes.isEmpty())
       
  2957         return;
       
  2958 
       
  2959     //if the current item is now invisible, the autoscroll will expand the tree to see it, so disable the autoscroll
       
  2960     delayedAutoScroll.stop();
       
  2961 
       
  2962     int total = viewItems.at(item).total;
       
  2963     const QModelIndex &modelIndex = viewItems.at(item).index;
       
  2964     if (!isPersistent(modelIndex))
       
  2965         return; // if the index is not persistent, no chances it is expanded
       
  2966     QSet<QPersistentModelIndex>::iterator it = expandedIndexes.find(modelIndex);
       
  2967     if (it == expandedIndexes.end() || viewItems.at(item).expanded == false)
       
  2968         return; // nothing to do
       
  2969 
       
  2970 #ifndef QT_NO_ANIMATION
       
  2971     if (emitSignal && animationsEnabled)
       
  2972         prepareAnimatedOperation(item, QVariantAnimation::Backward);
       
  2973 #endif //QT_NO_ANIMATION
       
  2974 
       
  2975     QAbstractItemView::State oldState = state;
       
  2976     q->setState(QAbstractItemView::CollapsingState);
       
  2977     expandedIndexes.erase(it);
       
  2978     viewItems[item].expanded = false;
       
  2979     int index = item;
       
  2980     QModelIndex parent = modelIndex;
       
  2981     while (parent.isValid() && parent != root) {
       
  2982         Q_ASSERT(index > -1);
       
  2983         viewItems[index].total -= total;
       
  2984         parent = parent.parent();
       
  2985         index = viewIndex(parent);
       
  2986     }
       
  2987     viewItems.remove(item + 1, total); // collapse
       
  2988     q->setState(oldState);
       
  2989 
       
  2990     if (emitSignal) {
       
  2991         emit q->collapsed(modelIndex);
       
  2992 #ifndef QT_NO_ANIMATION
       
  2993         if (animationsEnabled)
       
  2994             beginAnimatedOperation();
       
  2995 #endif //QT_NO_ANIMATION
       
  2996     }
       
  2997 }
       
  2998 
       
  2999 #ifndef QT_NO_ANIMATION
       
  3000 void QTreeViewPrivate::prepareAnimatedOperation(int item, QVariantAnimation::Direction direction)
       
  3001 {
       
  3002     animatedOperation.item = item;
       
  3003     animatedOperation.viewport = viewport;
       
  3004     animatedOperation.setDirection(direction);
       
  3005 
       
  3006     int top = coordinateForItem(item) + itemHeight(item);
       
  3007     QRect rect = viewport->rect();
       
  3008     rect.setTop(top);
       
  3009     if (direction == QVariantAnimation::Backward) {
       
  3010         const int limit = rect.height() * 2;
       
  3011         int h = 0;
       
  3012         int c = item + viewItems.at(item).total + 1;
       
  3013         for (int i = item + 1; i < c && h < limit; ++i)
       
  3014             h += itemHeight(i);
       
  3015         rect.setHeight(h);
       
  3016         animatedOperation.setEndValue(top + h);
       
  3017     }
       
  3018     animatedOperation.setStartValue(top);
       
  3019     animatedOperation.before = renderTreeToPixmapForAnimation(rect);
       
  3020 }
       
  3021 
       
  3022 void QTreeViewPrivate::beginAnimatedOperation()
       
  3023 {
       
  3024     Q_Q(QTreeView);
       
  3025 
       
  3026     QRect rect = viewport->rect();
       
  3027     rect.setTop(animatedOperation.top());
       
  3028     if (animatedOperation.direction() == QVariantAnimation::Forward) {
       
  3029         const int limit = rect.height() * 2;
       
  3030         int h = 0;
       
  3031         int c = animatedOperation.item + viewItems.at(animatedOperation.item).total + 1;
       
  3032         for (int i = animatedOperation.item + 1; i < c && h < limit; ++i)
       
  3033             h += itemHeight(i);
       
  3034         rect.setHeight(h);
       
  3035         animatedOperation.setEndValue(animatedOperation.top() + h);
       
  3036     }
       
  3037 
       
  3038     if (!rect.isEmpty()) {
       
  3039         animatedOperation.after = renderTreeToPixmapForAnimation(rect);
       
  3040 
       
  3041         q->setState(QAbstractItemView::AnimatingState);
       
  3042         animatedOperation.start(); //let's start the animation
       
  3043     }
       
  3044 }
       
  3045 
       
  3046 void QTreeViewPrivate::drawAnimatedOperation(QPainter *painter) const
       
  3047 {
       
  3048     const int start = animatedOperation.startValue().toInt(),
       
  3049         end = animatedOperation.endValue().toInt(),
       
  3050         current = animatedOperation.currentValue().toInt();
       
  3051     bool collapsing = animatedOperation.direction() == QVariantAnimation::Backward;
       
  3052     const QPixmap top = collapsing ? animatedOperation.before : animatedOperation.after;
       
  3053     painter->drawPixmap(0, start, top, 0, end - current - 1, top.width(), top.height());
       
  3054     const QPixmap bottom = collapsing ? animatedOperation.after : animatedOperation.before;
       
  3055     painter->drawPixmap(0, current, bottom);
       
  3056 }
       
  3057 
       
  3058 QPixmap QTreeViewPrivate::renderTreeToPixmapForAnimation(const QRect &rect) const
       
  3059 {
       
  3060     Q_Q(const QTreeView);
       
  3061     QPixmap pixmap(rect.size());
       
  3062     if (rect.size().isEmpty())
       
  3063         return pixmap;
       
  3064     pixmap.fill(Qt::transparent); //the base might not be opaque, and we don't want uninitialized pixels.
       
  3065     QPainter painter(&pixmap);
       
  3066     painter.fillRect(QRect(QPoint(0,0), rect.size()), q->palette().base());
       
  3067     painter.translate(0, -rect.top());
       
  3068     q->drawTree(&painter, QRegion(rect));
       
  3069     painter.end();
       
  3070 
       
  3071     //and now let's render the editors the editors
       
  3072     QStyleOptionViewItemV4 option = viewOptionsV4();
       
  3073     for (QList<QEditorInfo>::const_iterator it = editors.constBegin(); it != editors.constEnd(); ++it) {
       
  3074         QWidget *editor = it->editor;
       
  3075         QModelIndex index = it->index;
       
  3076         option.rect = q->visualRect(index);
       
  3077         if (option.rect.isValid()) {
       
  3078 
       
  3079             if (QAbstractItemDelegate *delegate = delegateForIndex(index))
       
  3080                 delegate->updateEditorGeometry(editor, option, index);
       
  3081 
       
  3082             const QPoint pos = editor->pos();
       
  3083             if (rect.contains(pos)) {
       
  3084                 editor->render(&pixmap, pos - rect.topLeft());
       
  3085                 //the animation uses pixmap to display the treeview's content
       
  3086                 //the editor is rendered on this pixmap and thus can (should) be hidden
       
  3087                 editor->hide();
       
  3088             }
       
  3089         }
       
  3090     }
       
  3091 
       
  3092 
       
  3093     return pixmap;
       
  3094 }
       
  3095 
       
  3096 void QTreeViewPrivate::_q_endAnimatedOperation()
       
  3097 {
       
  3098     Q_Q(QTreeView);
       
  3099     q->setState(QAbstractItemView::NoState);
       
  3100     q->updateGeometries();
       
  3101     viewport->update();
       
  3102 }
       
  3103 #endif //QT_NO_ANIMATION
       
  3104 
       
  3105 void QTreeViewPrivate::_q_modelAboutToBeReset()
       
  3106 {
       
  3107     viewItems.clear();
       
  3108 }
       
  3109 
       
  3110 void QTreeViewPrivate::_q_columnsAboutToBeRemoved(const QModelIndex &parent, int start, int end)
       
  3111 {
       
  3112     if (start <= 0 && 0 <= end)
       
  3113         viewItems.clear();
       
  3114     QAbstractItemViewPrivate::_q_columnsAboutToBeRemoved(parent, start, end);
       
  3115 }
       
  3116 
       
  3117 void QTreeViewPrivate::_q_columnsRemoved(const QModelIndex &parent, int start, int end)
       
  3118 {
       
  3119     if (start <= 0 && 0 <= end)
       
  3120         doDelayedItemsLayout();
       
  3121     QAbstractItemViewPrivate::_q_columnsRemoved(parent, start, end);
       
  3122 }
       
  3123 
       
  3124 void QTreeViewPrivate::layout(int i)
       
  3125 {
       
  3126     Q_Q(QTreeView);
       
  3127     QModelIndex current;
       
  3128     QModelIndex parent = (i < 0) ? (QModelIndex)root : modelIndex(i);
       
  3129 
       
  3130     if (i>=0 && !parent.isValid()) {
       
  3131         //modelIndex() should never return something invalid for the real items.
       
  3132         //This can happen if columncount has been set to 0.
       
  3133         //To avoid infinite loop we stop here.
       
  3134         return;
       
  3135     }
       
  3136 
       
  3137     int count = 0;
       
  3138     if (model->hasChildren(parent)) {
       
  3139         if (model->canFetchMore(parent))
       
  3140             model->fetchMore(parent);
       
  3141         count = model->rowCount(parent);
       
  3142     }
       
  3143 
       
  3144     bool expanding = true;
       
  3145     if (i == -1) {
       
  3146         if (uniformRowHeights) {
       
  3147             QModelIndex index = model->index(0, 0, parent);
       
  3148             defaultItemHeight = q->indexRowSizeHint(index);
       
  3149         }
       
  3150         viewItems.resize(count);
       
  3151     } else if (viewItems[i].total != (uint)count) {
       
  3152             viewItems.insert(i + 1, count, QTreeViewItem()); // expand
       
  3153     } else {
       
  3154         expanding = false;
       
  3155     }
       
  3156 
       
  3157     int first = i + 1;
       
  3158     int level = (i >= 0 ? viewItems.at(i).level + 1 : 0);
       
  3159     int hidden = 0;
       
  3160     int last = 0;
       
  3161     int children = 0;
       
  3162     QTreeViewItem *item = 0;
       
  3163     for (int j = first; j < first + count; ++j) {
       
  3164         current = model->index(j - first, 0, parent);
       
  3165         if (isRowHidden(current)) {
       
  3166             ++hidden;
       
  3167             last = j - hidden + children;
       
  3168         } else {
       
  3169             last = j - hidden + children;
       
  3170             if (item)
       
  3171                 item->hasMoreSiblings = true;
       
  3172             item = &viewItems[last];
       
  3173             item->index = current;
       
  3174             item->level = level;
       
  3175             item->height = 0;
       
  3176             item->spanning = q->isFirstColumnSpanned(current.row(), parent);
       
  3177             item->expanded = false;
       
  3178             item->total = 0;
       
  3179             item->hasMoreSiblings = false;
       
  3180             if (isIndexExpanded(current)) {
       
  3181                 item->expanded = true;
       
  3182                 layout(last);
       
  3183                 item = &viewItems[last];
       
  3184                 children += item->total;
       
  3185                 item->hasChildren = item->total > 0;
       
  3186                 last = j - hidden + children;
       
  3187             } else {
       
  3188                 item->hasChildren = hasVisibleChildren(current);
       
  3189             }
       
  3190         }
       
  3191     }
       
  3192 
       
  3193     // remove hidden items
       
  3194     if (hidden > 0)
       
  3195         viewItems.remove(last + 1, hidden); // collapse
       
  3196 
       
  3197     if (!expanding)
       
  3198         return; // nothing changed
       
  3199 
       
  3200     while (parent != root) {
       
  3201         Q_ASSERT(i > -1);
       
  3202         viewItems[i].total += count - hidden;
       
  3203         parent = parent.parent();
       
  3204         i = viewIndex(parent);
       
  3205     }
       
  3206 }
       
  3207 
       
  3208 int QTreeViewPrivate::pageUp(int i) const
       
  3209 {
       
  3210     int index = itemAtCoordinate(coordinateForItem(i) - viewport->height());
       
  3211     return index == -1 ? 0 : index;
       
  3212 }
       
  3213 
       
  3214 int QTreeViewPrivate::pageDown(int i) const
       
  3215 {
       
  3216     int index = itemAtCoordinate(coordinateForItem(i) + viewport->height());
       
  3217     return index == -1 ? viewItems.count() - 1 : index;
       
  3218 }
       
  3219 
       
  3220 int QTreeViewPrivate::indentationForItem(int item) const
       
  3221 {
       
  3222     if (item < 0 || item >= viewItems.count())
       
  3223         return 0;
       
  3224     int level = viewItems.at(item).level;
       
  3225     if (rootDecoration)
       
  3226         ++level;
       
  3227     return level * indent;
       
  3228 }
       
  3229 
       
  3230 int QTreeViewPrivate::itemHeight(int item) const
       
  3231 {
       
  3232     if (uniformRowHeights)
       
  3233         return defaultItemHeight;
       
  3234     if (viewItems.isEmpty())
       
  3235         return 0;
       
  3236     const QModelIndex &index = viewItems.at(item).index;
       
  3237     int height = viewItems.at(item).height;
       
  3238     if (height <= 0 && index.isValid()) {
       
  3239         height = q_func()->indexRowSizeHint(index);
       
  3240         viewItems[item].height = height;
       
  3241     }
       
  3242     if (!index.isValid() || height < 0)
       
  3243         return 0;
       
  3244     return height;
       
  3245 }
       
  3246 
       
  3247 
       
  3248 /*!
       
  3249   \internal
       
  3250   Returns the viewport y coordinate for \a item.
       
  3251 */
       
  3252 int QTreeViewPrivate::coordinateForItem(int item) const
       
  3253 {
       
  3254     if (verticalScrollMode == QAbstractItemView::ScrollPerPixel) {
       
  3255         if (uniformRowHeights)
       
  3256             return (item * defaultItemHeight) - vbar->value();
       
  3257         // ### optimize (spans or caching)
       
  3258         int y = 0;
       
  3259         for (int i = 0; i < viewItems.count(); ++i) {
       
  3260             if (i == item)
       
  3261                 return y - vbar->value();
       
  3262             y += itemHeight(i);
       
  3263         }
       
  3264     } else { // ScrollPerItem
       
  3265         int topViewItemIndex = vbar->value();
       
  3266         if (uniformRowHeights)
       
  3267             return defaultItemHeight * (item - topViewItemIndex);
       
  3268         if (item >= topViewItemIndex) {
       
  3269             // search in the visible area first and continue down
       
  3270             // ### slow if the item is not visible
       
  3271             int viewItemCoordinate = 0;
       
  3272             int viewItemIndex = topViewItemIndex;
       
  3273             while (viewItemIndex < viewItems.count()) {
       
  3274                 if (viewItemIndex == item)
       
  3275                     return viewItemCoordinate;
       
  3276                 viewItemCoordinate += itemHeight(viewItemIndex);
       
  3277                 ++viewItemIndex;
       
  3278             }
       
  3279             // below the last item in the view
       
  3280             Q_ASSERT(false);
       
  3281             return viewItemCoordinate;
       
  3282         } else {
       
  3283             // search the area above the viewport (used for editor widgets)
       
  3284             int viewItemCoordinate = 0;
       
  3285             for (int viewItemIndex = topViewItemIndex; viewItemIndex > 0; --viewItemIndex) {
       
  3286                 if (viewItemIndex == item)
       
  3287                     return viewItemCoordinate;
       
  3288                 viewItemCoordinate -= itemHeight(viewItemIndex - 1);
       
  3289             }
       
  3290             return viewItemCoordinate;
       
  3291         }
       
  3292     }
       
  3293     return 0;
       
  3294 }
       
  3295 
       
  3296 /*!
       
  3297   \internal
       
  3298   Returns the index of the view item at the
       
  3299   given viewport \a coordinate.
       
  3300 
       
  3301   \sa modelIndex()
       
  3302 */
       
  3303 int QTreeViewPrivate::itemAtCoordinate(int coordinate) const
       
  3304 {
       
  3305     const int itemCount = viewItems.count();
       
  3306     if (itemCount == 0)
       
  3307         return -1;
       
  3308     if (uniformRowHeights && defaultItemHeight <= 0)
       
  3309         return -1;
       
  3310     if (verticalScrollMode == QAbstractItemView::ScrollPerPixel) {
       
  3311         if (uniformRowHeights) {
       
  3312             const int viewItemIndex = (coordinate + vbar->value()) / defaultItemHeight;
       
  3313             return ((viewItemIndex >= itemCount || viewItemIndex < 0) ? -1 : viewItemIndex);
       
  3314         }
       
  3315         // ### optimize
       
  3316         int viewItemCoordinate = 0;
       
  3317         const int contentsCoordinate = coordinate + vbar->value();
       
  3318         for (int viewItemIndex = 0; viewItemIndex < viewItems.count(); ++viewItemIndex) {
       
  3319             viewItemCoordinate += itemHeight(viewItemIndex);
       
  3320             if (viewItemCoordinate >= contentsCoordinate)
       
  3321                 return (viewItemIndex >= itemCount ? -1 : viewItemIndex);
       
  3322         }
       
  3323     } else { // ScrollPerItem
       
  3324         int topViewItemIndex = vbar->value();
       
  3325         if (uniformRowHeights) {
       
  3326             if (coordinate < 0)
       
  3327                 coordinate -= defaultItemHeight - 1;
       
  3328             const int viewItemIndex = topViewItemIndex + (coordinate / defaultItemHeight);
       
  3329             return ((viewItemIndex >= itemCount || viewItemIndex < 0) ? -1 : viewItemIndex);
       
  3330         }
       
  3331         if (coordinate >= 0) {
       
  3332             // the coordinate is in or below the viewport
       
  3333             int viewItemCoordinate = 0;
       
  3334             for (int viewItemIndex = topViewItemIndex; viewItemIndex < viewItems.count(); ++viewItemIndex) {
       
  3335                 viewItemCoordinate += itemHeight(viewItemIndex);
       
  3336                 if (viewItemCoordinate > coordinate)
       
  3337                     return (viewItemIndex >= itemCount ? -1 : viewItemIndex);
       
  3338             }
       
  3339         } else {
       
  3340             // the coordinate is above the viewport
       
  3341             int viewItemCoordinate = 0;
       
  3342             for (int viewItemIndex = topViewItemIndex; viewItemIndex >= 0; --viewItemIndex) {
       
  3343                 if (viewItemCoordinate <= coordinate)
       
  3344                     return (viewItemIndex >= itemCount ? -1 : viewItemIndex);
       
  3345                 viewItemCoordinate -= itemHeight(viewItemIndex);
       
  3346             }
       
  3347         }
       
  3348     }
       
  3349     return -1;
       
  3350 }
       
  3351 
       
  3352 int QTreeViewPrivate::viewIndex(const QModelIndex &_index) const
       
  3353 {
       
  3354     if (!_index.isValid() || viewItems.isEmpty())
       
  3355         return -1;
       
  3356 
       
  3357     const int totalCount = viewItems.count();
       
  3358     const QModelIndex index = _index.sibling(_index.row(), 0);
       
  3359 
       
  3360 
       
  3361     // A quick check near the last item to see if we are just incrementing
       
  3362     const int start = lastViewedItem > 2 ? lastViewedItem - 2 : 0;
       
  3363     const int end = lastViewedItem < totalCount - 2 ? lastViewedItem + 2 : totalCount;
       
  3364     int row = index.row();
       
  3365     for (int i = start; i < end; ++i) {
       
  3366         const QModelIndex &idx = viewItems.at(i).index;
       
  3367         if (idx.row() == row) {
       
  3368             if (idx.internalId() == index.internalId()) {
       
  3369                 lastViewedItem = i;
       
  3370                 return i;
       
  3371             }
       
  3372         }
       
  3373     }
       
  3374 
       
  3375     // NOTE: this function is slow if the item is outside the visible area
       
  3376     // search in visible items first and below
       
  3377     int t = firstVisibleItem();
       
  3378     t = t > 100 ? t - 100 : 0; // start 100 items above the visible area
       
  3379 
       
  3380     for (int i = t; i < totalCount; ++i) {
       
  3381         const QModelIndex &idx = viewItems.at(i).index;
       
  3382         if (idx.row() == row) {
       
  3383             if (idx.internalId() == index.internalId()) {
       
  3384                 lastViewedItem = i;
       
  3385                 return i;
       
  3386             }
       
  3387         }
       
  3388     }
       
  3389     // search from top to first visible
       
  3390     for (int j = 0; j < t; ++j) {
       
  3391         const QModelIndex &idx = viewItems.at(j).index;
       
  3392         if (idx.row() == row) {
       
  3393             if (idx.internalId() == index.internalId()) {
       
  3394                 lastViewedItem = j;
       
  3395                 return j;
       
  3396             }
       
  3397         }
       
  3398     }
       
  3399     // nothing found
       
  3400     return -1;
       
  3401 }
       
  3402 
       
  3403 QModelIndex QTreeViewPrivate::modelIndex(int i, int column) const
       
  3404 {
       
  3405     if (i < 0 || i >= viewItems.count())
       
  3406         return QModelIndex();
       
  3407 
       
  3408     QModelIndex ret = viewItems.at(i).index;
       
  3409     if (column)
       
  3410         ret = ret.sibling(ret.row(), column);
       
  3411     return ret;
       
  3412 }
       
  3413 
       
  3414 int QTreeViewPrivate::firstVisibleItem(int *offset) const
       
  3415 {
       
  3416     const int value = vbar->value();
       
  3417     if (verticalScrollMode == QAbstractItemView::ScrollPerItem) {
       
  3418         if (offset)
       
  3419             *offset = 0;
       
  3420         return (value < 0 || value >= viewItems.count()) ? -1 : value;
       
  3421     }
       
  3422     // ScrollMode == ScrollPerPixel
       
  3423     if (uniformRowHeights) {
       
  3424         if (!defaultItemHeight)
       
  3425             return -1;
       
  3426 
       
  3427         if (offset)
       
  3428             *offset = -(value % defaultItemHeight);
       
  3429         return value / defaultItemHeight;
       
  3430     }
       
  3431     int y = 0; // ### optimize (use spans ?)
       
  3432     for (int i = 0; i < viewItems.count(); ++i) {
       
  3433         y += itemHeight(i); // the height value is cached
       
  3434         if (y > value) {
       
  3435             if (offset)
       
  3436                 *offset = y - value - itemHeight(i);
       
  3437             return i;
       
  3438         }
       
  3439     }
       
  3440     return -1;
       
  3441 }
       
  3442 
       
  3443 int QTreeViewPrivate::columnAt(int x) const
       
  3444 {
       
  3445     return header->logicalIndexAt(x);
       
  3446 }
       
  3447 
       
  3448 void QTreeViewPrivate::relayout(const QModelIndex &parent)
       
  3449 {
       
  3450     Q_Q(QTreeView);
       
  3451     // do a local relayout of the items
       
  3452     if (parent.isValid()) {
       
  3453         int parentViewIndex = viewIndex(parent);
       
  3454         if (parentViewIndex > -1 && viewItems.at(parentViewIndex).expanded) {
       
  3455             collapse(parentViewIndex, false); // remove the current layout
       
  3456             expand(parentViewIndex, false); // do the relayout
       
  3457             q->updateGeometries();
       
  3458             viewport->update();
       
  3459         }
       
  3460     } else {
       
  3461         viewItems.clear();
       
  3462         q->doItemsLayout();
       
  3463     }
       
  3464 }
       
  3465 
       
  3466 
       
  3467 void QTreeViewPrivate::updateScrollBars()
       
  3468 {
       
  3469     Q_Q(QTreeView);
       
  3470     QSize viewportSize = viewport->size();
       
  3471     if (!viewportSize.isValid())
       
  3472         viewportSize = QSize(0, 0);
       
  3473 
       
  3474     int itemsInViewport = 0;
       
  3475     if (uniformRowHeights) {
       
  3476         if (defaultItemHeight <= 0)
       
  3477             itemsInViewport = viewItems.count();
       
  3478         else
       
  3479             itemsInViewport = viewportSize.height() / defaultItemHeight;
       
  3480     } else {
       
  3481         const int itemsCount = viewItems.count();
       
  3482         const int viewportHeight = viewportSize.height();
       
  3483         for (int height = 0, item = itemsCount - 1; item >= 0; --item) {
       
  3484             height += itemHeight(item);
       
  3485             if (height > viewportHeight)
       
  3486                 break;
       
  3487             ++itemsInViewport;
       
  3488         }
       
  3489     }
       
  3490     if (verticalScrollMode == QAbstractItemView::ScrollPerItem) {
       
  3491         if (!viewItems.isEmpty())
       
  3492             itemsInViewport = qMax(1, itemsInViewport);
       
  3493         vbar->setRange(0, viewItems.count() - itemsInViewport);
       
  3494         vbar->setPageStep(itemsInViewport);
       
  3495         vbar->setSingleStep(1);
       
  3496     } else { // scroll per pixel
       
  3497         int contentsHeight = 0;
       
  3498         if (uniformRowHeights) {
       
  3499             contentsHeight = defaultItemHeight * viewItems.count();
       
  3500         } else { // ### optimize (spans or caching)
       
  3501             for (int i = 0; i < viewItems.count(); ++i)
       
  3502                 contentsHeight += itemHeight(i);
       
  3503         }
       
  3504         vbar->setRange(0, contentsHeight - viewportSize.height());
       
  3505         vbar->setPageStep(viewportSize.height());
       
  3506         vbar->setSingleStep(qMax(viewportSize.height() / (itemsInViewport + 1), 2));
       
  3507     }
       
  3508 
       
  3509     const int columnCount = header->count();
       
  3510     const int viewportWidth = viewportSize.width();
       
  3511     int columnsInViewport = 0;
       
  3512     for (int width = 0, column = columnCount - 1; column >= 0; --column) {
       
  3513         int logical = header->logicalIndex(column);
       
  3514         width += header->sectionSize(logical);
       
  3515         if (width > viewportWidth)
       
  3516             break;
       
  3517         ++columnsInViewport;
       
  3518     }
       
  3519     if (columnCount > 0)
       
  3520         columnsInViewport = qMax(1, columnsInViewport);
       
  3521     if (horizontalScrollMode == QAbstractItemView::ScrollPerItem) {
       
  3522         hbar->setRange(0, columnCount - columnsInViewport);
       
  3523         hbar->setPageStep(columnsInViewport);
       
  3524         hbar->setSingleStep(1);
       
  3525     } else { // scroll per pixel
       
  3526         const int horizontalLength = header->length();
       
  3527         const QSize maxSize = q->maximumViewportSize();
       
  3528         if (maxSize.width() >= horizontalLength && vbar->maximum() <= 0)
       
  3529             viewportSize = maxSize;
       
  3530         hbar->setPageStep(viewportSize.width());
       
  3531         hbar->setRange(0, qMax(horizontalLength - viewportSize.width(), 0));
       
  3532         hbar->setSingleStep(qMax(viewportSize.width() / (columnsInViewport + 1), 2));
       
  3533     }
       
  3534 }
       
  3535 
       
  3536 int QTreeViewPrivate::itemDecorationAt(const QPoint &pos) const
       
  3537 {
       
  3538     executePostedLayout();
       
  3539     int x = pos.x();
       
  3540     int column = header->logicalIndexAt(x);
       
  3541     if (column != 0)
       
  3542         return -1; // no logical index at x
       
  3543 
       
  3544     int viewItemIndex = itemAtCoordinate(pos.y());
       
  3545     QRect returning = itemDecorationRect(modelIndex(viewItemIndex));
       
  3546     if (!returning.contains(pos))
       
  3547         return -1;
       
  3548 
       
  3549     return viewItemIndex;
       
  3550 }
       
  3551 
       
  3552 QRect QTreeViewPrivate::itemDecorationRect(const QModelIndex &index) const
       
  3553 {
       
  3554     Q_Q(const QTreeView);
       
  3555     if (!rootDecoration && index.parent() == root)
       
  3556         return QRect(); // no decoration at root
       
  3557 
       
  3558     int viewItemIndex = viewIndex(index);
       
  3559     if (viewItemIndex < 0 || !hasVisibleChildren(viewItems.at(viewItemIndex).index))
       
  3560         return QRect();
       
  3561 
       
  3562     int itemIndentation = indentationForItem(viewItemIndex);
       
  3563     int position = header->sectionViewportPosition(0);
       
  3564     int size = header->sectionSize(0);
       
  3565 
       
  3566     QRect rect;
       
  3567     if (q->isRightToLeft())
       
  3568         rect = QRect(position + size - itemIndentation, coordinateForItem(viewItemIndex),
       
  3569                      indent, itemHeight(viewItemIndex));
       
  3570     else
       
  3571         rect = QRect(position + itemIndentation - indent, coordinateForItem(viewItemIndex),
       
  3572                      indent, itemHeight(viewItemIndex));
       
  3573     QStyleOption opt;
       
  3574     opt.initFrom(q);
       
  3575     opt.rect = rect;
       
  3576     return q->style()->subElementRect(QStyle::SE_TreeViewDisclosureItem, &opt, q);
       
  3577 }
       
  3578 
       
  3579 QList<QPair<int, int> > QTreeViewPrivate::columnRanges(const QModelIndex &topIndex,
       
  3580                                                           const QModelIndex &bottomIndex) const
       
  3581 {
       
  3582     const int topVisual = header->visualIndex(topIndex.column()),
       
  3583         bottomVisual = header->visualIndex(bottomIndex.column());
       
  3584 
       
  3585     const int start = qMin(topVisual, bottomVisual);
       
  3586     const int end = qMax(topVisual, bottomVisual);
       
  3587 
       
  3588     QList<int> logicalIndexes;
       
  3589 
       
  3590     //we iterate over the visual indexes to get the logical indexes
       
  3591     for (int c = start; c <= end; c++) {
       
  3592         const int logical = header->logicalIndex(c);
       
  3593         if (!header->isSectionHidden(logical)) {
       
  3594             logicalIndexes << logical;
       
  3595         }
       
  3596     }
       
  3597     //let's sort the list
       
  3598     qSort(logicalIndexes.begin(), logicalIndexes.end());
       
  3599 
       
  3600     QList<QPair<int, int> > ret;
       
  3601     QPair<int, int> current;
       
  3602     current.first = -2; // -1 is not enough because -1+1 = 0
       
  3603     current.second = -2;
       
  3604     for(int i = 0; i < logicalIndexes.count(); ++i) {
       
  3605         const int logicalColumn = logicalIndexes.at(i);
       
  3606         if (current.second + 1 != logicalColumn) {
       
  3607             if (current.first != -2) {
       
  3608                 //let's save the current one
       
  3609                 ret += current;
       
  3610             }
       
  3611             //let's start a new one
       
  3612             current.first = current.second = logicalColumn;
       
  3613         } else {
       
  3614             current.second++;
       
  3615         }
       
  3616     }
       
  3617 
       
  3618     //let's get the last range
       
  3619     if (current.first != -2) {
       
  3620         ret += current;
       
  3621     }
       
  3622 
       
  3623     return ret;
       
  3624 }
       
  3625 
       
  3626 void QTreeViewPrivate::select(const QModelIndex &topIndex, const QModelIndex &bottomIndex,
       
  3627                               QItemSelectionModel::SelectionFlags command)
       
  3628 {
       
  3629     Q_Q(QTreeView);
       
  3630     QItemSelection selection;
       
  3631     const int top = viewIndex(topIndex),
       
  3632         bottom = viewIndex(bottomIndex);
       
  3633 
       
  3634     const QList< QPair<int, int> > colRanges = columnRanges(topIndex, bottomIndex);
       
  3635     QList< QPair<int, int> >::const_iterator it;
       
  3636     for (it = colRanges.begin(); it != colRanges.end(); ++it) {
       
  3637         const int left = (*it).first,
       
  3638             right = (*it).second;
       
  3639 
       
  3640         QModelIndex previous;
       
  3641         QItemSelectionRange currentRange;
       
  3642         QStack<QItemSelectionRange> rangeStack;
       
  3643         for (int i = top; i <= bottom; ++i) {
       
  3644             QModelIndex index = modelIndex(i);
       
  3645             QModelIndex parent = index.parent();
       
  3646             QModelIndex previousParent = previous.parent();
       
  3647             if (previous.isValid() && parent == previousParent) {
       
  3648                 // same parent
       
  3649                 if (qAbs(previous.row() - index.row()) > 1) {
       
  3650                     //a hole (hidden index inside a range) has been detected
       
  3651                     if (currentRange.isValid()) {
       
  3652                         selection.append(currentRange);
       
  3653                     }
       
  3654                     //let's start a new range
       
  3655                     currentRange = QItemSelectionRange(index.sibling(index.row(), left), index.sibling(index.row(), right));
       
  3656                 } else {
       
  3657                     QModelIndex tl = model->index(currentRange.top(), currentRange.left(),
       
  3658                         currentRange.parent());
       
  3659                     currentRange = QItemSelectionRange(tl, index.sibling(index.row(), right));
       
  3660                 }
       
  3661             } else if (previous.isValid() && parent == model->index(previous.row(), 0, previousParent)) {
       
  3662                 // item is child of previous
       
  3663                 rangeStack.push(currentRange);
       
  3664                 currentRange = QItemSelectionRange(index.sibling(index.row(), left), index.sibling(index.row(), right));
       
  3665             } else {
       
  3666                 if (currentRange.isValid())
       
  3667                     selection.append(currentRange);
       
  3668                 if (rangeStack.isEmpty()) {
       
  3669                     currentRange = QItemSelectionRange(index.sibling(index.row(), left), index.sibling(index.row(), right));
       
  3670                 } else {
       
  3671                     currentRange = rangeStack.pop();
       
  3672                     index = currentRange.bottomRight(); //let's resume the range
       
  3673                     --i; //we process again the current item
       
  3674                 }
       
  3675             }
       
  3676             previous = index;
       
  3677         }
       
  3678         if (currentRange.isValid())
       
  3679             selection.append(currentRange);
       
  3680         for (int i = 0; i < rangeStack.count(); ++i)
       
  3681             selection.append(rangeStack.at(i));
       
  3682     }
       
  3683     q->selectionModel()->select(selection, command);
       
  3684 }
       
  3685 
       
  3686 QPair<int,int> QTreeViewPrivate::startAndEndColumns(const QRect &rect) const
       
  3687 {
       
  3688     Q_Q(const QTreeView);
       
  3689     int start = header->visualIndexAt(rect.left());
       
  3690     int end = header->visualIndexAt(rect.right());
       
  3691     if (q->isRightToLeft()) {
       
  3692         start = (start == -1 ? header->count() - 1 : start);
       
  3693         end = (end == -1 ? 0 : end);
       
  3694     } else {
       
  3695         start = (start == -1 ? 0 : start);
       
  3696         end = (end == -1 ? header->count() - 1 : end);
       
  3697     }
       
  3698     return qMakePair<int,int>(qMin(start, end), qMax(start, end));
       
  3699 }
       
  3700 
       
  3701 bool QTreeViewPrivate::hasVisibleChildren(const QModelIndex& parent) const
       
  3702 {
       
  3703     Q_Q(const QTreeView);
       
  3704     if (model->hasChildren(parent)) {
       
  3705         if (hiddenIndexes.isEmpty())
       
  3706             return true;
       
  3707         if (q->isIndexHidden(parent))
       
  3708             return false;
       
  3709         int rowCount = model->rowCount(parent);
       
  3710         for (int i = 0; i < rowCount; ++i) {
       
  3711             if (!q->isRowHidden(i, parent))
       
  3712                 return true;
       
  3713         }
       
  3714         if (rowCount == 0)
       
  3715             return true;
       
  3716     }
       
  3717     return false;
       
  3718 }
       
  3719 
       
  3720 void QTreeViewPrivate::rowsRemoved(const QModelIndex &parent,
       
  3721                                    int start, int end, bool after)
       
  3722 {
       
  3723     Q_Q(QTreeView);
       
  3724     // if we are going to do a complete relayout anyway, there is no need to update
       
  3725     if (delayedPendingLayout) {
       
  3726         _q_rowsRemoved(parent, start, end);
       
  3727         return;
       
  3728     }
       
  3729 
       
  3730     const int parentItem = viewIndex(parent);
       
  3731     if ((parentItem != -1) || (parent == root)) {
       
  3732 
       
  3733         const uint childLevel = (parentItem == -1)
       
  3734                                 ? uint(0) : viewItems.at(parentItem).level + 1;
       
  3735         Q_UNUSED(childLevel); // unused in release mode, used in assert below
       
  3736 
       
  3737         const int firstChildItem = parentItem + 1;
       
  3738         int lastChildItem = firstChildItem + ((parentItem == -1)
       
  3739                                               ? viewItems.count()
       
  3740                                               : viewItems.at(parentItem).total) - 1;
       
  3741 
       
  3742         const int delta = end - start + 1;
       
  3743 
       
  3744         int previousSibiling = -1;
       
  3745         int removedCount = 0;
       
  3746         for (int item = firstChildItem; item <= lastChildItem; ) {
       
  3747             Q_ASSERT(viewItems.at(item).level == childLevel);
       
  3748             const QModelIndex modelIndex = viewItems.at(item).index;
       
  3749             //Q_ASSERT(modelIndex.parent() == parent);
       
  3750             const int count = viewItems.at(item).total + 1;
       
  3751             if (modelIndex.row() < start) {
       
  3752                 previousSibiling = item;
       
  3753                 // not affected by the removal
       
  3754                 item += count;
       
  3755             } else if (modelIndex.row() <= end) {
       
  3756                 // removed
       
  3757                 viewItems.remove(item, count);
       
  3758                 removedCount += count;
       
  3759                 lastChildItem -= count;
       
  3760             } else {
       
  3761                 if (after) {
       
  3762                     // moved; update the model index
       
  3763                     viewItems[item].index = model->index(
       
  3764                         modelIndex.row() - delta, modelIndex.column(), parent);
       
  3765                 }
       
  3766                 item += count;
       
  3767             }
       
  3768         }
       
  3769 
       
  3770         if (previousSibiling != -1 && after && model->rowCount(parent) == start)
       
  3771             viewItems[previousSibiling].hasMoreSiblings = false;
       
  3772 
       
  3773         if (parentItem != -1) {
       
  3774             if (viewItems.at(parentItem).expanded) {
       
  3775                 updateChildCount(parentItem, -removedCount);
       
  3776                 if (viewItems.at(parentItem).total == 0)
       
  3777                     viewItems[parentItem].hasChildren = false; //every children have been removed;
       
  3778             } else if (viewItems[parentItem].hasChildren && !hasVisibleChildren(parent)) {
       
  3779                 viewItems[parentItem].hasChildren = false;
       
  3780             }
       
  3781         }
       
  3782         if (after) {
       
  3783             q->updateGeometries();
       
  3784             viewport->update();
       
  3785         } else {
       
  3786             //we have removed items: we should at least update the scroll bar values.
       
  3787             // They are used to determine the item geometry.
       
  3788             updateScrollBars();
       
  3789         }
       
  3790     } else {
       
  3791         // If an ancestor of root is removed then relayout
       
  3792         QModelIndex idx = root;
       
  3793         while (idx.isValid()) {
       
  3794             idx = idx.parent();
       
  3795             if (idx == parent) {
       
  3796                 doDelayedItemsLayout();
       
  3797                 break;
       
  3798             }
       
  3799         }
       
  3800     }
       
  3801     _q_rowsRemoved(parent, start, end);
       
  3802 
       
  3803     QSet<QPersistentModelIndex>::iterator it = expandedIndexes.begin();
       
  3804     while (it != expandedIndexes.constEnd()) {
       
  3805         if (!it->isValid())
       
  3806             it = expandedIndexes.erase(it);
       
  3807         else
       
  3808             ++it;
       
  3809     }
       
  3810     it = hiddenIndexes.begin();
       
  3811     while (it != hiddenIndexes.constEnd()) {
       
  3812         if (!it->isValid())
       
  3813             it = hiddenIndexes.erase(it);
       
  3814         else
       
  3815             ++it;
       
  3816     }
       
  3817 }
       
  3818 
       
  3819 void QTreeViewPrivate::updateChildCount(const int parentItem, const int delta)
       
  3820 {
       
  3821     if ((parentItem != -1) && delta) {
       
  3822         int level = viewItems.at(parentItem).level;
       
  3823         int item = parentItem;
       
  3824         do {
       
  3825             Q_ASSERT(item >= 0);
       
  3826             for ( ; int(viewItems.at(item).level) != level; --item) ;
       
  3827             viewItems[item].total += delta;
       
  3828             --level;
       
  3829         } while (level >= 0);
       
  3830     }
       
  3831 }
       
  3832 
       
  3833 
       
  3834 void QTreeViewPrivate::_q_sortIndicatorChanged(int column, Qt::SortOrder order)
       
  3835 {
       
  3836     model->sort(column, order);
       
  3837 }
       
  3838 
       
  3839 /*!
       
  3840   \reimp
       
  3841  */
       
  3842 void QTreeView::currentChanged(const QModelIndex &current, const QModelIndex &previous)
       
  3843 {
       
  3844 #ifndef QT_NO_ACCESSIBILITY
       
  3845     if (QAccessible::isActive()) {
       
  3846         int entry = visualIndex(current) + 1;
       
  3847         if (header())
       
  3848             ++entry;
       
  3849         QAccessible::updateAccessibility(viewport(), entry, QAccessible::Focus);
       
  3850     }
       
  3851 #endif
       
  3852     QAbstractItemView::currentChanged(current, previous);
       
  3853 
       
  3854     if (allColumnsShowFocus()) {
       
  3855         if (previous.isValid()) {
       
  3856             QRect previousRect = visualRect(previous);
       
  3857             previousRect.setX(0);
       
  3858             previousRect.setWidth(viewport()->width());
       
  3859             viewport()->update(previousRect);
       
  3860         }
       
  3861         if (current.isValid()) {
       
  3862             QRect currentRect = visualRect(current);
       
  3863             currentRect.setX(0);
       
  3864             currentRect.setWidth(viewport()->width());
       
  3865             viewport()->update(currentRect);
       
  3866         }
       
  3867     }
       
  3868 }
       
  3869 
       
  3870 /*!
       
  3871   \reimp
       
  3872  */
       
  3873 void QTreeView::selectionChanged(const QItemSelection &selected,
       
  3874                                  const QItemSelection &deselected)
       
  3875 {
       
  3876 #ifndef QT_NO_ACCESSIBILITY
       
  3877     if (QAccessible::isActive()) {
       
  3878         // ### does not work properly for selection ranges.
       
  3879         QModelIndex sel = selected.indexes().value(0);
       
  3880         if (sel.isValid()) {
       
  3881             int entry = visualIndex(sel) + 1;
       
  3882             if (header())
       
  3883                 ++entry;
       
  3884             QAccessible::updateAccessibility(viewport(), entry, QAccessible::Selection);
       
  3885         }
       
  3886         QModelIndex desel = deselected.indexes().value(0);
       
  3887         if (desel.isValid()) {
       
  3888             int entry = visualIndex(desel) + 1;
       
  3889             if (header())
       
  3890                 ++entry;
       
  3891             QAccessible::updateAccessibility(viewport(), entry, QAccessible::SelectionRemove);
       
  3892         }
       
  3893     }
       
  3894 #endif
       
  3895     QAbstractItemView::selectionChanged(selected, deselected);
       
  3896 }
       
  3897 
       
  3898 int QTreeView::visualIndex(const QModelIndex &index) const
       
  3899 {
       
  3900     Q_D(const QTreeView);
       
  3901     d->executePostedLayout();
       
  3902     return d->viewIndex(index);
       
  3903 }
       
  3904 
       
  3905 QT_END_NAMESPACE
       
  3906 
       
  3907 #include "moc_qtreeview.cpp"
       
  3908 
       
  3909 #endif // QT_NO_TREEVIEW