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