src/gui/itemviews/qitemselectionmodel.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 "qitemselectionmodel.h"
       
    43 #include <private/qitemselectionmodel_p.h>
       
    44 #include <qdebug.h>
       
    45 
       
    46 #ifndef QT_NO_ITEMVIEWS
       
    47 
       
    48 QT_BEGIN_NAMESPACE
       
    49 
       
    50 /*!
       
    51     \class QItemSelectionRange
       
    52 
       
    53     \brief The QItemSelectionRange class manages information about a
       
    54     range of selected items in a model.
       
    55 
       
    56     \ingroup model-view
       
    57 
       
    58     A QItemSelectionRange contains information about a range of
       
    59     selected items in a model. A range of items is a contiguous array
       
    60     of model items, extending to cover a number of adjacent rows and
       
    61     columns with a common parent item; this can be visualized as a
       
    62     two-dimensional block of cells in a table. A selection range has a
       
    63     top(), left() a bottom(), right() and a parent().
       
    64 
       
    65     The QItemSelectionRange class is one of the \l{Model/View Classes}
       
    66     and is part of Qt's \l{Model/View Programming}{model/view framework}.
       
    67 
       
    68     The model items contained in the selection range can be obtained
       
    69     using the indexes() function. Use QItemSelectionModel::selectedIndexes()
       
    70     to get a list of all selected items for a view.
       
    71 
       
    72     You can determine whether a given model item lies within a
       
    73     particular range by using the contains() function. Ranges can also
       
    74     be compared using the overloaded operators for equality and
       
    75     inequality, and the intersects() function allows you to determine
       
    76     whether two ranges overlap.
       
    77 
       
    78     \sa {Model/View Programming}, QAbstractItemModel, QItemSelection,
       
    79         QItemSelectionModel
       
    80 */
       
    81 
       
    82 /*!
       
    83     \fn QItemSelectionRange::QItemSelectionRange()
       
    84 
       
    85     Constructs an empty selection range.
       
    86 */
       
    87 
       
    88 /*!
       
    89     \fn QItemSelectionRange::QItemSelectionRange(const QItemSelectionRange &other)
       
    90 
       
    91     Copy constructor. Constructs a new selection range with the same contents
       
    92     as the \a other range given.
       
    93 
       
    94 */
       
    95 
       
    96 /*!
       
    97     \fn QItemSelectionRange::QItemSelectionRange(const QModelIndex &topLeft, const QModelIndex &bottomRight)
       
    98 
       
    99     Constructs a new selection range containing only the index specified
       
   100     by the \a topLeft and the index \a bottomRight.
       
   101 
       
   102 */
       
   103 
       
   104 /*!
       
   105     \fn QItemSelectionRange::QItemSelectionRange(const QModelIndex &index)
       
   106 
       
   107     Constructs a new selection range containing only the model item specified
       
   108     by the model index \a index.
       
   109 */
       
   110 
       
   111 /*!
       
   112     \fn int QItemSelectionRange::top() const
       
   113 
       
   114     Returns the row index corresponding to the uppermost selected row in the
       
   115     selection range.
       
   116 
       
   117 */
       
   118 
       
   119 /*!
       
   120     \fn int QItemSelectionRange::left() const
       
   121 
       
   122     Returns the column index corresponding to the leftmost selected column in the
       
   123     selection range.
       
   124 */
       
   125 
       
   126 /*!
       
   127     \fn int QItemSelectionRange::bottom() const
       
   128 
       
   129     Returns the row index corresponding to the lowermost selected row in the
       
   130     selection range.
       
   131 
       
   132 */
       
   133 
       
   134 /*!
       
   135     \fn int QItemSelectionRange::right() const
       
   136 
       
   137     Returns the column index corresponding to the rightmost selected column in
       
   138     the selection range.
       
   139 
       
   140 */
       
   141 
       
   142 /*!
       
   143     \fn int QItemSelectionRange::width() const
       
   144 
       
   145     Returns the number of selected columns in the selection range.
       
   146 
       
   147 */
       
   148 
       
   149 /*!
       
   150     \fn int QItemSelectionRange::height() const
       
   151 
       
   152     Returns the number of selected rows in the selection range.
       
   153 
       
   154 */
       
   155 
       
   156 /*!
       
   157     \fn const QAbstractItemModel *QItemSelectionRange::model() const
       
   158 
       
   159     Returns the model that the items in the selection range belong to.
       
   160 */
       
   161 
       
   162 /*!
       
   163     \fn QModelIndex QItemSelectionRange::topLeft() const
       
   164 
       
   165     Returns the index for the item located at the top-left corner of
       
   166     the selection range.
       
   167 
       
   168     \sa top(), left(), bottomRight()
       
   169 */
       
   170 
       
   171 /*!
       
   172     \fn QModelIndex QItemSelectionRange::bottomRight() const
       
   173 
       
   174     Returns the index for the item located at the bottom-right corner
       
   175     of the selection range.
       
   176 
       
   177     \sa bottom(), right(), topLeft()
       
   178 */
       
   179 
       
   180 /*!
       
   181     \fn QModelIndex QItemSelectionRange::parent() const
       
   182 
       
   183     Returns the parent model item index of the items in the selection range.
       
   184 
       
   185 */
       
   186 
       
   187 /*!
       
   188     \fn bool QItemSelectionRange::contains(const QModelIndex &index) const
       
   189 
       
   190     Returns true if the model item specified by the \a index lies within the
       
   191     range of selected items; otherwise returns false.
       
   192 */
       
   193 
       
   194 /*!
       
   195     \fn bool QItemSelectionRange::contains(int row, int column,
       
   196                                            const QModelIndex &parentIndex) const
       
   197     \overload
       
   198 
       
   199     Returns true if the model item specified by (\a row, \a column)
       
   200     and with \a parentIndex as the parent item lies within the range
       
   201     of selected items; otherwise returns false.
       
   202 */
       
   203 
       
   204 /*!
       
   205     \fn bool QItemSelectionRange::intersects(const QItemSelectionRange &other) const
       
   206 
       
   207     Returns true if this selection range intersects (overlaps with) the \a other
       
   208     range given; otherwise returns false.
       
   209 
       
   210 */
       
   211 bool QItemSelectionRange::intersects(const QItemSelectionRange &other) const
       
   212 {
       
   213     return (isValid() && other.isValid()
       
   214             && parent() == other.parent()
       
   215             && ((top() <= other.top() && bottom() >= other.top())
       
   216                 || (top() >= other.top() && top() <= other.bottom()))
       
   217             && ((left() <= other.left() && right() >= other.left())
       
   218                 || (left() >= other.left() && left() <= other.right())));
       
   219 }
       
   220 
       
   221 /*!
       
   222     \fn QItemSelectionRange QItemSelectionRange::intersect(const QItemSelectionRange &other) const
       
   223     \obsolete
       
   224 
       
   225     Use intersected(\a other) instead.
       
   226 */
       
   227 
       
   228 /*!
       
   229     \fn QItemSelectionRange QItemSelectionRange::intersected(const QItemSelectionRange &other) const
       
   230     \since 4.2
       
   231 
       
   232     Returns a new selection range containing only the items that are found in
       
   233     both the selection range and the \a other selection range.
       
   234 */
       
   235 
       
   236 QItemSelectionRange QItemSelectionRange::intersect(const QItemSelectionRange &other) const
       
   237 {
       
   238     if (model() == other.model() && parent() == other.parent()) {
       
   239         QModelIndex topLeft = model()->index(qMax(top(), other.top()),
       
   240                                              qMax(left(), other.left()),
       
   241                                              other.parent());
       
   242         QModelIndex bottomRight = model()->index(qMin(bottom(), other.bottom()),
       
   243                                                  qMin(right(), other.right()),
       
   244                                                  other.parent());
       
   245         return QItemSelectionRange(topLeft, bottomRight);
       
   246     }
       
   247     return QItemSelectionRange();
       
   248 }
       
   249 
       
   250 /*!
       
   251     \fn bool QItemSelectionRange::operator==(const QItemSelectionRange &other) const
       
   252 
       
   253     Returns true if the selection range is exactly the same as the \a other
       
   254     range given; otherwise returns false.
       
   255 
       
   256 */
       
   257 
       
   258 /*!
       
   259     \fn bool QItemSelectionRange::operator!=(const QItemSelectionRange &other) const
       
   260 
       
   261     Returns true if the selection range differs from the \a other range given;
       
   262     otherwise returns false.
       
   263 
       
   264 */
       
   265 
       
   266 /*!
       
   267     \fn bool QItemSelectionRange::isValid() const
       
   268 
       
   269     Returns true if the selection range is valid; otherwise returns false.
       
   270 
       
   271 */
       
   272 
       
   273 /*
       
   274   \internal
       
   275 
       
   276   utility function for getting the indexes from a range
       
   277   it avoid concatenating list and works on one
       
   278  */
       
   279 
       
   280 static void indexesFromRange(const QItemSelectionRange &range, QModelIndexList &result)
       
   281 {
       
   282     if (range.isValid() && range.model()) {
       
   283         for (int column = range.left(); column <= range.right(); ++column) {
       
   284             for (int row = range.top(); row <= range.bottom(); ++row) {
       
   285                 QModelIndex index = range.model()->index(row, column, range.parent());
       
   286                 Qt::ItemFlags flags = range.model()->flags(index);
       
   287                 if ((flags & Qt::ItemIsSelectable) && (flags & Qt::ItemIsEnabled))
       
   288                     result.append(index);
       
   289             }
       
   290         }
       
   291     }
       
   292 }
       
   293 
       
   294 /*!
       
   295     Returns the list of model index items stored in the selection.
       
   296 */
       
   297 
       
   298 QModelIndexList QItemSelectionRange::indexes() const
       
   299 {
       
   300     QModelIndexList result;
       
   301     indexesFromRange(*this, result);
       
   302     return result;
       
   303 }
       
   304 
       
   305 /*!
       
   306     \class QItemSelection
       
   307 
       
   308     \brief The QItemSelection class manages information about selected items in a model.
       
   309 
       
   310     \ingroup model-view
       
   311 
       
   312     A QItemSelection describes the items in a model that have been
       
   313     selected by the user. A QItemSelection is basically a list of
       
   314     selection ranges, see QItemSelectionRange. It provides functions for
       
   315     creating and manipulating selections, and selecting a range of items
       
   316     from a model.
       
   317 
       
   318     The QItemSelection class is one of the \l{Model/View Classes}
       
   319     and is part of Qt's \l{Model/View Programming}{model/view framework}.
       
   320 
       
   321     An item selection can be constructed and initialized to contain a
       
   322     range of items from an existing model. The following example constructs
       
   323     a selection that contains a range of items from the given \c model,
       
   324     beginning at the \c topLeft, and ending at the \c bottomRight.
       
   325 
       
   326     \snippet doc/src/snippets/code/src_gui_itemviews_qitemselectionmodel.cpp 0
       
   327 
       
   328     An empty item selection can be constructed, and later populated as
       
   329     required. So, if the model is going to be unavailable when we construct
       
   330     the item selection, we can rewrite the above code in the following way:
       
   331 
       
   332     \snippet doc/src/snippets/code/src_gui_itemviews_qitemselectionmodel.cpp 1
       
   333 
       
   334     QItemSelection saves memory, and avoids unnecessary work, by working with
       
   335     selection ranges rather than recording the model item index for each
       
   336     item in the selection. Generally, an instance of this class will contain
       
   337     a list of non-overlapping selection ranges.
       
   338 
       
   339     Use merge() to merge one item selection into another without making
       
   340     overlapping ranges. Use split() to split one selection range into
       
   341     smaller ranges based on a another selection range.
       
   342 
       
   343     \sa {Model/View Programming}, QItemSelectionModel
       
   344 */
       
   345 
       
   346 /*!
       
   347     \fn QItemSelection::QItemSelection()
       
   348 
       
   349     Constructs an empty selection.
       
   350 */
       
   351 
       
   352 /*!
       
   353     Constructs an item selection that extends from the top-left model item,
       
   354     specified by the \a topLeft index, to the bottom-right item, specified
       
   355     by \a bottomRight.
       
   356 */
       
   357 QItemSelection::QItemSelection(const QModelIndex &topLeft, const QModelIndex &bottomRight)
       
   358 {
       
   359     select(topLeft, bottomRight);
       
   360 }
       
   361 
       
   362 /*!
       
   363     Adds the items in the range that extends from the top-left model
       
   364     item, specified by the \a topLeft index, to the bottom-right item,
       
   365     specified by \a bottomRight to the list.
       
   366 
       
   367     \note \a topLeft and \a bottomRight must have the same parent.
       
   368 */
       
   369 void QItemSelection::select(const QModelIndex &topLeft, const QModelIndex &bottomRight)
       
   370 {
       
   371     if (!topLeft.isValid() || !bottomRight.isValid())
       
   372         return;
       
   373 
       
   374     if ((topLeft.model() != bottomRight.model())
       
   375         || topLeft.parent() != bottomRight.parent()) {
       
   376         qWarning("Can't select indexes from different model or with different parents");
       
   377         return;
       
   378     }
       
   379     if (topLeft.row() > bottomRight.row() || topLeft.column() > bottomRight.column()) {
       
   380         int top = qMin(topLeft.row(), bottomRight.row());
       
   381         int bottom = qMax(topLeft.row(), bottomRight.row());
       
   382         int left = qMin(topLeft.column(), bottomRight.column());
       
   383         int right = qMax(topLeft.column(), bottomRight.column());
       
   384         QModelIndex tl = topLeft.sibling(top, left);
       
   385         QModelIndex br = bottomRight.sibling(bottom, right);
       
   386         append(QItemSelectionRange(tl, br));
       
   387         return;
       
   388     }
       
   389     append(QItemSelectionRange(topLeft, bottomRight));
       
   390 }
       
   391 
       
   392 /*!
       
   393     Returns true if the selection contains the given \a index; otherwise
       
   394     returns false.
       
   395 */
       
   396 
       
   397 bool QItemSelection::contains(const QModelIndex &index) const
       
   398 {
       
   399     if (index.flags() & Qt::ItemIsSelectable) {
       
   400         QList<QItemSelectionRange>::const_iterator it = begin();
       
   401         for (; it != end(); ++it)
       
   402             if ((*it).contains(index))
       
   403                 return true;
       
   404     }
       
   405     return false;
       
   406 }
       
   407 
       
   408 /*!
       
   409     Returns a list of model indexes that correspond to the selected items.
       
   410 */
       
   411 
       
   412 QModelIndexList QItemSelection::indexes() const
       
   413 {
       
   414     QModelIndexList result;
       
   415     QList<QItemSelectionRange>::const_iterator it = begin();
       
   416     for (; it != end(); ++it)
       
   417         indexesFromRange(*it, result);
       
   418     return result;
       
   419 }
       
   420 
       
   421 /*!
       
   422     Merges the \a other selection with this QItemSelection using the
       
   423     \a command given. This method guarantees that no ranges are overlapping.
       
   424 
       
   425     Note that only QItemSelectionModel::Select,
       
   426     QItemSelectionModel::Deselect, and QItemSelectionModel::Toggle are
       
   427     supported.
       
   428 
       
   429     \sa split()
       
   430 */
       
   431 void QItemSelection::merge(const QItemSelection &other, QItemSelectionModel::SelectionFlags command)
       
   432 {
       
   433     if (other.isEmpty() ||
       
   434           !(command & QItemSelectionModel::Select ||
       
   435           command & QItemSelectionModel::Deselect ||
       
   436           command & QItemSelectionModel::Toggle))
       
   437         return;
       
   438 
       
   439     QItemSelection newSelection = other;
       
   440     // Collect intersections
       
   441     QItemSelection intersections;
       
   442     QItemSelection::iterator it = newSelection.begin();
       
   443     while (it != newSelection.end()) {
       
   444         if (!(*it).isValid()) {
       
   445             it = newSelection.erase(it);
       
   446             continue;
       
   447         }
       
   448         for (int t = 0; t < count(); ++t) {
       
   449             if ((*it).intersects(at(t)))
       
   450                 intersections.append(at(t).intersected(*it));
       
   451         }
       
   452         ++it;
       
   453     }
       
   454 
       
   455     //  Split the old (and new) ranges using the intersections
       
   456     for (int i = 0; i < intersections.count(); ++i) { // for each intersection
       
   457         for (int t = 0; t < count();) { // splitt each old range
       
   458             if (at(t).intersects(intersections.at(i))) {
       
   459                 split(at(t), intersections.at(i), this);
       
   460                 removeAt(t);
       
   461             } else {
       
   462                 ++t;
       
   463             }
       
   464         }
       
   465         // only split newSelection if Toggle is specified
       
   466         for (int n = 0; (command & QItemSelectionModel::Toggle) && n < newSelection.count();) {
       
   467             if (newSelection.at(n).intersects(intersections.at(i))) {
       
   468                 split(newSelection.at(n), intersections.at(i), &newSelection);
       
   469                 newSelection.removeAt(n);
       
   470             } else {
       
   471                 ++n;
       
   472             }
       
   473         }
       
   474     }
       
   475     // do not add newSelection for Deselect
       
   476     if (!(command & QItemSelectionModel::Deselect))
       
   477         operator+=(newSelection);
       
   478 }
       
   479 
       
   480 /*!
       
   481     Splits the selection \a range using the selection \a other range.
       
   482     Removes all items in \a other from \a range and puts the result in \a result.
       
   483     This can be compared with the semantics of the \e subtract operation of a set.
       
   484     \sa merge()
       
   485 */
       
   486 
       
   487 void QItemSelection::split(const QItemSelectionRange &range,
       
   488                            const QItemSelectionRange &other, QItemSelection *result)
       
   489 {
       
   490     if (range.parent() != other.parent())
       
   491         return;
       
   492 
       
   493     QModelIndex parent = other.parent();
       
   494     int top = range.top();
       
   495     int left = range.left();
       
   496     int bottom = range.bottom();
       
   497     int right = range.right();
       
   498     int other_top = other.top();
       
   499     int other_left = other.left();
       
   500     int other_bottom = other.bottom();
       
   501     int other_right = other.right();
       
   502     const QAbstractItemModel *model = range.model();
       
   503     Q_ASSERT(model);
       
   504     if (other_top > top) {
       
   505         QModelIndex tl = model->index(top, left, parent);
       
   506         QModelIndex br = model->index(other_top - 1, right, parent);
       
   507         result->append(QItemSelectionRange(tl, br));
       
   508         top = other_top;
       
   509     }
       
   510     if (other_bottom < bottom) {
       
   511         QModelIndex tl = model->index(other_bottom + 1, left, parent);
       
   512         QModelIndex br = model->index(bottom, right, parent);
       
   513         result->append(QItemSelectionRange(tl, br));
       
   514         bottom = other_bottom;
       
   515     }
       
   516     if (other_left > left) {
       
   517         QModelIndex tl = model->index(top, left, parent);
       
   518         QModelIndex br = model->index(bottom, other_left - 1, parent);
       
   519         result->append(QItemSelectionRange(tl, br));
       
   520         left = other_left;
       
   521     }
       
   522     if (other_right < right) {
       
   523         QModelIndex tl = model->index(top, other_right + 1, parent);
       
   524         QModelIndex br = model->index(bottom, right, parent);
       
   525         result->append(QItemSelectionRange(tl, br));
       
   526         right = other_right;
       
   527     }
       
   528 }
       
   529 
       
   530 /*!
       
   531     \internal
       
   532 
       
   533     returns a QItemSelection where all ranges have been expanded to:
       
   534     Rows: left: 0 and right: columnCount()-1
       
   535     Columns: top: 0 and bottom: rowCount()-1
       
   536 */
       
   537 
       
   538 QItemSelection QItemSelectionModelPrivate::expandSelection(const QItemSelection &selection,
       
   539                                                            QItemSelectionModel::SelectionFlags command) const
       
   540 {
       
   541     if (selection.isEmpty() && !((command & QItemSelectionModel::Rows) ||
       
   542                                  (command & QItemSelectionModel::Columns)))
       
   543         return selection;
       
   544 
       
   545     QItemSelection expanded;
       
   546     if (command & QItemSelectionModel::Rows) {
       
   547         for (int i = 0; i < selection.count(); ++i) {
       
   548             QModelIndex parent = selection.at(i).parent();
       
   549             int colCount = model->columnCount(parent);
       
   550             QModelIndex tl = model->index(selection.at(i).top(), 0, parent);
       
   551             QModelIndex br = model->index(selection.at(i).bottom(), colCount - 1, parent);
       
   552             //we need to merge because the same row could have already been inserted
       
   553             expanded.merge(QItemSelection(tl, br), QItemSelectionModel::Select);
       
   554         }
       
   555     }
       
   556     if (command & QItemSelectionModel::Columns) {
       
   557         for (int i = 0; i < selection.count(); ++i) {
       
   558             QModelIndex parent = selection.at(i).parent();
       
   559             int rowCount = model->rowCount(parent);
       
   560             QModelIndex tl = model->index(0, selection.at(i).left(), parent);
       
   561             QModelIndex br = model->index(rowCount - 1, selection.at(i).right(), parent);
       
   562             //we need to merge because the same column could have already been inserted
       
   563             expanded.merge(QItemSelection(tl, br), QItemSelectionModel::Select);
       
   564         }
       
   565     }
       
   566     return expanded;
       
   567 }
       
   568 
       
   569 /*!
       
   570     \internal
       
   571 */
       
   572 void QItemSelectionModelPrivate::_q_rowsAboutToBeRemoved(const QModelIndex &parent,
       
   573                                                          int start, int end)
       
   574 {
       
   575     Q_Q(QItemSelectionModel);
       
   576     finalize();
       
   577 
       
   578     // update current index
       
   579     if (currentIndex.isValid() && parent == currentIndex.parent()
       
   580         && currentIndex.row() >= start && currentIndex.row() <= end) {
       
   581         QModelIndex old = currentIndex;
       
   582         if (start > 0) // there are rows left above the change
       
   583             currentIndex = model->index(start - 1, old.column(), parent);
       
   584         else if (model && end < model->rowCount(parent) - 1) // there are rows left below the change
       
   585             currentIndex = model->index(end + 1, old.column(), parent);
       
   586         else // there are no rows left in the table
       
   587             currentIndex = QModelIndex();
       
   588         emit q->currentChanged(currentIndex, old);
       
   589         emit q->currentRowChanged(currentIndex, old);
       
   590         if (currentIndex.column() != old.column())
       
   591             emit q->currentColumnChanged(currentIndex, old);
       
   592     }
       
   593 
       
   594     QItemSelection deselected;
       
   595     QItemSelection::iterator it = ranges.begin();
       
   596     while (it != ranges.end()) {
       
   597         if (it->topLeft().parent() != parent) {  // Check parents until reaching root or contained in range
       
   598             QModelIndex itParent = it->topLeft().parent();
       
   599             while (itParent.isValid() && itParent.parent() != parent)
       
   600                 itParent = itParent.parent();
       
   601 
       
   602             if (parent.isValid() && start <= itParent.row() && itParent.row() <= end) {
       
   603                 deselected.append(*it);
       
   604                 it = ranges.erase(it);
       
   605             } else {
       
   606                 ++it;
       
   607             }
       
   608         } else if (start <= it->bottom() && it->bottom() <= end    // Full inclusion
       
   609                    && start <= it->top() && it->top() <= end) {
       
   610             deselected.append(*it);
       
   611             it = ranges.erase(it);
       
   612         } else if (start <= it->top() && it->top() <= end) {      // Top intersection
       
   613             deselected.append(QItemSelectionRange(it->topLeft(), model->index(end, it->left(), it->parent())));
       
   614             *it = QItemSelectionRange(model->index(end + 1, it->left(), it->parent()), it->bottomRight());
       
   615             ++it;
       
   616         } else if (start <= it->bottom() && it->bottom() <= end) {    // Bottom intersection
       
   617             deselected.append(QItemSelectionRange(model->index(start, it->right(), it->parent()), it->bottomRight()));
       
   618             *it = QItemSelectionRange(it->topLeft(), model->index(start - 1, it->right(), it->parent()));
       
   619             ++it;
       
   620         } else {
       
   621             if (it->top() < start && end < it->bottom())  // Middle intersection (do nothing)
       
   622                 deselected.append(QItemSelectionRange(model->index(start, it->right(), it->parent()),
       
   623                                                       model->index(end, it->left(), it->parent())));
       
   624             ++it;
       
   625        }
       
   626     }
       
   627 
       
   628     if (!deselected.isEmpty())
       
   629         emit q->selectionChanged(QItemSelection(), deselected);
       
   630 }
       
   631 
       
   632 /*!
       
   633     \internal
       
   634 */
       
   635 void QItemSelectionModelPrivate::_q_columnsAboutToBeRemoved(const QModelIndex &parent,
       
   636                                                             int start, int end)
       
   637 {
       
   638     Q_Q(QItemSelectionModel);
       
   639 
       
   640     // update current index
       
   641     if (currentIndex.isValid() && parent == currentIndex.parent()
       
   642         && currentIndex.column() >= start && currentIndex.column() <= end) {
       
   643         QModelIndex old = currentIndex;
       
   644         if (start > 0) // there are columns to the left of the change
       
   645             currentIndex = model->index(old.row(), start - 1, parent);
       
   646         else if (model && end < model->columnCount() - 1) // there are columns to the right of the change
       
   647             currentIndex = model->index(old.row(), end + 1, parent);
       
   648         else // there are no columns left in the table
       
   649             currentIndex = QModelIndex();
       
   650         emit q->currentChanged(currentIndex, old);
       
   651         if (currentIndex.row() != old.row())
       
   652             emit q->currentRowChanged(currentIndex, old);
       
   653         emit q->currentColumnChanged(currentIndex, old);
       
   654     }
       
   655 
       
   656     // update selections
       
   657     QModelIndex tl = model->index(0, start, parent);
       
   658     QModelIndex br = model->index(model->rowCount(parent) - 1, end, parent);
       
   659     q->select(QItemSelection(tl, br), QItemSelectionModel::Deselect);
       
   660     finalize();
       
   661 }
       
   662 
       
   663 /*!
       
   664     \internal
       
   665 
       
   666     Split selection ranges if columns are about to be inserted in the middle.
       
   667 */
       
   668 void QItemSelectionModelPrivate::_q_columnsAboutToBeInserted(const QModelIndex &parent,
       
   669                                                              int start, int end)
       
   670 {
       
   671     Q_UNUSED(end);
       
   672     finalize();
       
   673     QList<QItemSelectionRange> split;
       
   674     QList<QItemSelectionRange>::iterator it = ranges.begin();
       
   675     for (; it != ranges.end(); ) {
       
   676         if ((*it).isValid() && (*it).parent() == parent
       
   677             && (*it).left() < start && (*it).right() >= start) {
       
   678             QModelIndex bottomMiddle = model->index((*it).bottom(), start - 1, (*it).parent());
       
   679             QItemSelectionRange left((*it).topLeft(), bottomMiddle);
       
   680             QModelIndex topMiddle = model->index((*it).top(), start, (*it).parent());
       
   681             QItemSelectionRange right(topMiddle, (*it).bottomRight());
       
   682             it = ranges.erase(it);
       
   683             split.append(left);
       
   684             split.append(right);
       
   685         } else {
       
   686             ++it;
       
   687         }
       
   688     }
       
   689     ranges += split;
       
   690 }
       
   691 
       
   692 /*!
       
   693     \internal
       
   694 
       
   695     Split selection ranges if rows are about to be inserted in the middle.
       
   696 */
       
   697 void QItemSelectionModelPrivate::_q_rowsAboutToBeInserted(const QModelIndex &parent,
       
   698                                                           int start, int end)
       
   699 {
       
   700     Q_UNUSED(end);
       
   701     finalize();
       
   702     QList<QItemSelectionRange> split;
       
   703     QList<QItemSelectionRange>::iterator it = ranges.begin();
       
   704     for (; it != ranges.end(); ) {
       
   705         if ((*it).isValid() && (*it).parent() == parent
       
   706             && (*it).top() < start && (*it).bottom() >= start) {
       
   707             QModelIndex middleRight = model->index(start - 1, (*it).right(), (*it).parent());
       
   708             QItemSelectionRange top((*it).topLeft(), middleRight);
       
   709             QModelIndex middleLeft = model->index(start, (*it).left(), (*it).parent());
       
   710             QItemSelectionRange bottom(middleLeft, (*it).bottomRight());
       
   711             it = ranges.erase(it);
       
   712             split.append(top);
       
   713             split.append(bottom);
       
   714         } else {
       
   715             ++it;
       
   716         }
       
   717     }
       
   718     ranges += split;
       
   719 }
       
   720 
       
   721 /*!
       
   722     \internal
       
   723 
       
   724     Split selection into individual (persistent) indexes. This is done in
       
   725     preparation for the layoutChanged() signal, where the indexes can be
       
   726     merged again.
       
   727 */
       
   728 void QItemSelectionModelPrivate::_q_layoutAboutToBeChanged()
       
   729 {
       
   730     savedPersistentIndexes.clear();
       
   731     savedPersistentCurrentIndexes.clear();
       
   732 
       
   733     // special case for when all indexes are selected
       
   734     if (ranges.isEmpty() && currentSelection.count() == 1) {
       
   735         QItemSelectionRange range = currentSelection.first();
       
   736         QModelIndex parent = range.parent();
       
   737         tableRowCount = model->rowCount(parent);
       
   738         tableColCount = model->columnCount(parent);
       
   739         if (tableRowCount * tableColCount > 100
       
   740             && range.top() == 0
       
   741             && range.left() == 0
       
   742             && range.bottom() == tableRowCount - 1
       
   743             && range.right() == tableColCount - 1) {
       
   744             tableSelected = true;
       
   745             tableParent = parent;
       
   746             return;
       
   747         }
       
   748     }
       
   749     tableSelected = false;
       
   750 
       
   751     QModelIndexList indexes = ranges.indexes();
       
   752     QModelIndexList::const_iterator it;
       
   753     for (it = indexes.constBegin(); it != indexes.constEnd(); ++it)
       
   754         savedPersistentIndexes.append(QPersistentModelIndex(*it));
       
   755     indexes = currentSelection.indexes();
       
   756     for (it = indexes.constBegin(); it != indexes.constEnd(); ++it)
       
   757         savedPersistentCurrentIndexes.append(QPersistentModelIndex(*it));
       
   758 }
       
   759 
       
   760 /*!
       
   761     \internal
       
   762 
       
   763     Merges \a indexes into an item selection made up of ranges.
       
   764     Assumes that the indexes are sorted.
       
   765 */
       
   766 static QItemSelection mergeIndexes(const QList<QPersistentModelIndex> &indexes)
       
   767 {
       
   768     QItemSelection colSpans;
       
   769     // merge columns
       
   770     int i = 0;
       
   771     while (i < indexes.count()) {
       
   772         QModelIndex tl = indexes.at(i);
       
   773         QModelIndex br = tl;
       
   774         while (++i < indexes.count()) {
       
   775             QModelIndex next = indexes.at(i);
       
   776             if ((next.parent() == br.parent())
       
   777                  && (next.row() == br.row())
       
   778                  && (next.column() == br.column() + 1))
       
   779                 br = next;
       
   780             else
       
   781                 break;
       
   782         }
       
   783         colSpans.append(QItemSelectionRange(tl, br));
       
   784     }
       
   785     // merge rows
       
   786     QItemSelection rowSpans;
       
   787     i = 0;
       
   788     while (i < colSpans.count()) {
       
   789         QModelIndex tl = colSpans.at(i).topLeft();
       
   790         QModelIndex br = colSpans.at(i).bottomRight();
       
   791         QModelIndex prevTl = tl;
       
   792         while (++i < colSpans.count()) {
       
   793             QModelIndex nextTl = colSpans.at(i).topLeft();
       
   794             QModelIndex nextBr = colSpans.at(i).bottomRight();
       
   795             if ((nextTl.column() == prevTl.column()) && (nextBr.column() == br.column())
       
   796                 && (nextTl.row() == prevTl.row() + 1) && (nextBr.row() == br.row() + 1)) {
       
   797                 br = nextBr;
       
   798                 prevTl = nextTl;
       
   799             } else {
       
   800                 break;
       
   801             }
       
   802         }
       
   803         rowSpans.append(QItemSelectionRange(tl, br));
       
   804     }
       
   805     return rowSpans;
       
   806 }
       
   807 
       
   808 /*!
       
   809     \internal
       
   810 
       
   811     Merge the selected indexes into selection ranges again.
       
   812 */
       
   813 void QItemSelectionModelPrivate::_q_layoutChanged()
       
   814 {
       
   815     // special case for when all indexes are selected
       
   816     if (tableSelected && tableColCount == model->columnCount(tableParent)
       
   817         && tableRowCount == model->rowCount(tableParent)) {
       
   818         ranges.clear();
       
   819         currentSelection.clear();
       
   820         int bottom = tableRowCount - 1;
       
   821         int right = tableColCount - 1;
       
   822         QModelIndex tl = model->index(0, 0, tableParent);
       
   823         QModelIndex br = model->index(bottom, right, tableParent);
       
   824         currentSelection << QItemSelectionRange(tl, br);
       
   825         tableParent = QModelIndex();
       
   826         tableSelected = false;
       
   827         return;
       
   828     }
       
   829 
       
   830     if (savedPersistentCurrentIndexes.isEmpty() && savedPersistentIndexes.isEmpty()) {
       
   831         // either the selection was actually empty, or we
       
   832         // didn't get the layoutAboutToBeChanged() signal
       
   833         return;
       
   834     }
       
   835     // clear the "old" selection
       
   836     ranges.clear();
       
   837     currentSelection.clear();
       
   838 
       
   839     // sort the "new" selection, as preparation for merging
       
   840     qStableSort(savedPersistentIndexes.begin(), savedPersistentIndexes.end());
       
   841     qStableSort(savedPersistentCurrentIndexes.begin(), savedPersistentCurrentIndexes.end());
       
   842 
       
   843     // update the selection by merging the individual indexes
       
   844     ranges = mergeIndexes(savedPersistentIndexes);
       
   845     currentSelection = mergeIndexes(savedPersistentCurrentIndexes);
       
   846 
       
   847     // release the persistent indexes
       
   848     savedPersistentIndexes.clear();
       
   849     savedPersistentCurrentIndexes.clear();
       
   850 }
       
   851 
       
   852 /*!
       
   853     \class QItemSelectionModel
       
   854 
       
   855     \brief The QItemSelectionModel class keeps track of a view's selected items.
       
   856 
       
   857     \ingroup model-view
       
   858 
       
   859     A QItemSelectionModel keeps track of the selected items in a view, or
       
   860     in several views onto the same model. It also keeps track of the
       
   861     currently selected item in a view.
       
   862 
       
   863     The QItemSelectionModel class is one of the \l{Model/View Classes}
       
   864     and is part of Qt's \l{Model/View Programming}{model/view framework}.
       
   865 
       
   866     The selected items are stored using ranges. Whenever you want to
       
   867     modify the selected items use select() and provide either a
       
   868     QItemSelection, or a QModelIndex and a QItemSelectionModel::SelectionFlag.
       
   869 
       
   870     The QItemSelectionModel takes a two layer approach to selection
       
   871     management, dealing with both selected items that have been committed
       
   872     and items that are part of the current selection. The current
       
   873     selected items are part of the current interactive selection (for
       
   874     example with rubber-band selection or keyboard-shift selections).
       
   875 
       
   876     To update the currently selected items, use the bitwise OR of
       
   877     QItemSelectionModel::Current and any of the other SelectionFlags.
       
   878     If you omit the QItemSelectionModel::Current command, a new current
       
   879     selection will be created, and the previous one added to the whole
       
   880     selection. All functions operate on both layers; for example,
       
   881     selectedItems() will return items from both layers.
       
   882 
       
   883     \sa {Model/View Programming}, QAbstractItemModel, {Chart Example}
       
   884 */
       
   885 
       
   886 /*!
       
   887     Constructs a selection model that operates on the specified item \a model.
       
   888 */
       
   889 QItemSelectionModel::QItemSelectionModel(QAbstractItemModel *model)
       
   890     : QObject(*new QItemSelectionModelPrivate, model)
       
   891 {
       
   892     d_func()->model = model;
       
   893     if (model) {
       
   894         connect(model, SIGNAL(rowsAboutToBeRemoved(QModelIndex,int,int)),
       
   895                 this, SLOT(_q_rowsAboutToBeRemoved(QModelIndex,int,int)));
       
   896         connect(model, SIGNAL(columnsAboutToBeRemoved(QModelIndex,int,int)),
       
   897                 this, SLOT(_q_columnsAboutToBeRemoved(QModelIndex,int,int)));
       
   898         connect(model, SIGNAL(rowsAboutToBeInserted(QModelIndex,int,int)),
       
   899                 this, SLOT(_q_rowsAboutToBeInserted(QModelIndex,int,int)));
       
   900         connect(model, SIGNAL(columnsAboutToBeInserted(QModelIndex,int,int)),
       
   901                 this, SLOT(_q_columnsAboutToBeInserted(QModelIndex,int,int)));
       
   902         connect(model, SIGNAL(layoutAboutToBeChanged()),
       
   903                 this, SLOT(_q_layoutAboutToBeChanged()));
       
   904         connect(model, SIGNAL(layoutChanged()),
       
   905                 this, SLOT(_q_layoutChanged()));
       
   906     }
       
   907 }
       
   908 
       
   909 /*!
       
   910     Constructs a selection model that operates on the specified item \a model with \a parent.
       
   911 */
       
   912 QItemSelectionModel::QItemSelectionModel(QAbstractItemModel *model, QObject *parent)
       
   913     : QObject(*new QItemSelectionModelPrivate, parent)
       
   914 {
       
   915     d_func()->model = model;
       
   916     if (model) {
       
   917         connect(model, SIGNAL(rowsAboutToBeRemoved(QModelIndex,int,int)),
       
   918                 this, SLOT(_q_rowsAboutToBeRemoved(QModelIndex,int,int)));
       
   919         connect(model, SIGNAL(columnsAboutToBeRemoved(QModelIndex,int,int)),
       
   920                 this, SLOT(_q_columnsAboutToBeRemoved(QModelIndex,int,int)));
       
   921         connect(model, SIGNAL(rowsAboutToBeInserted(QModelIndex,int,int)),
       
   922                 this, SLOT(_q_rowsAboutToBeInserted(QModelIndex,int,int)));
       
   923         connect(model, SIGNAL(columnsAboutToBeInserted(QModelIndex,int,int)),
       
   924                 this, SLOT(_q_columnsAboutToBeInserted(QModelIndex,int,int)));
       
   925         connect(model, SIGNAL(layoutAboutToBeChanged()),
       
   926                 this, SLOT(_q_layoutAboutToBeChanged()));
       
   927         connect(model, SIGNAL(layoutChanged()),
       
   928                 this, SLOT(_q_layoutChanged()));
       
   929     }
       
   930 }
       
   931 
       
   932 /*!
       
   933     \internal
       
   934 */
       
   935 QItemSelectionModel::QItemSelectionModel(QItemSelectionModelPrivate &dd, QAbstractItemModel *model)
       
   936     : QObject(dd, model)
       
   937 {
       
   938     d_func()->model = model;
       
   939     if (model) {
       
   940         connect(model, SIGNAL(rowsAboutToBeRemoved(QModelIndex,int,int)),
       
   941                 this, SLOT(_q_rowsAboutToBeRemoved(QModelIndex,int,int)));
       
   942         connect(model, SIGNAL(columnsAboutToBeRemoved(QModelIndex,int,int)),
       
   943                 this, SLOT(_q_columnsAboutToBeRemoved(QModelIndex,int,int)));
       
   944         connect(model, SIGNAL(rowsAboutToBeInserted(QModelIndex,int,int)),
       
   945                 this, SLOT(_q_rowsAboutToBeInserted(QModelIndex,int,int)));
       
   946         connect(model, SIGNAL(columnsAboutToBeInserted(QModelIndex,int,int)),
       
   947                 this, SLOT(_q_columnsAboutToBeInserted(QModelIndex,int,int)));
       
   948         connect(model, SIGNAL(layoutAboutToBeChanged()),
       
   949                 this, SLOT(_q_layoutAboutToBeChanged()));
       
   950         connect(model, SIGNAL(layoutChanged()),
       
   951                 this, SLOT(_q_layoutChanged()));
       
   952     }
       
   953 }
       
   954 
       
   955 /*!
       
   956     Destroys the selection model.
       
   957 */
       
   958 QItemSelectionModel::~QItemSelectionModel()
       
   959 {
       
   960     Q_D(QItemSelectionModel);
       
   961     if (d->model) {
       
   962         disconnect(d->model, SIGNAL(rowsAboutToBeRemoved(QModelIndex,int,int)),
       
   963                 this, SLOT(_q_rowsAboutToBeRemoved(QModelIndex,int,int)));
       
   964         disconnect(d->model, SIGNAL(columnsAboutToBeRemoved(QModelIndex,int,int)),
       
   965                 this, SLOT(_q_columnsAboutToBeRemoved(QModelIndex,int,int)));
       
   966         disconnect(d->model, SIGNAL(rowsAboutToBeInserted(QModelIndex,int,int)),
       
   967                 this, SLOT(_q_rowsAboutToBeInserted(QModelIndex,int,int)));
       
   968         disconnect(d->model, SIGNAL(columnsAboutToBeInserted(QModelIndex,int,int)),
       
   969                 this, SLOT(_q_columnsAboutToBeInserted(QModelIndex,int,int)));
       
   970         disconnect(d->model, SIGNAL(layoutAboutToBeChanged()),
       
   971                 this, SLOT(_q_layoutAboutToBeChanged()));
       
   972         disconnect(d->model, SIGNAL(layoutChanged()),
       
   973                 this, SLOT(_q_layoutChanged()));
       
   974     }
       
   975 }
       
   976 
       
   977 /*!
       
   978     Selects the model item \a index using the specified \a command, and emits
       
   979     selectionChanged().
       
   980 
       
   981     \sa QItemSelectionModel::SelectionFlags
       
   982 */
       
   983 void QItemSelectionModel::select(const QModelIndex &index, QItemSelectionModel::SelectionFlags command)
       
   984 {
       
   985     QItemSelection selection(index, index);
       
   986     select(selection, command);
       
   987 }
       
   988 
       
   989 /*!
       
   990     \fn void QItemSelectionModel::currentChanged(const QModelIndex &current, const QModelIndex &previous)
       
   991 
       
   992     This signal is emitted whenever the current item changes. The \a previous
       
   993     model item index is replaced by the \a current index as the selection's
       
   994     current item.
       
   995 
       
   996     Note that this signal will not be emitted when the item model is reset.
       
   997 
       
   998     \sa currentIndex() setCurrentIndex() selectionChanged()
       
   999 */
       
  1000 
       
  1001 /*!
       
  1002     \fn void QItemSelectionModel::currentColumnChanged(const QModelIndex &current, const QModelIndex &previous)
       
  1003 
       
  1004     This signal is emitted if the \a current item changes and its column is
       
  1005     different to the column of the \a previous current item.
       
  1006 
       
  1007     Note that this signal will not be emitted when the item model is reset.
       
  1008 
       
  1009     \sa currentChanged() currentRowChanged() currentIndex() setCurrentIndex()
       
  1010 */
       
  1011 
       
  1012 /*!
       
  1013     \fn void QItemSelectionModel::currentRowChanged(const QModelIndex &current, const QModelIndex &previous)
       
  1014 
       
  1015     This signal is emitted if the \a current item changes and its row is
       
  1016     different to the row of the \a previous current item.
       
  1017 
       
  1018     Note that this signal will not be emitted when the item model is reset.
       
  1019 
       
  1020     \sa currentChanged() currentColumnChanged() currentIndex() setCurrentIndex()
       
  1021 */
       
  1022 
       
  1023 /*!
       
  1024     \fn void QItemSelectionModel::selectionChanged(const QItemSelection &selected, const QItemSelection &deselected)
       
  1025 
       
  1026     This signal is emitted whenever the selection changes. The change in the
       
  1027     selection is represented as an item selection of \a deselected items and
       
  1028     an item selection of \a selected items.
       
  1029 
       
  1030     Note the that the current index changes independently from the selection.
       
  1031     Also note that this signal will not be emitted when the item model is reset.
       
  1032 
       
  1033     \sa select() currentChanged()
       
  1034 */
       
  1035 
       
  1036 /*!
       
  1037     \enum QItemSelectionModel::SelectionFlag
       
  1038 
       
  1039     This enum describes the way the selection model will be updated.
       
  1040 
       
  1041     \value NoUpdate       No selection will be made.
       
  1042     \value Clear          The complete selection will be cleared.
       
  1043     \value Select         All specified indexes will be selected.
       
  1044     \value Deselect       All specified indexes will be deselected.
       
  1045     \value Toggle         All specified indexes will be selected or
       
  1046                           deselected depending on their current state.
       
  1047     \value Current        The current selection will be updated.
       
  1048     \value Rows           All indexes will be expanded to span rows.
       
  1049     \value Columns        All indexes will be expanded to span columns.
       
  1050     \value SelectCurrent  A combination of Select and Current, provided for
       
  1051                           convenience.
       
  1052     \value ToggleCurrent  A combination of Toggle and Current, provided for
       
  1053                           convenience.
       
  1054     \value ClearAndSelect A combination of Clear and Select, provided for
       
  1055                           convenience.
       
  1056 */
       
  1057 
       
  1058 /*!
       
  1059     Selects the item \a selection using the specified \a command, and emits
       
  1060     selectionChanged().
       
  1061 
       
  1062     \sa QItemSelectionModel::SelectionFlag
       
  1063 */
       
  1064 void QItemSelectionModel::select(const QItemSelection &selection, QItemSelectionModel::SelectionFlags command)
       
  1065 {
       
  1066     Q_D(QItemSelectionModel);
       
  1067     if (command == NoUpdate)
       
  1068         return;
       
  1069 
       
  1070     // store old selection
       
  1071     QItemSelection sel = selection;
       
  1072     QItemSelection old = d->ranges;
       
  1073     old.merge(d->currentSelection, d->currentCommand);
       
  1074 
       
  1075     // expand selection according to SelectionBehavior
       
  1076     if (command & Rows || command & Columns)
       
  1077         sel = d->expandSelection(sel, command);
       
  1078 
       
  1079     // clear ranges and currentSelection
       
  1080     if (command & Clear) {
       
  1081         d->ranges.clear();
       
  1082         d->currentSelection.clear();
       
  1083     }
       
  1084 
       
  1085     // merge and clear currentSelection if Current was not set (ie. start new currentSelection)
       
  1086     if (!(command & Current))
       
  1087         d->finalize();
       
  1088 
       
  1089     // update currentSelection
       
  1090     if (command & Toggle || command & Select || command & Deselect) {
       
  1091         d->currentCommand = command;
       
  1092         d->currentSelection = sel;
       
  1093     }
       
  1094 
       
  1095     // generate new selection, compare with old and emit selectionChanged()
       
  1096     QItemSelection newSelection = d->ranges;
       
  1097     newSelection.merge(d->currentSelection, d->currentCommand);
       
  1098     emitSelectionChanged(newSelection, old);
       
  1099 }
       
  1100 
       
  1101 /*!
       
  1102     Clears the selection model. Emits selectionChanged() and currentChanged().
       
  1103 */
       
  1104 void QItemSelectionModel::clear()
       
  1105 {
       
  1106     Q_D(QItemSelectionModel);
       
  1107     clearSelection();
       
  1108     QModelIndex previous = d->currentIndex;
       
  1109     d->currentIndex = QModelIndex();
       
  1110     if (previous.isValid()) {
       
  1111         emit currentChanged(d->currentIndex, previous);
       
  1112         emit currentRowChanged(d->currentIndex, previous);
       
  1113         emit currentColumnChanged(d->currentIndex, previous);
       
  1114     }
       
  1115 }
       
  1116 
       
  1117 /*!
       
  1118     Clears the selection model. Does not emit any signals.
       
  1119 */
       
  1120 void QItemSelectionModel::reset()
       
  1121 {
       
  1122     bool block = blockSignals(true);
       
  1123     clear();
       
  1124     blockSignals(block);
       
  1125 }
       
  1126 
       
  1127 /*!
       
  1128     \since 4.2
       
  1129     Clears the selection in the selection model. Emits selectionChanged().
       
  1130 */
       
  1131 void QItemSelectionModel::clearSelection()
       
  1132 {
       
  1133     Q_D(QItemSelectionModel);
       
  1134     if (d->ranges.count() == 0 && d->currentSelection.count() == 0)
       
  1135         return;
       
  1136     QItemSelection selection = d->ranges;
       
  1137     selection.merge(d->currentSelection, d->currentCommand);
       
  1138     d->ranges.clear();
       
  1139     d->currentSelection.clear();
       
  1140     emit selectionChanged(QItemSelection(), selection);
       
  1141 }
       
  1142 
       
  1143 
       
  1144 /*!
       
  1145     Sets the model item \a index to be the current item, and emits
       
  1146     currentChanged(). The current item is used for keyboard navigation and
       
  1147     focus indication; it is independent of any selected items, although a
       
  1148     selected item can also be the current item.
       
  1149 
       
  1150     Depending on the specified \a command, the \a index can also become part
       
  1151     of the current selection.
       
  1152     \sa select()
       
  1153 */
       
  1154 void QItemSelectionModel::setCurrentIndex(const QModelIndex &index, QItemSelectionModel::SelectionFlags command)
       
  1155 {
       
  1156     Q_D(QItemSelectionModel);
       
  1157     if (index == d->currentIndex) {
       
  1158         if (command != NoUpdate)
       
  1159             select(index, command); // select item
       
  1160         return;
       
  1161     }
       
  1162     QPersistentModelIndex previous = d->currentIndex;
       
  1163     d->currentIndex = index; // set current before emitting selection changed below
       
  1164     if (command != NoUpdate)
       
  1165         select(d->currentIndex, command); // select item
       
  1166     emit currentChanged(d->currentIndex, previous);
       
  1167     if (d->currentIndex.row() != previous.row() ||
       
  1168             d->currentIndex.parent() != previous.parent())
       
  1169         emit currentRowChanged(d->currentIndex, previous);
       
  1170     if (d->currentIndex.column() != previous.column() ||
       
  1171             d->currentIndex.parent() != previous.parent())
       
  1172         emit currentColumnChanged(d->currentIndex, previous);
       
  1173 }
       
  1174 
       
  1175 /*!
       
  1176     Returns the model item index for the current item, or an invalid index
       
  1177     if there is no current item.
       
  1178 */
       
  1179 QModelIndex QItemSelectionModel::currentIndex() const
       
  1180 {
       
  1181     return static_cast<QModelIndex>(d_func()->currentIndex);
       
  1182 }
       
  1183 
       
  1184 /*!
       
  1185     Returns true if the given model item \a index is selected.
       
  1186 */
       
  1187 bool QItemSelectionModel::isSelected(const QModelIndex &index) const
       
  1188 {
       
  1189     Q_D(const QItemSelectionModel);
       
  1190     if (d->model != index.model() || !index.isValid())
       
  1191         return false;
       
  1192 
       
  1193     bool selected = false;
       
  1194     //  search model ranges
       
  1195     QList<QItemSelectionRange>::const_iterator it = d->ranges.begin();
       
  1196     for (; it != d->ranges.end(); ++it) {
       
  1197         if ((*it).isValid() && (*it).contains(index)) {
       
  1198             selected = true;
       
  1199             break;
       
  1200         }
       
  1201     }
       
  1202 
       
  1203     // check  currentSelection
       
  1204     if (d->currentSelection.count()) {
       
  1205         if ((d->currentCommand & Deselect) && selected)
       
  1206             selected = !d->currentSelection.contains(index);
       
  1207         else if (d->currentCommand & Toggle)
       
  1208             selected ^= d->currentSelection.contains(index);
       
  1209         else if ((d->currentCommand & Select) && !selected)
       
  1210             selected = d->currentSelection.contains(index);
       
  1211     }
       
  1212 
       
  1213     if (selected) {
       
  1214         Qt::ItemFlags flags = d->model->flags(index);
       
  1215         return (flags & Qt::ItemIsSelectable);
       
  1216     }
       
  1217 
       
  1218     return false;
       
  1219 }
       
  1220 
       
  1221 /*!
       
  1222     Returns true if all items are selected in the \a row with the given
       
  1223     \a parent.
       
  1224 
       
  1225     Note that this function is usually faster than calling isSelected()
       
  1226     on all items in the same row and that unselectable items are
       
  1227     ignored.
       
  1228 */
       
  1229 bool QItemSelectionModel::isRowSelected(int row, const QModelIndex &parent) const
       
  1230 {
       
  1231     Q_D(const QItemSelectionModel);
       
  1232     if (parent.isValid() && d->model != parent.model())
       
  1233         return false;
       
  1234 
       
  1235     // return false if row exist in currentSelection (Deselect)
       
  1236     if (d->currentCommand & Deselect && d->currentSelection.count()) {
       
  1237         for (int i=0; i<d->currentSelection.count(); ++i) {
       
  1238             if (d->currentSelection.at(i).parent() == parent &&
       
  1239                 row >= d->currentSelection.at(i).top() &&
       
  1240                 row <= d->currentSelection.at(i).bottom())
       
  1241                 return false;
       
  1242         }
       
  1243     }
       
  1244     // return false if ranges in both currentSelection and ranges
       
  1245     // intersect and have the same row contained
       
  1246     if (d->currentCommand & Toggle && d->currentSelection.count()) {
       
  1247         for (int i=0; i<d->currentSelection.count(); ++i)
       
  1248             if (d->currentSelection.at(i).top() <= row &&
       
  1249                 d->currentSelection.at(i).bottom() >= row)
       
  1250                 for (int j=0; j<d->ranges.count(); ++j)
       
  1251                     if (d->ranges.at(j).top() <= row && d->ranges.at(j).bottom() >= row
       
  1252                         && d->currentSelection.at(i).intersected(d->ranges.at(j)).isValid())
       
  1253                         return false;
       
  1254     }
       
  1255     // add ranges and currentSelection and check through them all
       
  1256     QList<QItemSelectionRange>::const_iterator it;
       
  1257     QList<QItemSelectionRange> joined = d->ranges;
       
  1258     if (d->currentSelection.count())
       
  1259         joined += d->currentSelection;
       
  1260     int colCount = d->model->columnCount(parent);
       
  1261     for (int column = 0; column < colCount; ++column) {
       
  1262         for (it = joined.constBegin(); it != joined.constEnd(); ++it) {
       
  1263             if ((*it).contains(row, column, parent)) {
       
  1264                 bool selectable = false;
       
  1265                 for (int i = column; !selectable && i <= (*it).right(); ++i) {
       
  1266                     Qt::ItemFlags flags = d->model->index(row, i, parent).flags();
       
  1267                     selectable = flags & Qt::ItemIsSelectable;
       
  1268                 }
       
  1269                 if (selectable){
       
  1270                     column = qMax(column, (*it).right());
       
  1271                     break;
       
  1272                 }
       
  1273             }
       
  1274         }
       
  1275         if (it == joined.constEnd())
       
  1276             return false;
       
  1277     }
       
  1278     return colCount > 0; // no columns means no selected items
       
  1279 }
       
  1280 
       
  1281 /*!
       
  1282     Returns true if all items are selected in the \a column with the given
       
  1283     \a parent.
       
  1284 
       
  1285     Note that this function is usually faster than calling isSelected()
       
  1286     on all items in the same column and that unselectable items are
       
  1287     ignored.
       
  1288 */
       
  1289 bool QItemSelectionModel::isColumnSelected(int column, const QModelIndex &parent) const
       
  1290 {
       
  1291     Q_D(const QItemSelectionModel);
       
  1292     if (parent.isValid() && d->model != parent.model())
       
  1293         return false;
       
  1294 
       
  1295     // return false if column exist in currentSelection (Deselect)
       
  1296     if (d->currentCommand & Deselect && d->currentSelection.count()) {
       
  1297         for (int i = 0; i < d->currentSelection.count(); ++i) {
       
  1298             if (d->currentSelection.at(i).parent() == parent &&
       
  1299                 column >= d->currentSelection.at(i).left() &&
       
  1300                 column <= d->currentSelection.at(i).right())
       
  1301                 return false;
       
  1302         }
       
  1303     }
       
  1304     // return false if ranges in both currentSelection and the selection model
       
  1305     // intersect and have the same column contained
       
  1306     if (d->currentCommand & Toggle && d->currentSelection.count()) {
       
  1307         for (int i = 0; i < d->currentSelection.count(); ++i) {
       
  1308             if (d->currentSelection.at(i).left() <= column &&
       
  1309                 d->currentSelection.at(i).right() >= column) {
       
  1310                 for (int j = 0; j < d->ranges.count(); ++j) {
       
  1311                     if (d->ranges.at(j).left() <= column && d->ranges.at(j).right() >= column
       
  1312                         && d->currentSelection.at(i).intersected(d->ranges.at(j)).isValid()) {
       
  1313                         return false;
       
  1314                     }
       
  1315                 }
       
  1316             }
       
  1317         }
       
  1318     }
       
  1319     // add ranges and currentSelection and check through them all
       
  1320     QList<QItemSelectionRange>::const_iterator it;
       
  1321     QList<QItemSelectionRange> joined = d->ranges;
       
  1322     if (d->currentSelection.count())
       
  1323         joined += d->currentSelection;
       
  1324     int rowCount = d->model->rowCount(parent);
       
  1325     for (int row = 0; row < rowCount; ++row) {
       
  1326          for (it = joined.constBegin(); it != joined.constEnd(); ++it) {
       
  1327              if ((*it).contains(row, column, parent)) {
       
  1328                  Qt::ItemFlags flags = d->model->index(row, column, parent).flags();
       
  1329                  if ((flags & Qt::ItemIsSelectable) && (flags & Qt::ItemIsEnabled)) {
       
  1330                      row = qMax(row, (*it).bottom());
       
  1331                      break;
       
  1332                  }
       
  1333              }
       
  1334          }
       
  1335          if (it == joined.constEnd())
       
  1336              return false;
       
  1337     }
       
  1338     return rowCount > 0; // no rows means no selected items
       
  1339 }
       
  1340 
       
  1341 /*!
       
  1342     Returns true if there are any items selected in the \a row with the given
       
  1343     \a parent.
       
  1344 */
       
  1345 bool QItemSelectionModel::rowIntersectsSelection(int row, const QModelIndex &parent) const
       
  1346 {
       
  1347     Q_D(const QItemSelectionModel);
       
  1348     if (parent.isValid() && d->model != parent.model())
       
  1349          return false;
       
  1350 
       
  1351     QItemSelection sel = d->ranges;
       
  1352     sel.merge(d->currentSelection, d->currentCommand);
       
  1353     for (int i = 0; i < sel.count(); ++i) {
       
  1354         int top = sel.at(i).top();
       
  1355         int bottom = sel.at(i).bottom();
       
  1356         int left = sel.at(i).left();
       
  1357         int right = sel.at(i).right();
       
  1358         if (top <= row && bottom >= row) {
       
  1359             for (int j = left; j <= right; j++) {
       
  1360                 const Qt::ItemFlags flags = d->model->index(row, j, parent).flags();
       
  1361                 if ((flags & Qt::ItemIsSelectable) && (flags & Qt::ItemIsEnabled))
       
  1362                     return true;
       
  1363             }
       
  1364         }
       
  1365     }
       
  1366 
       
  1367     return false;
       
  1368 }
       
  1369 
       
  1370 /*!
       
  1371     Returns true if there are any items selected in the \a column with the given
       
  1372     \a parent.
       
  1373 */
       
  1374 bool QItemSelectionModel::columnIntersectsSelection(int column, const QModelIndex &parent) const
       
  1375 {
       
  1376     Q_D(const QItemSelectionModel);
       
  1377     if (parent.isValid() && d->model != parent.model())
       
  1378         return false;
       
  1379 
       
  1380     QItemSelection sel = d->ranges;
       
  1381     sel.merge(d->currentSelection, d->currentCommand);
       
  1382     for (int i = 0; i < sel.count(); ++i) {
       
  1383         int left = sel.at(i).left();
       
  1384         int right = sel.at(i).right();
       
  1385         int top =  sel.at(i).top();
       
  1386         int bottom =  sel.at(i).bottom();
       
  1387         if (left <= column && right >= column) {
       
  1388             for (int j = top; j <= bottom; j++) {
       
  1389                 const Qt::ItemFlags flags = d->model->index(j, column, parent).flags();
       
  1390                 if ((flags & Qt::ItemIsSelectable) && (flags & Qt::ItemIsEnabled))
       
  1391                     return true;
       
  1392             }
       
  1393         }
       
  1394     }
       
  1395 
       
  1396     return false;
       
  1397 }
       
  1398 
       
  1399 /*!
       
  1400     \since 4.2
       
  1401 
       
  1402     Returns true if the selection model contains any selection ranges;
       
  1403     otherwise returns false.
       
  1404 */
       
  1405 bool QItemSelectionModel::hasSelection() const
       
  1406 {
       
  1407     Q_D(const QItemSelectionModel);
       
  1408     if (d->currentCommand & (Toggle | Deselect)) {
       
  1409         QItemSelection sel = d->ranges;
       
  1410         sel.merge(d->currentSelection, d->currentCommand);
       
  1411         return !sel.isEmpty();
       
  1412     } else {
       
  1413         return !(d->ranges.isEmpty() && d->currentSelection.isEmpty());
       
  1414     }
       
  1415 }
       
  1416 
       
  1417 /*!
       
  1418     Returns a list of all selected model item indexes. The list contains no
       
  1419     duplicates, and is not sorted.
       
  1420 */
       
  1421 QModelIndexList QItemSelectionModel::selectedIndexes() const
       
  1422 {
       
  1423     Q_D(const QItemSelectionModel);
       
  1424     QItemSelection selected = d->ranges;
       
  1425     selected.merge(d->currentSelection, d->currentCommand);
       
  1426     return selected.indexes();
       
  1427 }
       
  1428 
       
  1429 /*!
       
  1430     \since 4.2
       
  1431     Returns the indexes in the given \a column for the rows where all columns are selected.
       
  1432 
       
  1433     \sa selectedIndexes(), selectedColumns()
       
  1434 */
       
  1435 
       
  1436 QModelIndexList QItemSelectionModel::selectedRows(int column) const
       
  1437 {
       
  1438     QModelIndexList indexes;
       
  1439     //the QSet contains pairs of parent modelIndex
       
  1440     //and row number
       
  1441     QSet< QPair<QModelIndex, int> > rowsSeen;
       
  1442 
       
  1443     const QItemSelection ranges = selection();
       
  1444     for (int i = 0; i < ranges.count(); ++i) {
       
  1445         const QItemSelectionRange &range = ranges.at(i);
       
  1446         QModelIndex parent = range.parent();
       
  1447         for (int row = range.top(); row <= range.bottom(); row++) {
       
  1448             QPair<QModelIndex, int> rowDef = qMakePair(parent, row);
       
  1449             if (!rowsSeen.contains(rowDef)) {
       
  1450                 rowsSeen << rowDef;
       
  1451                 if (isRowSelected(row, parent)) {
       
  1452                     indexes.append(model()->index(row, column, parent));
       
  1453                 }
       
  1454             }
       
  1455         }
       
  1456     }
       
  1457 
       
  1458     return indexes;
       
  1459 }
       
  1460 
       
  1461 /*!
       
  1462     \since 4.2
       
  1463     Returns the indexes in the given \a row for columns where all rows are selected.
       
  1464 
       
  1465     \sa selectedIndexes(), selectedRows()
       
  1466 */
       
  1467 
       
  1468 QModelIndexList QItemSelectionModel::selectedColumns(int row) const
       
  1469 {
       
  1470     QModelIndexList indexes;
       
  1471     //the QSet contains pairs of parent modelIndex
       
  1472     //and column number
       
  1473     QSet< QPair<QModelIndex, int> > columnsSeen;
       
  1474 
       
  1475     const QItemSelection ranges = selection();
       
  1476     for (int i = 0; i < ranges.count(); ++i) {
       
  1477         const QItemSelectionRange &range = ranges.at(i);
       
  1478         QModelIndex parent = range.parent();
       
  1479         for (int column = range.left(); column <= range.right(); column++) {
       
  1480             QPair<QModelIndex, int> columnDef = qMakePair(parent, column);
       
  1481             if (!columnsSeen.contains(columnDef)) {
       
  1482                 columnsSeen << columnDef;
       
  1483                 if (isColumnSelected(column, parent)) {
       
  1484                     indexes.append(model()->index(row, column, parent));
       
  1485                 }
       
  1486             }
       
  1487         }
       
  1488     }
       
  1489 
       
  1490     return indexes;
       
  1491 }
       
  1492 
       
  1493 /*!
       
  1494     Returns the selection ranges stored in the selection model.
       
  1495 */
       
  1496 const QItemSelection QItemSelectionModel::selection() const
       
  1497 {
       
  1498     Q_D(const QItemSelectionModel);
       
  1499     QItemSelection selected = d->ranges;
       
  1500     selected.merge(d->currentSelection, d->currentCommand);
       
  1501     int i = 0;
       
  1502     // make sure we have no invalid ranges
       
  1503     // ###  should probably be handled more generic somewhere else
       
  1504     while (i<selected.count()) {
       
  1505         if (selected.at(i).isValid())
       
  1506             ++i;
       
  1507         else
       
  1508             (selected.removeAt(i));
       
  1509     }
       
  1510     return selected;
       
  1511 }
       
  1512 
       
  1513 /*!
       
  1514     Returns the item model operated on by the selection model.
       
  1515 */
       
  1516 const QAbstractItemModel *QItemSelectionModel::model() const
       
  1517 {
       
  1518     return d_func()->model;
       
  1519 }
       
  1520 
       
  1521 /*!
       
  1522     Compares the two selections \a newSelection and \a oldSelection
       
  1523     and emits selectionChanged() with the deselected and selected items.
       
  1524 */
       
  1525 void QItemSelectionModel::emitSelectionChanged(const QItemSelection &newSelection,
       
  1526                                                const QItemSelection &oldSelection)
       
  1527 {
       
  1528     // if both selections are empty or equal we return
       
  1529     if ((oldSelection.isEmpty() && newSelection.isEmpty()) ||
       
  1530         oldSelection == newSelection)
       
  1531         return;
       
  1532 
       
  1533     // if either selection is empty we do not need to compare
       
  1534     if (oldSelection.isEmpty() || newSelection.isEmpty()) {
       
  1535         emit selectionChanged(newSelection, oldSelection);
       
  1536         return;
       
  1537     }
       
  1538 
       
  1539     QItemSelection deselected = oldSelection;
       
  1540     QItemSelection selected = newSelection;
       
  1541 
       
  1542     // remove equal ranges
       
  1543     bool advance;
       
  1544     for (int o = 0; o < deselected.count(); ++o) {
       
  1545         advance = true;
       
  1546         for (int s = 0; s < selected.count() && o < deselected.count();) {
       
  1547             if (deselected.at(o) == selected.at(s)) {
       
  1548                 deselected.removeAt(o);
       
  1549                 selected.removeAt(s);
       
  1550                 advance = false;
       
  1551             } else {
       
  1552                 ++s;
       
  1553             }
       
  1554         }
       
  1555         if (advance)
       
  1556             ++o;
       
  1557     }
       
  1558 
       
  1559     // find intersections
       
  1560     QItemSelection intersections;
       
  1561     for (int o = 0; o < deselected.count(); ++o) {
       
  1562         for (int s = 0; s < selected.count(); ++s) {
       
  1563             if (deselected.at(o).intersects(selected.at(s)))
       
  1564                 intersections.append(deselected.at(o).intersected(selected.at(s)));
       
  1565         }
       
  1566     }
       
  1567 
       
  1568     // compare remaining ranges with intersections and split them to find deselected and selected
       
  1569     for (int i = 0; i < intersections.count(); ++i) {
       
  1570         // split deselected
       
  1571         for (int o = 0; o < deselected.count();) {
       
  1572             if (deselected.at(o).intersects(intersections.at(i))) {
       
  1573                 QItemSelection::split(deselected.at(o), intersections.at(i), &deselected);
       
  1574                 deselected.removeAt(o);
       
  1575             } else {
       
  1576                 ++o;
       
  1577             }
       
  1578         }
       
  1579         // split selected
       
  1580         for (int s = 0; s < selected.count();) {
       
  1581             if (selected.at(s).intersects(intersections.at(i))) {
       
  1582                 QItemSelection::split(selected.at(s), intersections.at(i), &selected);
       
  1583                 selected.removeAt(s);
       
  1584             } else {
       
  1585                 ++s;
       
  1586             }
       
  1587         }
       
  1588     }
       
  1589 
       
  1590     emit selectionChanged(selected, deselected);
       
  1591 }
       
  1592 
       
  1593 #ifndef QT_NO_DEBUG_STREAM
       
  1594 QDebug operator<<(QDebug dbg, const QItemSelectionRange &range)
       
  1595 {
       
  1596 #ifndef Q_BROKEN_DEBUG_STREAM
       
  1597     dbg.nospace() << "QItemSelectionRange(" << range.topLeft()
       
  1598                   << ',' << range.bottomRight() << ')';
       
  1599     return dbg.space();
       
  1600 #else
       
  1601     qWarning("This compiler doesn't support streaming QItemSelectionRange to QDebug");
       
  1602     return dbg;
       
  1603     Q_UNUSED(range);
       
  1604 #endif
       
  1605 }
       
  1606 #endif
       
  1607 
       
  1608 QT_END_NAMESPACE
       
  1609 
       
  1610 #include "moc_qitemselectionmodel.cpp"
       
  1611 
       
  1612 #endif // QT_NO_ITEMVIEWS