1 /****************************************************************************
2 **
3 ** Copyright (C) 2020 The Qt Company Ltd.
4 ** Contact: https://www.qt.io/licensing/
5 **
6 ** This file is part of the QtCore module of the Qt Toolkit.
7 **
8 ** $QT_BEGIN_LICENSE:LGPL$
9 ** Commercial License Usage
10 ** Licensees holding valid commercial Qt licenses may use this file in
11 ** accordance with the commercial license agreement provided with the
12 ** Software or, alternatively, in accordance with the terms contained in
13 ** a written agreement between you and The Qt Company. For licensing terms
14 ** and conditions see https://www.qt.io/terms-conditions. For further
15 ** information use the contact form at https://www.qt.io/contact-us.
16 **
17 ** GNU Lesser General Public License Usage
18 ** Alternatively, this file may be used under the terms of the GNU Lesser
19 ** General Public License version 3 as published by the Free Software
20 ** Foundation and appearing in the file LICENSE.LGPL3 included in the
21 ** packaging of this file. Please review the following information to
22 ** ensure the GNU Lesser General Public License version 3 requirements
23 ** will be met: https://www.gnu.org/licenses/lgpl-3.0.html.
24 **
25 ** GNU General Public License Usage
26 ** Alternatively, this file may be used under the terms of the GNU
27 ** General Public License version 2.0 or (at your option) the GNU General
28 ** Public license version 3 or any later version approved by the KDE Free
29 ** Qt Foundation. The licenses are as published by the Free Software
30 ** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3
31 ** included in the packaging of this file. Please review the following
32 ** information to ensure the GNU General Public License requirements will
33 ** be met: https://www.gnu.org/licenses/gpl-2.0.html and
34 ** https://www.gnu.org/licenses/gpl-3.0.html.
35 **
36 ** $QT_END_LICENSE$
37 **
38 ****************************************************************************/
39 
40 #include "qitemselectionmodel.h"
41 #include <private/qitemselectionmodel_p.h>
42 #include <qdebug.h>
43 
44 #include <algorithm>
45 #include <functional>
46 
47 QT_BEGIN_NAMESPACE
48 
49 /*!
50     \class QItemSelectionRange
51     \inmodule QtCore
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 QItemSelectionRange::swap(QItemSelectionRange &other)
113     \since 5.6
114 
115     Swaps this selection range's contents with \a other.
116     This function is very fast and never fails.
117 */
118 
119 /*!
120     \fn int QItemSelectionRange::top() const
121 
122     Returns the row index corresponding to the uppermost selected row in the
123     selection range.
124 
125 */
126 
127 /*!
128     \fn int QItemSelectionRange::left() const
129 
130     Returns the column index corresponding to the leftmost selected column in the
131     selection range.
132 */
133 
134 /*!
135     \fn int QItemSelectionRange::bottom() const
136 
137     Returns the row index corresponding to the lowermost selected row in the
138     selection range.
139 
140 */
141 
142 /*!
143     \fn int QItemSelectionRange::right() const
144 
145     Returns the column index corresponding to the rightmost selected column in
146     the selection range.
147 
148 */
149 
150 /*!
151     \fn int QItemSelectionRange::width() const
152 
153     Returns the number of selected columns in the selection range.
154 
155 */
156 
157 /*!
158     \fn int QItemSelectionRange::height() const
159 
160     Returns the number of selected rows in the selection range.
161 
162 */
163 
164 /*!
165     \fn const QAbstractItemModel *QItemSelectionRange::model() const
166 
167     Returns the model that the items in the selection range belong to.
168 */
169 
170 /*!
171     \fn QModelIndex QItemSelectionRange::topLeft() const
172 
173     Returns the index for the item located at the top-left corner of
174     the selection range.
175 
176     \sa top(), left(), bottomRight()
177 */
178 
179 /*!
180     \fn QModelIndex QItemSelectionRange::bottomRight() const
181 
182     Returns the index for the item located at the bottom-right corner
183     of the selection range.
184 
185     \sa bottom(), right(), topLeft()
186 */
187 
188 /*!
189     \fn QModelIndex QItemSelectionRange::parent() const
190 
191     Returns the parent model item index of the items in the selection range.
192 
193 */
194 
195 /*!
196     \fn bool QItemSelectionRange::contains(const QModelIndex &index) const
197 
198     Returns \c true if the model item specified by the \a index lies within the
199     range of selected items; otherwise returns \c false.
200 */
201 
202 /*!
203     \fn bool QItemSelectionRange::contains(int row, int column,
204                                            const QModelIndex &parentIndex) const
205     \overload
206 
207     Returns \c true if the model item specified by (\a row, \a column)
208     and with \a parentIndex as the parent item lies within the range
209     of selected items; otherwise returns \c false.
210 */
211 
212 /*!
213     \fn bool QItemSelectionRange::intersects(const QItemSelectionRange &other) const
214 
215     Returns \c true if this selection range intersects (overlaps with) the \a other
216     range given; otherwise returns \c false.
217 
218 */
intersects(const QItemSelectionRange & other) const219 bool QItemSelectionRange::intersects(const QItemSelectionRange &other) const
220 {
221     // isValid() and parent() last since they are more expensive
222     return (model() == other.model()
223             && ((top() <= other.top() && bottom() >= other.top())
224                 || (top() >= other.top() && top() <= other.bottom()))
225             && ((left() <= other.left() && right() >= other.left())
226                 || (left() >= other.left() && left() <= other.right()))
227             && parent() == other.parent()
228             && isValid() && other.isValid()
229             );
230 }
231 
232 /*!
233     \fn QItemSelectionRange QItemSelectionRange::intersect(const QItemSelectionRange &other) const
234     \obsolete
235 
236     Use intersected(\a other) instead.
237 */
238 
239 /*!
240     \fn QItemSelectionRange QItemSelectionRange::intersected(const QItemSelectionRange &other) const
241     \since 4.2
242 
243     Returns a new selection range containing only the items that are found in
244     both the selection range and the \a other selection range.
245 */
246 
intersected(const QItemSelectionRange & other) const247 QItemSelectionRange QItemSelectionRange::intersected(const QItemSelectionRange &other) const
248 {
249     if (model() == other.model() && parent() == other.parent()) {
250         QModelIndex topLeft = model()->index(qMax(top(), other.top()),
251                                              qMax(left(), other.left()),
252                                              other.parent());
253         QModelIndex bottomRight = model()->index(qMin(bottom(), other.bottom()),
254                                                  qMin(right(), other.right()),
255                                                  other.parent());
256         return QItemSelectionRange(topLeft, bottomRight);
257     }
258     return QItemSelectionRange();
259 }
260 
261 /*!
262     \fn bool QItemSelectionRange::operator==(const QItemSelectionRange &other) const
263 
264     Returns \c true if the selection range is exactly the same as the \a other
265     range given; otherwise returns \c false.
266 
267 */
268 
269 /*!
270     \fn bool QItemSelectionRange::operator!=(const QItemSelectionRange &other) const
271 
272     Returns \c true if the selection range differs from the \a other range given;
273     otherwise returns \c false.
274 
275 */
276 
277 #if QT_DEPRECATED_SINCE(5, 15)
278 /*!
279     Returns \c true if the selection range is less than the \a other
280     range given; otherwise returns \c false.
281 
282     The less than calculation is not directly useful to developers - the way that ranges
283     with different parents compare is not defined. This operator only exists so that the
284     class can be used with QMap.
285 
286 */
operator <(const QItemSelectionRange & other) const287 bool QItemSelectionRange::operator<(const QItemSelectionRange &other) const
288 {
289     // ### Qt 6: This is inconsistent with op== and needs to be fixed, nay,
290     // ###       removed, but cannot, because it was inline up to and including 5.9
291 
292     // Comparing parents will compare the models, but if two equivalent ranges
293     // in two different models have invalid parents, they would appear the same
294     if (other.tl.model() == tl.model()) {
295         // parent has to be calculated, so we only do so once.
296         const QModelIndex topLeftParent = tl.parent();
297         const QModelIndex otherTopLeftParent = other.tl.parent();
298         if (topLeftParent == otherTopLeftParent) {
299             if (other.tl.row() == tl.row()) {
300                 if (other.tl.column() == tl.column()) {
301                     if (other.br.row() == br.row()) {
302                         return br.column() < other.br.column();
303                     }
304                     return br.row() < other.br.row();
305                 }
306                 return tl.column() < other.tl.column();
307             }
308             return tl.row() < other.tl.row();
309         }
310         return topLeftParent < otherTopLeftParent;
311     }
312 
313     std::less<const QAbstractItemModel *> less;
314     return less(tl.model(), other.tl.model());
315 }
316 #endif
317 
318 /*!
319     \fn bool QItemSelectionRange::isValid() const
320 
321     Returns \c true if the selection range is valid; otherwise returns \c false.
322 
323 */
324 
rowLengthsFromRange(const QItemSelectionRange & range,QVector<QPair<QPersistentModelIndex,uint>> & result)325 static void rowLengthsFromRange(const QItemSelectionRange &range, QVector<QPair<QPersistentModelIndex, uint> > &result)
326 {
327     if (range.isValid() && range.model()) {
328         const QModelIndex topLeft = range.topLeft();
329         const int bottom = range.bottom();
330         const uint width = range.width();
331         const int column = topLeft.column();
332         for (int row = topLeft.row(); row <= bottom; ++row) {
333             // We don't need to keep track of ItemIsSelectable and ItemIsEnabled here. That is
334             // required in indexesFromRange() because that method is called from public API
335             // which requires the limitation.
336             result.push_back(qMakePair(QPersistentModelIndex(topLeft.sibling(row, column)), width));
337         }
338     }
339 }
340 
341 template<typename ModelIndexContainer>
indexesFromRange(const QItemSelectionRange & range,ModelIndexContainer & result)342 static void indexesFromRange(const QItemSelectionRange &range, ModelIndexContainer &result)
343 {
344     if (range.isValid() && range.model()) {
345         const QModelIndex topLeft = range.topLeft();
346         const int bottom = range.bottom();
347         const int right = range.right();
348         for (int row = topLeft.row(); row <= bottom; ++row) {
349             const QModelIndex columnLeader = topLeft.sibling(row, topLeft.column());
350             for (int column = topLeft.column(); column <= right; ++column) {
351                 QModelIndex index = columnLeader.sibling(row, column);
352                 Qt::ItemFlags flags = range.model()->flags(index);
353                 if ((flags & Qt::ItemIsSelectable) && (flags & Qt::ItemIsEnabled))
354                     result.push_back(index);
355             }
356         }
357     }
358 }
359 
360 template<typename ModelIndexContainer>
qSelectionIndexes(const QItemSelection & selection)361 static ModelIndexContainer qSelectionIndexes(const QItemSelection &selection)
362 {
363     ModelIndexContainer result;
364     for (const auto &range : selection)
365         indexesFromRange(range, result);
366     return result;
367 }
368 
369 /*!
370     Returns \c true if the selection range contains no selectable item
371     \since 4.7
372 */
373 
isEmpty() const374 bool QItemSelectionRange::isEmpty() const
375 {
376     if (!isValid() || !model())
377         return true;
378 
379     for (int column = left(); column <= right(); ++column) {
380         for (int row = top(); row <= bottom(); ++row) {
381             QModelIndex index = model()->index(row, column, parent());
382             Qt::ItemFlags flags = model()->flags(index);
383             if ((flags & Qt::ItemIsSelectable) && (flags & Qt::ItemIsEnabled))
384                 return false;
385         }
386     }
387     return true;
388 }
389 
390 /*!
391     Returns the list of model index items stored in the selection.
392 */
393 
indexes() const394 QModelIndexList QItemSelectionRange::indexes() const
395 {
396     QModelIndexList result;
397     indexesFromRange(*this, result);
398     return result;
399 }
400 
401 /*!
402     \class QItemSelection
403     \inmodule QtCore
404 
405     \brief The QItemSelection class manages information about selected items in a model.
406 
407     \ingroup model-view
408 
409     A QItemSelection describes the items in a model that have been
410     selected by the user. A QItemSelection is basically a list of
411     selection ranges, see QItemSelectionRange. It provides functions for
412     creating and manipulating selections, and selecting a range of items
413     from a model.
414 
415     The QItemSelection class is one of the \l{Model/View Classes}
416     and is part of Qt's \l{Model/View Programming}{model/view framework}.
417 
418     An item selection can be constructed and initialized to contain a
419     range of items from an existing model. The following example constructs
420     a selection that contains a range of items from the given \c model,
421     beginning at the \c topLeft, and ending at the \c bottomRight.
422 
423     \snippet code/src_gui_itemviews_qitemselectionmodel.cpp 0
424 
425     An empty item selection can be constructed, and later populated as
426     required. So, if the model is going to be unavailable when we construct
427     the item selection, we can rewrite the above code in the following way:
428 
429     \snippet code/src_gui_itemviews_qitemselectionmodel.cpp 1
430 
431     QItemSelection saves memory, and avoids unnecessary work, by working with
432     selection ranges rather than recording the model item index for each
433     item in the selection. Generally, an instance of this class will contain
434     a list of non-overlapping selection ranges.
435 
436     Use merge() to merge one item selection into another without making
437     overlapping ranges. Use split() to split one selection range into
438     smaller ranges based on a another selection range.
439 
440     \sa {Model/View Programming}, QItemSelectionModel
441 */
442 
443 /*!
444     \fn QItemSelection::QItemSelection()
445 
446     Constructs an empty selection.
447 */
448 
449 /*!
450     Constructs an item selection that extends from the top-left model item,
451     specified by the \a topLeft index, to the bottom-right item, specified
452     by \a bottomRight.
453 */
QItemSelection(const QModelIndex & topLeft,const QModelIndex & bottomRight)454 QItemSelection::QItemSelection(const QModelIndex &topLeft, const QModelIndex &bottomRight)
455 {
456     select(topLeft, bottomRight);
457 }
458 
459 /*!
460     Adds the items in the range that extends from the top-left model
461     item, specified by the \a topLeft index, to the bottom-right item,
462     specified by \a bottomRight to the list.
463 
464     \note \a topLeft and \a bottomRight must have the same parent.
465 */
select(const QModelIndex & topLeft,const QModelIndex & bottomRight)466 void QItemSelection::select(const QModelIndex &topLeft, const QModelIndex &bottomRight)
467 {
468     if (!topLeft.isValid() || !bottomRight.isValid())
469         return;
470 
471     if ((topLeft.model() != bottomRight.model())
472         || topLeft.parent() != bottomRight.parent()) {
473         qWarning("Can't select indexes from different model or with different parents");
474         return;
475     }
476     if (topLeft.row() > bottomRight.row() || topLeft.column() > bottomRight.column()) {
477         int top = qMin(topLeft.row(), bottomRight.row());
478         int bottom = qMax(topLeft.row(), bottomRight.row());
479         int left = qMin(topLeft.column(), bottomRight.column());
480         int right = qMax(topLeft.column(), bottomRight.column());
481         QModelIndex tl = topLeft.sibling(top, left);
482         QModelIndex br = bottomRight.sibling(bottom, right);
483         append(QItemSelectionRange(tl, br));
484         return;
485     }
486     append(QItemSelectionRange(topLeft, bottomRight));
487 }
488 
489 /*!
490     Returns \c true if the selection contains the given \a index; otherwise
491     returns \c false.
492 */
493 
contains(const QModelIndex & index) const494 bool QItemSelection::contains(const QModelIndex &index) const
495 {
496     if (index.flags() & Qt::ItemIsSelectable) {
497         QList<QItemSelectionRange>::const_iterator it = begin();
498         for (; it != end(); ++it)
499             if ((*it).contains(index))
500                 return true;
501     }
502     return false;
503 }
504 
505 /*!
506     Returns a list of model indexes that correspond to the selected items.
507 */
508 
indexes() const509 QModelIndexList QItemSelection::indexes() const
510 {
511     return qSelectionIndexes<QModelIndexList>(*this);
512 }
513 
qSelectionPersistentRowLengths(const QItemSelection & sel)514 static QVector<QPair<QPersistentModelIndex, uint> > qSelectionPersistentRowLengths(const QItemSelection &sel)
515 {
516     QVector<QPair<QPersistentModelIndex, uint> > result;
517     for (const QItemSelectionRange &range : sel)
518         rowLengthsFromRange(range, result);
519     return result;
520 }
521 
522 /*!
523     Merges the \a other selection with this QItemSelection using the
524     \a command given. This method guarantees that no ranges are overlapping.
525 
526     Note that only QItemSelectionModel::Select,
527     QItemSelectionModel::Deselect, and QItemSelectionModel::Toggle are
528     supported.
529 
530     \sa split()
531 */
merge(const QItemSelection & other,QItemSelectionModel::SelectionFlags command)532 void QItemSelection::merge(const QItemSelection &other, QItemSelectionModel::SelectionFlags command)
533 {
534     if (other.isEmpty() ||
535           !(command & QItemSelectionModel::Select ||
536           command & QItemSelectionModel::Deselect ||
537           command & QItemSelectionModel::Toggle))
538         return;
539 
540     QItemSelection newSelection = other;
541     // Collect intersections
542     QItemSelection intersections;
543     QItemSelection::iterator it = newSelection.begin();
544     while (it != newSelection.end()) {
545         if (!(*it).isValid()) {
546             it = newSelection.erase(it);
547             continue;
548         }
549         for (int t = 0; t < count(); ++t) {
550             if ((*it).intersects(at(t)))
551                 intersections.append(at(t).intersected(*it));
552         }
553         ++it;
554     }
555 
556     //  Split the old (and new) ranges using the intersections
557     for (int i = 0; i < intersections.count(); ++i) { // for each intersection
558         for (int t = 0; t < count();) { // splitt each old range
559             if (at(t).intersects(intersections.at(i))) {
560                 split(at(t), intersections.at(i), this);
561                 removeAt(t);
562             } else {
563                 ++t;
564             }
565         }
566         // only split newSelection if Toggle is specified
567         for (int n = 0; (command & QItemSelectionModel::Toggle) && n < newSelection.count();) {
568             if (newSelection.at(n).intersects(intersections.at(i))) {
569                 split(newSelection.at(n), intersections.at(i), &newSelection);
570                 newSelection.removeAt(n);
571             } else {
572                 ++n;
573             }
574         }
575     }
576     // do not add newSelection for Deselect
577     if (!(command & QItemSelectionModel::Deselect))
578         operator+=(newSelection);
579 }
580 
581 /*!
582     Splits the selection \a range using the selection \a other range.
583     Removes all items in \a other from \a range and puts the result in \a result.
584     This can be compared with the semantics of the \e subtract operation of a set.
585     \sa merge()
586 */
587 
split(const QItemSelectionRange & range,const QItemSelectionRange & other,QItemSelection * result)588 void QItemSelection::split(const QItemSelectionRange &range,
589                            const QItemSelectionRange &other, QItemSelection *result)
590 {
591     if (range.parent() != other.parent() || range.model() != other.model())
592         return;
593 
594     QModelIndex parent = other.parent();
595     int top = range.top();
596     int left = range.left();
597     int bottom = range.bottom();
598     int right = range.right();
599     int other_top = other.top();
600     int other_left = other.left();
601     int other_bottom = other.bottom();
602     int other_right = other.right();
603     const QAbstractItemModel *model = range.model();
604     Q_ASSERT(model);
605     if (other_top > top) {
606         QModelIndex tl = model->index(top, left, parent);
607         QModelIndex br = model->index(other_top - 1, right, parent);
608         result->append(QItemSelectionRange(tl, br));
609         top = other_top;
610     }
611     if (other_bottom < bottom) {
612         QModelIndex tl = model->index(other_bottom + 1, left, parent);
613         QModelIndex br = model->index(bottom, right, parent);
614         result->append(QItemSelectionRange(tl, br));
615         bottom = other_bottom;
616     }
617     if (other_left > left) {
618         QModelIndex tl = model->index(top, left, parent);
619         QModelIndex br = model->index(bottom, other_left - 1, parent);
620         result->append(QItemSelectionRange(tl, br));
621         left = other_left;
622     }
623     if (other_right < right) {
624         QModelIndex tl = model->index(top, other_right + 1, parent);
625         QModelIndex br = model->index(bottom, right, parent);
626         result->append(QItemSelectionRange(tl, br));
627         right = other_right;
628     }
629 }
630 
631 
initModel(QAbstractItemModel * m)632 void QItemSelectionModelPrivate::initModel(QAbstractItemModel *m)
633 {
634     struct Cx {
635         const char *signal;
636         const char *slot;
637     };
638     static const Cx connections[] = {
639         { SIGNAL(rowsAboutToBeRemoved(QModelIndex,int,int)),
640           SLOT(_q_rowsAboutToBeRemoved(QModelIndex,int,int)) },
641         { SIGNAL(columnsAboutToBeRemoved(QModelIndex,int,int)),
642           SLOT(_q_columnsAboutToBeRemoved(QModelIndex,int,int)) },
643         { SIGNAL(rowsAboutToBeInserted(QModelIndex,int,int)),
644           SLOT(_q_rowsAboutToBeInserted(QModelIndex,int,int)) },
645         { SIGNAL(columnsAboutToBeInserted(QModelIndex,int,int)),
646           SLOT(_q_columnsAboutToBeInserted(QModelIndex,int,int)) },
647         { SIGNAL(rowsAboutToBeMoved(QModelIndex,int,int,QModelIndex,int)),
648           SLOT(_q_layoutAboutToBeChanged()) },
649         { SIGNAL(columnsAboutToBeMoved(QModelIndex,int,int,QModelIndex,int)),
650           SLOT(_q_layoutAboutToBeChanged()) },
651         { SIGNAL(rowsMoved(QModelIndex,int,int,QModelIndex,int)),
652           SLOT(_q_layoutChanged()) },
653         { SIGNAL(columnsMoved(QModelIndex,int,int,QModelIndex,int)),
654           SLOT(_q_layoutChanged()) },
655         { SIGNAL(layoutAboutToBeChanged(QList<QPersistentModelIndex>,QAbstractItemModel::LayoutChangeHint)),
656           SLOT(_q_layoutAboutToBeChanged(QList<QPersistentModelIndex>,QAbstractItemModel::LayoutChangeHint)) },
657         { SIGNAL(layoutChanged(QList<QPersistentModelIndex>,QAbstractItemModel::LayoutChangeHint)),
658           SLOT(_q_layoutChanged(QList<QPersistentModelIndex>,QAbstractItemModel::LayoutChangeHint)) },
659         { SIGNAL(modelReset()),
660           SLOT(reset()) },
661         { nullptr, nullptr }
662     };
663 
664     if (model == m)
665         return;
666 
667     Q_Q(QItemSelectionModel);
668     if (model) {
669         for (const Cx *cx = &connections[0]; cx->signal; cx++)
670             QObject::disconnect(model, cx->signal, q, cx->slot);
671         q->reset();
672     }
673     model = m;
674     if (model) {
675         for (const Cx *cx = &connections[0]; cx->signal; cx++)
676             QObject::connect(model, cx->signal, q, cx->slot);
677     }
678 }
679 
680 /*!
681     \internal
682 
683     returns a QItemSelection where all ranges have been expanded to:
684     Rows: left: 0 and right: columnCount()-1
685     Columns: top: 0 and bottom: rowCount()-1
686 */
687 
expandSelection(const QItemSelection & selection,QItemSelectionModel::SelectionFlags command) const688 QItemSelection QItemSelectionModelPrivate::expandSelection(const QItemSelection &selection,
689                                                            QItemSelectionModel::SelectionFlags command) const
690 {
691     if (selection.isEmpty() && !((command & QItemSelectionModel::Rows) ||
692                                  (command & QItemSelectionModel::Columns)))
693         return selection;
694 
695     QItemSelection expanded;
696     if (command & QItemSelectionModel::Rows) {
697         for (int i = 0; i < selection.count(); ++i) {
698             QModelIndex parent = selection.at(i).parent();
699             int colCount = model->columnCount(parent);
700             QModelIndex tl = model->index(selection.at(i).top(), 0, parent);
701             QModelIndex br = model->index(selection.at(i).bottom(), colCount - 1, parent);
702             //we need to merge because the same row could have already been inserted
703             expanded.merge(QItemSelection(tl, br), QItemSelectionModel::Select);
704         }
705     }
706     if (command & QItemSelectionModel::Columns) {
707         for (int i = 0; i < selection.count(); ++i) {
708             QModelIndex parent = selection.at(i).parent();
709             int rowCount = model->rowCount(parent);
710             QModelIndex tl = model->index(0, selection.at(i).left(), parent);
711             QModelIndex br = model->index(rowCount - 1, selection.at(i).right(), parent);
712             //we need to merge because the same column could have already been inserted
713             expanded.merge(QItemSelection(tl, br), QItemSelectionModel::Select);
714         }
715     }
716     return expanded;
717 }
718 
719 /*!
720     \internal
721 */
_q_rowsAboutToBeRemoved(const QModelIndex & parent,int start,int end)722 void QItemSelectionModelPrivate::_q_rowsAboutToBeRemoved(const QModelIndex &parent,
723                                                          int start, int end)
724 {
725     Q_Q(QItemSelectionModel);
726     finalize();
727 
728     // update current index
729     if (currentIndex.isValid() && parent == currentIndex.parent()
730         && currentIndex.row() >= start && currentIndex.row() <= end) {
731         QModelIndex old = currentIndex;
732         if (start > 0) // there are rows left above the change
733             currentIndex = model->index(start - 1, old.column(), parent);
734         else if (model && end < model->rowCount(parent) - 1) // there are rows left below the change
735             currentIndex = model->index(end + 1, old.column(), parent);
736         else // there are no rows left in the table
737             currentIndex = QModelIndex();
738         emit q->currentChanged(currentIndex, old);
739         emit q->currentRowChanged(currentIndex, old);
740         if (currentIndex.column() != old.column())
741             emit q->currentColumnChanged(currentIndex, old);
742     }
743 
744     QItemSelection deselected;
745     QItemSelection newParts;
746     QItemSelection::iterator it = ranges.begin();
747     while (it != ranges.end()) {
748         if (it->topLeft().parent() != parent) {  // Check parents until reaching root or contained in range
749             QModelIndex itParent = it->topLeft().parent();
750             while (itParent.isValid() && itParent.parent() != parent)
751                 itParent = itParent.parent();
752 
753             if (itParent.isValid() && start <= itParent.row() && itParent.row() <= end) {
754                 deselected.append(*it);
755                 it = ranges.erase(it);
756             } else {
757                 ++it;
758             }
759         } else if (start <= it->bottom() && it->bottom() <= end    // Full inclusion
760                    && start <= it->top() && it->top() <= end) {
761             deselected.append(*it);
762             it = ranges.erase(it);
763         } else if (start <= it->top() && it->top() <= end) {      // Top intersection
764             deselected.append(QItemSelectionRange(it->topLeft(), model->index(end, it->right(), it->parent())));
765             *it = QItemSelectionRange(model->index(end + 1, it->left(), it->parent()), it->bottomRight());
766             ++it;
767         } else if (start <= it->bottom() && it->bottom() <= end) {    // Bottom intersection
768             deselected.append(QItemSelectionRange(model->index(start, it->left(), it->parent()), it->bottomRight()));
769             *it = QItemSelectionRange(it->topLeft(), model->index(start - 1, it->right(), it->parent()));
770             ++it;
771         } else if (it->top() < start && end < it->bottom()) { // Middle intersection
772             // If the parent contains (1, 2, 3, 4, 5, 6, 7, 8) and [3, 4, 5, 6] is selected,
773             // and [4, 5] is removed, we need to split [3, 4, 5, 6] into [3], [4, 5] and [6].
774             // [4, 5] is appended to deselected, and [3] and [6] remain part of the selection
775             // in ranges.
776             const QItemSelectionRange removedRange(model->index(start, it->left(), it->parent()),
777                                                     model->index(end, it->right(), it->parent()));
778             deselected.append(removedRange);
779             QItemSelection::split(*it, removedRange, &newParts);
780             it = ranges.erase(it);
781         } else
782             ++it;
783     }
784     ranges.append(newParts);
785 
786     if (!deselected.isEmpty())
787         emit q->selectionChanged(QItemSelection(), deselected);
788 }
789 
790 /*!
791     \internal
792 */
_q_columnsAboutToBeRemoved(const QModelIndex & parent,int start,int end)793 void QItemSelectionModelPrivate::_q_columnsAboutToBeRemoved(const QModelIndex &parent,
794                                                             int start, int end)
795 {
796     Q_Q(QItemSelectionModel);
797 
798     // update current index
799     if (currentIndex.isValid() && parent == currentIndex.parent()
800         && currentIndex.column() >= start && currentIndex.column() <= end) {
801         QModelIndex old = currentIndex;
802         if (start > 0) // there are columns to the left of the change
803             currentIndex = model->index(old.row(), start - 1, parent);
804         else if (model && end < model->columnCount() - 1) // there are columns to the right of the change
805             currentIndex = model->index(old.row(), end + 1, parent);
806         else // there are no columns left in the table
807             currentIndex = QModelIndex();
808         emit q->currentChanged(currentIndex, old);
809         if (currentIndex.row() != old.row())
810             emit q->currentRowChanged(currentIndex, old);
811         emit q->currentColumnChanged(currentIndex, old);
812     }
813 
814     // update selections
815     QModelIndex tl = model->index(0, start, parent);
816     QModelIndex br = model->index(model->rowCount(parent) - 1, end, parent);
817     q->select(QItemSelection(tl, br), QItemSelectionModel::Deselect);
818     finalize();
819 }
820 
821 /*!
822     \internal
823 
824     Split selection ranges if columns are about to be inserted in the middle.
825 */
_q_columnsAboutToBeInserted(const QModelIndex & parent,int start,int end)826 void QItemSelectionModelPrivate::_q_columnsAboutToBeInserted(const QModelIndex &parent,
827                                                              int start, int end)
828 {
829     Q_UNUSED(end);
830     finalize();
831     QList<QItemSelectionRange> split;
832     QList<QItemSelectionRange>::iterator it = ranges.begin();
833     for (; it != ranges.end(); ) {
834         if ((*it).isValid() && (*it).parent() == parent
835             && (*it).left() < start && (*it).right() >= start) {
836             QModelIndex bottomMiddle = model->index((*it).bottom(), start - 1, (*it).parent());
837             QItemSelectionRange left((*it).topLeft(), bottomMiddle);
838             QModelIndex topMiddle = model->index((*it).top(), start, (*it).parent());
839             QItemSelectionRange right(topMiddle, (*it).bottomRight());
840             it = ranges.erase(it);
841             split.append(left);
842             split.append(right);
843         } else {
844             ++it;
845         }
846     }
847     ranges += split;
848 }
849 
850 /*!
851     \internal
852 
853     Split selection ranges if rows are about to be inserted in the middle.
854 */
_q_rowsAboutToBeInserted(const QModelIndex & parent,int start,int end)855 void QItemSelectionModelPrivate::_q_rowsAboutToBeInserted(const QModelIndex &parent,
856                                                           int start, int end)
857 {
858     Q_UNUSED(end);
859     finalize();
860     QList<QItemSelectionRange> split;
861     QList<QItemSelectionRange>::iterator it = ranges.begin();
862     for (; it != ranges.end(); ) {
863         if ((*it).isValid() && (*it).parent() == parent
864             && (*it).top() < start && (*it).bottom() >= start) {
865             QModelIndex middleRight = model->index(start - 1, (*it).right(), (*it).parent());
866             QItemSelectionRange top((*it).topLeft(), middleRight);
867             QModelIndex middleLeft = model->index(start, (*it).left(), (*it).parent());
868             QItemSelectionRange bottom(middleLeft, (*it).bottomRight());
869             it = ranges.erase(it);
870             split.append(top);
871             split.append(bottom);
872         } else {
873             ++it;
874         }
875     }
876     ranges += split;
877 }
878 
879 /*!
880     \internal
881 
882     Split selection into individual (persistent) indexes. This is done in
883     preparation for the layoutChanged() signal, where the indexes can be
884     merged again.
885 */
_q_layoutAboutToBeChanged(const QList<QPersistentModelIndex> &,QAbstractItemModel::LayoutChangeHint hint)886 void QItemSelectionModelPrivate::_q_layoutAboutToBeChanged(const QList<QPersistentModelIndex> &, QAbstractItemModel::LayoutChangeHint hint)
887 {
888     savedPersistentIndexes.clear();
889     savedPersistentCurrentIndexes.clear();
890     savedPersistentRowLengths.clear();
891     savedPersistentCurrentRowLengths.clear();
892 
893     // optimization for when all indexes are selected
894     // (only if there is lots of items (1000) because this is not entirely correct)
895     if (ranges.isEmpty() && currentSelection.count() == 1) {
896         QItemSelectionRange range = currentSelection.constFirst();
897         QModelIndex parent = range.parent();
898         tableRowCount = model->rowCount(parent);
899         tableColCount = model->columnCount(parent);
900         if (tableRowCount * tableColCount > 1000
901             && range.top() == 0
902             && range.left() == 0
903             && range.bottom() == tableRowCount - 1
904             && range.right() == tableColCount - 1) {
905             tableSelected = true;
906             tableParent = parent;
907             return;
908         }
909     }
910     tableSelected = false;
911 
912     if (hint == QAbstractItemModel::VerticalSortHint) {
913         // Special case when we know we're sorting vertically. We can assume that all indexes for columns
914         // are displaced the same way, and therefore we only need to track an index from one column per
915         // row with a QPersistentModelIndex together with the length of items to the right of it
916         // which are displaced the same way.
917         // An algorithm which contains the same assumption is used to process layoutChanged.
918         savedPersistentRowLengths = qSelectionPersistentRowLengths(ranges);
919         savedPersistentCurrentRowLengths = qSelectionPersistentRowLengths(currentSelection);
920     } else {
921         savedPersistentIndexes = qSelectionIndexes<QVector<QPersistentModelIndex>>(ranges);
922         savedPersistentCurrentIndexes = qSelectionIndexes<QVector<QPersistentModelIndex>>(currentSelection);
923     }
924 }
925 /*!
926     \internal
927 */
mergeRowLengths(const QVector<QPair<QPersistentModelIndex,uint>> & rowLengths)928 static QItemSelection mergeRowLengths(const QVector<QPair<QPersistentModelIndex, uint> > &rowLengths)
929 {
930     if (rowLengths.isEmpty())
931       return QItemSelection();
932 
933     QItemSelection result;
934     int i = 0;
935     while (i < rowLengths.count()) {
936         const QPersistentModelIndex &tl = rowLengths.at(i).first;
937         if (!tl.isValid()) {
938             ++i;
939             continue;
940         }
941         QPersistentModelIndex br = tl;
942         const uint length = rowLengths.at(i).second;
943         while (++i < rowLengths.count()) {
944             const QPersistentModelIndex &next = rowLengths.at(i).first;
945             if (!next.isValid())
946                 continue;
947             const uint nextLength = rowLengths.at(i).second;
948             if ((nextLength == length)
949                 && (next.row() == br.row() + 1)
950                 && (next.column() == br.column())
951                 && (next.parent() == br.parent())) {
952                 br = next;
953             } else {
954                 break;
955             }
956         }
957         result.append(QItemSelectionRange(tl, br.sibling(br.row(), br.column() + length - 1)));
958     }
959     return result;
960 }
961 
962 /*!
963     \internal
964 
965     Merges \a indexes into an item selection made up of ranges.
966     Assumes that the indexes are sorted.
967 */
mergeIndexes(const QVector<QPersistentModelIndex> & indexes)968 static QItemSelection mergeIndexes(const QVector<QPersistentModelIndex> &indexes)
969 {
970     QItemSelection colSpans;
971     // merge columns
972     int i = 0;
973     while (i < indexes.count()) {
974         const QPersistentModelIndex &tl = indexes.at(i);
975         if (!tl.isValid()) {
976             ++i;
977             continue;
978         }
979         QPersistentModelIndex br = tl;
980         QModelIndex brParent = br.parent();
981         int brRow = br.row();
982         int brColumn = br.column();
983         while (++i < indexes.count()) {
984             const QPersistentModelIndex &next = indexes.at(i);
985             if (!next.isValid())
986                 continue;
987             const QModelIndex nextParent = next.parent();
988             const int nextRow = next.row();
989             const int nextColumn = next.column();
990             if ((nextParent == brParent)
991                  && (nextRow == brRow)
992                  && (nextColumn == brColumn + 1)) {
993                 br = next;
994                 brParent = nextParent;
995                 brRow = nextRow;
996                 brColumn = nextColumn;
997             } else {
998                 break;
999             }
1000         }
1001         colSpans.append(QItemSelectionRange(tl, br));
1002     }
1003     // merge rows
1004     QItemSelection rowSpans;
1005     i = 0;
1006     while (i < colSpans.count()) {
1007         QModelIndex tl = colSpans.at(i).topLeft();
1008         QModelIndex br = colSpans.at(i).bottomRight();
1009         QModelIndex prevTl = tl;
1010         while (++i < colSpans.count()) {
1011             QModelIndex nextTl = colSpans.at(i).topLeft();
1012             QModelIndex nextBr = colSpans.at(i).bottomRight();
1013 
1014             if (nextTl.parent() != tl.parent())
1015                 break; // we can't merge selection ranges from different parents
1016 
1017             if ((nextTl.column() == prevTl.column()) && (nextBr.column() == br.column())
1018                 && (nextTl.row() == prevTl.row() + 1) && (nextBr.row() == br.row() + 1)) {
1019                 br = nextBr;
1020                 prevTl = nextTl;
1021             } else {
1022                 break;
1023             }
1024         }
1025         rowSpans.append(QItemSelectionRange(tl, br));
1026     }
1027     return rowSpans;
1028 }
1029 
1030 /*!
1031     \internal
1032 
1033     Sort predicate function for QItemSelectionModelPrivate::_q_layoutChanged(),
1034     sorting by parent first in addition to operator<(). This is to prevent
1035     fragmentation of the selection by grouping indexes with the same row, column
1036     of different parents next to each other, which may happen when a selection
1037     spans sub-trees.
1038 */
qt_PersistentModelIndexLessThan(const QPersistentModelIndex & i1,const QPersistentModelIndex & i2)1039 static bool qt_PersistentModelIndexLessThan(const QPersistentModelIndex &i1, const QPersistentModelIndex &i2)
1040 {
1041     const QModelIndex parent1 = i1.parent();
1042     const QModelIndex parent2 = i2.parent();
1043     return parent1 == parent2 ? i1 < i2 : parent1 < parent2;
1044 }
1045 
1046 /*!
1047     \internal
1048 
1049     Merge the selected indexes into selection ranges again.
1050 */
_q_layoutChanged(const QList<QPersistentModelIndex> &,QAbstractItemModel::LayoutChangeHint hint)1051 void QItemSelectionModelPrivate::_q_layoutChanged(const QList<QPersistentModelIndex> &, QAbstractItemModel::LayoutChangeHint hint)
1052 {
1053     // special case for when all indexes are selected
1054     if (tableSelected && tableColCount == model->columnCount(tableParent)
1055         && tableRowCount == model->rowCount(tableParent)) {
1056         ranges.clear();
1057         currentSelection.clear();
1058         int bottom = tableRowCount - 1;
1059         int right = tableColCount - 1;
1060         QModelIndex tl = model->index(0, 0, tableParent);
1061         QModelIndex br = model->index(bottom, right, tableParent);
1062         currentSelection << QItemSelectionRange(tl, br);
1063         tableParent = QModelIndex();
1064         tableSelected = false;
1065         return;
1066     }
1067 
1068     if ((hint != QAbstractItemModel::VerticalSortHint && savedPersistentCurrentIndexes.isEmpty() && savedPersistentIndexes.isEmpty())
1069      || (hint == QAbstractItemModel::VerticalSortHint && savedPersistentRowLengths.isEmpty() && savedPersistentCurrentRowLengths.isEmpty())) {
1070         // either the selection was actually empty, or we
1071         // didn't get the layoutAboutToBeChanged() signal
1072         return;
1073     }
1074 
1075     // clear the "old" selection
1076     ranges.clear();
1077     currentSelection.clear();
1078 
1079     if (hint != QAbstractItemModel::VerticalSortHint) {
1080         // sort the "new" selection, as preparation for merging
1081         std::stable_sort(savedPersistentIndexes.begin(), savedPersistentIndexes.end(),
1082                          qt_PersistentModelIndexLessThan);
1083         std::stable_sort(savedPersistentCurrentIndexes.begin(), savedPersistentCurrentIndexes.end(),
1084                          qt_PersistentModelIndexLessThan);
1085 
1086         // update the selection by merging the individual indexes
1087         ranges = mergeIndexes(savedPersistentIndexes);
1088         currentSelection = mergeIndexes(savedPersistentCurrentIndexes);
1089 
1090         // release the persistent indexes
1091         savedPersistentIndexes.clear();
1092         savedPersistentCurrentIndexes.clear();
1093     } else {
1094         // sort the "new" selection, as preparation for merging
1095         std::stable_sort(savedPersistentRowLengths.begin(), savedPersistentRowLengths.end());
1096         std::stable_sort(savedPersistentCurrentRowLengths.begin(), savedPersistentCurrentRowLengths.end());
1097 
1098         // update the selection by merging the individual indexes
1099         ranges = mergeRowLengths(savedPersistentRowLengths);
1100         currentSelection = mergeRowLengths(savedPersistentCurrentRowLengths);
1101 
1102         // release the persistent indexes
1103         savedPersistentRowLengths.clear();
1104         savedPersistentCurrentRowLengths.clear();
1105     }
1106 }
1107 
1108 /*!
1109     \class QItemSelectionModel
1110     \inmodule QtCore
1111 
1112     \brief The QItemSelectionModel class keeps track of a view's selected items.
1113 
1114     \ingroup model-view
1115 
1116     A QItemSelectionModel keeps track of the selected items in a view, or
1117     in several views onto the same model. It also keeps track of the
1118     currently selected item in a view.
1119 
1120     The QItemSelectionModel class is one of the \l{Model/View Classes}
1121     and is part of Qt's \l{Model/View Programming}{model/view framework}.
1122 
1123     The selected items are stored using ranges. Whenever you want to
1124     modify the selected items use select() and provide either a
1125     QItemSelection, or a QModelIndex and a QItemSelectionModel::SelectionFlag.
1126 
1127     The QItemSelectionModel takes a two layer approach to selection
1128     management, dealing with both selected items that have been committed
1129     and items that are part of the current selection. The current
1130     selected items are part of the current interactive selection (for
1131     example with rubber-band selection or keyboard-shift selections).
1132 
1133     To update the currently selected items, use the bitwise OR of
1134     QItemSelectionModel::Current and any of the other SelectionFlags.
1135     If you omit the QItemSelectionModel::Current command, a new current
1136     selection will be created, and the previous one added to the whole
1137     selection. All functions operate on both layers; for example,
1138     \l {QTableWidget::selectedItems()}{selecteditems()} will return items from both layers.
1139 
1140     \note Since 5.5, \l{QItemSelectionModel::model()}{model},
1141     \l{QItemSelectionModel::hasSelection()}{hasSelection}, and
1142     \l{QItemSelectionModel::currentIndex()}{currentIndex} are meta-object properties.
1143 
1144     \sa {Model/View Programming}, QAbstractItemModel, {Chart Example}
1145 */
1146 
1147 /*!
1148     Constructs a selection model that operates on the specified item \a model.
1149 */
QItemSelectionModel(QAbstractItemModel * model)1150 QItemSelectionModel::QItemSelectionModel(QAbstractItemModel *model)
1151     : QObject(*new QItemSelectionModelPrivate, model)
1152 {
1153     d_func()->initModel(model);
1154 }
1155 
1156 /*!
1157     Constructs a selection model that operates on the specified item \a model with \a parent.
1158 */
QItemSelectionModel(QAbstractItemModel * model,QObject * parent)1159 QItemSelectionModel::QItemSelectionModel(QAbstractItemModel *model, QObject *parent)
1160     : QObject(*new QItemSelectionModelPrivate, parent)
1161 {
1162     d_func()->initModel(model);
1163 }
1164 
1165 /*!
1166     \internal
1167 */
QItemSelectionModel(QItemSelectionModelPrivate & dd,QAbstractItemModel * model)1168 QItemSelectionModel::QItemSelectionModel(QItemSelectionModelPrivate &dd, QAbstractItemModel *model)
1169     : QObject(dd, model)
1170 {
1171     dd.initModel(model);
1172 }
1173 
1174 /*!
1175     Destroys the selection model.
1176 */
~QItemSelectionModel()1177 QItemSelectionModel::~QItemSelectionModel()
1178 {
1179 }
1180 
1181 /*!
1182     Selects the model item \a index using the specified \a command, and emits
1183     selectionChanged().
1184 
1185     \sa QItemSelectionModel::SelectionFlags
1186 */
select(const QModelIndex & index,QItemSelectionModel::SelectionFlags command)1187 void QItemSelectionModel::select(const QModelIndex &index, QItemSelectionModel::SelectionFlags command)
1188 {
1189     QItemSelection selection(index, index);
1190     select(selection, command);
1191 }
1192 
1193 /*!
1194     \fn void QItemSelectionModel::currentChanged(const QModelIndex &current, const QModelIndex &previous)
1195 
1196     This signal is emitted whenever the current item changes. The \a previous
1197     model item index is replaced by the \a current index as the selection's
1198     current item.
1199 
1200     Note that this signal will not be emitted when the item model is reset.
1201 
1202     \sa currentIndex(), setCurrentIndex(), selectionChanged()
1203 */
1204 
1205 /*!
1206     \fn void QItemSelectionModel::currentColumnChanged(const QModelIndex &current, const QModelIndex &previous)
1207 
1208     This signal is emitted if the \a current item changes and its column is
1209     different to the column of the \a previous current item.
1210 
1211     Note that this signal will not be emitted when the item model is reset.
1212 
1213     \sa currentChanged(), currentRowChanged(), currentIndex(), setCurrentIndex()
1214 */
1215 
1216 /*!
1217     \fn void QItemSelectionModel::currentRowChanged(const QModelIndex &current, const QModelIndex &previous)
1218 
1219     This signal is emitted if the \a current item changes and its row is
1220     different to the row of the \a previous current item.
1221 
1222     Note that this signal will not be emitted when the item model is reset.
1223 
1224     \sa currentChanged(), currentColumnChanged(), currentIndex(), setCurrentIndex()
1225 */
1226 
1227 /*!
1228     \fn void QItemSelectionModel::selectionChanged(const QItemSelection &selected, const QItemSelection &deselected)
1229 
1230     This signal is emitted whenever the selection changes. The change in the
1231     selection is represented as an item selection of \a deselected items and
1232     an item selection of \a selected items.
1233 
1234     Note the that the current index changes independently from the selection.
1235     Also note that this signal will not be emitted when the item model is reset.
1236 
1237     \sa select(), currentChanged()
1238 */
1239 
1240 /*!
1241     \fn void QItemSelectionModel::modelChanged(QAbstractItemModel *model)
1242     \since 5.5
1243 
1244     This signal is emitted when the \a model is successfully set with setModel().
1245 
1246     \sa model(), setModel()
1247 */
1248 
1249 
1250 /*!
1251     \enum QItemSelectionModel::SelectionFlag
1252 
1253     This enum describes the way the selection model will be updated.
1254 
1255     \value NoUpdate       No selection will be made.
1256     \value Clear          The complete selection will be cleared.
1257     \value Select         All specified indexes will be selected.
1258     \value Deselect       All specified indexes will be deselected.
1259     \value Toggle         All specified indexes will be selected or
1260                           deselected depending on their current state.
1261     \value Current        The current selection will be updated.
1262     \value Rows           All indexes will be expanded to span rows.
1263     \value Columns        All indexes will be expanded to span columns.
1264     \value SelectCurrent  A combination of Select and Current, provided for
1265                           convenience.
1266     \value ToggleCurrent  A combination of Toggle and Current, provided for
1267                           convenience.
1268     \value ClearAndSelect A combination of Clear and Select, provided for
1269                           convenience.
1270 */
1271 
1272 namespace {
1273 namespace QtFunctionObjects {
1274 struct IsNotValid {
1275     typedef bool result_type;
1276     struct is_transparent : std::true_type {};
1277     template <typename T>
operator ()__anon3b845bc70111::QtFunctionObjects::IsNotValid1278     Q_DECL_CONSTEXPR bool operator()(T &t) const noexcept(noexcept(t.isValid()))
1279     { return !t.isValid(); }
1280     template <typename T>
operator ()__anon3b845bc70111::QtFunctionObjects::IsNotValid1281     Q_DECL_CONSTEXPR bool operator()(T *t) const noexcept(noexcept(t->isValid()))
1282     { return !t->isValid(); }
1283 };
1284 }
1285 } // unnamed namespace
1286 
1287 /*!
1288     Selects the item \a selection using the specified \a command, and emits
1289     selectionChanged().
1290 
1291     \sa QItemSelectionModel::SelectionFlag
1292 */
select(const QItemSelection & selection,QItemSelectionModel::SelectionFlags command)1293 void QItemSelectionModel::select(const QItemSelection &selection, QItemSelectionModel::SelectionFlags command)
1294 {
1295     Q_D(QItemSelectionModel);
1296     if (!d->model) {
1297         qWarning("QItemSelectionModel: Selecting when no model has been set will result in a no-op.");
1298         return;
1299     }
1300     if (command == NoUpdate)
1301         return;
1302 
1303     // store old selection
1304     QItemSelection sel = selection;
1305     // If d->ranges is non-empty when the source model is reset the persistent indexes
1306     // it contains will be invalid. We can't clear them in a modelReset slot because that might already
1307     // be too late if another model observer is connected to the same modelReset slot and is invoked first
1308     // it might call select() on this selection model before any such QItemSelectionModelPrivate::_q_modelReset() slot
1309     // is invoked, so it would not be cleared yet. We clear it invalid ranges in it here.
1310     using namespace QtFunctionObjects;
1311     d->ranges.erase(std::remove_if(d->ranges.begin(), d->ranges.end(), IsNotValid()),
1312                     d->ranges.end());
1313 
1314     QItemSelection old = d->ranges;
1315     old.merge(d->currentSelection, d->currentCommand);
1316 
1317     // expand selection according to SelectionBehavior
1318     if (command & Rows || command & Columns)
1319         sel = d->expandSelection(sel, command);
1320 
1321     // clear ranges and currentSelection
1322     if (command & Clear) {
1323         d->ranges.clear();
1324         d->currentSelection.clear();
1325     }
1326 
1327     // merge and clear currentSelection if Current was not set (ie. start new currentSelection)
1328     if (!(command & Current))
1329         d->finalize();
1330 
1331     // update currentSelection
1332     if (command & Toggle || command & Select || command & Deselect) {
1333         d->currentCommand = command;
1334         d->currentSelection = sel;
1335     }
1336 
1337     // generate new selection, compare with old and emit selectionChanged()
1338     QItemSelection newSelection = d->ranges;
1339     newSelection.merge(d->currentSelection, d->currentCommand);
1340     emitSelectionChanged(newSelection, old);
1341 }
1342 
1343 /*!
1344     Clears the selection model. Emits selectionChanged() and currentChanged().
1345 */
clear()1346 void QItemSelectionModel::clear()
1347 {
1348     clearSelection();
1349     clearCurrentIndex();
1350 }
1351 
1352 /*!
1353     Clears the current index. Emits currentChanged().
1354  */
clearCurrentIndex()1355 void QItemSelectionModel::clearCurrentIndex()
1356 {
1357     Q_D(QItemSelectionModel);
1358     QModelIndex previous = d->currentIndex;
1359     d->currentIndex = QModelIndex();
1360     if (previous.isValid()) {
1361         emit currentChanged(d->currentIndex, previous);
1362         emit currentRowChanged(d->currentIndex, previous);
1363         emit currentColumnChanged(d->currentIndex, previous);
1364     }
1365 }
1366 
1367 /*!
1368     Clears the selection model. Does not emit any signals.
1369 */
reset()1370 void QItemSelectionModel::reset()
1371 {
1372     const QSignalBlocker blocker(this);
1373     clear();
1374 }
1375 
1376 /*!
1377     \since 4.2
1378     Clears the selection in the selection model. Emits selectionChanged().
1379 */
clearSelection()1380 void QItemSelectionModel::clearSelection()
1381 {
1382     Q_D(QItemSelectionModel);
1383     if (d->ranges.count() == 0 && d->currentSelection.count() == 0)
1384         return;
1385 
1386     select(QItemSelection(), Clear);
1387 }
1388 
1389 
1390 /*!
1391     Sets the model item \a index to be the current item, and emits
1392     currentChanged(). The current item is used for keyboard navigation and
1393     focus indication; it is independent of any selected items, although a
1394     selected item can also be the current item.
1395 
1396     Depending on the specified \a command, the \a index can also become part
1397     of the current selection.
1398     \sa select()
1399 */
setCurrentIndex(const QModelIndex & index,QItemSelectionModel::SelectionFlags command)1400 void QItemSelectionModel::setCurrentIndex(const QModelIndex &index, QItemSelectionModel::SelectionFlags command)
1401 {
1402     Q_D(QItemSelectionModel);
1403     if (!d->model) {
1404         qWarning("QItemSelectionModel: Setting the current index when no model has been set will result in a no-op.");
1405         return;
1406     }
1407     if (index == d->currentIndex) {
1408         if (command != NoUpdate)
1409             select(index, command); // select item
1410         return;
1411     }
1412     QPersistentModelIndex previous = d->currentIndex;
1413     d->currentIndex = index; // set current before emitting selection changed below
1414     if (command != NoUpdate)
1415         select(d->currentIndex, command); // select item
1416     emit currentChanged(d->currentIndex, previous);
1417     if (d->currentIndex.row() != previous.row() ||
1418             d->currentIndex.parent() != previous.parent())
1419         emit currentRowChanged(d->currentIndex, previous);
1420     if (d->currentIndex.column() != previous.column() ||
1421             d->currentIndex.parent() != previous.parent())
1422         emit currentColumnChanged(d->currentIndex, previous);
1423 }
1424 
1425 /*!
1426     Returns the model item index for the current item, or an invalid index
1427     if there is no current item.
1428 */
currentIndex() const1429 QModelIndex QItemSelectionModel::currentIndex() const
1430 {
1431     return static_cast<QModelIndex>(d_func()->currentIndex);
1432 }
1433 
1434 /*!
1435     Returns \c true if the given model item \a index is selected.
1436 */
isSelected(const QModelIndex & index) const1437 bool QItemSelectionModel::isSelected(const QModelIndex &index) const
1438 {
1439     Q_D(const QItemSelectionModel);
1440     if (d->model != index.model() || !index.isValid())
1441         return false;
1442 
1443     bool selected = false;
1444     //  search model ranges
1445     QList<QItemSelectionRange>::const_iterator it = d->ranges.begin();
1446     for (; it != d->ranges.end(); ++it) {
1447         if ((*it).isValid() && (*it).contains(index)) {
1448             selected = true;
1449             break;
1450         }
1451     }
1452 
1453     // check  currentSelection
1454     if (d->currentSelection.count()) {
1455         if ((d->currentCommand & Deselect) && selected)
1456             selected = !d->currentSelection.contains(index);
1457         else if (d->currentCommand & Toggle)
1458             selected ^= d->currentSelection.contains(index);
1459         else if ((d->currentCommand & Select) && !selected)
1460             selected = d->currentSelection.contains(index);
1461     }
1462 
1463     if (selected) {
1464         Qt::ItemFlags flags = d->model->flags(index);
1465         return (flags & Qt::ItemIsSelectable);
1466     }
1467 
1468     return false;
1469 }
1470 
1471 /*!
1472     Returns \c true if all items are selected in the \a row with the given
1473     \a parent.
1474 
1475     Note that this function is usually faster than calling isSelected()
1476     on all items in the same row and that unselectable items are
1477     ignored.
1478 
1479     \note Since Qt 5.15, the default argument for \a parent is an empty
1480           model index.
1481 */
isRowSelected(int row,const QModelIndex & parent) const1482 bool QItemSelectionModel::isRowSelected(int row, const QModelIndex &parent) const
1483 {
1484     Q_D(const QItemSelectionModel);
1485     if (!d->model)
1486         return false;
1487     if (parent.isValid() && d->model != parent.model())
1488         return false;
1489 
1490     // return false if row exist in currentSelection (Deselect)
1491     if (d->currentCommand & Deselect && d->currentSelection.count()) {
1492         for (int i=0; i<d->currentSelection.count(); ++i) {
1493             if (d->currentSelection.at(i).parent() == parent &&
1494                 row >= d->currentSelection.at(i).top() &&
1495                 row <= d->currentSelection.at(i).bottom())
1496                 return false;
1497         }
1498     }
1499     // return false if ranges in both currentSelection and ranges
1500     // intersect and have the same row contained
1501     if (d->currentCommand & Toggle && d->currentSelection.count()) {
1502         for (int i=0; i<d->currentSelection.count(); ++i)
1503             if (d->currentSelection.at(i).top() <= row &&
1504                 d->currentSelection.at(i).bottom() >= row)
1505                 for (int j=0; j<d->ranges.count(); ++j)
1506                     if (d->ranges.at(j).top() <= row && d->ranges.at(j).bottom() >= row
1507                         && d->currentSelection.at(i).intersected(d->ranges.at(j)).isValid())
1508                         return false;
1509     }
1510 
1511     auto isSelectable = [&](int row, int column) {
1512         Qt::ItemFlags flags = d->model->index(row, column, parent).flags();
1513         return (flags & Qt::ItemIsSelectable);
1514     };
1515 
1516     const int colCount = d->model->columnCount(parent);
1517     int unselectable = 0;
1518     // add ranges and currentSelection and check through them all
1519     QList<QItemSelectionRange>::const_iterator it;
1520     QList<QItemSelectionRange> joined = d->ranges;
1521     if (d->currentSelection.count())
1522         joined += d->currentSelection;
1523     for (int column = 0; column < colCount; ++column) {
1524         if (!isSelectable(row, column)) {
1525             ++unselectable;
1526             continue;
1527         }
1528 
1529         for (it = joined.constBegin(); it != joined.constEnd(); ++it) {
1530             if ((*it).contains(row, column, parent)) {
1531                 for (int i = column; i <= (*it).right(); ++i) {
1532                     if (!isSelectable(row, i))
1533                         ++unselectable;
1534                 }
1535 
1536                 column = qMax(column, (*it).right());
1537                 break;
1538             }
1539         }
1540         if (it == joined.constEnd())
1541             return false;
1542     }
1543     return unselectable < colCount;
1544 }
1545 
1546 /*!
1547     Returns \c true if all items are selected in the \a column with the given
1548     \a parent.
1549 
1550     Note that this function is usually faster than calling isSelected()
1551     on all items in the same column and that unselectable items are
1552     ignored.
1553 
1554     \note Since Qt 5.15, the default argument for \a parent is an empty
1555           model index.
1556 */
isColumnSelected(int column,const QModelIndex & parent) const1557 bool QItemSelectionModel::isColumnSelected(int column, const QModelIndex &parent) const
1558 {
1559     Q_D(const QItemSelectionModel);
1560     if (!d->model)
1561         return false;
1562     if (parent.isValid() && d->model != parent.model())
1563         return false;
1564 
1565     // return false if column exist in currentSelection (Deselect)
1566     if (d->currentCommand & Deselect && d->currentSelection.count()) {
1567         for (int i = 0; i < d->currentSelection.count(); ++i) {
1568             if (d->currentSelection.at(i).parent() == parent &&
1569                 column >= d->currentSelection.at(i).left() &&
1570                 column <= d->currentSelection.at(i).right())
1571                 return false;
1572         }
1573     }
1574     // return false if ranges in both currentSelection and the selection model
1575     // intersect and have the same column contained
1576     if (d->currentCommand & Toggle && d->currentSelection.count()) {
1577         for (int i = 0; i < d->currentSelection.count(); ++i) {
1578             if (d->currentSelection.at(i).left() <= column &&
1579                 d->currentSelection.at(i).right() >= column) {
1580                 for (int j = 0; j < d->ranges.count(); ++j) {
1581                     if (d->ranges.at(j).left() <= column && d->ranges.at(j).right() >= column
1582                         && d->currentSelection.at(i).intersected(d->ranges.at(j)).isValid()) {
1583                         return false;
1584                     }
1585                 }
1586             }
1587         }
1588     }
1589 
1590     auto isSelectable = [&](int row, int column) {
1591         Qt::ItemFlags flags = d->model->index(row, column, parent).flags();
1592         return (flags & Qt::ItemIsSelectable);
1593     };
1594     const int rowCount = d->model->rowCount(parent);
1595     int unselectable = 0;
1596 
1597     // add ranges and currentSelection and check through them all
1598     QList<QItemSelectionRange>::const_iterator it;
1599     QList<QItemSelectionRange> joined = d->ranges;
1600     if (d->currentSelection.count())
1601         joined += d->currentSelection;
1602     for (int row = 0; row < rowCount; ++row) {
1603         if (!isSelectable(row, column)) {
1604             ++unselectable;
1605             continue;
1606         }
1607         for (it = joined.constBegin(); it != joined.constEnd(); ++it) {
1608             if ((*it).contains(row, column, parent)) {
1609                 for (int i = row; i <= (*it).bottom(); ++i) {
1610                     if (!isSelectable(i, column)) {
1611                         ++unselectable;
1612                     }
1613                 }
1614                 row = qMax(row, (*it).bottom());
1615                 break;
1616             }
1617         }
1618         if (it == joined.constEnd())
1619             return false;
1620     }
1621     return unselectable < rowCount;
1622 }
1623 
1624 /*!
1625     Returns \c true if there are any items selected in the \a row with the given
1626     \a parent.
1627 
1628     \note Since Qt 5.15, the default argument for \a parent is an empty
1629           model index.
1630 */
rowIntersectsSelection(int row,const QModelIndex & parent) const1631 bool QItemSelectionModel::rowIntersectsSelection(int row, const QModelIndex &parent) const
1632 {
1633     Q_D(const QItemSelectionModel);
1634     if (!d->model)
1635         return false;
1636     if (parent.isValid() && d->model != parent.model())
1637          return false;
1638 
1639     QItemSelection sel = d->ranges;
1640     sel.merge(d->currentSelection, d->currentCommand);
1641     for (const QItemSelectionRange &range : qAsConst(sel)) {
1642         if (range.parent() != parent)
1643             return false;
1644         int top = range.top();
1645         int bottom = range.bottom();
1646         int left = range.left();
1647         int right = range.right();
1648         if (top <= row && bottom >= row) {
1649             for (int j = left; j <= right; j++) {
1650                 const Qt::ItemFlags flags = d->model->index(row, j, parent).flags();
1651                 if ((flags & Qt::ItemIsSelectable) && (flags & Qt::ItemIsEnabled))
1652                     return true;
1653             }
1654         }
1655     }
1656 
1657     return false;
1658 }
1659 
1660 /*!
1661     Returns \c true if there are any items selected in the \a column with the given
1662     \a parent.
1663 
1664     \note Since Qt 5.15, the default argument for \a parent is an empty
1665           model index.
1666 */
columnIntersectsSelection(int column,const QModelIndex & parent) const1667 bool QItemSelectionModel::columnIntersectsSelection(int column, const QModelIndex &parent) const
1668 {
1669     Q_D(const QItemSelectionModel);
1670     if (!d->model)
1671         return false;
1672     if (parent.isValid() && d->model != parent.model())
1673         return false;
1674 
1675     QItemSelection sel = d->ranges;
1676     sel.merge(d->currentSelection, d->currentCommand);
1677     for (const QItemSelectionRange &range : qAsConst(sel)) {
1678         if (range.parent() != parent)
1679             return false;
1680         int top = range.top();
1681         int bottom = range.bottom();
1682         int left = range.left();
1683         int right = range.right();
1684         if (left <= column && right >= column) {
1685             for (int j = top; j <= bottom; j++) {
1686                 const Qt::ItemFlags flags = d->model->index(j, column, parent).flags();
1687                 if ((flags & Qt::ItemIsSelectable) && (flags & Qt::ItemIsEnabled))
1688                     return true;
1689             }
1690         }
1691     }
1692 
1693     return false;
1694 }
1695 
1696 /*!
1697     \since 4.2
1698 
1699     Returns \c true if the selection model contains any selection ranges;
1700     otherwise returns \c false.
1701 */
hasSelection() const1702 bool QItemSelectionModel::hasSelection() const
1703 {
1704     Q_D(const QItemSelectionModel);
1705     if (d->currentCommand & (Toggle | Deselect)) {
1706         QItemSelection sel = d->ranges;
1707         sel.merge(d->currentSelection, d->currentCommand);
1708         return !sel.isEmpty();
1709     } else {
1710         return !(d->ranges.isEmpty() && d->currentSelection.isEmpty());
1711     }
1712 }
1713 
1714 /*!
1715     Returns a list of all selected model item indexes. The list contains no
1716     duplicates, and is not sorted.
1717 */
selectedIndexes() const1718 QModelIndexList QItemSelectionModel::selectedIndexes() const
1719 {
1720     Q_D(const QItemSelectionModel);
1721     QItemSelection selected = d->ranges;
1722     selected.merge(d->currentSelection, d->currentCommand);
1723     return selected.indexes();
1724 }
1725 
1726 /*!
1727     \since 4.2
1728     Returns the indexes in the given \a column for the rows where all columns are selected.
1729 
1730     \sa selectedIndexes(), selectedColumns()
1731 */
1732 
selectedRows(int column) const1733 QModelIndexList QItemSelectionModel::selectedRows(int column) const
1734 {
1735     QModelIndexList indexes;
1736     //the QSet contains pairs of parent modelIndex
1737     //and row number
1738     QSet< QPair<QModelIndex, int> > rowsSeen;
1739 
1740     const QItemSelection ranges = selection();
1741     for (int i = 0; i < ranges.count(); ++i) {
1742         const QItemSelectionRange &range = ranges.at(i);
1743         QModelIndex parent = range.parent();
1744         for (int row = range.top(); row <= range.bottom(); row++) {
1745             QPair<QModelIndex, int> rowDef = qMakePair(parent, row);
1746             if (!rowsSeen.contains(rowDef)) {
1747                 rowsSeen << rowDef;
1748                 if (isRowSelected(row, parent)) {
1749                     indexes.append(model()->index(row, column, parent));
1750                 }
1751             }
1752         }
1753     }
1754 
1755     return indexes;
1756 }
1757 
1758 /*!
1759     \since 4.2
1760     Returns the indexes in the given \a row for columns where all rows are selected.
1761 
1762     \sa selectedIndexes(), selectedRows()
1763 */
1764 
selectedColumns(int row) const1765 QModelIndexList QItemSelectionModel::selectedColumns(int row) const
1766 {
1767     QModelIndexList indexes;
1768     //the QSet contains pairs of parent modelIndex
1769     //and column number
1770     QSet< QPair<QModelIndex, int> > columnsSeen;
1771 
1772     const QItemSelection ranges = selection();
1773     for (int i = 0; i < ranges.count(); ++i) {
1774         const QItemSelectionRange &range = ranges.at(i);
1775         QModelIndex parent = range.parent();
1776         for (int column = range.left(); column <= range.right(); column++) {
1777             QPair<QModelIndex, int> columnDef = qMakePair(parent, column);
1778             if (!columnsSeen.contains(columnDef)) {
1779                 columnsSeen << columnDef;
1780                 if (isColumnSelected(column, parent)) {
1781                     indexes.append(model()->index(row, column, parent));
1782                 }
1783             }
1784         }
1785     }
1786 
1787     return indexes;
1788 }
1789 
1790 /*!
1791     Returns the selection ranges stored in the selection model.
1792 */
selection() const1793 const QItemSelection QItemSelectionModel::selection() const
1794 {
1795     Q_D(const QItemSelectionModel);
1796     QItemSelection selected = d->ranges;
1797     selected.merge(d->currentSelection, d->currentCommand);
1798     // make sure we have no invalid ranges
1799     // ###  should probably be handled more generic somewhere else
1800     using namespace QtFunctionObjects;
1801     selected.erase(std::remove_if(selected.begin(), selected.end(),
1802                                   IsNotValid()),
1803                    selected.end());
1804     return selected;
1805 }
1806 
1807 /*!
1808     \since 5.5
1809 
1810     \property QItemSelectionModel::hasSelection
1811     \internal
1812 */
1813 /*!
1814     \since 5.5
1815 
1816     \property QItemSelectionModel::currentIndex
1817     \internal
1818 */
1819 /*!
1820     \since 5.5
1821 
1822     \property QItemSelectionModel::selectedIndexes
1823 */
1824 
1825 /*!
1826     \since 5.5
1827 
1828     \property QItemSelectionModel::selection
1829     \internal
1830 */
1831 /*!
1832     \since 5.5
1833 
1834     \property QItemSelectionModel::model
1835     \internal
1836 */
1837 /*!
1838     \since 5.5
1839 
1840     Returns the item model operated on by the selection model.
1841 */
model()1842 QAbstractItemModel *QItemSelectionModel::model()
1843 {
1844     return d_func()->model;
1845 }
1846 
1847 /*!
1848     Returns the item model operated on by the selection model.
1849 */
model() const1850 const QAbstractItemModel *QItemSelectionModel::model() const
1851 {
1852     return d_func()->model;
1853 }
1854 
1855 /*!
1856     \since 5.5
1857 
1858     Sets the model to \a model. The modelChanged() signal will be emitted.
1859 
1860     \sa model(), modelChanged()
1861 */
setModel(QAbstractItemModel * model)1862 void QItemSelectionModel::setModel(QAbstractItemModel *model)
1863 {
1864     Q_D(QItemSelectionModel);
1865     if (d->model == model)
1866         return;
1867 
1868     d->initModel(model);
1869     emit modelChanged(model);
1870 }
1871 
1872 /*!
1873     Compares the two selections \a newSelection and \a oldSelection
1874     and emits selectionChanged() with the deselected and selected items.
1875 */
emitSelectionChanged(const QItemSelection & newSelection,const QItemSelection & oldSelection)1876 void QItemSelectionModel::emitSelectionChanged(const QItemSelection &newSelection,
1877                                                const QItemSelection &oldSelection)
1878 {
1879     // if both selections are empty or equal we return
1880     if ((oldSelection.isEmpty() && newSelection.isEmpty()) ||
1881         oldSelection == newSelection)
1882         return;
1883 
1884     // if either selection is empty we do not need to compare
1885     if (oldSelection.isEmpty() || newSelection.isEmpty()) {
1886         emit selectionChanged(newSelection, oldSelection);
1887         return;
1888     }
1889 
1890     QItemSelection deselected = oldSelection;
1891     QItemSelection selected = newSelection;
1892 
1893     // remove equal ranges
1894     bool advance;
1895     for (int o = 0; o < deselected.count(); ++o) {
1896         advance = true;
1897         for (int s = 0; s < selected.count() && o < deselected.count();) {
1898             if (deselected.at(o) == selected.at(s)) {
1899                 deselected.removeAt(o);
1900                 selected.removeAt(s);
1901                 advance = false;
1902             } else {
1903                 ++s;
1904             }
1905         }
1906         if (advance)
1907             ++o;
1908     }
1909 
1910     // find intersections
1911     QItemSelection intersections;
1912     for (int o = 0; o < deselected.count(); ++o) {
1913         for (int s = 0; s < selected.count(); ++s) {
1914             if (deselected.at(o).intersects(selected.at(s)))
1915                 intersections.append(deselected.at(o).intersected(selected.at(s)));
1916         }
1917     }
1918 
1919     // compare remaining ranges with intersections and split them to find deselected and selected
1920     for (int i = 0; i < intersections.count(); ++i) {
1921         // split deselected
1922         for (int o = 0; o < deselected.count();) {
1923             if (deselected.at(o).intersects(intersections.at(i))) {
1924                 QItemSelection::split(deselected.at(o), intersections.at(i), &deselected);
1925                 deselected.removeAt(o);
1926             } else {
1927                 ++o;
1928             }
1929         }
1930         // split selected
1931         for (int s = 0; s < selected.count();) {
1932             if (selected.at(s).intersects(intersections.at(i))) {
1933                 QItemSelection::split(selected.at(s), intersections.at(i), &selected);
1934                 selected.removeAt(s);
1935             } else {
1936                 ++s;
1937             }
1938         }
1939     }
1940 
1941     if (!selected.isEmpty() || !deselected.isEmpty())
1942         emit selectionChanged(selected, deselected);
1943 }
1944 
1945 #ifndef QT_NO_DEBUG_STREAM
operator <<(QDebug dbg,const QItemSelectionRange & range)1946 QDebug operator<<(QDebug dbg, const QItemSelectionRange &range)
1947 {
1948     QDebugStateSaver saver(dbg);
1949     dbg.nospace() << "QItemSelectionRange(" << range.topLeft()
1950                   << ',' << range.bottomRight() << ')';
1951     return dbg;
1952 }
1953 #endif
1954 
1955 QT_END_NAMESPACE
1956 
1957 #include "moc_qitemselectionmodel.cpp"
1958