Qt 6.x
The Qt SDK
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
183bool QItemSelectionRange::intersects(const QItemSelectionRange &other) const
184{
185 // isValid() and parent() last since they are more expensive
186 return (model() == other.model()
187 && ((top() <= other.top() && bottom() >= other.top())
188 || (top() >= other.top() && top() <= other.bottom()))
189 && ((left() <= other.left() && right() >= other.left())
190 || (left() >= other.left() && left() <= other.right()))
191 && parent() == other.parent()
192 && isValid() && other.isValid()
193 );
194}
195
205{
206 if (model() == other.model() && parent() == other.parent()) {
207 QModelIndex topLeft = model()->index(qMax(top(), other.top()),
208 qMax(left(), other.left()),
209 other.parent());
211 qMin(right(), other.right()),
212 other.parent());
214 }
215 return QItemSelectionRange();
216}
217
242{
243 if (range.isValid() && range.model()) {
244 const QModelIndex topLeft = range.topLeft();
245 const int bottom = range.bottom();
246 const uint width = range.width();
247 const int column = topLeft.column();
248 for (int row = topLeft.row(); row <= bottom; ++row) {
249 // We don't need to keep track of ItemIsSelectable and ItemIsEnabled here. That is
250 // required in indexesFromRange() because that method is called from public API
251 // which requires the limitation.
253 }
254 }
255}
256
257static bool isSelectableAndEnabled(Qt::ItemFlags flags)
258{
259 return flags.testFlags(Qt::ItemIsSelectable | Qt::ItemIsEnabled);
260}
261
262template<typename ModelIndexContainer>
263static void indexesFromRange(const QItemSelectionRange &range, ModelIndexContainer &result)
264{
265 if (range.isValid() && range.model()) {
266 const QModelIndex topLeft = range.topLeft();
267 const int bottom = range.bottom();
268 const int right = range.right();
269 for (int row = topLeft.row(); row <= bottom; ++row) {
270 const QModelIndex columnLeader = topLeft.sibling(row, topLeft.column());
271 for (int column = topLeft.column(); column <= right; ++column) {
272 QModelIndex index = columnLeader.sibling(row, column);
273 if (isSelectableAndEnabled(range.model()->flags(index)))
274 result.push_back(index);
275 }
276 }
277 }
278}
279
280template<typename ModelIndexContainer>
281static ModelIndexContainer qSelectionIndexes(const QItemSelection &selection)
282{
283 ModelIndexContainer result;
284 for (const auto &range : selection)
286 return result;
287}
288
297{
298 if (!isValid() || !model())
299 return true;
300
301 for (int column = left(); column <= right(); ++column) {
302 for (int row = top(); row <= bottom(); ++row) {
305 return false;
306 }
307 }
308 return true;
309}
310
316{
318 indexesFromRange(*this, result);
319 return result;
320}
321
375QItemSelection::QItemSelection(const QModelIndex &topLeft, const QModelIndex &bottomRight)
376{
377 select(topLeft, bottomRight);
378}
379
387void QItemSelection::select(const QModelIndex &topLeft, const QModelIndex &bottomRight)
388{
389 if (!topLeft.isValid() || !bottomRight.isValid())
390 return;
391
392 if ((topLeft.model() != bottomRight.model())
393 || topLeft.parent() != bottomRight.parent()) {
394 qWarning("Can't select indexes from different model or with different parents");
395 return;
396 }
397 if (topLeft.row() > bottomRight.row() || topLeft.column() > bottomRight.column()) {
398 int top = qMin(topLeft.row(), bottomRight.row());
399 int bottom = qMax(topLeft.row(), bottomRight.row());
400 int left = qMin(topLeft.column(), bottomRight.column());
401 int right = qMax(topLeft.column(), bottomRight.column());
402 QModelIndex tl = topLeft.sibling(top, left);
403 QModelIndex br = bottomRight.sibling(bottom, right);
405 return;
406 }
407 append(QItemSelectionRange(topLeft, bottomRight));
408}
409
416{
417 if (isSelectableAndEnabled(index.flags())) {
419 for (; it != end(); ++it)
420 if ((*it).contains(index))
421 return true;
422 }
423 return false;
424}
425
431{
432 return qSelectionIndexes<QModelIndexList>(*this);
433}
434
436{
438 for (const QItemSelectionRange &range : sel)
440 return result;
441}
442
453void QItemSelection::merge(const QItemSelection &other, QItemSelectionModel::SelectionFlags command)
454{
455 if (other.isEmpty() ||
456 !(command & QItemSelectionModel::Select ||
459 return;
460
461 QItemSelection newSelection;
462 newSelection.reserve(other.size());
463 // Collect intersections
464 QItemSelection intersections;
465 for (const auto &range : other) {
466 if (!range.isValid())
467 continue;
468 newSelection.push_back(range);
469 for (int t = 0; t < size(); ++t) {
470 if (range.intersects(at(t)))
471 intersections.append(at(t).intersected(range));
472 }
473 }
474
475 // Split the old (and new) ranges using the intersections
476 for (int i = 0; i < intersections.size(); ++i) { // for each intersection
477 for (int t = 0; t < size();) { // splitt each old range
478 if (at(t).intersects(intersections.at(i))) {
479 split(at(t), intersections.at(i), this);
480 removeAt(t);
481 } else {
482 ++t;
483 }
484 }
485 // only split newSelection if Toggle is specified
486 for (int n = 0; (command & QItemSelectionModel::Toggle) && n < newSelection.size();) {
487 if (newSelection.at(n).intersects(intersections.at(i))) {
488 split(newSelection.at(n), intersections.at(i), &newSelection);
489 newSelection.removeAt(n);
490 } else {
491 ++n;
492 }
493 }
494 }
495 // do not add newSelection for Deselect
496 if (!(command & QItemSelectionModel::Deselect))
497 operator+=(newSelection);
498}
499
509{
510 if (range.parent() != other.parent() || range.model() != other.model())
511 return;
512
513 QModelIndex parent = other.parent();
514 int top = range.top();
515 int left = range.left();
516 int bottom = range.bottom();
517 int right = range.right();
518 int other_top = other.top();
519 int other_left = other.left();
520 int other_bottom = other.bottom();
521 int other_right = other.right();
522 const QAbstractItemModel *model = range.model();
524 if (other_top > top) {
526 QModelIndex br = model->index(other_top - 1, right, parent);
527 result->append(QItemSelectionRange(tl, br));
528 top = other_top;
529 }
530 if (other_bottom < bottom) {
531 QModelIndex tl = model->index(other_bottom + 1, left, parent);
533 result->append(QItemSelectionRange(tl, br));
534 bottom = other_bottom;
535 }
536 if (other_left > left) {
538 QModelIndex br = model->index(bottom, other_left - 1, parent);
539 result->append(QItemSelectionRange(tl, br));
540 left = other_left;
541 }
542 if (other_right < right) {
543 QModelIndex tl = model->index(top, other_right + 1, parent);
545 result->append(QItemSelectionRange(tl, br));
546 right = other_right;
547 }
548}
549
550
552{
553 static constexpr auto connections = qOffsetStringArray(
554 QT_STRINGIFY_SIGNAL(rowsAboutToBeRemoved(QModelIndex,int,int)),
556 QT_STRINGIFY_SIGNAL(columnsAboutToBeRemoved(QModelIndex,int,int)),
558 QT_STRINGIFY_SIGNAL(rowsAboutToBeInserted(QModelIndex,int,int)),
560 QT_STRINGIFY_SIGNAL(columnsAboutToBeInserted(QModelIndex,int,int)),
562 QT_STRINGIFY_SIGNAL(rowsAboutToBeMoved(QModelIndex,int,int,QModelIndex,int)),
564 QT_STRINGIFY_SIGNAL(columnsAboutToBeMoved(QModelIndex,int,int,QModelIndex,int)),
566 QT_STRINGIFY_SIGNAL(rowsMoved(QModelIndex,int,int,QModelIndex,int)),
568 QT_STRINGIFY_SIGNAL(columnsMoved(QModelIndex,int,int,QModelIndex,int)),
574 QT_STRINGIFY_SIGNAL(modelReset()),
576 QT_STRINGIFY_SIGNAL(destroyed(QObject*)),
578 );
579
580 if (model == m)
581 return;
582
584 if (model.value()) {
585 for (int i = 0; i < connections.count(); i += 2)
586 QObject::disconnect(model.value(), connections.at(i), q, connections.at(i + 1));
587 q->reset();
588 }
589
590 // Caller has to call notify(), unless calling during construction (the common case).
591 model.setValueBypassingBindings(m);
592
593 if (model.value()) {
594 for (int i = 0; i < connections.count(); i += 2)
595 QObject::connect(model.value(), connections.at(i), q, connections.at(i + 1));
596 }
597}
598
608 QItemSelectionModel::SelectionFlags command) const
609{
610 if (selection.isEmpty() && !((command & QItemSelectionModel::Rows) ||
611 (command & QItemSelectionModel::Columns)))
612 return selection;
613
614 QItemSelection expanded;
615 if (command & QItemSelectionModel::Rows) {
616 for (int i = 0; i < selection.size(); ++i) {
618 int colCount = model->columnCount(parent);
620 QModelIndex br = model->index(selection.at(i).bottom(), colCount - 1, parent);
621 //we need to merge because the same row could have already been inserted
623 }
624 }
625 if (command & QItemSelectionModel::Columns) {
626 for (int i = 0; i < selection.size(); ++i) {
628 int rowCount = model->rowCount(parent);
630 QModelIndex br = model->index(rowCount - 1, selection.at(i).right(), parent);
631 //we need to merge because the same column could have already been inserted
633 }
634 }
635 return expanded;
636}
637
642 int start, int end)
643{
645 Q_ASSERT(start <= end);
646 finalize();
647
648 // update current index
650 && currentIndex.row() >= start && currentIndex.row() <= end) {
652 if (start > 0) {
653 // there are rows left above the change
654 currentIndex = model->index(start - 1, old.column(), parent);
655 } else if (model.value() && end < model->rowCount(parent) - 1) {
656 // there are rows left below the change
657 currentIndex = model->index(end + 1, old.column(), parent);
658 } else {
659 // there are no rows left in the table
661 }
662 emit q->currentChanged(currentIndex, old);
663 emit q->currentRowChanged(currentIndex, old);
664 if (currentIndex.column() != old.column())
665 emit q->currentColumnChanged(currentIndex, old);
666 }
667
668 QItemSelection deselected;
669 QItemSelection newParts;
670 bool indexesOfSelectionChanged = false;
671 QItemSelection::iterator it = ranges.begin();
672 while (it != ranges.end()) {
673 if (it->topLeft().parent() != parent) { // Check parents until reaching root or contained in range
674 QModelIndex itParent = it->topLeft().parent();
675 while (itParent.isValid() && itParent.parent() != parent)
676 itParent = itParent.parent();
677
678 if (itParent.isValid() && start <= itParent.row() && itParent.row() <= end) {
679 deselected.append(*it);
680 it = ranges.erase(it);
681 } else {
682 if (itParent.isValid() && end < itParent.row())
683 indexesOfSelectionChanged = true;
684 ++it;
685 }
686 } else if (start <= it->bottom() && it->bottom() <= end // Full inclusion
687 && start <= it->top() && it->top() <= end) {
688 deselected.append(*it);
689 it = ranges.erase(it);
690 } else if (start <= it->top() && it->top() <= end) { // Top intersection
691 deselected.append(QItemSelectionRange(it->topLeft(), model->index(end, it->right(), it->parent())));
692 *it = QItemSelectionRange(model->index(end + 1, it->left(), it->parent()), it->bottomRight());
693 ++it;
694 } else if (start <= it->bottom() && it->bottom() <= end) { // Bottom intersection
695 deselected.append(QItemSelectionRange(model->index(start, it->left(), it->parent()), it->bottomRight()));
696 *it = QItemSelectionRange(it->topLeft(), model->index(start - 1, it->right(), it->parent()));
697 ++it;
698 } else if (it->top() < start && end < it->bottom()) { // Middle intersection
699 // If the parent contains (1, 2, 3, 4, 5, 6, 7, 8) and [3, 4, 5, 6] is selected,
700 // and [4, 5] is removed, we need to split [3, 4, 5, 6] into [3], [4, 5] and [6].
701 // [4, 5] is appended to deselected, and [3] and [6] remain part of the selection
702 // in ranges.
703 const QItemSelectionRange removedRange(model->index(start, it->left(), it->parent()),
704 model->index(end, it->right(), it->parent()));
705 deselected.append(removedRange);
706 QItemSelection::split(*it, removedRange, &newParts);
707 it = ranges.erase(it);
708 } else if (end < it->top()) { // deleted row before selection
709 indexesOfSelectionChanged = true;
710 ++it;
711 } else {
712 ++it;
713 }
714 }
715 ranges.append(newParts);
716
717 if (!deselected.isEmpty() || indexesOfSelectionChanged)
718 emit q->selectionChanged(QItemSelection(), deselected);
719}
720
725 int start, int end)
726{
728
729 // update current index
733 if (start > 0) {
734 // there are columns to the left of the change
735 currentIndex = model->index(old.row(), start - 1, parent);
736 } else if (model.value() && end < model->columnCount() - 1) {
737 // there are columns to the right of the change
738 currentIndex = model->index(old.row(), end + 1, parent);
739 } else {
740 // there are no columns left in the table
742 }
743 emit q->currentChanged(currentIndex, old);
744 if (currentIndex.row() != old.row())
745 emit q->currentRowChanged(currentIndex, old);
746 emit q->currentColumnChanged(currentIndex, old);
747 }
748
749 // update selections
753 finalize();
754}
755
762 int start, int end)
763{
764 Q_UNUSED(end);
765 finalize();
768 for (; it != ranges.end(); ) {
769 const QModelIndex &itParent = it->parent();
770 if ((*it).isValid() && itParent == parent
771 && (*it).left() < start && (*it).right() >= start) {
772 QModelIndex bottomMiddle = model->index((*it).bottom(), start - 1, itParent);
773 QItemSelectionRange left((*it).topLeft(), bottomMiddle);
774 QModelIndex topMiddle = model->index((*it).top(), start, itParent);
775 QItemSelectionRange right(topMiddle, (*it).bottomRight());
776 it = ranges.erase(it);
777 split.append(left);
778 split.append(right);
779 } else {
780 ++it;
781 }
782 }
783 ranges += split;
784}
785
792 int start, int end)
793{
795 Q_UNUSED(end);
796 finalize();
799 bool indexesOfSelectionChanged = false;
800 for (; it != ranges.end(); ) {
801 const QModelIndex &itParent = it->parent();
802 if ((*it).isValid() && itParent == parent
803 && (*it).top() < start && (*it).bottom() >= start) {
804 QModelIndex middleRight = model->index(start - 1, (*it).right(), itParent);
805 QItemSelectionRange top((*it).topLeft(), middleRight);
806 QModelIndex middleLeft = model->index(start, (*it).left(), itParent);
807 QItemSelectionRange bottom(middleLeft, (*it).bottomRight());
808 it = ranges.erase(it);
809 split.append(top);
810 split.append(bottom);
811 } else if ((*it).isValid() && itParent == parent // insertion before selection
812 && (*it).top() >= start) {
813 indexesOfSelectionChanged = true;
814 ++it;
815 } else {
816 ++it;
817 }
818 }
819 ranges += split;
820
821 if (indexesOfSelectionChanged)
822 emit q->selectionChanged(QItemSelection(), QItemSelection());
823}
824
833{
838
839 // optimization for when all indexes are selected
840 // (only if there is lots of items (1000) because this is not entirely correct)
841 if (ranges.isEmpty() && currentSelection.size() == 1) {
846 if (tableRowCount * tableColCount > 1000
847 && range.top() == 0
848 && range.left() == 0
849 && range.bottom() == tableRowCount - 1
850 && range.right() == tableColCount - 1) {
851 tableSelected = true;
853 return;
854 }
855 }
856 tableSelected = false;
857
859 // Special case when we know we're sorting vertically. We can assume that all indexes for columns
860 // are displaced the same way, and therefore we only need to track an index from one column per
861 // row with a QPersistentModelIndex together with the length of items to the right of it
862 // which are displaced the same way.
863 // An algorithm which contains the same assumption is used to process layoutChanged.
866 } else {
867 savedPersistentIndexes = qSelectionIndexes<QList<QPersistentModelIndex>>(ranges);
868 savedPersistentCurrentIndexes = qSelectionIndexes<QList<QPersistentModelIndex>>(currentSelection);
869 }
870}
875{
876 if (rowLengths.isEmpty())
877 return QItemSelection();
878
880 int i = 0;
881 while (i < rowLengths.size()) {
882 const QPersistentModelIndex &tl = rowLengths.at(i).first;
883 if (!tl.isValid()) {
884 ++i;
885 continue;
886 }
887 QPersistentModelIndex br = tl;
888 const uint length = rowLengths.at(i).second;
889 while (++i < rowLengths.size()) {
890 const QPersistentModelIndex &next = rowLengths.at(i).first;
891 if (!next.isValid())
892 continue;
893 const uint nextLength = rowLengths.at(i).second;
894 if ((nextLength == length)
895 && (next.row() == br.row() + 1)
896 && (next.column() == br.column())
897 && (next.parent() == br.parent())) {
898 br = next;
899 } else {
900 break;
901 }
902 }
903 result.append(QItemSelectionRange(tl, br.sibling(br.row(), br.column() + length - 1)));
904 }
905 return result;
906}
907
915{
916 QItemSelection colSpans;
917 // merge columns
918 int i = 0;
919 while (i < indexes.size()) {
920 const QPersistentModelIndex &tl = indexes.at(i);
921 if (!tl.isValid()) {
922 ++i;
923 continue;
924 }
925 QPersistentModelIndex br = tl;
926 QModelIndex brParent = br.parent();
927 int brRow = br.row();
928 int brColumn = br.column();
929 while (++i < indexes.size()) {
930 const QPersistentModelIndex &next = indexes.at(i);
931 if (!next.isValid())
932 continue;
933 const QModelIndex nextParent = next.parent();
934 const int nextRow = next.row();
935 const int nextColumn = next.column();
936 if ((nextParent == brParent)
937 && (nextRow == brRow)
938 && (nextColumn == brColumn + 1)) {
939 br = next;
940 brParent = nextParent;
941 brRow = nextRow;
942 brColumn = nextColumn;
943 } else {
944 break;
945 }
946 }
947 colSpans.append(QItemSelectionRange(tl, br));
948 }
949 // merge rows
950 QItemSelection rowSpans;
951 i = 0;
952 while (i < colSpans.size()) {
953 QModelIndex tl = colSpans.at(i).topLeft();
954 QModelIndex br = colSpans.at(i).bottomRight();
955 QModelIndex prevTl = tl;
956 while (++i < colSpans.size()) {
957 QModelIndex nextTl = colSpans.at(i).topLeft();
958 QModelIndex nextBr = colSpans.at(i).bottomRight();
959
960 if (nextTl.parent() != tl.parent())
961 break; // we can't merge selection ranges from different parents
962
963 if ((nextTl.column() == prevTl.column()) && (nextBr.column() == br.column())
964 && (nextTl.row() == prevTl.row() + 1) && (nextBr.row() == br.row() + 1)) {
965 br = nextBr;
966 prevTl = nextTl;
967 } else {
968 break;
969 }
970 }
971 rowSpans.append(QItemSelectionRange(tl, br));
972 }
973 return rowSpans;
974}
975
986{
987 const QModelIndex parent1 = i1.parent();
988 const QModelIndex parent2 = i2.parent();
989 return parent1 == parent2 ? i1 < i2 : parent1 < parent2;
990}
991
998{
999 // special case for when all indexes are selected
1002 ranges.clear();
1004 int bottom = tableRowCount - 1;
1005 int right = tableColCount - 1;
1006 QModelIndex tl = model->index(0, 0, tableParent);
1010 tableSelected = false;
1011 return;
1012 }
1013
1016 // either the selection was actually empty, or we
1017 // didn't get the layoutAboutToBeChanged() signal
1018 return;
1019 }
1020
1021 // clear the "old" selection
1022 ranges.clear();
1024
1026 // sort the "new" selection, as preparation for merging
1031
1032 // update the selection by merging the individual indexes
1035
1036 // release the persistent indexes
1039 } else {
1040 // sort the "new" selection, as preparation for merging
1043
1044 // update the selection by merging the individual indexes
1047
1048 // release the persistent indexes
1051 }
1052}
1053
1082{
1083 model.setValueBypassingBindings(nullptr);
1084 model.notify();
1085}
1086
1131{
1132 d_func()->initModel(model);
1133}
1134
1140{
1141 d_func()->initModel(model);
1142}
1143
1148 : QObject(dd, model)
1149{
1150 dd.initModel(model);
1151}
1152
1157{
1158}
1159
1166void QItemSelectionModel::select(const QModelIndex &index, QItemSelectionModel::SelectionFlags command)
1167{
1169 select(selection, command);
1170}
1171
1256namespace {
1258struct IsNotValid {
1259 typedef bool result_type;
1260 struct is_transparent : std::true_type {};
1261 template <typename T>
1262 constexpr bool operator()(T &t) const noexcept(noexcept(t.isValid()))
1263 { return !t.isValid(); }
1264 template <typename T>
1265 constexpr bool operator()(T *t) const noexcept(noexcept(t->isValid()))
1266 { return !t->isValid(); }
1267};
1268}
1269} // unnamed namespace
1270
1277void QItemSelectionModel::select(const QItemSelection &selection, QItemSelectionModel::SelectionFlags command)
1278{
1280 if (!d->model.value()) {
1281 qWarning("QItemSelectionModel: Selecting when no model has been set will result in a no-op.");
1282 return;
1283 }
1284 if (command == NoUpdate)
1285 return;
1286
1287 // store old selection
1289 // If d->ranges is non-empty when the source model is reset the persistent indexes
1290 // it contains will be invalid. We can't clear them in a modelReset slot because that might already
1291 // be too late if another model observer is connected to the same modelReset slot and is invoked first
1292 // it might call select() on this selection model before any such QItemSelectionModelPrivate::_q_modelReset() slot
1293 // is invoked, so it would not be cleared yet. We clear it invalid ranges in it here.
1294 d->ranges.removeIf(QtFunctionObjects::IsNotValid());
1295
1296 QItemSelection old = d->ranges;
1297 old.merge(d->currentSelection, d->currentCommand);
1298
1299 // expand selection according to SelectionBehavior
1300 if (command & Rows || command & Columns)
1301 sel = d->expandSelection(sel, command);
1302
1303 // clear ranges and currentSelection
1304 if (command & Clear) {
1305 d->ranges.clear();
1306 d->currentSelection.clear();
1307 }
1308
1309 // merge and clear currentSelection if Current was not set (ie. start new currentSelection)
1310 if (!(command & Current))
1311 d->finalize();
1312
1313 // update currentSelection
1314 if (command & Toggle || command & Select || command & Deselect) {
1315 d->currentCommand = command;
1316 d->currentSelection = sel;
1317 }
1318
1319 // generate new selection, compare with old and emit selectionChanged()
1320 QItemSelection newSelection = d->ranges;
1321 newSelection.merge(d->currentSelection, d->currentCommand);
1322 emitSelectionChanged(newSelection, old);
1323}
1324
1329{
1332}
1333
1338{
1340 QModelIndex previous = d->currentIndex;
1341 d->currentIndex = QModelIndex();
1342 if (previous.isValid()) {
1343 emit currentChanged(d->currentIndex, previous);
1344 emit currentRowChanged(d->currentIndex, previous);
1345 emit currentColumnChanged(d->currentIndex, previous);
1346 }
1347}
1348
1353{
1354 const QSignalBlocker blocker(this);
1355 clear();
1356}
1357
1363{
1365 if (d->ranges.size() == 0 && d->currentSelection.size() == 0)
1366 return;
1367
1369}
1370
1371
1382void QItemSelectionModel::setCurrentIndex(const QModelIndex &index, QItemSelectionModel::SelectionFlags command)
1383{
1385 if (!d->model.value()) {
1386 qWarning("QItemSelectionModel: Setting the current index when no model has been set will result in a no-op.");
1387 return;
1388 }
1389 if (index == d->currentIndex) {
1390 if (command != NoUpdate)
1391 select(index, command); // select item
1392 return;
1393 }
1394 QPersistentModelIndex previous = d->currentIndex;
1395 d->currentIndex = index; // set current before emitting selection changed below
1396 if (command != NoUpdate)
1397 select(d->currentIndex, command); // select item
1398 emit currentChanged(d->currentIndex, previous);
1399 if (d->currentIndex.row() != previous.row() ||
1400 d->currentIndex.parent() != previous.parent())
1401 emit currentRowChanged(d->currentIndex, previous);
1402 if (d->currentIndex.column() != previous.column() ||
1403 d->currentIndex.parent() != previous.parent())
1404 emit currentColumnChanged(d->currentIndex, previous);
1405}
1406
1412{
1413 return static_cast<QModelIndex>(d_func()->currentIndex);
1414}
1415
1420{
1421 Q_D(const QItemSelectionModel);
1422 if (d->model != index.model() || !index.isValid())
1423 return false;
1424
1425 bool selected = false;
1426 // search model ranges
1428 for (; it != d->ranges.end(); ++it) {
1429 if ((*it).isValid() && (*it).contains(index)) {
1430 selected = true;
1431 break;
1432 }
1433 }
1434
1435 // check currentSelection
1436 if (d->currentSelection.size()) {
1437 if ((d->currentCommand & Deselect) && selected)
1438 selected = !d->currentSelection.contains(index);
1439 else if (d->currentCommand & Toggle)
1440 selected ^= d->currentSelection.contains(index);
1441 else if ((d->currentCommand & Select) && !selected)
1442 selected = d->currentSelection.contains(index);
1443 }
1444
1445 if (selected)
1446 return isSelectableAndEnabled(d->model->flags(index));
1447
1448 return false;
1449}
1450
1463{
1464 Q_D(const QItemSelectionModel);
1465 if (!d->model.value())
1466 return false;
1467 if (parent.isValid() && d->model != parent.model())
1468 return false;
1469
1470 // return false if row exist in currentSelection (Deselect)
1471 if (d->currentCommand & Deselect && d->currentSelection.size()) {
1472 for (int i=0; i<d->currentSelection.size(); ++i) {
1473 if (d->currentSelection.at(i).parent() == parent &&
1474 row >= d->currentSelection.at(i).top() &&
1475 row <= d->currentSelection.at(i).bottom())
1476 return false;
1477 }
1478 }
1479 // return false if ranges in both currentSelection and ranges
1480 // intersect and have the same row contained
1481 if (d->currentCommand & Toggle && d->currentSelection.size()) {
1482 for (int i=0; i<d->currentSelection.size(); ++i)
1483 if (d->currentSelection.at(i).top() <= row &&
1484 d->currentSelection.at(i).bottom() >= row)
1485 for (int j=0; j<d->ranges.size(); ++j)
1486 if (d->ranges.at(j).top() <= row && d->ranges.at(j).bottom() >= row
1487 && d->currentSelection.at(i).intersected(d->ranges.at(j)).isValid())
1488 return false;
1489 }
1490
1491 auto isSelectable = [&](int row, int column) {
1492 return isSelectableAndEnabled(d->model->index(row, column, parent).flags());
1493 };
1494
1495 const int colCount = d->model->columnCount(parent);
1496 int unselectable = 0;
1497 // add ranges and currentSelection and check through them all
1499 QList<QItemSelectionRange> joined = d->ranges;
1500 if (d->currentSelection.size())
1501 joined += d->currentSelection;
1502 for (int column = 0; column < colCount; ++column) {
1503 if (!isSelectable(row, column)) {
1504 ++unselectable;
1505 continue;
1506 }
1507
1508 for (it = joined.constBegin(); it != joined.constEnd(); ++it) {
1509 if ((*it).contains(row, column, parent)) {
1510 for (int i = column; i <= (*it).right(); ++i) {
1511 if (!isSelectable(row, i))
1512 ++unselectable;
1513 }
1514
1515 column = qMax(column, (*it).right());
1516 break;
1517 }
1518 }
1519 if (it == joined.constEnd())
1520 return false;
1521 }
1522 return unselectable < colCount;
1523}
1524
1537{
1538 Q_D(const QItemSelectionModel);
1539 if (!d->model.value())
1540 return false;
1541 if (parent.isValid() && d->model != parent.model())
1542 return false;
1543
1544 // return false if column exist in currentSelection (Deselect)
1545 if (d->currentCommand & Deselect && d->currentSelection.size()) {
1546 for (int i = 0; i < d->currentSelection.size(); ++i) {
1547 if (d->currentSelection.at(i).parent() == parent &&
1548 column >= d->currentSelection.at(i).left() &&
1549 column <= d->currentSelection.at(i).right())
1550 return false;
1551 }
1552 }
1553 // return false if ranges in both currentSelection and the selection model
1554 // intersect and have the same column contained
1555 if (d->currentCommand & Toggle && d->currentSelection.size()) {
1556 for (int i = 0; i < d->currentSelection.size(); ++i) {
1557 if (d->currentSelection.at(i).left() <= column &&
1558 d->currentSelection.at(i).right() >= column) {
1559 for (int j = 0; j < d->ranges.size(); ++j) {
1560 if (d->ranges.at(j).left() <= column && d->ranges.at(j).right() >= column
1561 && d->currentSelection.at(i).intersected(d->ranges.at(j)).isValid()) {
1562 return false;
1563 }
1564 }
1565 }
1566 }
1567 }
1568
1569 auto isSelectable = [&](int row, int column) {
1570 return isSelectableAndEnabled(d->model->index(row, column, parent).flags());
1571 };
1572 const int rowCount = d->model->rowCount(parent);
1573 int unselectable = 0;
1574
1575 // add ranges and currentSelection and check through them all
1577 QList<QItemSelectionRange> joined = d->ranges;
1578 if (d->currentSelection.size())
1579 joined += d->currentSelection;
1580 for (int row = 0; row < rowCount; ++row) {
1581 if (!isSelectable(row, column)) {
1582 ++unselectable;
1583 continue;
1584 }
1585 for (it = joined.constBegin(); it != joined.constEnd(); ++it) {
1586 if ((*it).contains(row, column, parent)) {
1587 for (int i = row; i <= (*it).bottom(); ++i) {
1588 if (!isSelectable(i, column)) {
1589 ++unselectable;
1590 }
1591 }
1592 row = qMax(row, (*it).bottom());
1593 break;
1594 }
1595 }
1596 if (it == joined.constEnd())
1597 return false;
1598 }
1599 return unselectable < rowCount;
1600}
1601
1610{
1611 Q_D(const QItemSelectionModel);
1612 if (!d->model.value())
1613 return false;
1614 if (parent.isValid() && d->model != parent.model())
1615 return false;
1616
1617 QItemSelection sel = d->ranges;
1618 sel.merge(d->currentSelection, d->currentCommand);
1619 for (const QItemSelectionRange &range : std::as_const(sel)) {
1620 if (range.parent() != parent)
1621 return false;
1622 int top = range.top();
1623 int bottom = range.bottom();
1624 int left = range.left();
1625 int right = range.right();
1626 if (top <= row && bottom >= row) {
1627 for (int j = left; j <= right; j++) {
1628 if (isSelectableAndEnabled(d->model->index(row, j, parent).flags()))
1629 return true;
1630 }
1631 }
1632 }
1633
1634 return false;
1635}
1636
1645{
1646 Q_D(const QItemSelectionModel);
1647 if (!d->model.value())
1648 return false;
1649 if (parent.isValid() && d->model != parent.model())
1650 return false;
1651
1652 QItemSelection sel = d->ranges;
1653 sel.merge(d->currentSelection, d->currentCommand);
1654 for (const QItemSelectionRange &range : std::as_const(sel)) {
1655 if (range.parent() != parent)
1656 return false;
1657 int top = range.top();
1658 int bottom = range.bottom();
1659 int left = range.left();
1660 int right = range.right();
1661 if (left <= column && right >= column) {
1662 for (int j = top; j <= bottom; j++) {
1663 if (isSelectableAndEnabled(d->model->index(j, column, parent).flags()))
1664 return true;
1665 }
1666 }
1667 }
1668
1669 return false;
1670}
1671
1680{
1681 return std::all_of(selection.begin(), selection.end(),
1682 [](const QItemSelectionRange &r) { return r.isEmpty(); });
1683}
1684
1692{
1693 Q_D(const QItemSelectionModel);
1694
1695 // QTreeModel unfortunately sorts itself lazily.
1696 // When it sorts itself, it emits are layoutChanged signal.
1697 // This layoutChanged signal invalidates d->ranges here.
1698 // So QTreeModel must not sort itself while we are iterating over
1699 // d->ranges here. It sorts itself in executePendingOperations,
1700 // thus preventing the sort to happen inside of selectionIsEmpty below.
1701 // Sad story, read more in QTBUG-94546
1703 if (model != nullptr) {
1704 auto model_p = static_cast<const QAbstractItemModelPrivate *>(QObjectPrivate::get(model));
1705 model_p->executePendingOperations();
1706 }
1707
1708 if (d->currentCommand & (Toggle | Deselect)) {
1709 QItemSelection sel = d->ranges;
1710 sel.merge(d->currentSelection, d->currentCommand);
1711 return !selectionIsEmpty(sel);
1712 } else {
1713 return !(selectionIsEmpty(d->ranges) && selectionIsEmpty(d->currentSelection));
1714 }
1715}
1716
1722{
1723 Q_D(const QItemSelectionModel);
1724 QItemSelection selected = d->ranges;
1725 selected.merge(d->currentSelection, d->currentCommand);
1726 return selected.indexes();
1727}
1728
1732
1733 friend bool operator==(const RowOrColumnDefinition &lhs, const RowOrColumnDefinition &rhs) noexcept
1734 { return lhs.parent == rhs.parent && lhs.rowOrColumn == rhs.rowOrColumn; }
1735 friend bool operator!=(const RowOrColumnDefinition &lhs, const RowOrColumnDefinition &rhs) noexcept
1736 { return !operator==(lhs, rhs); }
1737};
1738size_t qHash(const RowOrColumnDefinition &key, size_t seed = 0) noexcept
1739{
1741 seed = hash(seed, key.parent);
1742 seed = hash(seed, key.rowOrColumn);
1743 return seed;
1744}
1745
1747
1748
1756{
1757 QModelIndexList indexes;
1758
1760
1761 const QItemSelection ranges = selection();
1762 for (int i = 0; i < ranges.size(); ++i) {
1763 const QItemSelectionRange &range = ranges.at(i);
1764 QModelIndex parent = range.parent();
1765 for (int row = range.top(); row <= range.bottom(); row++) {
1766 if (!rowsSeen.hasSeen({parent, row})) {
1767 if (isRowSelected(row, parent)) {
1768 indexes.append(model()->index(row, column, parent));
1769 }
1770 }
1771 }
1772 }
1773
1774 return indexes;
1775}
1776
1785{
1786 QModelIndexList indexes;
1787
1789
1790 const QItemSelection ranges = selection();
1791 for (int i = 0; i < ranges.size(); ++i) {
1792 const QItemSelectionRange &range = ranges.at(i);
1794 for (int column = range.left(); column <= range.right(); column++) {
1795 if (!columnsSeen.hasSeen({parent, column})) {
1797 indexes.append(model()->index(row, column, parent));
1798 }
1799 }
1800 }
1801 }
1802
1803 return indexes;
1804}
1805
1810{
1811 Q_D(const QItemSelectionModel);
1812 QItemSelection selected = d->ranges;
1813 selected.merge(d->currentSelection, d->currentCommand);
1814 // make sure we have no invalid ranges
1815 // ### should probably be handled more generic somewhere else
1816 selected.removeIf(QtFunctionObjects::IsNotValid());
1817 return selected;
1818}
1819
1856{
1857 return d_func()->model.value();
1858}
1859
1864{
1865 return d_func()->model.value();
1866}
1867
1869{
1870 return &d_func()->model;
1871}
1872
1881{
1883 d->model.removeBindingUnlessInWrapper();
1884 if (d->model == model)
1885 return;
1886
1887 d->initModel(model);
1888 d->model.notify();
1889}
1890
1896 const QItemSelection &oldSelection)
1897{
1898 // if both selections are empty or equal we return
1899 if ((oldSelection.isEmpty() && newSelection.isEmpty()) ||
1900 oldSelection == newSelection)
1901 return;
1902
1903 // if either selection is empty we do not need to compare
1904 if (oldSelection.isEmpty() || newSelection.isEmpty()) {
1905 emit selectionChanged(newSelection, oldSelection);
1906 return;
1907 }
1908
1909 QItemSelection deselected = oldSelection;
1910 QItemSelection selected = newSelection;
1911
1912 // remove equal ranges
1913 bool advance;
1914 for (int o = 0; o < deselected.size(); ++o) {
1915 advance = true;
1916 for (int s = 0; s < selected.size() && o < deselected.size();) {
1917 if (deselected.at(o) == selected.at(s)) {
1918 deselected.removeAt(o);
1919 selected.removeAt(s);
1920 advance = false;
1921 } else {
1922 ++s;
1923 }
1924 }
1925 if (advance)
1926 ++o;
1927 }
1928
1929 // find intersections
1930 QItemSelection intersections;
1931 for (int o = 0; o < deselected.size(); ++o) {
1932 for (int s = 0; s < selected.size(); ++s) {
1933 if (deselected.at(o).intersects(selected.at(s)))
1934 intersections.append(deselected.at(o).intersected(selected.at(s)));
1935 }
1936 }
1937
1938 // compare remaining ranges with intersections and split them to find deselected and selected
1939 for (int i = 0; i < intersections.size(); ++i) {
1940 // split deselected
1941 for (int o = 0; o < deselected.size();) {
1942 if (deselected.at(o).intersects(intersections.at(i))) {
1943 QItemSelection::split(deselected.at(o), intersections.at(i), &deselected);
1944 deselected.removeAt(o);
1945 } else {
1946 ++o;
1947 }
1948 }
1949 // split selected
1950 for (int s = 0; s < selected.size();) {
1951 if (selected.at(s).intersects(intersections.at(i))) {
1952 QItemSelection::split(selected.at(s), intersections.at(i), &selected);
1953 selected.removeAt(s);
1954 } else {
1955 ++s;
1956 }
1957 }
1958 }
1959
1960 if (!selected.isEmpty() || !deselected.isEmpty())
1961 emit selectionChanged(selected, deselected);
1962}
1963
1964#ifndef QT_NO_DEBUG_STREAM
1966{
1967 QDebugStateSaver saver(dbg);
1968 dbg.nospace() << "QItemSelectionRange(" << range.topLeft()
1969 << ',' << range.bottomRight() << ')';
1970 return dbg;
1971}
1972#endif
1973
1975
1976#include "moc_qitemselectionmodel.cpp"
virtual void executePendingOperations() const
LayoutChangeHint
This enum describes the way the model changes layout.
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
Definition qproperty.h:809
\inmodule QtCore
\inmodule QtCore
bool hasSeen(const T &s)
QPersistentModelIndex tableParent
void _q_rowsAboutToBeInserted(const QModelIndex &parent, int start, int end)
void _q_columnsAboutToBeInserted(const QModelIndex &parent, int start, int end)
void _q_layoutChanged(const QList< QPersistentModelIndex > &parents=QList< QPersistentModelIndex >(), QAbstractItemModel::LayoutChangeHint hint=QAbstractItemModel::NoLayoutChangeHint)
QList< QPair< QPersistentModelIndex, uint > > savedPersistentRowLengths
QList< QPair< QPersistentModelIndex, uint > > savedPersistentCurrentRowLengths
void _q_columnsAboutToBeRemoved(const QModelIndex &parent, int start, int end)
QPersistentModelIndex currentIndex
QList< QPersistentModelIndex > savedPersistentCurrentIndexes
void initModel(QAbstractItemModel *model)
void _q_rowsAboutToBeRemoved(const QModelIndex &parent, int start, int end)
QList< QPersistentModelIndex > savedPersistentIndexes
QItemSelection expandSelection(const QItemSelection &selection, QItemSelectionModel::SelectionFlags command) const
void _q_layoutAboutToBeChanged(const QList< QPersistentModelIndex > &parents=QList< QPersistentModelIndex >(), QAbstractItemModel::LayoutChangeHint hint=QAbstractItemModel::NoLayoutChangeHint)
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:74
qsizetype size() const noexcept
Definition qlist.h:386
bool isEmpty() const noexcept
Definition qlist.h:390
void removeAt(qsizetype i)
Definition qlist.h:573
QList< QItemSelectionRange > & operator+=(const QList< QItemSelectionRange > &l)
Definition qlist.h:691
void push_back(parameter_type t)
Definition qlist.h:672
const_reference at(qsizetype i) const noexcept
Definition qlist.h:429
const_iterator constBegin() const noexcept
Definition qlist.h:615
qsizetype removeIf(Predicate pred)
Definition qlist.h:587
const T & constFirst() const noexcept
Definition qlist.h:630
void reserve(qsizetype size)
Definition qlist.h:746
void append(parameter_type t)
Definition qlist.h:441
const_iterator constEnd() const noexcept
Definition qlist.h:616
void clear()
Definition qlist.h:417
\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:61
QAtomicPointer< ConnectionData > connections
Definition qobject_p.h:205
static QObjectPrivate * get(QObject *o)
Definition qobject_p.h:153
\inmodule QtCore
Definition qobject.h:90
QObject * parent() const
Returns a pointer to the parent object.
Definition qobject.h:311
static QMetaObject::Connection connect(const QObject *sender, const char *signal, const QObject *receiver, const char *member, Qt::ConnectionType=Qt::AutoConnection)
\threadsafe
Definition qobject.cpp:2823
static bool disconnect(const QObject *sender, const char *signal, const QObject *receiver, const char *member)
\threadsafe
Definition qobject.cpp:3099
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
iterator erase(const_iterator i)
Definition qset.h:145
Exception-safe wrapper around QObject::blockSignals().
Definition qobject.h:443
int rowCount(const QModelIndex &parent=QModelIndex()) const override
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
std::pair< T1, T2 > QPair
#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 QList< QPair< QPersistentModelIndex, uint > > qSelectionPersistentRowLengths(const QItemSelection &sel)
static ModelIndexContainer qSelectionIndexes(const QItemSelection &selection)
static void rowLengthsFromRange(const QItemSelectionRange &range, QList< QPair< QPersistentModelIndex, uint > > &result)
static QItemSelection mergeRowLengths(const QList< QPair< QPersistentModelIndex, uint > > &rowLengths)
static void indexesFromRange(const QItemSelectionRange &range, ModelIndexContainer &result)
QDebug operator<<(QDebug dbg, const QItemSelectionRange &range)
static bool isSelectableAndEnabled(Qt::ItemFlags flags)
size_t qHash(const RowOrColumnDefinition &key, size_t seed=0) noexcept
#define qWarning
Definition qlogging.h:162
#define QT_IMPL_METATYPE_EXTERN(TYPE)
Definition qmetatype.h:1369
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
#define QT_STRINGIFY_SIGNAL(a)
Definition qobjectdefs.h:45
#define QT_STRINGIFY_SLOT(a)
Definition qobjectdefs.h:44
constexpr auto qOffsetStringArray(const char(&...strings)[Nx]) noexcept
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
GLboolean reset
GLdouble GLdouble t
Definition qopenglext.h:243
GLdouble GLdouble GLdouble GLdouble q
Definition qopenglext.h:259
GLenum GLenum GLsizei void * row
GLuint64EXT * result
[6]
GLdouble s
[6]
Definition qopenglext.h:235
constexpr decltype(auto) qMakePair(T1 &&value1, T2 &&value2) noexcept(noexcept(std::make_pair(std::forward< T1 >(value1), std::forward< T2 >(value2))))
Definition qpair.h:19
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:29
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
IUIAutomationTreeWalker __RPC__deref_out_opt IUIAutomationElement ** parent