Qt
Internal/Contributor docs for the Qt SDK. <b>Note:</b> These are NOT official API docs; those are found <a href='https://doc.qt.io/'>here</a>.
Loading...
Searching...
No Matches
qitemselectionmodel.cpp
Go to the documentation of this file.
1// Copyright (C) 2021 The Qt Company Ltd.
2// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only
3
6
7#include <private/qitemselectionmodel_p.h>
8#include <private/qabstractitemmodel_p.h>
9#include <private/qduplicatetracker_p.h>
10#include <private/qoffsetstringarray_p.h>
11#include <qdebug.h>
12
13#include <algorithm>
14#include <functional>
15
17
20
21
185bool QItemSelectionRange::intersects(const QItemSelectionRange &other) const
186{
187 // isValid() and parent() last since they are more expensive
188 return (model() == other.model()
189 && ((top() <= other.top() && bottom() >= other.top())
190 || (top() >= other.top() && top() <= other.bottom()))
191 && ((left() <= other.left() && right() >= other.left())
192 || (left() >= other.left() && left() <= other.right()))
193 && parent() == other.parent()
194 && isValid() && other.isValid()
195 );
196}
197
207{
208 if (model() == other.model() && parent() == other.parent()) {
209 QModelIndex topLeft = model()->index(qMax(top(), other.top()),
210 qMax(left(), other.left()),
211 other.parent());
213 qMin(right(), other.right()),
214 other.parent());
216 }
217 return QItemSelectionRange();
218}
219
243static void rowLengthsFromRange(const QItemSelectionRange &range, QList<std::pair<QPersistentModelIndex, uint>> &result)
244{
245 if (range.isValid() && range.model()) {
246 const QModelIndex topLeft = range.topLeft();
247 const int bottom = range.bottom();
248 const uint width = range.width();
249 const int column = topLeft.column();
250 for (int row = topLeft.row(); row <= bottom; ++row) {
251 // We don't need to keep track of ItemIsSelectable and ItemIsEnabled here. That is
252 // required in indexesFromRange() because that method is called from public API
253 // which requires the limitation.
254 result.emplace_back(topLeft.sibling(row, column), width);
255 }
256 }
257}
258
259static bool isSelectableAndEnabled(Qt::ItemFlags flags)
260{
261 return flags.testFlags(Qt::ItemIsSelectable | Qt::ItemIsEnabled);
262}
263
264template<typename ModelIndexContainer>
265static void indexesFromRange(const QItemSelectionRange &range, ModelIndexContainer &result)
266{
267 if (range.isValid() && range.model()) {
268 const QModelIndex topLeft = range.topLeft();
269 const int bottom = range.bottom();
270 const int right = range.right();
271 for (int row = topLeft.row(); row <= bottom; ++row) {
272 const QModelIndex columnLeader = topLeft.sibling(row, topLeft.column());
273 for (int column = topLeft.column(); column <= right; ++column) {
274 QModelIndex index = columnLeader.sibling(row, column);
275 if (isSelectableAndEnabled(range.model()->flags(index)))
276 result.push_back(index);
277 }
278 }
279 }
280}
281
282template<typename ModelIndexContainer>
283static ModelIndexContainer qSelectionIndexes(const QItemSelection &selection)
284{
285 ModelIndexContainer result;
286 for (const auto &range : selection)
288 return result;
289}
290
299{
300 if (!isValid() || !model())
301 return true;
302
303 for (int column = left(); column <= right(); ++column) {
304 for (int row = top(); row <= bottom(); ++row) {
307 return false;
308 }
309 }
310 return true;
311}
312
323
377QItemSelection::QItemSelection(const QModelIndex &topLeft, const QModelIndex &bottomRight)
378{
379 select(topLeft, bottomRight);
380}
381
389void QItemSelection::select(const QModelIndex &topLeft, const QModelIndex &bottomRight)
390{
391 if (!topLeft.isValid() || !bottomRight.isValid())
392 return;
393
394 if ((topLeft.model() != bottomRight.model())
395 || topLeft.parent() != bottomRight.parent()) {
396 qWarning("Can't select indexes from different model or with different parents");
397 return;
398 }
399 if (topLeft.row() > bottomRight.row() || topLeft.column() > bottomRight.column()) {
400 int top = qMin(topLeft.row(), bottomRight.row());
401 int bottom = qMax(topLeft.row(), bottomRight.row());
402 int left = qMin(topLeft.column(), bottomRight.column());
403 int right = qMax(topLeft.column(), bottomRight.column());
404 QModelIndex tl = topLeft.sibling(top, left);
405 QModelIndex br = bottomRight.sibling(bottom, right);
407 return;
408 }
409 append(QItemSelectionRange(topLeft, bottomRight));
410}
411
418{
419 if (isSelectableAndEnabled(index.flags())) {
421 for (; it != end(); ++it)
422 if ((*it).contains(index))
423 return true;
424 }
425 return false;
426}
427
433{
434 return qSelectionIndexes<QModelIndexList>(*this);
435}
436
437static QList<std::pair<QPersistentModelIndex, uint>> qSelectionPersistentRowLengths(const QItemSelection &sel)
438{
439 QList<std::pair<QPersistentModelIndex, uint>> result;
440 for (const QItemSelectionRange &range : sel)
442 return result;
443}
444
455void QItemSelection::merge(const QItemSelection &other, QItemSelectionModel::SelectionFlags command)
456{
457 if (other.isEmpty() ||
458 !(command & QItemSelectionModel::Select ||
461 return;
462
463 QItemSelection newSelection;
464 newSelection.reserve(other.size());
465 // Collect intersections
466 QItemSelection intersections;
467 for (const auto &range : other) {
468 if (!range.isValid())
469 continue;
470 newSelection.push_back(range);
471 for (int t = 0; t < size(); ++t) {
472 if (range.intersects(at(t)))
473 intersections.append(at(t).intersected(range));
474 }
475 }
476
477 // Split the old (and new) ranges using the intersections
478 for (int i = 0; i < intersections.size(); ++i) { // for each intersection
479 for (int t = 0; t < size();) { // splitt each old range
480 if (at(t).intersects(intersections.at(i))) {
481 split(at(t), intersections.at(i), this);
482 removeAt(t);
483 } else {
484 ++t;
485 }
486 }
487 // only split newSelection if Toggle is specified
488 for (int n = 0; (command & QItemSelectionModel::Toggle) && n < newSelection.size();) {
489 if (newSelection.at(n).intersects(intersections.at(i))) {
490 split(newSelection.at(n), intersections.at(i), &newSelection);
491 newSelection.removeAt(n);
492 } else {
493 ++n;
494 }
495 }
496 }
497 // do not add newSelection for Deselect
498 if (!(command & QItemSelectionModel::Deselect))
499 operator+=(newSelection);
500}
501
511{
512 if (range.parent() != other.parent() || range.model() != other.model())
513 return;
514
515 QModelIndex parent = other.parent();
516 int top = range.top();
517 int left = range.left();
518 int bottom = range.bottom();
519 int right = range.right();
520 int other_top = other.top();
521 int other_left = other.left();
522 int other_bottom = other.bottom();
523 int other_right = other.right();
524 const QAbstractItemModel *model = range.model();
526 if (other_top > top) {
527 QModelIndex tl = model->index(top, left, parent);
528 QModelIndex br = model->index(other_top - 1, right, parent);
529 result->append(QItemSelectionRange(tl, br));
530 top = other_top;
531 }
532 if (other_bottom < bottom) {
533 QModelIndex tl = model->index(other_bottom + 1, left, parent);
534 QModelIndex br = model->index(bottom, right, parent);
535 result->append(QItemSelectionRange(tl, br));
536 bottom = other_bottom;
537 }
538 if (other_left > left) {
539 QModelIndex tl = model->index(top, left, parent);
540 QModelIndex br = model->index(bottom, other_left - 1, parent);
541 result->append(QItemSelectionRange(tl, br));
542 left = other_left;
543 }
544 if (other_right < right) {
545 QModelIndex tl = model->index(top, other_right + 1, parent);
546 QModelIndex br = model->index(bottom, right, parent);
547 result->append(QItemSelectionRange(tl, br));
548 right = other_right;
549 }
550}
551
552
554{
556 const QAbstractItemModel *oldModel = model.valueBypassingBindings();
557 if (oldModel == m)
558 return;
559
560 if (oldModel) {
561 q->reset();
563 }
564
565 // Caller has to call notify(), unless calling during construction (the common case).
566 model.setValueBypassingBindings(m);
567
568 if (m) {
569 connections = std::array<QMetaObject::Connection, 12> {
594 };
595 }
596}
597
603
613 QItemSelectionModel::SelectionFlags command) const
614{
615 if (selection.isEmpty() && !((command & QItemSelectionModel::Rows) ||
616 (command & QItemSelectionModel::Columns)))
617 return selection;
618
619 QItemSelection expanded;
620 if (command & QItemSelectionModel::Rows) {
621 for (int i = 0; i < selection.size(); ++i) {
623 int colCount = model->columnCount(parent);
625 QModelIndex br = model->index(selection.at(i).bottom(), colCount - 1, parent);
626 //we need to merge because the same row could have already been inserted
628 }
629 }
630 if (command & QItemSelectionModel::Columns) {
631 for (int i = 0; i < selection.size(); ++i) {
633 int rowCount = model->rowCount(parent);
635 QModelIndex br = model->index(rowCount - 1, selection.at(i).right(), parent);
636 //we need to merge because the same column could have already been inserted
638 }
639 }
640 return expanded;
641}
642
647 int start, int end)
648{
650 Q_ASSERT(start <= end);
651 finalize();
652
653 // update current index
655 && currentIndex.row() >= start && currentIndex.row() <= end) {
657 if (start > 0) {
658 // there are rows left above the change
659 currentIndex = model->index(start - 1, old.column(), parent);
660 } else if (model.value() && end < model->rowCount(parent) - 1) {
661 // there are rows left below the change
662 currentIndex = model->index(end + 1, old.column(), parent);
663 } else {
664 // there are no rows left in the table
666 }
667 emit q->currentChanged(currentIndex, old);
668 emit q->currentRowChanged(currentIndex, old);
669 if (currentIndex.column() != old.column())
670 emit q->currentColumnChanged(currentIndex, old);
671 }
672
673 QItemSelection deselected;
674 QItemSelection newParts;
675 bool indexesOfSelectionChanged = false;
676 QItemSelection::iterator it = ranges.begin();
677 while (it != ranges.end()) {
678 if (it->topLeft().parent() != parent) { // Check parents until reaching root or contained in range
679 QModelIndex itParent = it->topLeft().parent();
680 while (itParent.isValid() && itParent.parent() != parent)
681 itParent = itParent.parent();
682
683 if (itParent.isValid() && start <= itParent.row() && itParent.row() <= end) {
684 deselected.append(*it);
685 it = ranges.erase(it);
686 } else {
687 if (itParent.isValid() && end < itParent.row())
688 indexesOfSelectionChanged = true;
689 ++it;
690 }
691 } else if (start <= it->bottom() && it->bottom() <= end // Full inclusion
692 && start <= it->top() && it->top() <= end) {
693 deselected.append(*it);
694 it = ranges.erase(it);
695 } else if (start <= it->top() && it->top() <= end) { // Top intersection
696 deselected.append(QItemSelectionRange(it->topLeft(), model->index(end, it->right(), it->parent())));
697 *it = QItemSelectionRange(model->index(end + 1, it->left(), it->parent()), it->bottomRight());
698 ++it;
699 } else if (start <= it->bottom() && it->bottom() <= end) { // Bottom intersection
700 deselected.append(QItemSelectionRange(model->index(start, it->left(), it->parent()), it->bottomRight()));
701 *it = QItemSelectionRange(it->topLeft(), model->index(start - 1, it->right(), it->parent()));
702 ++it;
703 } else if (it->top() < start && end < it->bottom()) { // Middle intersection
704 // If the parent contains (1, 2, 3, 4, 5, 6, 7, 8) and [3, 4, 5, 6] is selected,
705 // and [4, 5] is removed, we need to split [3, 4, 5, 6] into [3], [4, 5] and [6].
706 // [4, 5] is appended to deselected, and [3] and [6] remain part of the selection
707 // in ranges.
708 const QItemSelectionRange removedRange(model->index(start, it->left(), it->parent()),
709 model->index(end, it->right(), it->parent()));
710 deselected.append(removedRange);
711 QItemSelection::split(*it, removedRange, &newParts);
712 it = ranges.erase(it);
713 } else if (end < it->top()) { // deleted row before selection
714 indexesOfSelectionChanged = true;
715 ++it;
716 } else {
717 ++it;
718 }
719 }
720 ranges.append(newParts);
721
722 if (!deselected.isEmpty() || indexesOfSelectionChanged)
723 emit q->selectionChanged(QItemSelection(), deselected);
724}
725
730 int start, int end)
731{
733
734 // update current index
738 if (start > 0) {
739 // there are columns to the left of the change
740 currentIndex = model->index(old.row(), start - 1, parent);
741 } else if (model.value() && end < model->columnCount() - 1) {
742 // there are columns to the right of the change
743 currentIndex = model->index(old.row(), end + 1, parent);
744 } else {
745 // there are no columns left in the table
747 }
748 emit q->currentChanged(currentIndex, old);
749 if (currentIndex.row() != old.row())
750 emit q->currentRowChanged(currentIndex, old);
751 emit q->currentColumnChanged(currentIndex, old);
752 }
753
754 // update selections
758 finalize();
759}
760
767 int start, int end)
768{
769 Q_UNUSED(end);
770 finalize();
771 QList<QItemSelectionRange> split;
773 for (; it != ranges.end(); ) {
774 const QModelIndex &itParent = it->parent();
775 if ((*it).isValid() && itParent == parent
776 && (*it).left() < start && (*it).right() >= start) {
777 QModelIndex bottomMiddle = model->index((*it).bottom(), start - 1, itParent);
778 QItemSelectionRange left((*it).topLeft(), bottomMiddle);
779 QModelIndex topMiddle = model->index((*it).top(), start, itParent);
780 QItemSelectionRange right(topMiddle, (*it).bottomRight());
781 it = ranges.erase(it);
782 split.append(left);
783 split.append(right);
784 } else {
785 ++it;
786 }
787 }
788 ranges += split;
789}
790
797 int start, int end)
798{
800 Q_UNUSED(end);
801 finalize();
802 QList<QItemSelectionRange> split;
804 bool indexesOfSelectionChanged = false;
805 for (; it != ranges.end(); ) {
806 const QModelIndex &itParent = it->parent();
807 if ((*it).isValid() && itParent == parent
808 && (*it).top() < start && (*it).bottom() >= start) {
809 QModelIndex middleRight = model->index(start - 1, (*it).right(), itParent);
810 QItemSelectionRange top((*it).topLeft(), middleRight);
811 QModelIndex middleLeft = model->index(start, (*it).left(), itParent);
812 QItemSelectionRange bottom(middleLeft, (*it).bottomRight());
813 it = ranges.erase(it);
814 split.append(top);
815 split.append(bottom);
816 } else if ((*it).isValid() && itParent == parent // insertion before selection
817 && (*it).top() >= start) {
818 indexesOfSelectionChanged = true;
819 ++it;
820 } else {
821 ++it;
822 }
823 }
824 ranges += split;
825
826 if (indexesOfSelectionChanged)
827 emit q->selectionChanged(QItemSelection(), QItemSelection());
828}
829
837void QItemSelectionModelPrivate::layoutAboutToBeChanged(const QList<QPersistentModelIndex> &,
839{
844
845 // optimization for when all indexes are selected
846 // (only if there is lots of items (1000) because this is not entirely correct)
847 if (ranges.isEmpty() && currentSelection.size() == 1) {
852 if (tableRowCount * tableColCount > 1000
853 && range.top() == 0
854 && range.left() == 0
855 && range.bottom() == tableRowCount - 1
856 && range.right() == tableColCount - 1) {
857 tableSelected = true;
859 return;
860 }
861 }
862 tableSelected = false;
863
865 // Special case when we know we're sorting vertically. We can assume that all indexes for columns
866 // are displaced the same way, and therefore we only need to track an index from one column per
867 // row with a QPersistentModelIndex together with the length of items to the right of it
868 // which are displaced the same way.
869 // An algorithm which contains the same assumption is used to process layoutChanged.
872 } else {
873 savedPersistentIndexes = qSelectionIndexes<QList<QPersistentModelIndex>>(ranges);
874 savedPersistentCurrentIndexes = qSelectionIndexes<QList<QPersistentModelIndex>>(currentSelection);
875 }
876}
880static QItemSelection mergeRowLengths(const QList<std::pair<QPersistentModelIndex, uint>> &rowLengths)
881{
882 if (rowLengths.isEmpty())
883 return QItemSelection();
884
886 int i = 0;
887 while (i < rowLengths.size()) {
888 const QPersistentModelIndex &tl = rowLengths.at(i).first;
889 if (!tl.isValid()) {
890 ++i;
891 continue;
892 }
893 QPersistentModelIndex br = tl;
894 const uint length = rowLengths.at(i).second;
895 while (++i < rowLengths.size()) {
896 const QPersistentModelIndex &next = rowLengths.at(i).first;
897 if (!next.isValid())
898 continue;
899 const uint nextLength = rowLengths.at(i).second;
900 if ((nextLength == length)
901 && (next.row() == br.row() + 1)
902 && (next.column() == br.column())
903 && (next.parent() == br.parent())) {
904 br = next;
905 } else {
906 break;
907 }
908 }
909 result.append(QItemSelectionRange(tl, br.sibling(br.row(), br.column() + length - 1)));
910 }
911 return result;
912}
913
920static QItemSelection mergeIndexes(const QList<QPersistentModelIndex> &indexes)
921{
922 QItemSelection colSpans;
923 // merge columns
924 int i = 0;
925 while (i < indexes.size()) {
926 const QPersistentModelIndex &tl = indexes.at(i);
927 if (!tl.isValid()) {
928 ++i;
929 continue;
930 }
931 QPersistentModelIndex br = tl;
932 QModelIndex brParent = br.parent();
933 int brRow = br.row();
934 int brColumn = br.column();
935 while (++i < indexes.size()) {
936 const QPersistentModelIndex &next = indexes.at(i);
937 if (!next.isValid())
938 continue;
939 const QModelIndex nextParent = next.parent();
940 const int nextRow = next.row();
941 const int nextColumn = next.column();
942 if ((nextParent == brParent)
943 && (nextRow == brRow)
944 && (nextColumn == brColumn + 1)) {
945 br = next;
946 brParent = nextParent;
947 brRow = nextRow;
948 brColumn = nextColumn;
949 } else {
950 break;
951 }
952 }
953 colSpans.append(QItemSelectionRange(tl, br));
954 }
955 // merge rows
956 QItemSelection rowSpans;
957 i = 0;
958 while (i < colSpans.size()) {
959 QModelIndex tl = colSpans.at(i).topLeft();
960 QModelIndex br = colSpans.at(i).bottomRight();
961 QModelIndex prevTl = tl;
962 while (++i < colSpans.size()) {
963 QModelIndex nextTl = colSpans.at(i).topLeft();
964 QModelIndex nextBr = colSpans.at(i).bottomRight();
965
966 if (nextTl.parent() != tl.parent())
967 break; // we can't merge selection ranges from different parents
968
969 if ((nextTl.column() == prevTl.column()) && (nextBr.column() == br.column())
970 && (nextTl.row() == prevTl.row() + 1) && (nextBr.row() == br.row() + 1)) {
971 br = nextBr;
972 prevTl = nextTl;
973 } else {
974 break;
975 }
976 }
977 rowSpans.append(QItemSelectionRange(tl, br));
978 }
979 return rowSpans;
980}
981
992{
993 const QModelIndex parent1 = i1.parent();
994 const QModelIndex parent2 = i2.parent();
995 return parent1 == parent2 ? i1 < i2 : parent1 < parent2;
996}
997
1004{
1005 // special case for when all indexes are selected
1008 ranges.clear();
1010 int bottom = tableRowCount - 1;
1011 int right = tableColCount - 1;
1012 QModelIndex tl = model->index(0, 0, tableParent);
1016 tableSelected = false;
1017 return;
1018 }
1019
1022 // either the selection was actually empty, or we
1023 // didn't get the layoutAboutToBeChanged() signal
1024 return;
1025 }
1026
1027 // clear the "old" selection
1028 ranges.clear();
1030
1032 // sort the "new" selection, as preparation for merging
1037
1038 // update the selection by merging the individual indexes
1041
1042 // release the persistent indexes
1045 } else {
1046 // sort the "new" selection, as preparation for merging
1049
1050 // update the selection by merging the individual indexes
1053
1054 // release the persistent indexes
1057 }
1058}
1059
1088{
1089 model.setValueBypassingBindings(nullptr);
1091 model.notify();
1092}
1093
1141
1146 : QObject(*new QItemSelectionModelPrivate, parent)
1147{
1148 d_func()->initModel(model);
1149}
1150
1159
1166
1173void QItemSelectionModel::select(const QModelIndex &index, QItemSelectionModel::SelectionFlags command)
1174{
1176 select(selection, command);
1177}
1178
1263namespace {
1265struct IsNotValid {
1266 typedef bool result_type;
1267 struct is_transparent : std::true_type {};
1268 template <typename T>
1269 constexpr bool operator()(T &t) const noexcept(noexcept(t.isValid()))
1270 { return !t.isValid(); }
1271 template <typename T>
1272 constexpr bool operator()(T *t) const noexcept(noexcept(t->isValid()))
1273 { return !t->isValid(); }
1274};
1275}
1276} // unnamed namespace
1277
1284void QItemSelectionModel::select(const QItemSelection &selection, QItemSelectionModel::SelectionFlags command)
1285{
1287 if (!d->model.value()) {
1288 qWarning("QItemSelectionModel: Selecting when no model has been set will result in a no-op.");
1289 return;
1290 }
1291 if (command == NoUpdate)
1292 return;
1293
1294 // store old selection
1296 // If d->ranges is non-empty when the source model is reset the persistent indexes
1297 // it contains will be invalid. We can't clear them in a modelReset slot because that might already
1298 // be too late if another model observer is connected to the same modelReset slot and is invoked first
1299 // it might call select() on this selection model before any such QItemSelectionModelPrivate::modelReset() slot
1300 // is invoked, so it would not be cleared yet. We clear it invalid ranges in it here.
1301 d->ranges.removeIf(QtFunctionObjects::IsNotValid());
1302
1303 QItemSelection old = d->ranges;
1304 old.merge(d->currentSelection, d->currentCommand);
1305
1306 // expand selection according to SelectionBehavior
1307 if (command & Rows || command & Columns)
1308 sel = d->expandSelection(sel, command);
1309
1310 // clear ranges and currentSelection
1311 if (command & Clear) {
1312 d->ranges.clear();
1313 d->currentSelection.clear();
1314 }
1315
1316 // merge and clear currentSelection if Current was not set (ie. start new currentSelection)
1317 if (!(command & Current))
1318 d->finalize();
1319
1320 // update currentSelection
1321 if (command & Toggle || command & Select || command & Deselect) {
1322 d->currentCommand = command;
1323 d->currentSelection = sel;
1324 }
1325
1326 // generate new selection, compare with old and emit selectionChanged()
1327 QItemSelection newSelection = d->ranges;
1328 newSelection.merge(d->currentSelection, d->currentCommand);
1329 emitSelectionChanged(newSelection, old);
1330}
1331
1340
1345{
1347 QModelIndex previous = d->currentIndex;
1348 d->currentIndex = QModelIndex();
1349 if (previous.isValid()) {
1350 emit currentChanged(d->currentIndex, previous);
1351 emit currentRowChanged(d->currentIndex, previous);
1352 emit currentColumnChanged(d->currentIndex, previous);
1353 }
1354}
1355
1360{
1361 const QSignalBlocker blocker(this);
1362 clear();
1363}
1364
1370{
1372 if (d->ranges.size() == 0 && d->currentSelection.size() == 0)
1373 return;
1374
1376}
1377
1378
1389void QItemSelectionModel::setCurrentIndex(const QModelIndex &index, QItemSelectionModel::SelectionFlags command)
1390{
1392 if (!d->model.value()) {
1393 qWarning("QItemSelectionModel: Setting the current index when no model has been set will result in a no-op.");
1394 return;
1395 }
1396 if (index == d->currentIndex) {
1397 if (command != NoUpdate)
1398 select(index, command); // select item
1399 return;
1400 }
1401 QPersistentModelIndex previous = d->currentIndex;
1402 d->currentIndex = index; // set current before emitting selection changed below
1403 if (command != NoUpdate)
1404 select(d->currentIndex, command); // select item
1405 emit currentChanged(d->currentIndex, previous);
1406 if (d->currentIndex.row() != previous.row() ||
1407 d->currentIndex.parent() != previous.parent())
1408 emit currentRowChanged(d->currentIndex, previous);
1409 if (d->currentIndex.column() != previous.column() ||
1410 d->currentIndex.parent() != previous.parent())
1411 emit currentColumnChanged(d->currentIndex, previous);
1412}
1413
1419{
1420 return static_cast<QModelIndex>(d_func()->currentIndex);
1421}
1422
1427{
1428 Q_D(const QItemSelectionModel);
1429 if (d->model != index.model() || !index.isValid())
1430 return false;
1431
1432 bool selected = false;
1433 // search model ranges
1435 for (; it != d->ranges.end(); ++it) {
1436 if ((*it).isValid() && (*it).contains(index)) {
1437 selected = true;
1438 break;
1439 }
1440 }
1441
1442 // check currentSelection
1443 if (d->currentSelection.size()) {
1444 if ((d->currentCommand & Deselect) && selected)
1445 selected = !d->currentSelection.contains(index);
1446 else if (d->currentCommand & Toggle)
1447 selected ^= d->currentSelection.contains(index);
1448 else if ((d->currentCommand & Select) && !selected)
1449 selected = d->currentSelection.contains(index);
1450 }
1451
1452 if (selected)
1453 return isSelectableAndEnabled(d->model->flags(index));
1454
1455 return false;
1456}
1457
1470{
1471 Q_D(const QItemSelectionModel);
1472 if (!d->model.value())
1473 return false;
1474 if (parent.isValid() && d->model != parent.model())
1475 return false;
1476
1477 // return false if row exist in currentSelection (Deselect)
1478 if (d->currentCommand & Deselect && d->currentSelection.size()) {
1479 for (int i=0; i<d->currentSelection.size(); ++i) {
1480 if (d->currentSelection.at(i).parent() == parent &&
1481 row >= d->currentSelection.at(i).top() &&
1482 row <= d->currentSelection.at(i).bottom())
1483 return false;
1484 }
1485 }
1486 // return false if ranges in both currentSelection and ranges
1487 // intersect and have the same row contained
1488 if (d->currentCommand & Toggle && d->currentSelection.size()) {
1489 for (int i=0; i<d->currentSelection.size(); ++i)
1490 if (d->currentSelection.at(i).top() <= row &&
1491 d->currentSelection.at(i).bottom() >= row)
1492 for (int j=0; j<d->ranges.size(); ++j)
1493 if (d->ranges.at(j).top() <= row && d->ranges.at(j).bottom() >= row
1494 && d->currentSelection.at(i).intersected(d->ranges.at(j)).isValid())
1495 return false;
1496 }
1497
1498 auto isSelectable = [&](int row, int column) {
1499 return isSelectableAndEnabled(d->model->index(row, column, parent).flags());
1500 };
1501
1502 const int colCount = d->model->columnCount(parent);
1503 int unselectable = 0;
1504 // add ranges and currentSelection and check through them all
1506 QList<QItemSelectionRange> joined = d->ranges;
1507 if (d->currentSelection.size())
1508 joined += d->currentSelection;
1509 for (int column = 0; column < colCount; ++column) {
1510 if (!isSelectable(row, column)) {
1511 ++unselectable;
1512 continue;
1513 }
1514
1515 for (it = joined.constBegin(); it != joined.constEnd(); ++it) {
1516 if ((*it).contains(row, column, parent)) {
1517 for (int i = column; i <= (*it).right(); ++i) {
1518 if (!isSelectable(row, i))
1519 ++unselectable;
1520 }
1521
1522 column = qMax(column, (*it).right());
1523 break;
1524 }
1525 }
1526 if (it == joined.constEnd())
1527 return false;
1528 }
1529 return unselectable < colCount;
1530}
1531
1544{
1545 Q_D(const QItemSelectionModel);
1546 if (!d->model.value())
1547 return false;
1548 if (parent.isValid() && d->model != parent.model())
1549 return false;
1550
1551 // return false if column exist in currentSelection (Deselect)
1552 if (d->currentCommand & Deselect && d->currentSelection.size()) {
1553 for (int i = 0; i < d->currentSelection.size(); ++i) {
1554 if (d->currentSelection.at(i).parent() == parent &&
1555 column >= d->currentSelection.at(i).left() &&
1556 column <= d->currentSelection.at(i).right())
1557 return false;
1558 }
1559 }
1560 // return false if ranges in both currentSelection and the selection model
1561 // intersect and have the same column contained
1562 if (d->currentCommand & Toggle && d->currentSelection.size()) {
1563 for (int i = 0; i < d->currentSelection.size(); ++i) {
1564 if (d->currentSelection.at(i).left() <= column &&
1565 d->currentSelection.at(i).right() >= column) {
1566 for (int j = 0; j < d->ranges.size(); ++j) {
1567 if (d->ranges.at(j).left() <= column && d->ranges.at(j).right() >= column
1568 && d->currentSelection.at(i).intersected(d->ranges.at(j)).isValid()) {
1569 return false;
1570 }
1571 }
1572 }
1573 }
1574 }
1575
1576 auto isSelectable = [&](int row, int column) {
1577 return isSelectableAndEnabled(d->model->index(row, column, parent).flags());
1578 };
1579 const int rowCount = d->model->rowCount(parent);
1580 int unselectable = 0;
1581
1582 // add ranges and currentSelection and check through them all
1584 QList<QItemSelectionRange> joined = d->ranges;
1585 if (d->currentSelection.size())
1586 joined += d->currentSelection;
1587 for (int row = 0; row < rowCount; ++row) {
1588 if (!isSelectable(row, column)) {
1589 ++unselectable;
1590 continue;
1591 }
1592 for (it = joined.constBegin(); it != joined.constEnd(); ++it) {
1593 if ((*it).contains(row, column, parent)) {
1594 for (int i = row; i <= (*it).bottom(); ++i) {
1595 if (!isSelectable(i, column)) {
1596 ++unselectable;
1597 }
1598 }
1599 row = qMax(row, (*it).bottom());
1600 break;
1601 }
1602 }
1603 if (it == joined.constEnd())
1604 return false;
1605 }
1606 return unselectable < rowCount;
1607}
1608
1617{
1618 Q_D(const QItemSelectionModel);
1619 if (!d->model.value())
1620 return false;
1621 if (parent.isValid() && d->model != parent.model())
1622 return false;
1623
1624 QItemSelection sel = d->ranges;
1625 sel.merge(d->currentSelection, d->currentCommand);
1626 for (const QItemSelectionRange &range : std::as_const(sel)) {
1627 if (range.parent() != parent)
1628 return false;
1629 int top = range.top();
1630 int bottom = range.bottom();
1631 int left = range.left();
1632 int right = range.right();
1633 if (top <= row && bottom >= row) {
1634 for (int j = left; j <= right; j++) {
1635 if (isSelectableAndEnabled(d->model->index(row, j, parent).flags()))
1636 return true;
1637 }
1638 }
1639 }
1640
1641 return false;
1642}
1643
1652{
1653 Q_D(const QItemSelectionModel);
1654 if (!d->model.value())
1655 return false;
1656 if (parent.isValid() && d->model != parent.model())
1657 return false;
1658
1659 QItemSelection sel = d->ranges;
1660 sel.merge(d->currentSelection, d->currentCommand);
1661 for (const QItemSelectionRange &range : std::as_const(sel)) {
1662 if (range.parent() != parent)
1663 return false;
1664 int top = range.top();
1665 int bottom = range.bottom();
1666 int left = range.left();
1667 int right = range.right();
1668 if (left <= column && right >= column) {
1669 for (int j = top; j <= bottom; j++) {
1670 if (isSelectableAndEnabled(d->model->index(j, column, parent).flags()))
1671 return true;
1672 }
1673 }
1674 }
1675
1676 return false;
1677}
1678
1687{
1688 return std::all_of(selection.begin(), selection.end(),
1689 [](const QItemSelectionRange &r) { return r.isEmpty(); });
1690}
1691
1699{
1700 Q_D(const QItemSelectionModel);
1701
1702 // QTreeModel unfortunately sorts itself lazily.
1703 // When it sorts itself, it emits are layoutChanged signal.
1704 // This layoutChanged signal invalidates d->ranges here.
1705 // So QTreeModel must not sort itself while we are iterating over
1706 // d->ranges here. It sorts itself in executePendingOperations,
1707 // thus preventing the sort to happen inside of selectionIsEmpty below.
1708 // Sad story, read more in QTBUG-94546
1710 if (model != nullptr) {
1711 auto model_p = static_cast<const QAbstractItemModelPrivate *>(QObjectPrivate::get(model));
1712 model_p->executePendingOperations();
1713 }
1714
1715 if (d->currentCommand & (Toggle | Deselect)) {
1716 QItemSelection sel = d->ranges;
1717 sel.merge(d->currentSelection, d->currentCommand);
1718 return !selectionIsEmpty(sel);
1719 } else {
1720 return !(selectionIsEmpty(d->ranges) && selectionIsEmpty(d->currentSelection));
1721 }
1722}
1723
1729{
1730 Q_D(const QItemSelectionModel);
1731 QItemSelection selected = d->ranges;
1732 selected.merge(d->currentSelection, d->currentCommand);
1733 return selected.indexes();
1734}
1735
1739
1740 friend bool operator==(const RowOrColumnDefinition &lhs, const RowOrColumnDefinition &rhs) noexcept
1741 { return lhs.parent == rhs.parent && lhs.rowOrColumn == rhs.rowOrColumn; }
1742 friend bool operator!=(const RowOrColumnDefinition &lhs, const RowOrColumnDefinition &rhs) noexcept
1743 { return !operator==(lhs, rhs); }
1744};
1745size_t qHash(const RowOrColumnDefinition &key, size_t seed = 0) noexcept
1746{
1748 seed = hash(seed, key.parent);
1749 seed = hash(seed, key.rowOrColumn);
1750 return seed;
1751}
1752
1754
1755
1763{
1764 QModelIndexList indexes;
1765
1766 QDuplicateTracker<RowOrColumnDefinition> rowsSeen;
1767
1768 const QItemSelection ranges = selection();
1769 for (int i = 0; i < ranges.size(); ++i) {
1770 const QItemSelectionRange &range = ranges.at(i);
1771 QModelIndex parent = range.parent();
1772 for (int row = range.top(); row <= range.bottom(); row++) {
1773 if (!rowsSeen.hasSeen({parent, row})) {
1774 if (isRowSelected(row, parent)) {
1775 indexes.append(model()->index(row, column, parent));
1776 }
1777 }
1778 }
1779 }
1780
1781 return indexes;
1782}
1783
1792{
1793 QModelIndexList indexes;
1794
1795 QDuplicateTracker<RowOrColumnDefinition> columnsSeen;
1796
1797 const QItemSelection ranges = selection();
1798 for (int i = 0; i < ranges.size(); ++i) {
1799 const QItemSelectionRange &range = ranges.at(i);
1801 for (int column = range.left(); column <= range.right(); column++) {
1802 if (!columnsSeen.hasSeen({parent, column})) {
1804 indexes.append(model()->index(row, column, parent));
1805 }
1806 }
1807 }
1808 }
1809
1810 return indexes;
1811}
1812
1817{
1818 Q_D(const QItemSelectionModel);
1819 QItemSelection selected = d->ranges;
1820 selected.merge(d->currentSelection, d->currentCommand);
1821 // make sure we have no invalid ranges
1822 // ### should probably be handled more generic somewhere else
1823 selected.removeIf(QtFunctionObjects::IsNotValid());
1824 return selected;
1825}
1826
1863{
1864 return d_func()->model.value();
1865}
1866
1871{
1872 return d_func()->model.value();
1873}
1874
1875QBindable<QAbstractItemModel *> QItemSelectionModel::bindableModel()
1876{
1877 return &d_func()->model;
1878}
1879
1888{
1890 d->model.removeBindingUnlessInWrapper();
1891 if (d->model.valueBypassingBindings() == model)
1892 return;
1893 d->initModel(model);
1894 d->model.notify();
1895}
1896
1902 const QItemSelection &oldSelection)
1903{
1904 // if both selections are empty or equal we return
1905 if ((oldSelection.isEmpty() && newSelection.isEmpty()) ||
1906 oldSelection == newSelection)
1907 return;
1908
1909 // if either selection is empty we do not need to compare
1910 if (oldSelection.isEmpty() || newSelection.isEmpty()) {
1911 emit selectionChanged(newSelection, oldSelection);
1912 return;
1913 }
1914
1915 QItemSelection deselected = oldSelection;
1916 QItemSelection selected = newSelection;
1917
1918 // remove equal ranges
1919 bool advance;
1920 for (int o = 0; o < deselected.size(); ++o) {
1921 advance = true;
1922 for (int s = 0; s < selected.size() && o < deselected.size();) {
1923 if (deselected.at(o) == selected.at(s)) {
1924 deselected.removeAt(o);
1925 selected.removeAt(s);
1926 advance = false;
1927 } else {
1928 ++s;
1929 }
1930 }
1931 if (advance)
1932 ++o;
1933 }
1934
1935 // find intersections
1936 QItemSelection intersections;
1937 for (int o = 0; o < deselected.size(); ++o) {
1938 for (int s = 0; s < selected.size(); ++s) {
1939 if (deselected.at(o).intersects(selected.at(s)))
1940 intersections.append(deselected.at(o).intersected(selected.at(s)));
1941 }
1942 }
1943
1944 // compare remaining ranges with intersections and split them to find deselected and selected
1945 for (int i = 0; i < intersections.size(); ++i) {
1946 // split deselected
1947 for (int o = 0; o < deselected.size();) {
1948 if (deselected.at(o).intersects(intersections.at(i))) {
1949 QItemSelection::split(deselected.at(o), intersections.at(i), &deselected);
1950 deselected.removeAt(o);
1951 } else {
1952 ++o;
1953 }
1954 }
1955 // split selected
1956 for (int s = 0; s < selected.size();) {
1957 if (selected.at(s).intersects(intersections.at(i))) {
1958 QItemSelection::split(selected.at(s), intersections.at(i), &selected);
1959 selected.removeAt(s);
1960 } else {
1961 ++s;
1962 }
1963 }
1964 }
1965
1966 if (!selected.isEmpty() || !deselected.isEmpty())
1967 emit selectionChanged(selected, deselected);
1968}
1969
1970#ifndef QT_NO_DEBUG_STREAM
1972{
1973 QDebugStateSaver saver(dbg);
1974 dbg.nospace() << "QItemSelectionRange(" << range.topLeft()
1975 << ',' << range.bottomRight() << ')';
1976 return dbg;
1977}
1978#endif
1979
1981
1982#include "moc_qitemselectionmodel.cpp"
virtual void executePendingOperations() const
void rowsMoved(const QModelIndex &sourceParent, int sourceStart, int sourceEnd, const QModelIndex &destinationParent, int destinationRow, QPrivateSignal)
LayoutChangeHint
This enum describes the way the model changes layout.
void rowsAboutToBeInserted(const QModelIndex &parent, int first, int last, QPrivateSignal)
This signal is emitted just before rows are inserted into the model.
void columnsAboutToBeInserted(const QModelIndex &parent, int first, int last, QPrivateSignal)
This signal is emitted just before columns are inserted into the model.
void modelReset(QPrivateSignal)
void layoutAboutToBeChanged(const QList< QPersistentModelIndex > &parents=QList< QPersistentModelIndex >(), QAbstractItemModel::LayoutChangeHint hint=QAbstractItemModel::NoLayoutChangeHint)
void columnsAboutToBeMoved(const QModelIndex &sourceParent, int sourceStart, int sourceEnd, const QModelIndex &destinationParent, int destinationColumn, QPrivateSignal)
void columnsAboutToBeRemoved(const QModelIndex &parent, int first, int last, QPrivateSignal)
This signal is emitted just before columns are removed from the model.
void layoutChanged(const QList< QPersistentModelIndex > &parents=QList< QPersistentModelIndex >(), QAbstractItemModel::LayoutChangeHint hint=QAbstractItemModel::NoLayoutChangeHint)
void rowsAboutToBeRemoved(const QModelIndex &parent, int first, int last, QPrivateSignal)
This signal is emitted just before rows are removed from the model.
void rowsAboutToBeMoved(const QModelIndex &sourceParent, int sourceStart, int sourceEnd, const QModelIndex &destinationParent, int destinationRow, QPrivateSignal)
void columnsMoved(const QModelIndex &sourceParent, int sourceStart, int sourceEnd, const QModelIndex &destinationParent, int destinationColumn, QPrivateSignal)
virtual Q_INVOKABLE QModelIndex index(int row, int column, const QModelIndex &parent=QModelIndex()) const =0
Returns the index of the item in the model specified by the given row, column and parent index.
QModelIndex index(int row, int column, const QModelIndex &parent=QModelIndex()) const override
Returns the index of the data in row and column with parent.
\inmodule QtCore
\inmodule QtCore
QPersistentModelIndex tableParent
void layoutAboutToBeChanged(const QList< QPersistentModelIndex > &parents, QAbstractItemModel::LayoutChangeHint hint)
void rowsAboutToBeInserted(const QModelIndex &parent, int start, int end)
void columnsAboutToBeInserted(const QModelIndex &parent, int start, int end)
void columnsAboutToBeRemoved(const QModelIndex &parent, int start, int end)
QPersistentModelIndex currentIndex
QList< std::pair< QPersistentModelIndex, uint > > savedPersistentCurrentRowLengths
QList< std::pair< QPersistentModelIndex, uint > > savedPersistentRowLengths
QList< QPersistentModelIndex > savedPersistentCurrentIndexes
std::array< QMetaObject::Connection, 12 > connections
void initModel(QAbstractItemModel *model)
void layoutChanged(const QList< QPersistentModelIndex > &parents, QAbstractItemModel::LayoutChangeHint hint)
QList< QPersistentModelIndex > savedPersistentIndexes
QItemSelection expandSelection(const QItemSelection &selection, QItemSelectionModel::SelectionFlags command) const
void rowsAboutToBeRemoved(const QModelIndex &parent, int start, int end)
Q_INVOKABLE bool isColumnSelected(int column, const QModelIndex &parent=QModelIndex()) const
Returns true if all items are selected in the column with the given parent.
void selectionChanged(const QItemSelection &selected, const QItemSelection &deselected)
This signal is emitted whenever the selection changes.
void emitSelectionChanged(const QItemSelection &newSelection, const QItemSelection &oldSelection)
Compares the two selections newSelection and oldSelection and emits selectionChanged() with the desel...
void setModel(QAbstractItemModel *model)
QBindable< QAbstractItemModel * > bindableModel()
void currentChanged(const QModelIndex &current, const QModelIndex &previous)
This signal is emitted whenever the current item changes.
Q_INVOKABLE bool isSelected(const QModelIndex &index) const
Returns true if the given model item index is selected.
QModelIndexList selectedIndexes
virtual ~QItemSelectionModel()
Destroys the selection model.
virtual void setCurrentIndex(const QModelIndex &index, QItemSelectionModel::SelectionFlags command)
Sets the model item index to be the current item, and emits currentChanged().
virtual void reset()
Clears the selection model.
virtual void select(const QModelIndex &index, QItemSelectionModel::SelectionFlags command)
Selects the model item index using the specified command, and emits selectionChanged().
virtual void clearCurrentIndex()
Clears the current index.
Q_INVOKABLE bool isRowSelected(int row, const QModelIndex &parent=QModelIndex()) const
Returns true if all items are selected in the row with the given parent.
Q_INVOKABLE bool columnIntersectsSelection(int column, const QModelIndex &parent=QModelIndex()) const
Returns true if there are any items selected in the column with the given parent.
void currentColumnChanged(const QModelIndex &current, const QModelIndex &previous)
This signal is emitted if the current item changes and its column is different to the column of the p...
virtual void clear()
Clears the selection model.
void currentRowChanged(const QModelIndex &current, const QModelIndex &previous)
This signal is emitted if the current item changes and its row is different to the row of the previou...
QAbstractItemModel * model
QItemSelectionModel(QAbstractItemModel *model=nullptr)
Constructs a selection model that operates on the specified item model.
Q_INVOKABLE bool rowIntersectsSelection(int row, const QModelIndex &parent=QModelIndex()) const
Returns true if there are any items selected in the row with the given parent.
Q_INVOKABLE QModelIndexList selectedColumns(int row=0) const
bool intersects(const QItemSelectionRange &other) const
Returns true if this selection range intersects (overlaps with) the other range given; otherwise retu...
int bottom() const
Returns the row index corresponding to the lowermost selected row in the selection range.
const QPersistentModelIndex & topLeft() const
Returns the index for the item located at the top-left corner of the selection range.
int top() const
Returns the row index corresponding to the uppermost selected row in the selection range.
QItemSelectionRange()=default
Constructs an empty selection range.
QItemSelectionRange intersected(const QItemSelectionRange &other) const
bool isEmpty() const
Returns true if the selection range contains either no items or only items which are either disabled ...
QModelIndexList indexes() const
Returns the list of model index items stored in the selection.
const QPersistentModelIndex & bottomRight() const
Returns the index for the item located at the bottom-right corner of the selection range.
int right() const
Returns the column index corresponding to the rightmost selected column in the selection range.
const QAbstractItemModel * model() const
Returns the model that the items in the selection range belong to.
QModelIndex parent() const
Returns the parent model item index of the items in the selection range.
int left() const
Returns the column index corresponding to the leftmost selected column in the selection range.
bool isValid() const
Returns true if the selection range is valid; otherwise returns false.
\inmodule QtCore
static Q_CORE_EXPORT void split(const QItemSelectionRange &range, const QItemSelectionRange &other, QItemSelection *result)
Splits the selection range using the selection other range.
Q_CORE_EXPORT QModelIndexList indexes() const
Returns a list of model indexes that correspond to the selected items.
Q_CORE_EXPORT void select(const QModelIndex &topLeft, const QModelIndex &bottomRight)
Adds the items in the range that extends from the top-left model item, specified by the topLeft index...
Q_CORE_EXPORT QItemSelection(const QModelIndex &topLeft, const QModelIndex &bottomRight)
Constructs an empty selection.
Q_CORE_EXPORT void merge(const QItemSelection &other, QItemSelectionModel::SelectionFlags command)
Merges the other selection with this QItemSelection using the command given.
Q_CORE_EXPORT bool contains(const QModelIndex &index) const
Returns true if the selection contains the given index; otherwise returns false.
Definition qlist.h:75
qsizetype size() const noexcept
Definition qlist.h:397
bool isEmpty() const noexcept
Definition qlist.h:401
void removeAt(qsizetype i)
Definition qlist.h:590
QList< QItemSelectionRange > & operator+=(const QList< QItemSelectionRange > &l)
Definition qlist.h:698
void push_back(parameter_type t)
Definition qlist.h:675
const_reference at(qsizetype i) const noexcept
Definition qlist.h:446
qsizetype removeIf(Predicate pred)
Definition qlist.h:604
const T & constFirst() const noexcept
Definition qlist.h:647
void reserve(qsizetype size)
Definition qlist.h:753
void append(parameter_type t)
Definition qlist.h:458
void clear()
Definition qlist.h:434
\inmodule QtCore
constexpr int row() const noexcept
Returns the row this model index refers to.
QModelIndex parent() const
Returns the parent of the model index, or QModelIndex() if it has no parent.
constexpr const QAbstractItemModel * model() const noexcept
Returns a pointer to the model containing the item that this index refers to.
constexpr int column() const noexcept
Returns the column this model index refers to.
constexpr bool isValid() const noexcept
Returns {true} if this model index is valid; otherwise returns {false}.
QModelIndex sibling(int row, int column) const
Returns the sibling at row and column.
QObject * parent
Definition qobject.h:73
static QObjectPrivate * get(QObject *o)
Definition qobject_p.h:150
static QMetaObject::Connection connect(const typename QtPrivate::FunctionPointer< Func1 >::Object *sender, Func1 signal, const typename QtPrivate::FunctionPointer< Func2 >::Object *receiverPrivate, Func2 slot, Qt::ConnectionType type=Qt::AutoConnection)
Definition qobject_p.h:299
\inmodule QtCore
Definition qobject.h:103
QObject * parent() const
Returns a pointer to the parent object.
Definition qobject.h:346
static QMetaObject::Connection connect(const QObject *sender, const char *signal, const QObject *receiver, const char *member, Qt::ConnectionType=Qt::AutoConnection)
\threadsafe
Definition qobject.cpp:2960
static bool disconnect(const QObject *sender, const char *signal, const QObject *receiver, const char *member)
\threadsafe
Definition qobject.cpp:3236
void destroyed(QObject *=nullptr)
This signal is emitted immediately before the object obj is destroyed, after any instances of QPointe...
bool isValid() const
Returns {true} if this persistent model index is valid; otherwise returns {false}.
QModelIndex sibling(int row, int column) const
Returns the sibling at row and column or an invalid QModelIndex if there is no sibling at this positi...
QModelIndex parent() const
Returns the parent QModelIndex for this persistent index, or an invalid QModelIndex if it has no pare...
int column() const
Returns the column this persistent model index refers to.
int row() const
Returns the row this persistent model index refers to.
iterator begin()
Definition qset.h:136
iterator end()
Definition qset.h:140
const_iterator constBegin() const noexcept
Definition qset.h:139
const_iterator constEnd() const noexcept
Definition qset.h:143
iterator erase(const_iterator i)
Definition qset.h:145
Exception-safe wrapper around QObject::blockSignals().
Definition qobject.h:483
int rowCount(const QModelIndex &parent=QModelIndex()) const override
If the database supports returning the size of a query (see QSqlDriver::hasFeature()),...
int columnCount(const QModelIndex &parent=QModelIndex()) const override
\reimp
QHash< int, QWidget * > hash
[35multi]
QSet< QString >::iterator it
short next
Definition keywords.cpp:445
Combined button and popup list for selecting options.
@ ItemIsSelectable
@ ItemIsEnabled
DBusConnection * connection
#define QT_SPECIALIZE_STD_HASH_TO_CALL_QHASH_BY_CREF(Class)
static bool selectionIsEmpty(const QItemSelection &selection)
static QItemSelection mergeIndexes(const QList< QPersistentModelIndex > &indexes)
static bool qt_PersistentModelIndexLessThan(const QPersistentModelIndex &i1, const QPersistentModelIndex &i2)
static ModelIndexContainer qSelectionIndexes(const QItemSelection &selection)
static void indexesFromRange(const QItemSelectionRange &range, ModelIndexContainer &result)
static QList< std::pair< QPersistentModelIndex, uint > > qSelectionPersistentRowLengths(const QItemSelection &sel)
QDebug operator<<(QDebug dbg, const QItemSelectionRange &range)
static bool isSelectableAndEnabled(Qt::ItemFlags flags)
static void rowLengthsFromRange(const QItemSelectionRange &range, QList< std::pair< QPersistentModelIndex, uint > > &result)
static QItemSelection mergeRowLengths(const QList< std::pair< QPersistentModelIndex, uint > > &rowLengths)
size_t qHash(const RowOrColumnDefinition &key, size_t seed=0) noexcept
#define qWarning
Definition qlogging.h:166
#define QT_IMPL_METATYPE_EXTERN(TYPE)
Definition qmetatype.h:1390
constexpr const T & qMin(const T &a, const T &b)
Definition qminmax.h:40
constexpr const T & qMax(const T &a, const T &b)
Definition qminmax.h:42
const GLfloat * m
GLuint64 key
GLuint index
[2]
GLboolean r
[2]
GLuint GLuint end
GLenum GLuint GLenum GLsizei length
GLdouble GLdouble GLdouble GLdouble top
GLdouble GLdouble right
GLsizei range
GLint GLsizei width
GLint left
GLint GLint bottom
GLbitfield flags
GLuint start
GLfloat n
GLenum GLenum GLsizei void GLsizei void * column
GLdouble s
[6]
Definition qopenglext.h:235
GLdouble GLdouble t
Definition qopenglext.h:243
GLdouble GLdouble GLdouble GLdouble q
Definition qopenglext.h:259
GLenum GLenum GLsizei void * row
GLuint64EXT * result
[6]
static Q_CONSTINIT QBasicAtomicInteger< unsigned > seed
Definition qrandom.cpp:196
#define Q_ASSERT(cond)
Definition qrandom.cpp:47
static void split(QT_FT_Vector *b)
static QT_BEGIN_NAMESPACE QVariant hint(QPlatformIntegration::StyleHint h)
#define emit
#define Q_UNUSED(x)
unsigned int uint
Definition qtypes.h:34
QSqlQueryModel * model
[16]
QSharedPointer< T > other(t)
[5]
QItemSelection * selection
[0]
QAction * at
friend bool operator==(const RowOrColumnDefinition &lhs, const RowOrColumnDefinition &rhs) noexcept
friend bool operator!=(const RowOrColumnDefinition &lhs, const RowOrColumnDefinition &rhs) noexcept