src/gui/itemviews/qlistview.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 
       
    42 #include "qlistview.h"
       
    43 
       
    44 #ifndef QT_NO_LISTVIEW
       
    45 #include <qabstractitemdelegate.h>
       
    46 #include <qapplication.h>
       
    47 #include <qpainter.h>
       
    48 #include <qbitmap.h>
       
    49 #include <qvector.h>
       
    50 #include <qstyle.h>
       
    51 #include <qevent.h>
       
    52 #include <qscrollbar.h>
       
    53 #include <qrubberband.h>
       
    54 #include <private/qlistview_p.h>
       
    55 #include <qdebug.h>
       
    56 #ifndef QT_NO_ACCESSIBILITY
       
    57 #include <qaccessible.h>
       
    58 #endif
       
    59 
       
    60 QT_BEGIN_NAMESPACE
       
    61 
       
    62 /*!
       
    63     \class QListView
       
    64 
       
    65     \brief The QListView class provides a list or icon view onto a model.
       
    66 
       
    67     \ingroup model-view
       
    68     \ingroup advanced
       
    69 
       
    70 
       
    71     A QListView presents items stored in a model, either as a simple
       
    72     non-hierarchical list, or as a collection of icons. This class is used
       
    73     to provide lists and icon views that were previously provided by the
       
    74     \c QListBox and \c QIconView classes, but using the more flexible
       
    75     approach provided by Qt's model/view architecture.
       
    76 
       
    77     The QListView class is one of the \l{Model/View Classes}
       
    78     and is part of Qt's \l{Model/View Programming}{model/view framework}.
       
    79 
       
    80     This view does not display horizontal or vertical headers; to display
       
    81     a list of items with a horizontal header, use QTreeView instead.
       
    82 
       
    83     QListView implements the interfaces defined by the
       
    84     QAbstractItemView class to allow it to display data provided by
       
    85     models derived from the QAbstractItemModel class.
       
    86 
       
    87     Items in a list view can be displayed using one of two view modes:
       
    88     In \l ListMode, the items are displayed in the form of a simple list;
       
    89     in \l IconMode, the list view takes the form of an \e{icon view} in
       
    90     which the items are displayed with icons like files in a file manager.
       
    91     By default, the list view is in \l ListMode. To change the view mode,
       
    92     use the setViewMode() function, and to determine the current view mode,
       
    93     use viewMode().
       
    94 
       
    95     Items in these views are laid out in the direction specified by the
       
    96     flow() of the list view. The items may be fixed in place, or allowed
       
    97     to move, depending on the view's movement() state.
       
    98 
       
    99     If the items in the model cannot be completely laid out in the
       
   100     direction of flow, they can be wrapped at the boundary of the view
       
   101     widget; this depends on isWrapping(). This property is useful when the
       
   102     items are being represented by an icon view.
       
   103 
       
   104     The resizeMode() and layoutMode() govern how and when the items are
       
   105     laid out. Items are spaced according to their spacing(), and can exist
       
   106     within a notional grid of size specified by gridSize(). The items can
       
   107     be rendered as large or small icons depending on their iconSize().
       
   108 
       
   109     \table 100%
       
   110     \row \o \inlineimage windowsxp-listview.png Screenshot of a Windows XP style list view
       
   111          \o \inlineimage macintosh-listview.png Screenshot of a Macintosh style table view
       
   112          \o \inlineimage plastique-listview.png Screenshot of a Plastique style table view
       
   113     \row \o A \l{Windows XP Style Widget Gallery}{Windows XP style} list view.
       
   114          \o A \l{Macintosh Style Widget Gallery}{Macintosh style} list view.
       
   115          \o A \l{Plastique Style Widget Gallery}{Plastique style} list view.
       
   116     \endtable
       
   117 
       
   118     \section1 Improving Performance
       
   119 
       
   120     It is possible to give the view hints about the data it is handling in order
       
   121     to improve its performance when displaying large numbers of items. One approach
       
   122     that can be taken for views that are intended to display items with equal sizes
       
   123     is to set the \l uniformItemSizes property to true.
       
   124 
       
   125     \sa {View Classes}, QTreeView, QTableView, QListWidget
       
   126 */
       
   127 
       
   128 /*!
       
   129     \enum QListView::ViewMode
       
   130 
       
   131     \value ListMode The items are laid out using TopToBottom flow, with Small size and Static movement
       
   132     \value IconMode The items are laid out using LeftToRight flow, with Large size and Free movement
       
   133 */
       
   134 
       
   135 /*!
       
   136   \enum QListView::Movement
       
   137 
       
   138   \value Static The items cannot be moved by the user.
       
   139   \value Free The items can be moved freely by the user.
       
   140   \value Snap The items snap to the specified grid when moved; see
       
   141   setGridSize().
       
   142 */
       
   143 
       
   144 /*!
       
   145   \enum QListView::Flow
       
   146 
       
   147   \value LeftToRight The items are laid out in the view from the left
       
   148   to the right.
       
   149   \value TopToBottom The items are laid out in the view from the top
       
   150   to the bottom.
       
   151 */
       
   152 
       
   153 /*!
       
   154   \enum QListView::ResizeMode
       
   155 
       
   156   \value Fixed The items will only be laid out the first time the view is shown.
       
   157   \value Adjust The items will be laid out every time the view is resized.
       
   158 */
       
   159 
       
   160 /*!
       
   161   \enum QListView::LayoutMode
       
   162 
       
   163   \value SinglePass The items are laid out all at once.
       
   164   \value Batched The items are laid out in batches of \l batchSize items.
       
   165   \sa batchSize
       
   166 */
       
   167 
       
   168 /*!
       
   169   \since 4.2
       
   170   \fn void QListView::indexesMoved(const QModelIndexList &indexes)
       
   171 
       
   172   This signal is emitted when the specified \a indexes are moved in the view.
       
   173 */
       
   174 
       
   175 /*!
       
   176     Creates a new QListView with the given \a parent to view a model.
       
   177     Use setModel() to set the model.
       
   178 */
       
   179 QListView::QListView(QWidget *parent)
       
   180     : QAbstractItemView(*new QListViewPrivate, parent)
       
   181 {
       
   182     setViewMode(ListMode);
       
   183     setSelectionMode(SingleSelection);
       
   184     setAttribute(Qt::WA_MacShowFocusRect);
       
   185     Q_D(QListView);               // We rely on a qobject_cast for PM_DefaultFrameWidth to change
       
   186     d->updateStyledFrameWidths(); // hence we have to force an update now that the object has been constructed
       
   187 }
       
   188 
       
   189 /*!
       
   190   \internal
       
   191 */
       
   192 QListView::QListView(QListViewPrivate &dd, QWidget *parent)
       
   193     : QAbstractItemView(dd, parent)
       
   194 {
       
   195     setViewMode(ListMode);
       
   196     setSelectionMode(SingleSelection);
       
   197     setAttribute(Qt::WA_MacShowFocusRect);
       
   198     Q_D(QListView);               // We rely on a qobject_cast for PM_DefaultFrameWidth to change
       
   199     d->updateStyledFrameWidths(); // hence we have to force an update now that the object has been constructed
       
   200 }
       
   201 
       
   202 /*!
       
   203   Destroys the view.
       
   204 */
       
   205 QListView::~QListView()
       
   206 {
       
   207 }
       
   208 
       
   209 /*!
       
   210     \property QListView::movement
       
   211     \brief whether the items can be moved freely, are snapped to a
       
   212     grid, or cannot be moved at all.
       
   213 
       
   214     This property determines how the user can move the items in the
       
   215     view. \l Static means that the items can't be moved the user. \l
       
   216     Free means that the user can drag and drop the items to any
       
   217     position in the view. \l Snap means that the user can drag and
       
   218     drop the items, but only to the positions in a notional grid
       
   219     signified by the gridSize property.
       
   220 
       
   221     Setting this property when the view is visible will cause the
       
   222     items to be laid out again.
       
   223 
       
   224     By default, this property is set to \l Static.
       
   225 
       
   226     \sa gridSize, resizeMode, viewMode
       
   227 */
       
   228 void QListView::setMovement(Movement movement)
       
   229 {
       
   230     Q_D(QListView);
       
   231     d->modeProperties |= uint(QListViewPrivate::Movement);
       
   232     d->movement = movement;
       
   233 
       
   234 #ifndef QT_NO_DRAGANDDROP
       
   235     bool movable = (movement != Static);
       
   236     setDragEnabled(movable);
       
   237     d->viewport->setAcceptDrops(movable);
       
   238 #endif
       
   239     d->doDelayedItemsLayout();
       
   240 }
       
   241 
       
   242 QListView::Movement QListView::movement() const
       
   243 {
       
   244     Q_D(const QListView);
       
   245     return d->movement;
       
   246 }
       
   247 
       
   248 /*!
       
   249     \property QListView::flow
       
   250     \brief which direction the items layout should flow.
       
   251 
       
   252     If this property is \l LeftToRight, the items will be laid out left
       
   253     to right. If the \l isWrapping property is true, the layout will wrap
       
   254     when it reaches the right side of the visible area. If this
       
   255     property is \l TopToBottom, the items will be laid out from the top
       
   256     of the visible area, wrapping when it reaches the bottom.
       
   257 
       
   258     Setting this property when the view is visible will cause the
       
   259     items to be laid out again.
       
   260 
       
   261     By default, this property is set to \l TopToBottom.
       
   262 
       
   263     \sa viewMode
       
   264 */
       
   265 void QListView::setFlow(Flow flow)
       
   266 {
       
   267     Q_D(QListView);
       
   268     d->modeProperties |= uint(QListViewPrivate::Flow);
       
   269     d->flow = flow;
       
   270     d->doDelayedItemsLayout();
       
   271 }
       
   272 
       
   273 QListView::Flow QListView::flow() const
       
   274 {
       
   275     Q_D(const QListView);
       
   276     return d->flow;
       
   277 }
       
   278 
       
   279 /*!
       
   280     \property QListView::isWrapping
       
   281     \brief whether the items layout should wrap.
       
   282 
       
   283     This property holds whether the layout should wrap when there is
       
   284     no more space in the visible area. The point at which the layout wraps
       
   285     depends on the \l flow property.
       
   286 
       
   287     Setting this property when the view is visible will cause the
       
   288     items to be laid out again.
       
   289 
       
   290     By default, this property is false.
       
   291 
       
   292     \sa viewMode
       
   293 */
       
   294 void QListView::setWrapping(bool enable)
       
   295 {
       
   296     Q_D(QListView);
       
   297     d->modeProperties |= uint(QListViewPrivate::Wrap);
       
   298     d->setWrapping(enable);
       
   299     d->doDelayedItemsLayout();
       
   300 }
       
   301 
       
   302 bool QListView::isWrapping() const
       
   303 {
       
   304     Q_D(const QListView);
       
   305     return d->isWrapping();
       
   306 }
       
   307 
       
   308 /*!
       
   309     \property QListView::resizeMode
       
   310     \brief whether the items are laid out again when the view is resized.
       
   311 
       
   312     If this property is \l Adjust, the items will be laid out again
       
   313     when the view is resized. If the value is \l Fixed, the items will
       
   314     not be laid out when the view is resized.
       
   315 
       
   316     By default, this property is set to \l Fixed.
       
   317 
       
   318     \sa movement, gridSize, viewMode
       
   319 */
       
   320 void QListView::setResizeMode(ResizeMode mode)
       
   321 {
       
   322     Q_D(QListView);
       
   323     d->modeProperties |= uint(QListViewPrivate::ResizeMode);
       
   324     d->resizeMode = mode;
       
   325 }
       
   326 
       
   327 QListView::ResizeMode QListView::resizeMode() const
       
   328 {
       
   329     Q_D(const QListView);
       
   330     return d->resizeMode;
       
   331 }
       
   332 
       
   333 /*!
       
   334     \property QListView::layoutMode
       
   335     \brief determines whether the layout of items should happen immediately or be delayed.
       
   336 
       
   337     This property holds the layout mode for the items. When the mode
       
   338     is \l SinglePass (the default), the items are laid out all in one go.
       
   339     When the mode is \l Batched, the items are laid out in batches of \l batchSize
       
   340     items, while processing events. This makes it possible to
       
   341     instantly view and interact with the visible items while the rest
       
   342     are being laid out.
       
   343 
       
   344     \sa viewMode
       
   345 */
       
   346 void QListView::setLayoutMode(LayoutMode mode)
       
   347 {
       
   348     Q_D(QListView);
       
   349     d->layoutMode = mode;
       
   350 }
       
   351 
       
   352 QListView::LayoutMode QListView::layoutMode() const
       
   353 {
       
   354     Q_D(const QListView);
       
   355     return d->layoutMode;
       
   356 }
       
   357 
       
   358 /*!
       
   359     \property QListView::spacing
       
   360     \brief the space between items in the layout
       
   361 
       
   362     This property is the size of the empty space that is padded around
       
   363     an item in the layout.
       
   364 
       
   365     Setting this property when the view is visible will cause the
       
   366     items to be laid out again.
       
   367 
       
   368     By default, this property contains a value of 0.
       
   369 
       
   370     \sa viewMode
       
   371 */
       
   372 // ### Qt5: Use same semantic as layouts (spacing is the size of space
       
   373 // *between* items)
       
   374 void QListView::setSpacing(int space)
       
   375 {
       
   376     Q_D(QListView);
       
   377     d->modeProperties |= uint(QListViewPrivate::Spacing);
       
   378     d->setSpacing(space);
       
   379     d->doDelayedItemsLayout();
       
   380 }
       
   381 
       
   382 int QListView::spacing() const
       
   383 {
       
   384     Q_D(const QListView);
       
   385     return d->spacing();
       
   386 }
       
   387 
       
   388 /*!
       
   389     \property QListView::batchSize
       
   390     \brief the number of items laid out in each batch if \l layoutMode is
       
   391     set to \l Batched
       
   392 
       
   393     The default value is 100.
       
   394 
       
   395     \since 4.2
       
   396 */
       
   397 
       
   398 void QListView::setBatchSize(int batchSize)
       
   399 {
       
   400     Q_D(QListView);
       
   401     if (batchSize <= 0) {
       
   402         qWarning("Invalid batchSize (%d)", batchSize);
       
   403         return;
       
   404     }
       
   405     d->batchSize = batchSize;
       
   406 }
       
   407 
       
   408 int QListView::batchSize() const
       
   409 {
       
   410     Q_D(const QListView);
       
   411     return d->batchSize;
       
   412 }
       
   413 
       
   414 /*!
       
   415     \property QListView::gridSize
       
   416     \brief the size of the layout grid
       
   417 
       
   418     This property is the size of the grid in which the items are laid
       
   419     out. The default is an empty size which means that there is no
       
   420     grid and the layout is not done in a grid. Setting this property
       
   421     to a non-empty size switches on the grid layout. (When a grid
       
   422     layout is in force the \l spacing property is ignored.)
       
   423 
       
   424     Setting this property when the view is visible will cause the
       
   425     items to be laid out again.
       
   426 
       
   427     \sa viewMode
       
   428 */
       
   429 void QListView::setGridSize(const QSize &size)
       
   430 {
       
   431     Q_D(QListView);
       
   432     d->modeProperties |= uint(QListViewPrivate::GridSize);
       
   433     d->setGridSize(size);
       
   434     d->doDelayedItemsLayout();
       
   435 }
       
   436 
       
   437 QSize QListView::gridSize() const
       
   438 {
       
   439     Q_D(const QListView);
       
   440     return d->gridSize();
       
   441 }
       
   442 
       
   443 /*!
       
   444     \property QListView::viewMode
       
   445     \brief the view mode of the QListView.
       
   446 
       
   447     This property will change the other unset properties to conform
       
   448     with the set view mode. QListView-specific properties that have already been set
       
   449     will not be changed, unless clearPropertyFlags() has been called.
       
   450 
       
   451     Setting the view mode will enable or disable drag and drop based on the
       
   452     selected movement. For ListMode, the default movement is \l Static
       
   453     (drag and drop disabled); for IconMode, the default movement is
       
   454     \l Free (drag and drop enabled).
       
   455 
       
   456     \sa isWrapping, spacing, gridSize, flow, movement, resizeMode
       
   457 */
       
   458 void QListView::setViewMode(ViewMode mode)
       
   459 {
       
   460     Q_D(QListView);
       
   461     if (d->commonListView && d->viewMode == mode)
       
   462         return;
       
   463     d->viewMode = mode;
       
   464 
       
   465     delete d->commonListView;
       
   466     if (mode == ListMode) {
       
   467         d->commonListView = new QListModeViewBase(this, d);
       
   468         if (!(d->modeProperties & QListViewPrivate::Wrap))
       
   469             d->setWrapping(false);
       
   470         if (!(d->modeProperties & QListViewPrivate::Spacing))
       
   471             d->setSpacing(0);
       
   472         if (!(d->modeProperties & QListViewPrivate::GridSize))
       
   473             d->setGridSize(QSize());
       
   474         if (!(d->modeProperties & QListViewPrivate::Flow))
       
   475             d->flow = TopToBottom;
       
   476         if (!(d->modeProperties & QListViewPrivate::Movement))
       
   477             d->movement = Static;
       
   478         if (!(d->modeProperties & QListViewPrivate::ResizeMode))
       
   479             d->resizeMode = Fixed;
       
   480         if (!(d->modeProperties & QListViewPrivate::SelectionRectVisible))
       
   481             d->showElasticBand = false;
       
   482     } else {
       
   483         d->commonListView = new QIconModeViewBase(this, d);
       
   484         if (!(d->modeProperties & QListViewPrivate::Wrap))
       
   485             d->setWrapping(true);
       
   486         if (!(d->modeProperties & QListViewPrivate::Spacing))
       
   487             d->setSpacing(0);
       
   488         if (!(d->modeProperties & QListViewPrivate::GridSize))
       
   489             d->setGridSize(QSize());
       
   490         if (!(d->modeProperties & QListViewPrivate::Flow))
       
   491             d->flow = LeftToRight;
       
   492         if (!(d->modeProperties & QListViewPrivate::Movement))
       
   493             d->movement = Free;
       
   494         if (!(d->modeProperties & QListViewPrivate::ResizeMode))
       
   495             d->resizeMode = Fixed;
       
   496         if (!(d->modeProperties & QListViewPrivate::SelectionRectVisible))
       
   497             d->showElasticBand = true;
       
   498     }
       
   499 
       
   500 #ifndef QT_NO_DRAGANDDROP
       
   501     bool movable = (d->movement != Static);
       
   502     setDragEnabled(movable);
       
   503     setAcceptDrops(movable);
       
   504 #endif
       
   505     d->clear();
       
   506     d->doDelayedItemsLayout();
       
   507 }
       
   508 
       
   509 QListView::ViewMode QListView::viewMode() const
       
   510 {
       
   511     Q_D(const QListView);
       
   512     return d->viewMode;
       
   513 }
       
   514 
       
   515 /*!
       
   516     Clears the QListView-specific property flags. See \l{viewMode}.
       
   517 
       
   518     Properties inherited from QAbstractItemView are not covered by the
       
   519     property flags. Specifically, \l{QAbstractItemView::dragEnabled}
       
   520     {dragEnabled} and \l{QAbstractItemView::acceptDrops}
       
   521     {acceptsDrops} are computed by QListView when calling
       
   522     setMovement() or setViewMode().
       
   523 */
       
   524 void QListView::clearPropertyFlags()
       
   525 {
       
   526     Q_D(QListView);
       
   527     d->modeProperties = 0;
       
   528 }
       
   529 
       
   530 /*!
       
   531     Returns true if the \a row is hidden; otherwise returns false.
       
   532 */
       
   533 bool QListView::isRowHidden(int row) const
       
   534 {
       
   535     Q_D(const QListView);
       
   536     return d->isHidden(row);
       
   537 }
       
   538 
       
   539 /*!
       
   540     If \a hide is true, the given \a row will be hidden; otherwise
       
   541     the \a row will be shown.
       
   542 */
       
   543 void QListView::setRowHidden(int row, bool hide)
       
   544 {
       
   545     Q_D(QListView);
       
   546     const bool hidden = d->isHidden(row);
       
   547     if (hide && !hidden)
       
   548         d->commonListView->appendHiddenRow(row);
       
   549     else if (!hide && hidden)
       
   550         d->commonListView->removeHiddenRow(row);
       
   551     d->doDelayedItemsLayout();
       
   552     d->viewport->update();
       
   553 }
       
   554 
       
   555 /*!
       
   556   \reimp
       
   557 */
       
   558 QRect QListView::visualRect(const QModelIndex &index) const
       
   559 {
       
   560     Q_D(const QListView);
       
   561     return d->mapToViewport(rectForIndex(index));
       
   562 }
       
   563 
       
   564 /*!
       
   565   \reimp
       
   566 */
       
   567 void QListView::scrollTo(const QModelIndex &index, ScrollHint hint)
       
   568 {
       
   569     Q_D(QListView);
       
   570 
       
   571     if (index.parent() != d->root || index.column() != d->column)
       
   572         return;
       
   573 
       
   574     const QRect rect = visualRect(index);
       
   575     if (hint == EnsureVisible && d->viewport->rect().contains(rect)) {
       
   576         d->viewport->update(rect);
       
   577         return;
       
   578     }
       
   579 
       
   580     if (d->flow == QListView::TopToBottom || d->isWrapping()) // vertical
       
   581         verticalScrollBar()->setValue(d->verticalScrollToValue(index, rect, hint));
       
   582 
       
   583     if (d->flow == QListView::LeftToRight || d->isWrapping()) // horizontal
       
   584         horizontalScrollBar()->setValue(d->horizontalScrollToValue(index, rect, hint));
       
   585 }
       
   586 
       
   587 int QListViewPrivate::horizontalScrollToValue(const QModelIndex &index, const QRect &rect,
       
   588                                               QListView::ScrollHint hint) const
       
   589 {
       
   590     Q_Q(const QListView);
       
   591     const QRect area = viewport->rect();
       
   592     const bool leftOf = q->isRightToLeft()
       
   593                         ? (rect.left() < area.left()) && (rect.right() < area.right())
       
   594                         : rect.left() < area.left();
       
   595     const bool rightOf = q->isRightToLeft()
       
   596                          ? rect.right() > area.right()
       
   597                          : (rect.right() > area.right()) && (rect.left() > area.left());
       
   598     return commonListView->horizontalScrollToValue(q->visualIndex(index), hint, leftOf, rightOf, area, rect);
       
   599 }
       
   600 
       
   601 int QListViewPrivate::verticalScrollToValue(const QModelIndex &index, const QRect &rect,
       
   602                                             QListView::ScrollHint hint) const
       
   603 {
       
   604     Q_Q(const QListView);
       
   605     const QRect area = viewport->rect();
       
   606     const bool above = (hint == QListView::EnsureVisible && rect.top() < area.top());
       
   607     const bool below = (hint == QListView::EnsureVisible && rect.bottom() > area.bottom());
       
   608     return commonListView->verticalScrollToValue(q->visualIndex(index), hint, above, below, area, rect);
       
   609 }
       
   610 
       
   611 void QListViewPrivate::selectAll(QItemSelectionModel::SelectionFlags command)
       
   612 {
       
   613     if (!selectionModel)
       
   614         return;
       
   615 
       
   616     QItemSelection selection;
       
   617     QModelIndex topLeft;
       
   618     int row = 0;
       
   619     const int colCount = model->columnCount(root);
       
   620     for(; row < model->rowCount(root); ++row) {
       
   621         if (isHidden(row)) {
       
   622             //it might be the end of a selection range
       
   623             if (topLeft.isValid()) {
       
   624                 QModelIndex bottomRight = model->index(row - 1, colCount - 1, root);
       
   625                 selection.append(QItemSelectionRange(topLeft, bottomRight));
       
   626                 topLeft = QModelIndex();
       
   627             }
       
   628             continue;
       
   629         }
       
   630 
       
   631         if (!topLeft.isValid()) //start of a new selection range
       
   632             topLeft = model->index(row, 0, root);
       
   633     }
       
   634 
       
   635     if (topLeft.isValid()) {
       
   636         //last selected range
       
   637         QModelIndex bottomRight = model->index(row - 1, colCount - 1, root);
       
   638         selection.append(QItemSelectionRange(topLeft, bottomRight));
       
   639     }
       
   640 
       
   641     if (!selection.isEmpty())
       
   642         selectionModel->select(selection, command);
       
   643 }
       
   644 
       
   645 /*!
       
   646   \reimp
       
   647 
       
   648   We have a QListView way of knowing what elements are on the viewport
       
   649   through the intersectingSet function
       
   650 */
       
   651 QItemViewPaintPairs QListViewPrivate::draggablePaintPairs(const QModelIndexList &indexes, QRect *r) const
       
   652 {
       
   653     Q_ASSERT(r);
       
   654     Q_Q(const QListView);
       
   655     QRect &rect = *r;
       
   656     const QRect viewportRect = viewport->rect();
       
   657     QItemViewPaintPairs ret;
       
   658     const QSet<QModelIndex> visibleIndexes = intersectingSet(viewportRect).toList().toSet();
       
   659     for (int i = 0; i < indexes.count(); ++i) {
       
   660         const QModelIndex &index = indexes.at(i);
       
   661         if (visibleIndexes.contains(index)) {
       
   662             const QRect current = q->visualRect(index);
       
   663             ret += qMakePair(current, index);
       
   664             rect |= current;
       
   665         }
       
   666     }
       
   667     rect &= viewportRect;
       
   668     return ret;
       
   669 }
       
   670 
       
   671 /*!
       
   672   \internal
       
   673 */
       
   674 void QListView::reset()
       
   675 {
       
   676     Q_D(QListView);
       
   677     d->clear();
       
   678     d->hiddenRows.clear();
       
   679     QAbstractItemView::reset();
       
   680 }
       
   681 
       
   682 /*!
       
   683   \internal
       
   684 */
       
   685 void QListView::setRootIndex(const QModelIndex &index)
       
   686 {
       
   687     Q_D(QListView);
       
   688     d->column = qBound(0, d->column, d->model->columnCount(index) - 1);
       
   689     QAbstractItemView::setRootIndex(index);
       
   690     // sometimes we get an update before reset() is called
       
   691     d->clear();
       
   692     d->hiddenRows.clear();
       
   693 }
       
   694 
       
   695 /*!
       
   696     \internal
       
   697 
       
   698     Scroll the view contents by \a dx and \a dy.
       
   699 */
       
   700 
       
   701 void QListView::scrollContentsBy(int dx, int dy)
       
   702 {
       
   703     Q_D(QListView);
       
   704     d->delayedAutoScroll.stop(); // auto scroll was canceled by the user scrolling
       
   705     d->commonListView->scrollContentsBy(dx, dy, d->state == QListView::DragSelectingState);
       
   706 }
       
   707 
       
   708 /*!
       
   709     \internal
       
   710 
       
   711     Resize the internal contents to \a width and \a height and set the
       
   712     scroll bar ranges accordingly.
       
   713 */
       
   714 void QListView::resizeContents(int width, int height)
       
   715 {
       
   716     Q_D(QListView);
       
   717     d->setContentsSize(width, height);
       
   718 }
       
   719 
       
   720 /*!
       
   721     \internal
       
   722 */
       
   723 QSize QListView::contentsSize() const
       
   724 {
       
   725     Q_D(const QListView);
       
   726     return d->contentsSize();
       
   727 }
       
   728 
       
   729 /*!
       
   730   \reimp
       
   731 */
       
   732 void QListView::dataChanged(const QModelIndex &topLeft, const QModelIndex &bottomRight)
       
   733 {
       
   734     d_func()->commonListView->dataChanged(topLeft, bottomRight);
       
   735     QAbstractItemView::dataChanged(topLeft, bottomRight);
       
   736 }
       
   737 
       
   738 /*!
       
   739   \reimp
       
   740 */
       
   741 void QListView::rowsInserted(const QModelIndex &parent, int start, int end)
       
   742 {
       
   743     Q_D(QListView);
       
   744     // ### be smarter about inserted items
       
   745     d->clear();
       
   746     d->doDelayedItemsLayout();
       
   747     QAbstractItemView::rowsInserted(parent, start, end);
       
   748 }
       
   749 
       
   750 /*!
       
   751   \reimp
       
   752 */
       
   753 void QListView::rowsAboutToBeRemoved(const QModelIndex &parent, int start, int end)
       
   754 {
       
   755     Q_D(QListView);
       
   756     // if the parent is above d->root in the tree, nothing will happen
       
   757     QAbstractItemView::rowsAboutToBeRemoved(parent, start, end);
       
   758     if (parent == d->root) {
       
   759         for (int i = d->hiddenRows.count() - 1; i >= 0; --i) {
       
   760             int hiddenRow = d->hiddenRows.at(i).row();
       
   761             if (hiddenRow >= start && hiddenRow <= end) {
       
   762                 d->hiddenRows.remove(i);
       
   763             }
       
   764         }
       
   765     }
       
   766     d->clear();
       
   767     d->doDelayedItemsLayout();
       
   768 }
       
   769 
       
   770 /*!
       
   771   \reimp
       
   772 */
       
   773 void QListView::mouseMoveEvent(QMouseEvent *e)
       
   774 {
       
   775     if (!isVisible())
       
   776 	return;
       
   777     Q_D(QListView);
       
   778     QAbstractItemView::mouseMoveEvent(e);
       
   779     if (state() == DragSelectingState
       
   780         && d->showElasticBand
       
   781         && d->selectionMode != SingleSelection
       
   782         && d->selectionMode != NoSelection) {
       
   783         QRect rect(d->pressedPosition, e->pos() + QPoint(horizontalOffset(), verticalOffset()));
       
   784         rect = rect.normalized();
       
   785         d->viewport->update(d->mapToViewport(rect.united(d->elasticBand)));
       
   786         d->elasticBand = rect;
       
   787     }
       
   788 }
       
   789 
       
   790 /*!
       
   791   \reimp
       
   792 */
       
   793 void QListView::mouseReleaseEvent(QMouseEvent *e)
       
   794 {
       
   795     Q_D(QListView);
       
   796     QAbstractItemView::mouseReleaseEvent(e);
       
   797     // #### move this implementation into a dynamic class
       
   798     if (d->showElasticBand && d->elasticBand.isValid()) {
       
   799         d->viewport->update(d->mapToViewport(d->elasticBand));
       
   800         d->elasticBand = QRect();
       
   801     }
       
   802 }
       
   803 
       
   804 /*!
       
   805   \reimp
       
   806 */
       
   807 void QListView::timerEvent(QTimerEvent *e)
       
   808 {
       
   809     Q_D(QListView);
       
   810     if (e->timerId() == d->batchLayoutTimer.timerId()) {
       
   811         if (d->doItemsLayout(d->batchSize)) { // layout is done
       
   812             d->batchLayoutTimer.stop();
       
   813             updateGeometries();
       
   814             d->viewport->update();
       
   815         }
       
   816     }
       
   817     QAbstractItemView::timerEvent(e);
       
   818 }
       
   819 
       
   820 /*!
       
   821   \reimp
       
   822 */
       
   823 void QListView::resizeEvent(QResizeEvent *e)
       
   824 {
       
   825     Q_D(QListView);
       
   826     if (d->delayedPendingLayout)
       
   827         return;
       
   828 
       
   829     QSize delta = e->size() - e->oldSize();
       
   830 
       
   831     if (delta.isNull())
       
   832       return;
       
   833 
       
   834     bool listWrap = (d->viewMode == ListMode) && d->wrapItemText;
       
   835     bool flowDimensionChanged = (d->flow == LeftToRight && delta.width() != 0) 
       
   836 				|| (d->flow == TopToBottom && delta.height() != 0);
       
   837 
       
   838     // We post a delayed relayout in the following cases :
       
   839     // - we're wrapping
       
   840     // - the state is NoState, we're adjusting and the size has changed in the flowing direction
       
   841     if (listWrap 
       
   842         || (state() == NoState && d->resizeMode == Adjust && flowDimensionChanged)) {
       
   843 	d->doDelayedItemsLayout(100); // wait 1/10 sec before starting the layout
       
   844     } else {	
       
   845         QAbstractItemView::resizeEvent(e);
       
   846     }
       
   847 }
       
   848 
       
   849 #ifndef QT_NO_DRAGANDDROP
       
   850 
       
   851 /*!
       
   852   \reimp
       
   853 */
       
   854 void QListView::dragMoveEvent(QDragMoveEvent *e)
       
   855 {
       
   856     if (!d_func()->commonListView->filterDragMoveEvent(e))
       
   857         QAbstractItemView::dragMoveEvent(e);
       
   858 }
       
   859 
       
   860 
       
   861 /*!
       
   862   \reimp
       
   863 */
       
   864 void QListView::dragLeaveEvent(QDragLeaveEvent *e)
       
   865 {
       
   866     if (!d_func()->commonListView->filterDragLeaveEvent(e))
       
   867         QAbstractItemView::dragLeaveEvent(e);
       
   868 }
       
   869 
       
   870 /*!
       
   871   \reimp
       
   872 */
       
   873 void QListView::dropEvent(QDropEvent *e)
       
   874 {
       
   875     if (!d_func()->commonListView->filterDropEvent(e))
       
   876         QAbstractItemView::dropEvent(e);
       
   877 }
       
   878 
       
   879 /*!
       
   880   \reimp
       
   881 */
       
   882 void QListView::startDrag(Qt::DropActions supportedActions)
       
   883 {
       
   884     if (!d_func()->commonListView->filterStartDrag(supportedActions))
       
   885         QAbstractItemView::startDrag(supportedActions);
       
   886 }
       
   887 
       
   888 /*!
       
   889     \internal
       
   890 
       
   891     Called whenever items from the view is dropped on the viewport.
       
   892     The \a event provides additional information.
       
   893 */
       
   894 void QListView::internalDrop(QDropEvent *event)
       
   895 {
       
   896     // ### Qt5: remove that function
       
   897     Q_UNUSED(event);
       
   898 }
       
   899 
       
   900 /*!
       
   901     \internal
       
   902 
       
   903     Called whenever the user starts dragging items and the items are movable,
       
   904     enabling internal dragging and dropping of items.
       
   905 */
       
   906 void QListView::internalDrag(Qt::DropActions supportedActions)
       
   907 {
       
   908     // ### Qt5: remove that function
       
   909     Q_UNUSED(supportedActions);
       
   910 }
       
   911 
       
   912 #endif // QT_NO_DRAGANDDROP
       
   913 
       
   914 /*!
       
   915   \reimp
       
   916 */
       
   917 QStyleOptionViewItem QListView::viewOptions() const
       
   918 {
       
   919     Q_D(const QListView);
       
   920     QStyleOptionViewItem option = QAbstractItemView::viewOptions();
       
   921     if (!d->iconSize.isValid()) { // otherwise it was already set in abstractitemview
       
   922         int pm = (d->viewMode == ListMode
       
   923                   ? style()->pixelMetric(QStyle::PM_ListViewIconSize, 0, this)
       
   924                   : style()->pixelMetric(QStyle::PM_IconViewIconSize, 0, this));
       
   925         option.decorationSize = QSize(pm, pm);
       
   926     }
       
   927     if (d->viewMode == IconMode) {
       
   928         option.showDecorationSelected = false;
       
   929         option.decorationPosition = QStyleOptionViewItem::Top;
       
   930         option.displayAlignment = Qt::AlignCenter;
       
   931     } else {
       
   932         option.decorationPosition = QStyleOptionViewItem::Left;
       
   933     }
       
   934     return option;
       
   935 }
       
   936 
       
   937 
       
   938 /*!
       
   939   \reimp
       
   940 */
       
   941 void QListView::paintEvent(QPaintEvent *e)
       
   942 {
       
   943     Q_D(QListView);
       
   944     if (!d->itemDelegate)
       
   945         return;
       
   946     QStyleOptionViewItemV4 option = d->viewOptionsV4();
       
   947     QPainter painter(d->viewport);
       
   948 
       
   949     const QVector<QModelIndex> toBeRendered = d->intersectingSet(e->rect().translated(horizontalOffset(), verticalOffset()), false);
       
   950 
       
   951     const QModelIndex current = currentIndex();
       
   952     const QModelIndex hover = d->hover;
       
   953     const QAbstractItemModel *itemModel = d->model;
       
   954     const QItemSelectionModel *selections = d->selectionModel;
       
   955     const bool focus = (hasFocus() || d->viewport->hasFocus()) && current.isValid();
       
   956     const bool alternate = d->alternatingColors;
       
   957     const QStyle::State state = option.state;
       
   958     const QAbstractItemView::State viewState = this->state();
       
   959     const bool enabled = (state & QStyle::State_Enabled) != 0;
       
   960 
       
   961     bool alternateBase = false;
       
   962     int previousRow = -2; // trigger the alternateBase adjustment on first pass
       
   963 
       
   964     QVector<QModelIndex>::const_iterator end = toBeRendered.constEnd();
       
   965     for (QVector<QModelIndex>::const_iterator it = toBeRendered.constBegin(); it != end; ++it) {
       
   966         Q_ASSERT((*it).isValid());
       
   967         option.rect = visualRect(*it);
       
   968 
       
   969         if (flow() == TopToBottom)
       
   970             option.rect.setWidth(qMin(viewport()->size().width(), option.rect.width()));
       
   971         else
       
   972             option.rect.setHeight(qMin(viewport()->size().height(), option.rect.height()));
       
   973 
       
   974         option.state = state;
       
   975         if (selections && selections->isSelected(*it))
       
   976             option.state |= QStyle::State_Selected;
       
   977         if (enabled) {
       
   978             QPalette::ColorGroup cg;
       
   979             if ((itemModel->flags(*it) & Qt::ItemIsEnabled) == 0) {
       
   980                 option.state &= ~QStyle::State_Enabled;
       
   981                 cg = QPalette::Disabled;
       
   982             } else {
       
   983                 cg = QPalette::Normal;
       
   984             }
       
   985             option.palette.setCurrentColorGroup(cg);
       
   986         }
       
   987         if (focus && current == *it) {
       
   988             option.state |= QStyle::State_HasFocus;
       
   989             if (viewState == EditingState)
       
   990                 option.state |= QStyle::State_Editing;
       
   991         }
       
   992         if (*it == hover)
       
   993             option.state |= QStyle::State_MouseOver;
       
   994         else
       
   995             option.state &= ~QStyle::State_MouseOver;
       
   996 
       
   997         if (alternate) {
       
   998             int row = (*it).row();
       
   999             if (row != previousRow + 1) {
       
  1000                 // adjust alternateBase according to rows in the "gap"
       
  1001                 if (!d->hiddenRows.isEmpty()) {
       
  1002                     for (int r = qMax(previousRow + 1, 0); r < row; ++r) {
       
  1003                         if (!d->isHidden(r))
       
  1004                             alternateBase = !alternateBase;
       
  1005                     }
       
  1006                 } else {
       
  1007                     alternateBase = (row & 1) != 0;
       
  1008                 }
       
  1009             }
       
  1010             if (alternateBase) {
       
  1011                 option.features |= QStyleOptionViewItemV2::Alternate;
       
  1012             } else {
       
  1013                 option.features &= ~QStyleOptionViewItemV2::Alternate;
       
  1014             }
       
  1015 
       
  1016             // draw background of the item (only alternate row). rest of the background
       
  1017             // is provided by the delegate
       
  1018             QStyle::State oldState = option.state;
       
  1019             option.state &= ~QStyle::State_Selected;
       
  1020             style()->drawPrimitive(QStyle::PE_PanelItemViewRow, &option, &painter, this);
       
  1021             option.state = oldState;
       
  1022 
       
  1023             alternateBase = !alternateBase;
       
  1024             previousRow = row;
       
  1025         }
       
  1026 
       
  1027         if (const QWidget *widget = d->editorForIndex(*it).editor) {
       
  1028             QRegion itemGeometry(option.rect);
       
  1029             QRegion widgetGeometry(widget->geometry());
       
  1030             painter.save();
       
  1031             painter.setClipRegion(itemGeometry.subtracted(widgetGeometry));
       
  1032             d->delegateForIndex(*it)->paint(&painter, option, *it);
       
  1033             painter.restore();
       
  1034         } else {
       
  1035             d->delegateForIndex(*it)->paint(&painter, option, *it);
       
  1036         }
       
  1037     }
       
  1038 
       
  1039 #ifndef QT_NO_DRAGANDDROP
       
  1040     d->commonListView->paintDragDrop(&painter);
       
  1041 #endif
       
  1042 
       
  1043 #ifndef QT_NO_RUBBERBAND
       
  1044     // #### move this implementation into a dynamic class
       
  1045     if (d->showElasticBand && d->elasticBand.isValid()) {
       
  1046         QStyleOptionRubberBand opt;
       
  1047         opt.initFrom(this);
       
  1048         opt.shape = QRubberBand::Rectangle;
       
  1049         opt.opaque = false;
       
  1050         opt.rect = d->mapToViewport(d->elasticBand, false).intersected(
       
  1051             d->viewport->rect().adjusted(-16, -16, 16, 16));
       
  1052         painter.save();
       
  1053         style()->drawControl(QStyle::CE_RubberBand, &opt, &painter);
       
  1054         painter.restore();
       
  1055     }
       
  1056 #endif
       
  1057 }
       
  1058 
       
  1059 /*!
       
  1060   \reimp
       
  1061 */
       
  1062 QModelIndex QListView::indexAt(const QPoint &p) const
       
  1063 {
       
  1064     Q_D(const QListView);
       
  1065     QRect rect(p.x() + horizontalOffset(), p.y() + verticalOffset(), 1, 1);
       
  1066     const QVector<QModelIndex> intersectVector = d->intersectingSet(rect);
       
  1067     QModelIndex index = intersectVector.count() > 0
       
  1068                         ? intersectVector.last() : QModelIndex();
       
  1069     if (index.isValid() && visualRect(index).contains(p))
       
  1070         return index;
       
  1071     return QModelIndex();
       
  1072 }
       
  1073 
       
  1074 /*!
       
  1075   \reimp
       
  1076 */
       
  1077 int QListView::horizontalOffset() const
       
  1078 {
       
  1079     return d_func()->commonListView->horizontalOffset();
       
  1080 }
       
  1081 
       
  1082 /*!
       
  1083   \reimp
       
  1084 */
       
  1085 int QListView::verticalOffset() const
       
  1086 {
       
  1087     return d_func()->commonListView->verticalOffset();
       
  1088 }
       
  1089 
       
  1090 /*!
       
  1091   \reimp
       
  1092 */
       
  1093 QModelIndex QListView::moveCursor(CursorAction cursorAction, Qt::KeyboardModifiers modifiers)
       
  1094 {
       
  1095     Q_D(QListView);
       
  1096     Q_UNUSED(modifiers);
       
  1097 
       
  1098     QModelIndex current = currentIndex();
       
  1099     if (!current.isValid()) {
       
  1100         int rowCount = d->model->rowCount(d->root);
       
  1101         if (!rowCount)
       
  1102             return QModelIndex();
       
  1103         int row = 0;
       
  1104         while (row < rowCount && d->isHiddenOrDisabled(row))
       
  1105             ++row;
       
  1106         if (row >= rowCount)
       
  1107             return QModelIndex();
       
  1108         return d->model->index(row, d->column, d->root);
       
  1109     }
       
  1110 
       
  1111     const QRect initialRect = rectForIndex(current);
       
  1112     QRect rect = initialRect;
       
  1113     if (rect.isEmpty()) {
       
  1114         return d->model->index(0, d->column, d->root);
       
  1115     }
       
  1116     if (d->gridSize().isValid()) rect.setSize(d->gridSize());
       
  1117 
       
  1118     QSize contents = d->contentsSize();
       
  1119     QVector<QModelIndex> intersectVector;
       
  1120 
       
  1121     switch (cursorAction) {
       
  1122     case MoveLeft:
       
  1123         while (intersectVector.isEmpty()) {
       
  1124             rect.translate(-rect.width(), 0);
       
  1125             if (rect.right() <= 0)
       
  1126                 return current;
       
  1127             if (rect.left() < 0)
       
  1128                 rect.setLeft(0);
       
  1129             intersectVector = d->intersectingSet(rect);
       
  1130             d->removeCurrentAndDisabled(&intersectVector, current);
       
  1131         }
       
  1132         return d->closestIndex(initialRect, intersectVector);
       
  1133     case MoveRight:
       
  1134         while (intersectVector.isEmpty()) {
       
  1135             rect.translate(rect.width(), 0);
       
  1136             if (rect.left() >= contents.width())
       
  1137                 return current;
       
  1138             if (rect.right() > contents.width())
       
  1139                 rect.setRight(contents.width());
       
  1140             intersectVector = d->intersectingSet(rect);
       
  1141             d->removeCurrentAndDisabled(&intersectVector, current);
       
  1142         }
       
  1143         return d->closestIndex(initialRect, intersectVector);
       
  1144     case MovePageUp:
       
  1145         rect.moveTop(rect.top() - d->viewport->height());
       
  1146         if (rect.top() < rect.height())
       
  1147             rect.moveTop(rect.height());
       
  1148     case MovePrevious:
       
  1149     case MoveUp:
       
  1150         while (intersectVector.isEmpty()) {
       
  1151             rect.translate(0, -rect.height());
       
  1152             if (rect.bottom() <= 0) {
       
  1153 #ifdef QT_KEYPAD_NAVIGATION
       
  1154                 if (QApplication::keypadNavigationEnabled()) {
       
  1155                     int row = d->batchStartRow() - 1;
       
  1156                     while (row >= 0 && d->isHiddenOrDisabled(row))
       
  1157                         --row;
       
  1158                     if (row >= 0)
       
  1159                         return d->model->index(row, d->column, d->root);
       
  1160                 }
       
  1161 #endif
       
  1162                 return current;
       
  1163             }
       
  1164             if (rect.top() < 0)
       
  1165                 rect.setTop(0);
       
  1166             intersectVector = d->intersectingSet(rect);
       
  1167             d->removeCurrentAndDisabled(&intersectVector, current);
       
  1168         }
       
  1169         return d->closestIndex(initialRect, intersectVector);
       
  1170     case MovePageDown:
       
  1171         rect.moveTop(rect.top() + d->viewport->height());
       
  1172         if (rect.bottom() > contents.height() - rect.height())
       
  1173             rect.moveBottom(contents.height() - rect.height());
       
  1174     case MoveNext:
       
  1175     case MoveDown:
       
  1176         while (intersectVector.isEmpty()) {
       
  1177             rect.translate(0, rect.height());
       
  1178             if (rect.top() >= contents.height()) {
       
  1179 #ifdef QT_KEYPAD_NAVIGATION
       
  1180                 if (QApplication::keypadNavigationEnabled()) {
       
  1181                     int rowCount = d->model->rowCount(d->root);
       
  1182                     int row = 0;
       
  1183                     while (row < rowCount && d->isHiddenOrDisabled(row))
       
  1184                         ++row;
       
  1185                     if (row < rowCount)
       
  1186                         return d->model->index(row, d->column, d->root);
       
  1187                 }
       
  1188 #endif
       
  1189                 return current;
       
  1190             }
       
  1191             if (rect.bottom() > contents.height())
       
  1192                 rect.setBottom(contents.height());
       
  1193             intersectVector = d->intersectingSet(rect);
       
  1194             d->removeCurrentAndDisabled(&intersectVector, current);
       
  1195         }
       
  1196         return d->closestIndex(initialRect, intersectVector);
       
  1197     case MoveHome:
       
  1198         return d->model->index(0, d->column, d->root);
       
  1199     case MoveEnd:
       
  1200         return d->model->index(d->batchStartRow() - 1, d->column, d->root);}
       
  1201 
       
  1202     return current;
       
  1203 }
       
  1204 
       
  1205 /*!
       
  1206     Returns the rectangle of the item at position \a index in the
       
  1207     model. The rectangle is in contents coordinates.
       
  1208 
       
  1209     \sa visualRect()
       
  1210 */
       
  1211 QRect QListView::rectForIndex(const QModelIndex &index) const
       
  1212 {
       
  1213     return d_func()->rectForIndex(index);
       
  1214 }
       
  1215 
       
  1216 /*!
       
  1217     \since 4.1
       
  1218 
       
  1219     Sets the contents position of the item at \a index in the model to the given
       
  1220     \a position.
       
  1221     If the list view's movement mode is Static or its view mode is ListView,
       
  1222     this function will have no effect.
       
  1223 */
       
  1224 void QListView::setPositionForIndex(const QPoint &position, const QModelIndex &index)
       
  1225 {
       
  1226     Q_D(QListView);
       
  1227     if (d->movement == Static
       
  1228         || !d->isIndexValid(index)
       
  1229         || index.parent() != d->root
       
  1230         || index.column() != d->column)
       
  1231         return;
       
  1232 
       
  1233     d->executePostedLayout();
       
  1234     d->commonListView->setPositionForIndex(position, index);
       
  1235 }
       
  1236 
       
  1237 /*!
       
  1238   \reimp
       
  1239 */
       
  1240 void QListView::setSelection(const QRect &rect, QItemSelectionModel::SelectionFlags command)
       
  1241 {
       
  1242     Q_D(QListView);
       
  1243     if (!d->selectionModel)
       
  1244         return;
       
  1245 
       
  1246     // if we are wrapping, we can only selecte inside the contents rectangle
       
  1247     int w = qMax(d->contentsSize().width(), d->viewport->width());
       
  1248     int h = qMax(d->contentsSize().height(), d->viewport->height());
       
  1249     if (d->wrap && !QRect(0, 0, w, h).intersects(rect))
       
  1250         return;
       
  1251 
       
  1252     QItemSelection selection;
       
  1253 
       
  1254     if (rect.width() == 1 && rect.height() == 1) {
       
  1255         const QVector<QModelIndex> intersectVector = d->intersectingSet(rect.translated(horizontalOffset(), verticalOffset()));
       
  1256         QModelIndex tl;
       
  1257         if (!intersectVector.isEmpty())
       
  1258             tl = intersectVector.last(); // special case for mouse press; only select the top item
       
  1259         if (tl.isValid() && d->isIndexEnabled(tl))
       
  1260             selection.select(tl, tl);
       
  1261     } else {
       
  1262         if (state() == DragSelectingState) { // visual selection mode (rubberband selection)
       
  1263             selection = d->selection(rect.translated(horizontalOffset(), verticalOffset()));
       
  1264         } else { // logical selection mode (key and mouse click selection)
       
  1265             QModelIndex tl, br;
       
  1266             // get the first item
       
  1267             const QRect topLeft(rect.left() + horizontalOffset(), rect.top() + verticalOffset(), 1, 1);
       
  1268             QVector<QModelIndex> intersectVector = d->intersectingSet(topLeft);
       
  1269             if (!intersectVector.isEmpty())
       
  1270                 tl = intersectVector.last();
       
  1271             // get the last item
       
  1272             const QRect bottomRight(rect.right() + horizontalOffset(), rect.bottom() + verticalOffset(), 1, 1);
       
  1273             intersectVector = d->intersectingSet(bottomRight);
       
  1274             if (!intersectVector.isEmpty())
       
  1275                 br = intersectVector.last();
       
  1276 
       
  1277             // get the ranges
       
  1278             if (tl.isValid() && br.isValid()
       
  1279                 && d->isIndexEnabled(tl)
       
  1280                 && d->isIndexEnabled(br)) {
       
  1281                 QRect first = rectForIndex(tl);
       
  1282                 QRect last = rectForIndex(br);
       
  1283                 QRect middle;
       
  1284                 if (d->flow == LeftToRight) {
       
  1285                     QRect &top = first;
       
  1286                     QRect &bottom = last;
       
  1287                     // if bottom is above top, swap them
       
  1288                     if (top.center().y() > bottom.center().y()) {
       
  1289                         QRect tmp = top;
       
  1290                         top = bottom;
       
  1291                         bottom = tmp;
       
  1292                     }
       
  1293                     // if the rect are on differnet lines, expand
       
  1294                     if (top.top() != bottom.top()) {
       
  1295                         // top rectangle
       
  1296                         if (isRightToLeft())
       
  1297                             top.setLeft(0);
       
  1298                         else
       
  1299                             top.setRight(contentsSize().width());
       
  1300                         // bottom rectangle
       
  1301                         if (isRightToLeft())
       
  1302                             bottom.setRight(contentsSize().width());
       
  1303                         else
       
  1304                             bottom.setLeft(0);
       
  1305                     } else if (top.left() > bottom.right()) {
       
  1306                         if (isRightToLeft())
       
  1307                             bottom.setLeft(top.right());
       
  1308                         else
       
  1309                             bottom.setRight(top.left());
       
  1310                     } else {
       
  1311                         if (isRightToLeft())
       
  1312                             top.setLeft(bottom.right());
       
  1313                         else
       
  1314                             top.setRight(bottom.left());
       
  1315                     }
       
  1316                     // middle rectangle
       
  1317                     if (top.bottom() < bottom.top()) {
       
  1318                         if (gridSize().isValid() && !gridSize().isNull())
       
  1319                             middle.setTop(top.top() + gridSize().height());
       
  1320                         else
       
  1321                             middle.setTop(top.bottom() + 1);
       
  1322                         middle.setLeft(qMin(top.left(), bottom.left()));
       
  1323                         middle.setBottom(bottom.top() - 1);
       
  1324                         middle.setRight(qMax(top.right(), bottom.right()));
       
  1325                     }
       
  1326                 } else {    // TopToBottom
       
  1327                     QRect &left = first;
       
  1328                     QRect &right = last;
       
  1329                     if (left.center().x() > right.center().x())
       
  1330                         qSwap(left, right);
       
  1331 
       
  1332                     int ch = contentsSize().height();
       
  1333                     if (left.left() != right.left()) {
       
  1334                         // left rectangle
       
  1335                         if (isRightToLeft())
       
  1336                             left.setTop(0);
       
  1337                         else
       
  1338                             left.setBottom(ch);
       
  1339 
       
  1340                         // top rectangle
       
  1341                         if (isRightToLeft())
       
  1342                             right.setBottom(ch);
       
  1343                         else
       
  1344                             right.setTop(0);
       
  1345                         // only set middle if the
       
  1346                         middle.setTop(0);
       
  1347                         middle.setBottom(ch);
       
  1348                         if (gridSize().isValid() && !gridSize().isNull())
       
  1349                             middle.setLeft(left.left() + gridSize().width());
       
  1350                         else
       
  1351                             middle.setLeft(left.right() + 1);
       
  1352                         middle.setRight(right.left() - 1);
       
  1353                     } else if (left.bottom() < right.top()) {
       
  1354                         left.setBottom(right.top() - 1);
       
  1355                     } else {
       
  1356                         right.setBottom(left.top() - 1);
       
  1357                     }
       
  1358                 }
       
  1359 
       
  1360                 // do the selections
       
  1361                 QItemSelection topSelection = d->selection(first);
       
  1362                 QItemSelection middleSelection = d->selection(middle);
       
  1363                 QItemSelection bottomSelection = d->selection(last);
       
  1364                 // merge
       
  1365                 selection.merge(topSelection, QItemSelectionModel::Select);
       
  1366                 selection.merge(middleSelection, QItemSelectionModel::Select);
       
  1367                 selection.merge(bottomSelection, QItemSelectionModel::Select);
       
  1368             }
       
  1369         }
       
  1370     }
       
  1371 
       
  1372     d->selectionModel->select(selection, command);
       
  1373 }
       
  1374 
       
  1375 /*!
       
  1376   \reimp
       
  1377 */
       
  1378 QRegion QListView::visualRegionForSelection(const QItemSelection &selection) const
       
  1379 {
       
  1380     Q_D(const QListView);
       
  1381     // ### NOTE: this is a potential bottleneck in non-static mode
       
  1382     int c = d->column;
       
  1383     QRegion selectionRegion;
       
  1384     for (int i = 0; i < selection.count(); ++i) {
       
  1385         if (!selection.at(i).isValid())
       
  1386             continue;
       
  1387         QModelIndex parent = selection.at(i).topLeft().parent();
       
  1388         //we only display the children of the root in a listview
       
  1389         //we're not interested in the other model indexes
       
  1390         if (parent != d->root)
       
  1391             continue;
       
  1392         int t = selection.at(i).topLeft().row();
       
  1393         int b = selection.at(i).bottomRight().row();
       
  1394         if (d->viewMode == IconMode || d->isWrapping()) { // in non-static mode, we have to go through all selected items
       
  1395             for (int r = t; r <= b; ++r)
       
  1396                 selectionRegion += QRegion(visualRect(d->model->index(r, c, parent)));
       
  1397         } else { // in static mode, we can optimize a bit
       
  1398             while (t <= b && d->isHidden(t)) ++t;
       
  1399             while (b >= t && d->isHidden(b)) --b;
       
  1400             const QModelIndex top = d->model->index(t, c, parent);
       
  1401             const QModelIndex bottom = d->model->index(b, c, parent);
       
  1402             QRect rect(visualRect(top).topLeft(),
       
  1403                        visualRect(bottom).bottomRight());
       
  1404             selectionRegion += QRegion(rect);
       
  1405         }
       
  1406     }
       
  1407 
       
  1408     return selectionRegion;
       
  1409 }
       
  1410 
       
  1411 /*!
       
  1412   \reimp
       
  1413 */
       
  1414 QModelIndexList QListView::selectedIndexes() const
       
  1415 {
       
  1416     Q_D(const QListView);
       
  1417     if (!d->selectionModel)
       
  1418         return QModelIndexList();
       
  1419 
       
  1420     QModelIndexList viewSelected = d->selectionModel->selectedIndexes();
       
  1421     for (int i = 0; i < viewSelected.count(); ++i) {
       
  1422         const QModelIndex &index = viewSelected.at(i);
       
  1423         if (!isIndexHidden(index) && index.parent() == d->root && index.column() == d->column)
       
  1424             ++i;
       
  1425         else
       
  1426             viewSelected.removeAt(i);
       
  1427     }
       
  1428     return viewSelected;
       
  1429 }
       
  1430 
       
  1431 /*!
       
  1432     \internal
       
  1433 
       
  1434     Layout the items according to the flow and wrapping properties.
       
  1435 */
       
  1436 void QListView::doItemsLayout()
       
  1437 {
       
  1438     Q_D(QListView);
       
  1439     // showing the scroll bars will trigger a resize event,
       
  1440     // so we set the state to expanding to avoid
       
  1441     // triggering another layout
       
  1442     QAbstractItemView::State oldState = state();
       
  1443     setState(ExpandingState); 
       
  1444     if (d->model->columnCount(d->root) > 0) { // no columns means no contents
       
  1445         d->resetBatchStartRow();
       
  1446         if (layoutMode() == SinglePass)
       
  1447             d->doItemsLayout(d->model->rowCount(d->root)); // layout everything
       
  1448         else if (!d->batchLayoutTimer.isActive()) {
       
  1449             if (!d->doItemsLayout(d->batchSize)) // layout is done
       
  1450                 d->batchLayoutTimer.start(0, this); // do a new batch as fast as possible
       
  1451         }
       
  1452     }
       
  1453     QAbstractItemView::doItemsLayout();
       
  1454     setState(oldState);        // restoring the oldState
       
  1455 }
       
  1456 
       
  1457 /*!
       
  1458   \reimp
       
  1459 */
       
  1460 void QListView::updateGeometries()
       
  1461 {
       
  1462     Q_D(QListView);
       
  1463     if (d->model->rowCount(d->root) <= 0 || d->model->columnCount(d->root) <= 0) {
       
  1464         horizontalScrollBar()->setRange(0, 0);
       
  1465         verticalScrollBar()->setRange(0, 0);
       
  1466     } else {
       
  1467         QModelIndex index = d->model->index(0, d->column, d->root);
       
  1468         QStyleOptionViewItemV4 option = d->viewOptionsV4();
       
  1469         QSize step = d->itemSize(option, index);
       
  1470         d->commonListView->updateHorizontalScrollBar(step);
       
  1471         d->commonListView->updateVerticalScrollBar(step);
       
  1472     }
       
  1473 
       
  1474     QAbstractItemView::updateGeometries();
       
  1475 
       
  1476     // if the scroll bars are turned off, we resize the contents to the viewport
       
  1477     if (d->movement == Static && !d->isWrapping()) {
       
  1478         d->layoutChildren(); // we need the viewport size to be updated
       
  1479         if (d->flow == TopToBottom) {
       
  1480             if (horizontalScrollBarPolicy() == Qt::ScrollBarAlwaysOff) {
       
  1481                 d->setContentsSize(viewport()->width(), contentsSize().height());
       
  1482                 horizontalScrollBar()->setRange(0, 0); // we see all the contents anyway
       
  1483             }
       
  1484         } else { // LeftToRight
       
  1485             if (verticalScrollBarPolicy() == Qt::ScrollBarAlwaysOff) {
       
  1486                 d->setContentsSize(contentsSize().width(), viewport()->height());
       
  1487                 verticalScrollBar()->setRange(0, 0); // we see all the contents anyway
       
  1488             }
       
  1489         }
       
  1490     }
       
  1491 }
       
  1492 
       
  1493 /*!
       
  1494   \reimp
       
  1495 */
       
  1496 bool QListView::isIndexHidden(const QModelIndex &index) const
       
  1497 {
       
  1498     Q_D(const QListView);
       
  1499     return (d->isHidden(index.row())
       
  1500             && (index.parent() == d->root)
       
  1501             && index.column() == d->column);
       
  1502 }
       
  1503 
       
  1504 /*!
       
  1505     \property QListView::modelColumn
       
  1506     \brief the column in the model that is visible
       
  1507 
       
  1508     By default, this property contains 0, indicating that the first
       
  1509     column in the model will be shown.
       
  1510 */
       
  1511 void QListView::setModelColumn(int column)
       
  1512 {
       
  1513     Q_D(QListView);
       
  1514     if (column < 0 || column >= d->model->columnCount(d->root))
       
  1515         return;
       
  1516     d->column = column;
       
  1517     d->doDelayedItemsLayout();
       
  1518 }
       
  1519 
       
  1520 int QListView::modelColumn() const
       
  1521 {
       
  1522     Q_D(const QListView);
       
  1523     return d->column;
       
  1524 }
       
  1525 
       
  1526 /*!
       
  1527     \property QListView::uniformItemSizes
       
  1528     \brief whether all items in the listview have the same size
       
  1529     \since 4.1
       
  1530 
       
  1531     This property should only be set to true if it is guaranteed that all items
       
  1532     in the view have the same size. This enables the view to do some
       
  1533     optimizations for performance purposes.
       
  1534 
       
  1535     By default, this property is false.
       
  1536 */
       
  1537 void QListView::setUniformItemSizes(bool enable)
       
  1538 {
       
  1539     Q_D(QListView);
       
  1540     d->uniformItemSizes = enable;
       
  1541 }
       
  1542 
       
  1543 bool QListView::uniformItemSizes() const
       
  1544 {
       
  1545     Q_D(const QListView);
       
  1546     return d->uniformItemSizes;
       
  1547 }
       
  1548 
       
  1549 /*!
       
  1550     \property QListView::wordWrap
       
  1551     \brief the item text word-wrapping policy
       
  1552     \since 4.2
       
  1553 
       
  1554     If this property is true then the item text is wrapped where
       
  1555     necessary at word-breaks; otherwise it is not wrapped at all.
       
  1556     This property is false by default.
       
  1557 
       
  1558     Please note that even if wrapping is enabled, the cell will not be
       
  1559     expanded to make room for the text. It will print ellipsis for
       
  1560     text that cannot be shown, according to the view's
       
  1561     \l{QAbstractItemView::}{textElideMode}.
       
  1562 */
       
  1563 void QListView::setWordWrap(bool on)
       
  1564 {
       
  1565     Q_D(QListView);
       
  1566     if (d->wrapItemText == on)
       
  1567         return;
       
  1568     d->wrapItemText = on;
       
  1569     d->doDelayedItemsLayout();
       
  1570 }
       
  1571 
       
  1572 bool QListView::wordWrap() const
       
  1573 {
       
  1574     Q_D(const QListView);
       
  1575     return d->wrapItemText;
       
  1576 }
       
  1577 
       
  1578 /*!
       
  1579     \property QListView::selectionRectVisible
       
  1580     \brief if the selection rectangle should be visible
       
  1581     \since 4.3
       
  1582 
       
  1583     If this property is true then the selection rectangle is visible;
       
  1584     otherwise it will be hidden.
       
  1585 
       
  1586     \note The selection rectangle will only be visible if the selection mode
       
  1587     is in a mode where more than one item can be selected; i.e., it will not
       
  1588     draw a selection rectangle if the selection mode is
       
  1589     QAbstractItemView::SingleSelection.
       
  1590 
       
  1591     By default, this property is false.
       
  1592 */
       
  1593 void QListView::setSelectionRectVisible(bool show)
       
  1594 {
       
  1595     Q_D(QListView);
       
  1596     d->modeProperties |= uint(QListViewPrivate::SelectionRectVisible);
       
  1597     d->setSelectionRectVisible(show);
       
  1598 }
       
  1599 
       
  1600 bool QListView::isSelectionRectVisible() const
       
  1601 {
       
  1602     Q_D(const QListView);
       
  1603     return d->isSelectionRectVisible();
       
  1604 }
       
  1605 
       
  1606 /*!
       
  1607     \reimp
       
  1608 */
       
  1609 bool QListView::event(QEvent *e)
       
  1610 {
       
  1611     return QAbstractItemView::event(e);
       
  1612 }
       
  1613 
       
  1614 /*
       
  1615  * private object implementation
       
  1616  */
       
  1617 
       
  1618 QListViewPrivate::QListViewPrivate()
       
  1619     : QAbstractItemViewPrivate(),
       
  1620       commonListView(0),
       
  1621       wrap(false),
       
  1622       space(0),
       
  1623       flow(QListView::TopToBottom),
       
  1624       movement(QListView::Static),
       
  1625       resizeMode(QListView::Fixed),
       
  1626       layoutMode(QListView::SinglePass),
       
  1627       viewMode(QListView::ListMode),
       
  1628       modeProperties(0),
       
  1629       column(0),
       
  1630       uniformItemSizes(false),
       
  1631       batchSize(100),
       
  1632       showElasticBand(false)
       
  1633 {
       
  1634 }
       
  1635 
       
  1636 QListViewPrivate::~QListViewPrivate()
       
  1637 {
       
  1638     delete commonListView;
       
  1639 }
       
  1640 
       
  1641 void QListViewPrivate::clear()
       
  1642 {
       
  1643     // initialization of data structs
       
  1644     cachedItemSize = QSize();
       
  1645     commonListView->clear();
       
  1646 }
       
  1647 
       
  1648 void QListViewPrivate::prepareItemsLayout()
       
  1649 {
       
  1650     Q_Q(QListView);
       
  1651     clear();
       
  1652 
       
  1653     //take the size as if there were scrollbar in order to prevent scrollbar to blink
       
  1654     layoutBounds = QRect(QPoint(), q->maximumViewportSize());
       
  1655 
       
  1656     int frameAroundContents = 0;
       
  1657     if (q->style()->styleHint(QStyle::SH_ScrollView_FrameOnlyAroundContents))
       
  1658         frameAroundContents = q->style()->pixelMetric(QStyle::PM_DefaultFrameWidth) * 2;
       
  1659 
       
  1660     // maximumViewportSize() already takes scrollbar into account if policy is
       
  1661     // Qt::ScrollBarAlwaysOn but scrollbar extent must be deduced if policy
       
  1662     // is Qt::ScrollBarAsNeeded
       
  1663     int verticalMargin = vbarpolicy==Qt::ScrollBarAsNeeded
       
  1664         ? q->style()->pixelMetric(QStyle::PM_ScrollBarExtent, 0, vbar) + frameAroundContents
       
  1665         : 0;
       
  1666     int horizontalMargin =  hbarpolicy==Qt::ScrollBarAsNeeded
       
  1667         ? q->style()->pixelMetric(QStyle::PM_ScrollBarExtent, 0, hbar) + frameAroundContents
       
  1668         : 0;
       
  1669 
       
  1670     layoutBounds.adjust(0, 0, -verticalMargin, -horizontalMargin);
       
  1671 
       
  1672     int rowCount = model->columnCount(root) <= 0 ? 0 : model->rowCount(root);
       
  1673     commonListView->setRowCount(rowCount);
       
  1674 }
       
  1675 
       
  1676 /*!
       
  1677   \internal
       
  1678 */
       
  1679 bool QListViewPrivate::doItemsLayout(int delta)
       
  1680 {
       
  1681     int max = model->rowCount(root) - 1;
       
  1682     int first = batchStartRow();
       
  1683     int last = qMin(first + delta - 1, max);
       
  1684 
       
  1685     if (first == 0) {
       
  1686         layoutChildren(); // make sure the viewport has the right size
       
  1687         prepareItemsLayout();
       
  1688     }
       
  1689 
       
  1690     if (max < 0 || last < first) {
       
  1691         return true; // nothing to do
       
  1692     }
       
  1693 
       
  1694     QListViewLayoutInfo info;
       
  1695     info.bounds = layoutBounds;
       
  1696     info.grid = gridSize();
       
  1697     info.spacing = (info.grid.isValid() ? 0 : spacing());
       
  1698     info.first = first;
       
  1699     info.last = last;
       
  1700     info.wrap = isWrapping();
       
  1701     info.flow = flow;
       
  1702     info.max = max;
       
  1703 
       
  1704     return commonListView->doBatchedItemLayout(info, max);
       
  1705 }
       
  1706 
       
  1707 QListViewItem QListViewPrivate::indexToListViewItem(const QModelIndex &index) const
       
  1708 {
       
  1709     if (!index.isValid() || isHidden(index.row()))
       
  1710         return QListViewItem();
       
  1711 
       
  1712     return commonListView->indexToListViewItem(index);
       
  1713 }
       
  1714 
       
  1715 QRect QListViewPrivate::mapToViewport(const QRect &rect, bool extend) const
       
  1716 {
       
  1717     Q_Q(const QListView);
       
  1718     if (!rect.isValid())
       
  1719         return rect;
       
  1720 
       
  1721     QRect result = extend ? commonListView->mapToViewport(rect) : rect;
       
  1722     int dx = -q->horizontalOffset();
       
  1723     int dy = -q->verticalOffset();
       
  1724     return result.adjusted(dx, dy, dx, dy);
       
  1725 }
       
  1726 
       
  1727 QModelIndex QListViewPrivate::closestIndex(const QRect &target,
       
  1728                                            const QVector<QModelIndex> &candidates) const
       
  1729 {
       
  1730     int distance = 0;
       
  1731     int shortest = INT_MAX;
       
  1732     QModelIndex closest;
       
  1733     QVector<QModelIndex>::const_iterator it = candidates.begin();
       
  1734 
       
  1735     for (; it != candidates.end(); ++it) {
       
  1736         if (!(*it).isValid())
       
  1737             continue;
       
  1738 
       
  1739         const QRect indexRect = indexToListViewItem(*it).rect();
       
  1740 
       
  1741         //if the center x (or y) position of an item is included in the rect of the other item,
       
  1742         //we define the distance between them as the difference in x (or y) of their respective center.
       
  1743         // Otherwise, we use the nahattan  length between the 2 items
       
  1744         if ((target.center().x() >= indexRect.x() && target.center().x() < indexRect.right())
       
  1745             || (indexRect.center().x() >= target.x() && indexRect.center().x() < target.right())) {
       
  1746                 //one item's center is at the vertical of the other
       
  1747                 distance = qAbs(indexRect.center().y() - target.center().y());
       
  1748         } else if ((target.center().y() >= indexRect.y() && target.center().y() < indexRect.bottom())
       
  1749             || (indexRect.center().y() >= target.y() && indexRect.center().y() < target.bottom())) {
       
  1750                 //one item's center is at the vertical of the other
       
  1751                 distance = qAbs(indexRect.center().x() - target.center().x());
       
  1752         } else {
       
  1753             distance = (indexRect.center() - target.center()).manhattanLength();
       
  1754         }
       
  1755         if (distance < shortest) {
       
  1756             shortest = distance;
       
  1757             closest = *it;
       
  1758         }
       
  1759     }
       
  1760     return closest;
       
  1761 }
       
  1762 
       
  1763 QSize QListViewPrivate::itemSize(const QStyleOptionViewItem &option, const QModelIndex &index) const
       
  1764 {
       
  1765     if (!uniformItemSizes) {
       
  1766         const QAbstractItemDelegate *delegate = delegateForIndex(index);
       
  1767         return delegate ? delegate->sizeHint(option, index) : QSize();
       
  1768     }
       
  1769     if (!cachedItemSize.isValid()) { // the last item is probaly the largest, so we use its size
       
  1770         int row = model->rowCount(root) - 1;
       
  1771         QModelIndex sample = model->index(row, column, root);
       
  1772         const QAbstractItemDelegate *delegate = delegateForIndex(sample);
       
  1773         cachedItemSize = delegate ? delegate->sizeHint(option, sample) : QSize();
       
  1774     }
       
  1775     return cachedItemSize;
       
  1776 }
       
  1777 
       
  1778 QItemSelection QListViewPrivate::selection(const QRect &rect) const
       
  1779 {
       
  1780     QItemSelection selection;
       
  1781     QModelIndex tl, br;
       
  1782     const QVector<QModelIndex> intersectVector = intersectingSet(rect);
       
  1783     QVector<QModelIndex>::const_iterator it = intersectVector.begin();
       
  1784     for (; it != intersectVector.end(); ++it) {
       
  1785         if (!tl.isValid() && !br.isValid()) {
       
  1786             tl = br = *it;
       
  1787         } else if ((*it).row() == (tl.row() - 1)) {
       
  1788             tl = *it; // expand current range
       
  1789         } else if ((*it).row() == (br.row() + 1)) {
       
  1790             br = (*it); // expand current range
       
  1791         } else {
       
  1792             selection.select(tl, br); // select current range
       
  1793             tl = br = *it; // start new range
       
  1794         }
       
  1795     }
       
  1796 
       
  1797     if (tl.isValid() && br.isValid())
       
  1798         selection.select(tl, br);
       
  1799     else if (tl.isValid())
       
  1800         selection.select(tl, tl);
       
  1801     else if (br.isValid())
       
  1802         selection.select(br, br);
       
  1803 
       
  1804     return selection;
       
  1805 }
       
  1806 
       
  1807 /*
       
  1808  * Common ListView Implementation
       
  1809 */
       
  1810 
       
  1811 void QCommonListViewBase::appendHiddenRow(int row)
       
  1812 {
       
  1813     dd->hiddenRows.append(dd->model->index(row, 0, qq->rootIndex()));
       
  1814 }
       
  1815 
       
  1816 void QCommonListViewBase::removeHiddenRow(int row)
       
  1817 {
       
  1818     dd->hiddenRows.remove(dd->hiddenRows.indexOf(dd->model->index(row, 0, qq->rootIndex())));
       
  1819 }
       
  1820 
       
  1821 void QCommonListViewBase::updateHorizontalScrollBar(const QSize &step)
       
  1822 {
       
  1823     horizontalScrollBar()->setSingleStep(step.width() + spacing());
       
  1824     horizontalScrollBar()->setPageStep(viewport()->width());
       
  1825     horizontalScrollBar()->setRange(0, contentsSize.width() - viewport()->width());
       
  1826 }
       
  1827 
       
  1828 void QCommonListViewBase::updateVerticalScrollBar(const QSize &step)
       
  1829 {
       
  1830     verticalScrollBar()->setSingleStep(step.height() + spacing());
       
  1831     verticalScrollBar()->setPageStep(viewport()->height());
       
  1832     verticalScrollBar()->setRange(0, contentsSize.height() - viewport()->height());
       
  1833 }
       
  1834 
       
  1835 void QCommonListViewBase::scrollContentsBy(int dx, int dy, bool /*scrollElasticBand*/)
       
  1836 {
       
  1837     dd->scrollContentsBy(isRightToLeft() ? -dx : dx, dy);
       
  1838 }
       
  1839 
       
  1840 int QCommonListViewBase::verticalScrollToValue(int /*index*/, QListView::ScrollHint hint,
       
  1841                                           bool above, bool below, const QRect &area, const QRect &rect) const
       
  1842 {
       
  1843     int verticalValue = verticalScrollBar()->value();
       
  1844     QRect adjusted = rect.adjusted(-spacing(), -spacing(), spacing(), spacing());
       
  1845     if (hint == QListView::PositionAtTop || above)
       
  1846         verticalValue += adjusted.top();
       
  1847     else if (hint == QListView::PositionAtBottom || below)
       
  1848         verticalValue += qMin(adjusted.top(), adjusted.bottom() - area.height() + 1);
       
  1849     else if (hint == QListView::PositionAtCenter)
       
  1850         verticalValue += adjusted.top() - ((area.height() - adjusted.height()) / 2);
       
  1851     return verticalValue;
       
  1852 }
       
  1853 
       
  1854 int QCommonListViewBase::horizontalOffset() const
       
  1855 {
       
  1856     return (isRightToLeft() ? horizontalScrollBar()->maximum() - horizontalScrollBar()->value() : horizontalScrollBar()->value());
       
  1857 }
       
  1858 
       
  1859 int QCommonListViewBase::horizontalScrollToValue(const int /*index*/, QListView::ScrollHint hint,
       
  1860                                             bool leftOf, bool rightOf, const QRect &area, const QRect &rect) const
       
  1861 {
       
  1862     int horizontalValue = horizontalScrollBar()->value();
       
  1863     if (isRightToLeft()) {
       
  1864         if (hint == QListView::PositionAtCenter) {
       
  1865             horizontalValue += ((area.width() - rect.width()) / 2) - rect.left();
       
  1866         } else {
       
  1867             if (leftOf)
       
  1868                 horizontalValue -= rect.left();
       
  1869             else if (rightOf)
       
  1870                 horizontalValue += qMin(rect.left(), area.width() - rect.right());
       
  1871         }
       
  1872     } else {
       
  1873         if (hint == QListView::PositionAtCenter) {
       
  1874             horizontalValue += rect.left() - ((area.width()- rect.width()) / 2);
       
  1875         } else {
       
  1876             if (leftOf)
       
  1877                 horizontalValue += rect.left();
       
  1878             else if (rightOf)
       
  1879                 horizontalValue += qMin(rect.left(), rect.right() - area.width());
       
  1880         }
       
  1881     }
       
  1882     return horizontalValue;
       
  1883 }
       
  1884 
       
  1885 /*
       
  1886  * ListMode ListView Implementation
       
  1887 */
       
  1888 
       
  1889 #ifndef QT_NO_DRAGANDDROP
       
  1890 void QListModeViewBase::paintDragDrop(QPainter *painter)
       
  1891 {
       
  1892     // FIXME: Until the we can provide a proper drop indicator
       
  1893     // in IconMode, it makes no sense to show it
       
  1894     dd->paintDropIndicator(painter);
       
  1895 }
       
  1896 #endif //QT_NO_DRAGANDDROP
       
  1897 
       
  1898 void QListModeViewBase::updateVerticalScrollBar(const QSize &step)
       
  1899 {
       
  1900     if (verticalScrollMode() == QAbstractItemView::ScrollPerItem
       
  1901         && ((flow() == QListView::TopToBottom && !isWrapping())
       
  1902         || (flow() == QListView::LeftToRight && isWrapping()))) {
       
  1903             const int steps = (flow() == QListView::TopToBottom ? scrollValueMap : segmentPositions).count() - 1;
       
  1904             if (steps > 0) {
       
  1905                 const int pageSteps = perItemScrollingPageSteps(viewport()->height(), contentsSize.height(), isWrapping());
       
  1906                 verticalScrollBar()->setSingleStep(1);
       
  1907                 verticalScrollBar()->setPageStep(pageSteps);
       
  1908                 verticalScrollBar()->setRange(0, steps - pageSteps);
       
  1909             } else {
       
  1910                 verticalScrollBar()->setRange(0, 0);
       
  1911             }
       
  1912             // } else if (vertical && d->isWrapping() && d->movement == Static) {
       
  1913             // ### wrapped scrolling in flow direction
       
  1914     } else {
       
  1915         QCommonListViewBase::updateVerticalScrollBar(step);
       
  1916     }
       
  1917 }
       
  1918 
       
  1919 void QListModeViewBase::updateHorizontalScrollBar(const QSize &step)
       
  1920 {
       
  1921     if (horizontalScrollMode() == QAbstractItemView::ScrollPerItem
       
  1922         && ((flow() == QListView::TopToBottom && isWrapping())
       
  1923         || (flow() == QListView::LeftToRight && !isWrapping()))) {
       
  1924             int steps = (flow() == QListView::TopToBottom ? segmentPositions : scrollValueMap).count() - 1;
       
  1925             if (steps > 0) {
       
  1926                 const int pageSteps = perItemScrollingPageSteps(viewport()->width(), contentsSize.width(), isWrapping());
       
  1927                 horizontalScrollBar()->setSingleStep(1);
       
  1928                 horizontalScrollBar()->setPageStep(pageSteps);
       
  1929                 horizontalScrollBar()->setRange(0, steps - pageSteps);
       
  1930             } else {
       
  1931                 horizontalScrollBar()->setRange(0, 0);
       
  1932             }
       
  1933     } else {
       
  1934         QCommonListViewBase::updateHorizontalScrollBar(step);
       
  1935     }
       
  1936 }
       
  1937 
       
  1938 int QListModeViewBase::verticalScrollToValue(int index, QListView::ScrollHint hint,
       
  1939                                           bool above, bool below, const QRect &area, const QRect &rect) const
       
  1940 {
       
  1941     if (verticalScrollMode() == QAbstractItemView::ScrollPerItem) {
       
  1942         int value;
       
  1943         if (scrollValueMap.isEmpty())
       
  1944             value = 0;
       
  1945         else
       
  1946             value = qBound(0, scrollValueMap.at(verticalScrollBar()->value()), flowPositions.count() - 1);
       
  1947         if (above)
       
  1948             hint = QListView::PositionAtTop;
       
  1949         else if (below)
       
  1950             hint = QListView::PositionAtBottom;
       
  1951         if (hint == QListView::EnsureVisible)
       
  1952             return value;
       
  1953 
       
  1954         return perItemScrollToValue(index, value, area.height(), hint, Qt::Vertical, isWrapping(), rect.height());
       
  1955     }
       
  1956 
       
  1957     return QCommonListViewBase::verticalScrollToValue(index, hint, above, below, area, rect);
       
  1958 }
       
  1959 
       
  1960 int QListModeViewBase::horizontalOffset() const
       
  1961 {
       
  1962     if (horizontalScrollMode() == QAbstractItemView::ScrollPerItem) {
       
  1963         if (isWrapping()) {
       
  1964             if (flow() == QListView::TopToBottom && !segmentPositions.isEmpty()) {
       
  1965                 const int max = segmentPositions.count() - 1;
       
  1966                 int currentValue = qBound(0, horizontalScrollBar()->value(), max);
       
  1967                 int position = segmentPositions.at(currentValue);
       
  1968                 int maximumValue = qBound(0, horizontalScrollBar()->maximum(), max);
       
  1969                 int maximum = segmentPositions.at(maximumValue);
       
  1970                 return (isRightToLeft() ? maximum - position : position);
       
  1971             }
       
  1972         } else if (flow() == QListView::LeftToRight && !flowPositions.isEmpty()) {
       
  1973             int position = flowPositions.at(scrollValueMap.at(horizontalScrollBar()->value()));
       
  1974             int maximum = flowPositions.at(scrollValueMap.at(horizontalScrollBar()->maximum()));
       
  1975             return (isRightToLeft() ? maximum - position : position);
       
  1976         }
       
  1977     }
       
  1978     return QCommonListViewBase::horizontalOffset();
       
  1979 }
       
  1980 
       
  1981 int QListModeViewBase::verticalOffset() const
       
  1982 {
       
  1983     if (verticalScrollMode() == QAbstractItemView::ScrollPerItem) {
       
  1984         if (isWrapping()) {
       
  1985             if (flow() == QListView::LeftToRight && !segmentPositions.isEmpty()) {
       
  1986                 int value = verticalScrollBar()->value();
       
  1987                 if (value >= segmentPositions.count())
       
  1988                     return 0;
       
  1989                 return segmentPositions.at(value);
       
  1990             }
       
  1991         } else if (flow() == QListView::TopToBottom && !flowPositions.isEmpty()) {
       
  1992             int value = verticalScrollBar()->value();
       
  1993             if (value > scrollValueMap.count())
       
  1994                 return 0;
       
  1995             return flowPositions.at(scrollValueMap.at(value)) - spacing();
       
  1996         }
       
  1997     }
       
  1998     return QCommonListViewBase::verticalOffset();
       
  1999 }
       
  2000 
       
  2001 int QListModeViewBase::horizontalScrollToValue(int index, QListView::ScrollHint hint,
       
  2002                                             bool leftOf, bool rightOf, const QRect &area, const QRect &rect) const
       
  2003 {
       
  2004     if (horizontalScrollMode() != QAbstractItemView::ScrollPerItem)
       
  2005         return QCommonListViewBase::horizontalScrollToValue(index, hint, leftOf, rightOf, area, rect);
       
  2006 
       
  2007     int value;
       
  2008     if (scrollValueMap.isEmpty())
       
  2009         value = 0;
       
  2010     else
       
  2011         value = qBound(0, scrollValueMap.at(horizontalScrollBar()->value()), flowPositions.count() - 1);
       
  2012     if (leftOf)
       
  2013         hint = QListView::PositionAtTop;
       
  2014     else if (rightOf)
       
  2015         hint = QListView::PositionAtBottom;
       
  2016     if (hint == QListView::EnsureVisible)
       
  2017         return value;
       
  2018 
       
  2019     return perItemScrollToValue(index, value, area.width(), hint, Qt::Horizontal, isWrapping(), rect.width());
       
  2020 }
       
  2021 
       
  2022 void QListModeViewBase::scrollContentsBy(int dx, int dy, bool scrollElasticBand)
       
  2023 {
       
  2024     // ### reorder this logic
       
  2025     const int verticalValue = verticalScrollBar()->value();
       
  2026     const int horizontalValue = horizontalScrollBar()->value();
       
  2027     const bool vertical = (verticalScrollMode() == QAbstractItemView::ScrollPerItem);
       
  2028     const bool horizontal = (horizontalScrollMode() == QAbstractItemView::ScrollPerItem);
       
  2029 
       
  2030     if (isWrapping()) {
       
  2031         if (segmentPositions.isEmpty())
       
  2032             return;
       
  2033         const int max = segmentPositions.count() - 1;
       
  2034         if (horizontal && flow() == QListView::TopToBottom && dx != 0) {
       
  2035             int currentValue = qBound(0, horizontalValue, max);
       
  2036             int previousValue = qBound(0, currentValue + dx, max);
       
  2037             int currentCoordinate = segmentPositions.at(currentValue);
       
  2038             int previousCoordinate = segmentPositions.at(previousValue);
       
  2039             dx = previousCoordinate - currentCoordinate;
       
  2040         } else if (vertical && flow() == QListView::LeftToRight && dy != 0) {
       
  2041             int currentValue = qBound(0, verticalValue, max);
       
  2042             int previousValue = qBound(0, currentValue + dy, max);
       
  2043             int currentCoordinate = segmentPositions.at(currentValue);
       
  2044             int previousCoordinate = segmentPositions.at(previousValue);
       
  2045             dy = previousCoordinate - currentCoordinate;
       
  2046         }
       
  2047     } else {
       
  2048         if (flowPositions.isEmpty())
       
  2049             return;
       
  2050         const int max = flowPositions.count() - 1;
       
  2051         if (vertical && flow() == QListView::TopToBottom && dy != 0) {
       
  2052             int currentValue = qBound(0, verticalValue, max);
       
  2053             int previousValue = qBound(0, currentValue + dy, max);
       
  2054             int currentCoordinate = flowPositions.at(scrollValueMap.at(currentValue));
       
  2055             int previousCoordinate = flowPositions.at(scrollValueMap.at(previousValue));
       
  2056             dy = previousCoordinate - currentCoordinate;
       
  2057         } else if (horizontal && flow() == QListView::LeftToRight && dx != 0) {
       
  2058             int currentValue = qBound(0, horizontalValue, max);
       
  2059             int previousValue = qBound(0, currentValue + dx, max);
       
  2060             int currentCoordinate = flowPositions.at(scrollValueMap.at(currentValue));
       
  2061             int previousCoordinate = flowPositions.at(scrollValueMap.at(previousValue));
       
  2062             dx = previousCoordinate - currentCoordinate;
       
  2063         }
       
  2064     }
       
  2065     QCommonListViewBase::scrollContentsBy(dx, dy, scrollElasticBand);
       
  2066 }
       
  2067 
       
  2068 bool QListModeViewBase::doBatchedItemLayout(const QListViewLayoutInfo &info, int max)
       
  2069 {
       
  2070     doStaticLayout(info);
       
  2071     if (batchStartRow > max) { // stop items layout
       
  2072         flowPositions.resize(flowPositions.count());
       
  2073         segmentPositions.resize(segmentPositions.count());
       
  2074         segmentStartRows.resize(segmentStartRows.count());
       
  2075         return true; // done
       
  2076     }
       
  2077     return false; // not done
       
  2078 }
       
  2079 
       
  2080 QListViewItem QListModeViewBase::indexToListViewItem(const QModelIndex &index) const
       
  2081 {
       
  2082     if (flowPositions.isEmpty()
       
  2083         || segmentPositions.isEmpty()
       
  2084         || index.row() >= flowPositions.count())
       
  2085         return QListViewItem();
       
  2086 
       
  2087     const int segment = qBinarySearch<int>(segmentStartRows, index.row(),
       
  2088                                            0, segmentStartRows.count() - 1);
       
  2089 
       
  2090 
       
  2091     QStyleOptionViewItemV4 options = viewOptions();
       
  2092     options.rect.setSize(contentsSize);
       
  2093     QSize size = (uniformItemSizes() && cachedItemSize().isValid())
       
  2094                  ? cachedItemSize() : itemSize(options, index);
       
  2095 
       
  2096     QPoint pos;
       
  2097     if (flow() == QListView::LeftToRight) {
       
  2098         pos.setX(flowPositions.at(index.row()));
       
  2099         pos.setY(segmentPositions.at(segment));
       
  2100     } else { // TopToBottom
       
  2101         pos.setY(flowPositions.at(index.row()));
       
  2102         pos.setX(segmentPositions.at(segment));
       
  2103         if (isWrapping()) { // make the items as wide as the segment
       
  2104             int right = (segment + 1 >= segmentPositions.count()
       
  2105                      ? contentsSize.width()
       
  2106                      : segmentPositions.at(segment + 1));
       
  2107             size.setWidth(right - pos.x());
       
  2108         } else { // make the items as wide as the viewport
       
  2109             size.setWidth(qMax(size.width(), viewport()->width()));
       
  2110         }
       
  2111     }
       
  2112 
       
  2113     return QListViewItem(QRect(pos, size), index.row());
       
  2114 }
       
  2115 
       
  2116 QPoint QListModeViewBase::initStaticLayout(const QListViewLayoutInfo &info)
       
  2117 {
       
  2118     int x, y;
       
  2119     if (info.first == 0) {
       
  2120         flowPositions.clear();
       
  2121         segmentPositions.clear();
       
  2122         segmentStartRows.clear();
       
  2123         segmentExtents.clear();
       
  2124         scrollValueMap.clear();
       
  2125         x = info.bounds.left() + info.spacing;
       
  2126         y = info.bounds.top() + info.spacing;
       
  2127         segmentPositions.append(info.flow == QListView::LeftToRight ? y : x);
       
  2128         segmentStartRows.append(0);
       
  2129     } else if (info.wrap) {
       
  2130         if (info.flow == QListView::LeftToRight) {
       
  2131             x = batchSavedPosition;
       
  2132             y = segmentPositions.last();
       
  2133         } else { // flow == QListView::TopToBottom
       
  2134             x = segmentPositions.last();
       
  2135             y = batchSavedPosition;
       
  2136         }
       
  2137     } else { // not first and not wrap
       
  2138         if (info.flow == QListView::LeftToRight) {
       
  2139             x = batchSavedPosition;
       
  2140             y = info.bounds.top() + info.spacing;
       
  2141         } else { // flow == QListView::TopToBottom
       
  2142             x = info.bounds.left() + info.spacing;
       
  2143             y = batchSavedPosition;
       
  2144         }
       
  2145     }
       
  2146     return QPoint(x, y);
       
  2147 }
       
  2148 
       
  2149 /*!
       
  2150   \internal
       
  2151 */
       
  2152 void QListModeViewBase::doStaticLayout(const QListViewLayoutInfo &info)
       
  2153 {
       
  2154     const bool useItemSize = !info.grid.isValid();
       
  2155     const QPoint topLeft = initStaticLayout(info);
       
  2156     QStyleOptionViewItemV4 option = viewOptions();
       
  2157     option.rect = info.bounds;
       
  2158 
       
  2159     // The static layout data structures are as follows:
       
  2160     // One vector contains the coordinate in the direction of layout flow.
       
  2161     // Another vector contains the coordinates of the segments.
       
  2162     // A third vector contains the index (model row) of the first item
       
  2163     // of each segment.
       
  2164 
       
  2165     int segStartPosition;
       
  2166     int segEndPosition;
       
  2167     int deltaFlowPosition;
       
  2168     int deltaSegPosition;
       
  2169     int deltaSegHint;
       
  2170     int flowPosition;
       
  2171     int segPosition;
       
  2172 
       
  2173     if (info.flow == QListView::LeftToRight) {
       
  2174         segStartPosition = info.bounds.left();
       
  2175         segEndPosition = info.bounds.width();
       
  2176         flowPosition = topLeft.x();
       
  2177         segPosition = topLeft.y();
       
  2178         deltaFlowPosition = info.grid.width(); // dx
       
  2179         deltaSegPosition = useItemSize ? batchSavedDeltaSeg : info.grid.height(); // dy
       
  2180         deltaSegHint = info.grid.height();
       
  2181     } else { // flow == QListView::TopToBottom
       
  2182         segStartPosition = info.bounds.top();
       
  2183         segEndPosition = info.bounds.height();
       
  2184         flowPosition = topLeft.y();
       
  2185         segPosition = topLeft.x();
       
  2186         deltaFlowPosition = info.grid.height(); // dy
       
  2187         deltaSegPosition = useItemSize ? batchSavedDeltaSeg : info.grid.width(); // dx
       
  2188         deltaSegHint = info.grid.width();
       
  2189     }
       
  2190 
       
  2191     for (int row = info.first; row <= info.last; ++row) {
       
  2192         if (isHidden(row)) { // ###
       
  2193             flowPositions.append(flowPosition);
       
  2194         } else {
       
  2195             // if we are not using a grid, we need to find the deltas
       
  2196             if (useItemSize) {
       
  2197                 QSize hint = itemSize(option, modelIndex(row));
       
  2198                 if (info.flow == QListView::LeftToRight) {
       
  2199                     deltaFlowPosition = hint.width() + info.spacing;
       
  2200                     deltaSegHint = hint.height() + info.spacing;
       
  2201                 } else { // TopToBottom
       
  2202                     deltaFlowPosition = hint.height() + info.spacing;
       
  2203                     deltaSegHint = hint.width() + info.spacing;
       
  2204                 }
       
  2205             }
       
  2206             // create new segment
       
  2207             if (info.wrap && (flowPosition + deltaFlowPosition >= segEndPosition)) {
       
  2208                 segmentExtents.append(flowPosition);
       
  2209                 flowPosition = info.spacing + segStartPosition;
       
  2210                 segPosition += deltaSegPosition;
       
  2211                 segmentPositions.append(segPosition);
       
  2212                 segmentStartRows.append(row);
       
  2213                 deltaSegPosition = 0;
       
  2214             }
       
  2215             // save the flow position of this item
       
  2216             scrollValueMap.append(flowPositions.count());
       
  2217             flowPositions.append(flowPosition);
       
  2218             // prepare for the next item
       
  2219             deltaSegPosition = qMax(deltaSegHint, deltaSegPosition);
       
  2220             flowPosition += info.spacing + deltaFlowPosition;
       
  2221         }
       
  2222     }
       
  2223     // used when laying out next batch
       
  2224     batchSavedPosition = flowPosition;
       
  2225     batchSavedDeltaSeg = deltaSegPosition;
       
  2226     batchStartRow = info.last + 1;
       
  2227     if (info.last == info.max)
       
  2228         flowPosition -= info.spacing; // remove extra spacing
       
  2229     // set the contents size
       
  2230     QRect rect = info.bounds;
       
  2231     if (info.flow == QListView::LeftToRight) {
       
  2232         rect.setRight(segmentPositions.count() == 1 ? flowPosition : info.bounds.right());
       
  2233         rect.setBottom(segPosition + deltaSegPosition);
       
  2234     } else { // TopToBottom
       
  2235         rect.setRight(segPosition + deltaSegPosition);
       
  2236         rect.setBottom(segmentPositions.count() == 1 ? flowPosition : info.bounds.bottom());
       
  2237     }
       
  2238     contentsSize = QSize(rect.right(), rect.bottom());
       
  2239     // if it is the last batch, save the end of the segments
       
  2240     if (info.last == info.max) {
       
  2241         segmentExtents.append(flowPosition);
       
  2242         scrollValueMap.append(flowPositions.count());
       
  2243         flowPositions.append(flowPosition);
       
  2244         segmentPositions.append(info.wrap ? segPosition + deltaSegPosition : INT_MAX);
       
  2245     }
       
  2246     // if the new items are visble, update the viewport
       
  2247     QRect changedRect(topLeft, rect.bottomRight());
       
  2248     if (clipRect().intersects(changedRect))
       
  2249         viewport()->update();
       
  2250 }
       
  2251 
       
  2252 /*!
       
  2253   \internal
       
  2254   Finds the set of items intersecting with \a area.
       
  2255   In this function, itemsize is counted from topleft to the start of the next item.
       
  2256 */
       
  2257 QVector<QModelIndex> QListModeViewBase::intersectingSet(const QRect &area) const
       
  2258 {
       
  2259     QVector<QModelIndex> ret;
       
  2260     int segStartPosition;
       
  2261     int segEndPosition;
       
  2262     int flowStartPosition;
       
  2263     int flowEndPosition;
       
  2264     if (flow() == QListView::LeftToRight) {
       
  2265         segStartPosition = area.top();
       
  2266         segEndPosition = area.bottom();
       
  2267         flowStartPosition = area.left();
       
  2268         flowEndPosition = area.right();
       
  2269     } else {
       
  2270         segStartPosition = area.left();
       
  2271         segEndPosition = area.right();
       
  2272         flowStartPosition = area.top();
       
  2273         flowEndPosition = area.bottom();
       
  2274     }
       
  2275     if (segmentPositions.count() < 2 || flowPositions.isEmpty())
       
  2276         return ret;
       
  2277     // the last segment position is actually the edge of the last segment
       
  2278     const int segLast = segmentPositions.count() - 2;
       
  2279     int seg = qBinarySearch<int>(segmentPositions, segStartPosition, 0, segLast + 1);
       
  2280     for (; seg <= segLast && segmentPositions.at(seg) <= segEndPosition; ++seg) {
       
  2281         int first = segmentStartRows.at(seg);
       
  2282         int last = (seg < segLast ? segmentStartRows.at(seg + 1) : batchStartRow) - 1;
       
  2283         if (segmentExtents.at(seg) < flowStartPosition)
       
  2284             continue;
       
  2285         int row = qBinarySearch<int>(flowPositions, flowStartPosition, first, last);
       
  2286         for (; row <= last && flowPositions.at(row) <= flowEndPosition; ++row) {
       
  2287             if (isHidden(row))
       
  2288                 continue;
       
  2289             QModelIndex index = modelIndex(row);
       
  2290             if (index.isValid())
       
  2291                 ret += index;
       
  2292 #if 0 // for debugging
       
  2293             else
       
  2294                 qWarning("intersectingSet: row %d was invalid", row);
       
  2295 #endif
       
  2296         }
       
  2297     }
       
  2298     return ret;
       
  2299 }
       
  2300 
       
  2301 QRect QListModeViewBase::mapToViewport(const QRect &rect) const
       
  2302 {
       
  2303     if (isWrapping())
       
  2304         return rect;
       
  2305     // If the listview is in "listbox-mode", the items are as wide as the view.
       
  2306     // But we don't shrink the items.
       
  2307     QRect result = rect;
       
  2308     if (flow() == QListView::TopToBottom) {
       
  2309         result.setLeft(spacing());
       
  2310         result.setWidth(qMax(rect.width(), qMax(contentsSize.width(), viewport()->width()) - 2 * spacing()));
       
  2311     } else { // LeftToRight
       
  2312         result.setTop(spacing());
       
  2313         result.setHeight(qMax(rect.height(), qMax(contentsSize.height(), viewport()->height()) - 2 * spacing()));
       
  2314     }
       
  2315     return result;
       
  2316 }
       
  2317 
       
  2318 int QListModeViewBase::perItemScrollingPageSteps(int length, int bounds, bool wrap) const
       
  2319 {
       
  2320     QVector<int> positions;
       
  2321     if (wrap)
       
  2322         positions = segmentPositions;
       
  2323     else if (!flowPositions.isEmpty()) {
       
  2324         positions.reserve(scrollValueMap.size());
       
  2325         foreach (int itemShown, scrollValueMap)
       
  2326             positions.append(flowPositions.at(itemShown));
       
  2327     }
       
  2328     if (positions.isEmpty() || bounds <= length)
       
  2329         return positions.count();
       
  2330     if (uniformItemSizes()) {
       
  2331         for (int i = 1; i < positions.count(); ++i)
       
  2332             if (positions.at(i) > 0)
       
  2333                 return length / positions.at(i);
       
  2334         return 0; // all items had height 0
       
  2335     }
       
  2336     int pageSteps = 0;
       
  2337     int steps = positions.count() - 1;
       
  2338     int max = qMax(length, bounds);
       
  2339     int min = qMin(length, bounds);
       
  2340     int pos = min - (max - positions.last());
       
  2341 
       
  2342     while (pos >= 0 && steps > 0) {
       
  2343         pos -= (positions.at(steps) - positions.at(steps - 1));
       
  2344         if (pos >= 0) //this item should be visible
       
  2345             ++pageSteps;
       
  2346         --steps;
       
  2347     }
       
  2348 
       
  2349     // at this point we know that positions has at least one entry
       
  2350     return qMax(pageSteps, 1);
       
  2351 }
       
  2352 
       
  2353 int QListModeViewBase::perItemScrollToValue(int index, int scrollValue, int viewportSize,
       
  2354                                                  QAbstractItemView::ScrollHint hint,
       
  2355                                                  Qt::Orientation orientation, bool wrap, int itemExtent) const
       
  2356 {
       
  2357     if (index < 0)
       
  2358         return scrollValue;
       
  2359     if (!wrap) {
       
  2360         int topIndex = index;
       
  2361         const int bottomIndex = topIndex;
       
  2362         const int bottomCoordinate = flowPositions.at(index);
       
  2363 
       
  2364         while (topIndex > 0 &&
       
  2365             (bottomCoordinate - flowPositions.at(topIndex-1) + itemExtent) <= (viewportSize)) {
       
  2366             topIndex--;
       
  2367         }
       
  2368 
       
  2369         const int itemCount = bottomIndex - topIndex + 1;
       
  2370         switch (hint) {
       
  2371         case QAbstractItemView::PositionAtTop:
       
  2372             return index;
       
  2373         case QAbstractItemView::PositionAtBottom:
       
  2374             return index - itemCount + 1;
       
  2375         case QAbstractItemView::PositionAtCenter:
       
  2376             return index - (itemCount / 2);
       
  2377         default:
       
  2378             break;
       
  2379         }
       
  2380     } else { // wrapping
       
  2381         Qt::Orientation flowOrientation = (flow() == QListView::LeftToRight
       
  2382                                            ? Qt::Horizontal : Qt::Vertical);
       
  2383         if (flowOrientation == orientation) { // scrolling in the "flow" direction
       
  2384             // ### wrapped scrolling in the flow direction
       
  2385             return flowPositions.at(index); // ### always pixel based for now
       
  2386         } else if (!segmentStartRows.isEmpty()) { // we are scrolling in the "segment" direction
       
  2387             int segment = qBinarySearch<int>(segmentStartRows, index, 0, segmentStartRows.count() - 1);
       
  2388             int leftSegment = segment;
       
  2389             const int rightSegment = leftSegment;
       
  2390             const int bottomCoordinate = segmentPositions.at(segment);
       
  2391 
       
  2392             while (leftSegment > scrollValue &&
       
  2393                 (bottomCoordinate - segmentPositions.at(leftSegment-1) + itemExtent) <= (viewportSize)) {
       
  2394                     leftSegment--;
       
  2395             }
       
  2396 
       
  2397             const int segmentCount = rightSegment - leftSegment + 1;
       
  2398             switch (hint) {
       
  2399             case QAbstractItemView::PositionAtTop:
       
  2400                 return segment;
       
  2401             case QAbstractItemView::PositionAtBottom:
       
  2402                 return segment - segmentCount + 1;
       
  2403             case QAbstractItemView::PositionAtCenter:
       
  2404                 return segment - (segmentCount / 2);
       
  2405             default:
       
  2406                 break;
       
  2407             }
       
  2408         }
       
  2409     }
       
  2410     return scrollValue;
       
  2411 }
       
  2412 
       
  2413 void QListModeViewBase::clear()
       
  2414 {
       
  2415     flowPositions.clear();
       
  2416     segmentPositions.clear();
       
  2417     segmentStartRows.clear();
       
  2418     segmentExtents.clear();
       
  2419     batchSavedPosition = 0;
       
  2420     batchStartRow = 0;
       
  2421     batchSavedDeltaSeg = 0;
       
  2422 }
       
  2423 
       
  2424 /*
       
  2425  * IconMode ListView Implementation
       
  2426 */
       
  2427 
       
  2428 void QIconModeViewBase::setPositionForIndex(const QPoint &position, const QModelIndex &index)
       
  2429 {
       
  2430     if (index.row() >= items.count())
       
  2431         return;
       
  2432     const QSize oldContents = contentsSize;
       
  2433     qq->update(index); // update old position
       
  2434     moveItem(index.row(), position);
       
  2435     qq->update(index); // update new position
       
  2436 
       
  2437     if (contentsSize != oldContents)
       
  2438         dd->viewUpdateGeometries(); // update the scroll bars
       
  2439 }
       
  2440 
       
  2441 void QIconModeViewBase::appendHiddenRow(int row)
       
  2442 {
       
  2443     if (row >= 0 && row < items.count()) //remove item
       
  2444         tree.removeLeaf(items.at(row).rect(), row);
       
  2445     QCommonListViewBase::appendHiddenRow(row);
       
  2446 }
       
  2447 
       
  2448 void QIconModeViewBase::removeHiddenRow(int row)
       
  2449 {
       
  2450     QCommonListViewBase::removeHiddenRow(row);
       
  2451     if (row >= 0 && row < items.count()) //insert item
       
  2452         tree.insertLeaf(items.at(row).rect(), row);
       
  2453 }
       
  2454 
       
  2455 #ifndef QT_NO_DRAGANDDROP
       
  2456 void QIconModeViewBase::paintDragDrop(QPainter *painter)
       
  2457 {
       
  2458     if (!draggedItems.isEmpty() && viewport()->rect().contains(draggedItemsPos)) {
       
  2459         //we need to draw the items that arre dragged
       
  2460         painter->translate(draggedItemsDelta());
       
  2461         QStyleOptionViewItemV4 option = viewOptions();
       
  2462         option.state &= ~QStyle::State_MouseOver;
       
  2463         QVector<QModelIndex>::const_iterator it = draggedItems.begin();
       
  2464         QListViewItem item = indexToListViewItem(*it);
       
  2465         for (; it != draggedItems.end(); ++it) {
       
  2466             item = indexToListViewItem(*it);
       
  2467             option.rect = viewItemRect(item);
       
  2468             delegate(*it)->paint(painter, option, *it);
       
  2469         }
       
  2470     }
       
  2471 }
       
  2472 
       
  2473 bool QIconModeViewBase::filterStartDrag(Qt::DropActions supportedActions)
       
  2474 {
       
  2475     // This function does the same thing as in QAbstractItemView::startDrag(),
       
  2476     // plus adding viewitems to the draggedItems list.
       
  2477     // We need these items to draw the drag items
       
  2478     QModelIndexList indexes = dd->selectionModel->selectedIndexes();
       
  2479     if (indexes.count() > 0 ) {
       
  2480         if (viewport()->acceptDrops()) {
       
  2481             QModelIndexList::ConstIterator it = indexes.constBegin();
       
  2482             for (; it != indexes.constEnd(); ++it)
       
  2483                 if (dd->model->flags(*it) & Qt::ItemIsDragEnabled
       
  2484                     && (*it).column() == dd->column)
       
  2485                     draggedItems.push_back(*it);
       
  2486         }
       
  2487         QDrag *drag = new QDrag(qq);
       
  2488         drag->setMimeData(dd->model->mimeData(indexes));
       
  2489         Qt::DropAction action = drag->exec(supportedActions, Qt::CopyAction);
       
  2490         draggedItems.clear();
       
  2491         if (action == Qt::MoveAction)
       
  2492             dd->clearOrRemove();
       
  2493     }
       
  2494     return true;
       
  2495 }
       
  2496 
       
  2497 bool QIconModeViewBase::filterDropEvent(QDropEvent *e)
       
  2498 {
       
  2499     if (e->source() != qq)
       
  2500         return false;
       
  2501 
       
  2502     const QSize contents = contentsSize;
       
  2503     QPoint offset(horizontalOffset(), verticalOffset());
       
  2504     QPoint end = e->pos() + offset;
       
  2505     QPoint start = dd->pressedPosition;
       
  2506     QPoint delta = (dd->movement == QListView::Snap ? snapToGrid(end) - snapToGrid(start) : end - start);
       
  2507     QList<QModelIndex> indexes = dd->selectionModel->selectedIndexes();
       
  2508     for (int i = 0; i < indexes.count(); ++i) {
       
  2509         QModelIndex index = indexes.at(i);
       
  2510         QRect rect = dd->rectForIndex(index);
       
  2511         viewport()->update(dd->mapToViewport(rect, false));
       
  2512         QPoint dest = rect.topLeft() + delta;
       
  2513         if (qq->isRightToLeft())
       
  2514             dest.setX(dd->flipX(dest.x()) - rect.width());
       
  2515         moveItem(index.row(), dest);
       
  2516         qq->update(index);
       
  2517     }
       
  2518     dd->stopAutoScroll();
       
  2519     draggedItems.clear();
       
  2520     dd->emitIndexesMoved(indexes);
       
  2521     e->accept(); // we have handled the event
       
  2522     // if the size has not grown, we need to check if it has shrinked
       
  2523     if (contentsSize != contents) {
       
  2524         if ((contentsSize.width() <= contents.width()
       
  2525             || contentsSize.height() <= contents.height())) {
       
  2526                 updateContentsSize();
       
  2527         }
       
  2528         dd->viewUpdateGeometries();
       
  2529     }
       
  2530     return true;
       
  2531 }
       
  2532 
       
  2533 bool QIconModeViewBase::filterDragLeaveEvent(QDragLeaveEvent *e)
       
  2534 {
       
  2535     viewport()->update(draggedItemsRect()); // erase the area
       
  2536     draggedItemsPos = QPoint(-1, -1); // don't draw the dragged items
       
  2537     return QCommonListViewBase::filterDragLeaveEvent(e);
       
  2538 }
       
  2539 
       
  2540 bool QIconModeViewBase::filterDragMoveEvent(QDragMoveEvent *e)
       
  2541 {
       
  2542     if (e->source() != qq || !dd->canDecode(e))
       
  2543         return false;
       
  2544 
       
  2545     // ignore by default
       
  2546     e->ignore();
       
  2547     // get old dragged items rect
       
  2548     QRect itemsRect = this->itemsRect(draggedItems);
       
  2549     viewport()->update(itemsRect.translated(draggedItemsDelta()));
       
  2550     // update position
       
  2551     draggedItemsPos = e->pos();
       
  2552     // get new items rect
       
  2553     viewport()->update(itemsRect.translated(draggedItemsDelta()));
       
  2554     // set the item under the cursor to current
       
  2555     QModelIndex index;
       
  2556     if (movement() == QListView::Snap) {
       
  2557         QRect rect(snapToGrid(e->pos() + offset()), gridSize());
       
  2558         const QVector<QModelIndex> intersectVector = intersectingSet(rect);
       
  2559         index = intersectVector.count() > 0 ? intersectVector.last() : QModelIndex();
       
  2560     } else {
       
  2561         index = qq->indexAt(e->pos());
       
  2562     }
       
  2563     // check if we allow drops here
       
  2564     if (draggedItems.contains(index))
       
  2565         e->accept(); // allow changing item position
       
  2566     else if (dd->model->flags(index) & Qt::ItemIsDropEnabled)
       
  2567         e->accept(); // allow dropping on dropenabled items
       
  2568     else if (!index.isValid())
       
  2569         e->accept(); // allow dropping in empty areas
       
  2570 
       
  2571     // the event was treated. do autoscrolling
       
  2572     if (dd->shouldAutoScroll(e->pos()))
       
  2573         dd->startAutoScroll();
       
  2574     return true;
       
  2575 }
       
  2576 #endif // QT_NO_DRAGANDDROP
       
  2577 
       
  2578 void QIconModeViewBase::setRowCount(int rowCount)
       
  2579 {
       
  2580     tree.create(qMax(rowCount - hiddenCount(), 0));
       
  2581 }
       
  2582 
       
  2583 void QIconModeViewBase::scrollContentsBy(int dx, int dy, bool scrollElasticBand)
       
  2584 {
       
  2585     if (scrollElasticBand)
       
  2586         dd->scrollElasticBandBy(isRightToLeft() ? -dx : dx, dy);
       
  2587 
       
  2588     QCommonListViewBase::scrollContentsBy(dx, dy, scrollElasticBand);
       
  2589     if (!draggedItems.isEmpty())
       
  2590         viewport()->update(draggedItemsRect().translated(dx, dy));
       
  2591 }
       
  2592 
       
  2593 void QIconModeViewBase::dataChanged(const QModelIndex &topLeft, const QModelIndex &bottomRight)
       
  2594 {
       
  2595     if (column() >= topLeft.column() && column() <= bottomRight.column())  {
       
  2596         QStyleOptionViewItemV4 option = viewOptions();
       
  2597         int bottom = qMin(items.count(), bottomRight.row() + 1);
       
  2598         for (int row = topLeft.row(); row < bottom; ++row)
       
  2599             items[row].resize(itemSize(option, modelIndex(row)));
       
  2600     }
       
  2601 }
       
  2602 
       
  2603 bool QIconModeViewBase::doBatchedItemLayout(const QListViewLayoutInfo &info, int max)
       
  2604 {
       
  2605     if (info.last >= items.count()) {
       
  2606         //first we create the items
       
  2607         QStyleOptionViewItemV4 option = viewOptions();
       
  2608         for (int row = items.count(); row <= info.last; ++row) {
       
  2609             QSize size = itemSize(option, modelIndex(row));
       
  2610             QListViewItem item(QRect(0, 0, size.width(), size.height()), row); // default pos
       
  2611             items.append(item);
       
  2612         }
       
  2613         doDynamicLayout(info);
       
  2614     }
       
  2615     return (batchStartRow > max); // done
       
  2616 }
       
  2617 
       
  2618 QListViewItem QIconModeViewBase::indexToListViewItem(const QModelIndex &index) const
       
  2619 {
       
  2620     if (index.isValid() && index.row() < items.count())
       
  2621         return items.at(index.row());
       
  2622     return QListViewItem();
       
  2623 }
       
  2624 
       
  2625 void QIconModeViewBase::initBspTree(const QSize &contents)
       
  2626 {
       
  2627     // remove all items from the tree
       
  2628     int leafCount = tree.leafCount();
       
  2629     for (int l = 0; l < leafCount; ++l)
       
  2630         tree.leaf(l).clear();
       
  2631     // we have to get the bounding rect of the items before we can initialize the tree
       
  2632     QBspTree::Node::Type type = QBspTree::Node::Both; // 2D
       
  2633     // simple heuristics to get better bsp
       
  2634     if (contents.height() / contents.width() >= 3)
       
  2635         type = QBspTree::Node::HorizontalPlane;
       
  2636     else if (contents.width() / contents.height() >= 3)
       
  2637         type = QBspTree::Node::VerticalPlane;
       
  2638     // build tree for the bounding rect (not just the contents rect)
       
  2639     tree.init(QRect(0, 0, contents.width(), contents.height()), type);
       
  2640 }
       
  2641 
       
  2642 QPoint QIconModeViewBase::initDynamicLayout(const QListViewLayoutInfo &info)
       
  2643 {
       
  2644     int x, y;
       
  2645     if (info.first == 0) {
       
  2646         x = info.bounds.x() + info.spacing;
       
  2647         y = info.bounds.y() + info.spacing;
       
  2648         items.reserve(rowCount() - hiddenCount());
       
  2649     } else {
       
  2650         const QListViewItem item = items.at(info.first - 1);
       
  2651         x = item.x;
       
  2652         y = item.y;
       
  2653         if (info.flow == QListView::LeftToRight)
       
  2654             x += (info.grid.isValid() ? info.grid.width() : item.w) + info.spacing;
       
  2655         else
       
  2656             y += (info.grid.isValid() ? info.grid.height() : item.h) + info.spacing;
       
  2657     }
       
  2658     return QPoint(x, y);
       
  2659 }
       
  2660 
       
  2661 /*!
       
  2662   \internal
       
  2663 */
       
  2664 void QIconModeViewBase::doDynamicLayout(const QListViewLayoutInfo &info)
       
  2665 {
       
  2666     const bool useItemSize = !info.grid.isValid();
       
  2667     const QPoint topLeft = initDynamicLayout(info);
       
  2668 
       
  2669     int segStartPosition;
       
  2670     int segEndPosition;
       
  2671     int deltaFlowPosition;
       
  2672     int deltaSegPosition;
       
  2673     int deltaSegHint;
       
  2674     int flowPosition;
       
  2675     int segPosition;
       
  2676 
       
  2677     if (info.flow == QListView::LeftToRight) {
       
  2678         segStartPosition = info.bounds.left() + info.spacing;
       
  2679         segEndPosition = info.bounds.right();
       
  2680         deltaFlowPosition = info.grid.width(); // dx
       
  2681         deltaSegPosition = (useItemSize ? batchSavedDeltaSeg : info.grid.height()); // dy
       
  2682         deltaSegHint = info.grid.height();
       
  2683         flowPosition = topLeft.x();
       
  2684         segPosition = topLeft.y();
       
  2685     } else { // flow == QListView::TopToBottom
       
  2686         segStartPosition = info.bounds.top() + info.spacing;
       
  2687         segEndPosition = info.bounds.bottom();
       
  2688         deltaFlowPosition = info.grid.height(); // dy
       
  2689         deltaSegPosition = (useItemSize ? batchSavedDeltaSeg : info.grid.width()); // dx
       
  2690         deltaSegHint = info.grid.width();
       
  2691         flowPosition = topLeft.y();
       
  2692         segPosition = topLeft.x();
       
  2693     }
       
  2694 
       
  2695     if (moved.count() != items.count())
       
  2696         moved.resize(items.count());
       
  2697 
       
  2698     QRect rect(QPoint(), topLeft);
       
  2699     QListViewItem *item = 0;
       
  2700     for (int row = info.first; row <= info.last; ++row) {
       
  2701         item = &items[row];
       
  2702         if (isHidden(row)) {
       
  2703             item->invalidate();
       
  2704         } else {
       
  2705             // if we are not using a grid, we need to find the deltas
       
  2706             if (useItemSize) {
       
  2707                 if (info.flow == QListView::LeftToRight)
       
  2708                     deltaFlowPosition = item->w + info.spacing;
       
  2709                 else
       
  2710                     deltaFlowPosition = item->h + info.spacing;
       
  2711             } else {
       
  2712                 item->w = qMin<int>(info.grid.width(), item->w);
       
  2713                 item->h = qMin<int>(info.grid.height(), item->h);
       
  2714             }
       
  2715 
       
  2716             // create new segment
       
  2717             if (info.wrap
       
  2718                 && flowPosition + deltaFlowPosition > segEndPosition
       
  2719                 && flowPosition > segStartPosition) {
       
  2720                 flowPosition = segStartPosition;
       
  2721                 segPosition += deltaSegPosition;
       
  2722                 if (useItemSize)
       
  2723                     deltaSegPosition = 0;
       
  2724             }
       
  2725             // We must delay calculation of the seg adjustment, as this item
       
  2726             // may have caused a wrap to occur
       
  2727             if (useItemSize) {
       
  2728                 if (info.flow == QListView::LeftToRight)
       
  2729                     deltaSegHint = item->h + info.spacing;
       
  2730                 else
       
  2731                     deltaSegHint = item->w + info.spacing;
       
  2732                 deltaSegPosition = qMax(deltaSegPosition, deltaSegHint);
       
  2733             }
       
  2734 
       
  2735             // set the position of the item
       
  2736             // ### idealy we should have some sort of alignment hint for the item
       
  2737             // ### (normally that would be a point between the icon and the text)
       
  2738             if (!moved.testBit(row)) {
       
  2739                 if (info.flow == QListView::LeftToRight) {
       
  2740                     if (useItemSize) {
       
  2741                         item->x = flowPosition;
       
  2742                         item->y = segPosition;
       
  2743                     } else { // use grid
       
  2744                         item->x = flowPosition + ((deltaFlowPosition - item->w) / 2);
       
  2745                         item->y = segPosition;
       
  2746                     }
       
  2747                 } else { // TopToBottom
       
  2748                     if (useItemSize) {
       
  2749                         item->y = flowPosition;
       
  2750                         item->x = segPosition;
       
  2751                     } else { // use grid
       
  2752                         item->y = flowPosition + ((deltaFlowPosition - item->h) / 2);
       
  2753                         item->x = segPosition;
       
  2754                     }
       
  2755                 }
       
  2756             }
       
  2757 
       
  2758             // let the contents contain the new item
       
  2759             if (useItemSize)
       
  2760                 rect |= item->rect();
       
  2761             else if (info.flow == QListView::LeftToRight)
       
  2762                 rect |= QRect(flowPosition, segPosition, deltaFlowPosition, deltaSegPosition);
       
  2763             else // flow == TopToBottom
       
  2764                 rect |= QRect(segPosition, flowPosition, deltaSegPosition, deltaFlowPosition);
       
  2765 
       
  2766             // prepare for next item
       
  2767             flowPosition += deltaFlowPosition; // current position + item width + gap
       
  2768         }
       
  2769     }
       
  2770     batchSavedDeltaSeg = deltaSegPosition;
       
  2771     batchStartRow = info.last + 1;
       
  2772     bool done = (info.last >= rowCount() - 1);
       
  2773     // resize the content area
       
  2774     if (done || !info.bounds.contains(item->rect()))
       
  2775         contentsSize = QSize(rect.width(), rect.height());
       
  2776     // resize tree
       
  2777     int insertFrom = info.first;
       
  2778     if (done || info.first == 0) {
       
  2779         initBspTree(rect.size());
       
  2780         insertFrom = 0;
       
  2781     }
       
  2782     // insert items in tree
       
  2783     for (int row = insertFrom; row <= info.last; ++row)
       
  2784         tree.insertLeaf(items.at(row).rect(), row);
       
  2785     // if the new items are visble, update the viewport
       
  2786     QRect changedRect(topLeft, rect.bottomRight());
       
  2787     if (clipRect().intersects(changedRect))
       
  2788         viewport()->update();
       
  2789 }
       
  2790 
       
  2791 QVector<QModelIndex> QIconModeViewBase::intersectingSet(const QRect &area) const
       
  2792 {
       
  2793     QIconModeViewBase *that = const_cast<QIconModeViewBase*>(this);
       
  2794     QBspTree::Data data(static_cast<void*>(that));
       
  2795     QVector<QModelIndex> res;
       
  2796     that->interSectingVector = &res;
       
  2797     that->tree.climbTree(area, &QIconModeViewBase::addLeaf, data);
       
  2798     that->interSectingVector = 0;
       
  2799     return res;
       
  2800 }
       
  2801 
       
  2802 QRect QIconModeViewBase::itemsRect(const QVector<QModelIndex> &indexes) const
       
  2803 {
       
  2804     QVector<QModelIndex>::const_iterator it = indexes.begin();
       
  2805     QListViewItem item = indexToListViewItem(*it);
       
  2806     QRect rect(item.x, item.y, item.w, item.h);
       
  2807     for (; it != indexes.end(); ++it) {
       
  2808         item = indexToListViewItem(*it);
       
  2809         rect |= viewItemRect(item);
       
  2810     }
       
  2811     return rect;
       
  2812 }
       
  2813 
       
  2814 int QIconModeViewBase::itemIndex(const QListViewItem &item) const
       
  2815 {
       
  2816     if (!item.isValid())
       
  2817         return -1;
       
  2818     int i = item.indexHint;
       
  2819     if (i < items.count()) {
       
  2820         if (items.at(i) == item)
       
  2821             return i;
       
  2822     } else {
       
  2823         i = items.count() - 1;
       
  2824     }
       
  2825 
       
  2826     int j = i;
       
  2827     int c = items.count();
       
  2828     bool a = true;
       
  2829     bool b = true;
       
  2830 
       
  2831     while (a || b) {
       
  2832         if (a) {
       
  2833             if (items.at(i) == item) {
       
  2834                 items.at(i).indexHint = i;
       
  2835                 return i;
       
  2836             }
       
  2837             a = ++i < c;
       
  2838         }
       
  2839         if (b) {
       
  2840             if (items.at(j) == item) {
       
  2841                 items.at(j).indexHint = j;
       
  2842                 return j;
       
  2843             }
       
  2844             b = --j > -1;
       
  2845         }
       
  2846     }
       
  2847     return -1;
       
  2848 }
       
  2849 
       
  2850 void QIconModeViewBase::addLeaf(QVector<int> &leaf, const QRect &area,
       
  2851                                    uint visited, QBspTree::Data data)
       
  2852 {
       
  2853     QListViewItem *vi;
       
  2854     QIconModeViewBase *_this = static_cast<QIconModeViewBase *>(data.ptr);
       
  2855     for (int i = 0; i < leaf.count(); ++i) {
       
  2856         int idx = leaf.at(i);
       
  2857         if (idx < 0 || idx >= _this->items.count())
       
  2858             continue;
       
  2859         vi = &_this->items[idx];
       
  2860         Q_ASSERT(vi);
       
  2861         if (vi->isValid() && vi->rect().intersects(area) && vi->visited != visited) {
       
  2862             QModelIndex index  = _this->dd->listViewItemToIndex(*vi);
       
  2863             Q_ASSERT(index.isValid());
       
  2864             _this->interSectingVector->append(index);
       
  2865             vi->visited = visited;
       
  2866         }
       
  2867     }
       
  2868 }
       
  2869 
       
  2870 void QIconModeViewBase::moveItem(int index, const QPoint &dest)
       
  2871 {
       
  2872     // does not impact on the bintree itself or the contents rect
       
  2873     QListViewItem *item = &items[index];
       
  2874     QRect rect = item->rect();
       
  2875 
       
  2876     // move the item without removing it from the tree
       
  2877     tree.removeLeaf(rect, index);
       
  2878     item->move(dest);
       
  2879     tree.insertLeaf(QRect(dest, rect.size()), index);
       
  2880 
       
  2881     // resize the contents area
       
  2882     contentsSize = (QRect(QPoint(0, 0), contentsSize)|QRect(dest, rect.size())).size();
       
  2883 
       
  2884     // mark the item as moved
       
  2885     if (moved.count() != items.count())
       
  2886         moved.resize(items.count());
       
  2887     moved.setBit(index, true);
       
  2888 }
       
  2889 
       
  2890 QPoint QIconModeViewBase::snapToGrid(const QPoint &pos) const
       
  2891 {
       
  2892     int x = pos.x() - (pos.x() % gridSize().width());
       
  2893     int y = pos.y() - (pos.y() % gridSize().height());
       
  2894     return QPoint(x, y);
       
  2895 }
       
  2896 
       
  2897 QPoint QIconModeViewBase::draggedItemsDelta() const
       
  2898 {
       
  2899     if (movement() == QListView::Snap) {
       
  2900         QPoint snapdelta = QPoint((offset().x() % gridSize().width()),
       
  2901                                   (offset().y() % gridSize().height()));
       
  2902         return snapToGrid(draggedItemsPos + snapdelta) - snapToGrid(pressedPosition()) - snapdelta;
       
  2903     }
       
  2904     return draggedItemsPos - pressedPosition();
       
  2905 }
       
  2906 
       
  2907 QRect QIconModeViewBase::draggedItemsRect() const
       
  2908 {
       
  2909     QRect rect = itemsRect(draggedItems);
       
  2910     rect.translate(draggedItemsDelta());
       
  2911     return rect;
       
  2912 }
       
  2913 
       
  2914 void QListViewPrivate::scrollElasticBandBy(int dx, int dy)
       
  2915 {
       
  2916     if (dx > 0) // right
       
  2917         elasticBand.moveRight(elasticBand.right() + dx);
       
  2918     else if (dx < 0) // left
       
  2919         elasticBand.moveLeft(elasticBand.left() - dx);
       
  2920     if (dy > 0) // down
       
  2921         elasticBand.moveBottom(elasticBand.bottom() + dy);
       
  2922     else if (dy < 0) // up
       
  2923         elasticBand.moveTop(elasticBand.top() - dy);
       
  2924 }
       
  2925 
       
  2926 void QIconModeViewBase::clear()
       
  2927 {
       
  2928     tree.destroy();
       
  2929     items.clear();
       
  2930     moved.clear();
       
  2931     batchStartRow = 0;
       
  2932     batchSavedDeltaSeg = 0;
       
  2933 }
       
  2934 
       
  2935 void QIconModeViewBase::updateContentsSize()
       
  2936 {
       
  2937     QRect bounding;
       
  2938     for (int i = 0; i < items.count(); ++i)
       
  2939         bounding |= items.at(i).rect();
       
  2940     contentsSize = bounding.size();
       
  2941 }
       
  2942 
       
  2943 /*!
       
  2944   \reimp
       
  2945 */
       
  2946 void QListView::currentChanged(const QModelIndex &current, const QModelIndex &previous)
       
  2947 {
       
  2948 #ifndef QT_NO_ACCESSIBILITY
       
  2949     if (QAccessible::isActive()) {
       
  2950         if (current.isValid()) {
       
  2951             int entry = visualIndex(current) + 1;
       
  2952             QAccessible::updateAccessibility(viewport(), entry, QAccessible::Focus);
       
  2953         }
       
  2954     }
       
  2955 #endif
       
  2956     QAbstractItemView::currentChanged(current, previous);
       
  2957 }
       
  2958 
       
  2959 /*!
       
  2960   \reimp
       
  2961 */
       
  2962 void QListView::selectionChanged(const QItemSelection &selected,
       
  2963                                  const QItemSelection &deselected)
       
  2964 {
       
  2965 #ifndef QT_NO_ACCESSIBILITY
       
  2966     if (QAccessible::isActive()) {
       
  2967         // ### does not work properly for selection ranges.
       
  2968         QModelIndex sel = selected.indexes().value(0);
       
  2969         if (sel.isValid()) {
       
  2970             int entry = visualIndex(sel) + 1;
       
  2971             QAccessible::updateAccessibility(viewport(), entry, QAccessible::Selection);
       
  2972         }
       
  2973         QModelIndex desel = deselected.indexes().value(0);
       
  2974         if (desel.isValid()) {
       
  2975             int entry = visualIndex(desel) + 1;
       
  2976             QAccessible::updateAccessibility(viewport(), entry, QAccessible::SelectionRemove);
       
  2977         }
       
  2978     }
       
  2979 #endif
       
  2980     QAbstractItemView::selectionChanged(selected, deselected);
       
  2981 }
       
  2982 
       
  2983 int QListView::visualIndex(const QModelIndex &index) const
       
  2984 {
       
  2985     Q_D(const QListView);
       
  2986     d->executePostedLayout();
       
  2987     QListViewItem itm = d->indexToListViewItem(index);
       
  2988     return d->commonListView->itemIndex(itm);
       
  2989 }
       
  2990 
       
  2991 QT_END_NAMESPACE
       
  2992 
       
  2993 #endif // QT_NO_LISTVIEW