251QItemSelectionRange QItemSelectionRange::intersected(
const QItemSelectionRange &other)
const
253 if (model() == other.model() && parent() == other.parent()) {
254 QModelIndex topLeft = model()->index(qMax(top(), other.top()),
255 qMax(left(), other.left()),
257 QModelIndex bottomRight = model()->index(qMin(bottom(), other.bottom()),
258 qMin(right(), other.right()),
260 return QItemSelectionRange(topLeft, bottomRight);
262 return QItemSelectionRange();
288static void rowLengthsFromRange(
const QItemSelectionRange &range, QList<std::pair<QPersistentModelIndex, uint>> &result)
290 if (range.isValid() && range.model()) {
291 const QModelIndex topLeft = range.topLeft();
292 const int bottom = range.bottom();
293 const uint width = range.width();
294 const int column = topLeft.column();
295 for (
int row = topLeft.row(); row <= bottom; ++row) {
299 result.emplace_back(topLeft.sibling(row, column), width);
312 if (range.isValid() && range.model()) {
313 const QModelIndex topLeft = range.topLeft();
314 const int bottom = range.bottom();
315 const int right = range.right();
316 for (
int row = topLeft.row(); row <= bottom; ++row) {
317 const QModelIndex columnLeader = topLeft.sibling(row, topLeft.column());
318 for (
int column = topLeft.column(); column <= right; ++column) {
319 QModelIndex index = columnLeader.sibling(row, column);
320 if (isSelectableAndEnabled(range.model()->flags(index)))
321 result.push_back(index);
434void QItemSelection::select(
const QModelIndex &topLeft,
const QModelIndex &bottomRight)
436 if (!topLeft.isValid() || !bottomRight.isValid())
439 if ((topLeft.model() != bottomRight.model())
440 || topLeft.parent() != bottomRight.parent()) {
441 qWarning(
"Can't select indexes from different model or with different parents");
444 if (topLeft.row() > bottomRight.row() || topLeft.column() > bottomRight.column()) {
445 int top = qMin(topLeft.row(), bottomRight.row());
446 int bottom = qMax(topLeft.row(), bottomRight.row());
447 int left = qMin(topLeft.column(), bottomRight.column());
448 int right = qMax(topLeft.column(), bottomRight.column());
449 QModelIndex tl = topLeft.sibling(top, left);
450 QModelIndex br = bottomRight.sibling(bottom, right);
451 append(QItemSelectionRange(tl, br));
454 append(QItemSelectionRange(topLeft, bottomRight));
496void QItemSelection::merge(
const QItemSelection &other, QItemSelectionModel::SelectionFlags command)
498 if (other.isEmpty() ||
499 !(command & QItemSelectionModel::Select ||
500 command & QItemSelectionModel::Deselect ||
501 command & QItemSelectionModel::Toggle))
504 QItemSelection newSelection;
505 newSelection.reserve(other.size());
507 QItemSelection intersections;
508 for (
const auto &range : other) {
509 if (!range.isValid())
511 newSelection.push_back(range);
512 for (
int t = 0; t < size(); ++t) {
513 if (range.intersects(at(t)))
514 intersections.append(at(t).intersected(range));
519 for (
int i = 0; i < intersections.size(); ++i) {
520 for (
int t = 0; t < size();) {
521 if (at(t).intersects(intersections.at(i))) {
522 split(at(t), intersections.at(i),
this);
529 for (
int n = 0; (command & QItemSelectionModel::Toggle) && n < newSelection.size();) {
530 if (newSelection.at(n).intersects(intersections.at(i))) {
531 split(newSelection.at(n), intersections.at(i), &newSelection);
532 newSelection.removeAt(n);
539 if (!(command & QItemSelectionModel::Deselect))
540 operator+=(newSelection);
550void QItemSelection::split(
const QItemSelectionRange &range,
551 const QItemSelectionRange &other, QItemSelection *result)
553 if (range.parent() != other.parent() || range.model() != other.model())
556 QModelIndex parent = other.parent();
557 int top = range.top();
558 int left = range.left();
559 int bottom = range.bottom();
560 int right = range.right();
561 int other_top = other.top();
562 int other_left = other.left();
563 int other_bottom = other.bottom();
564 int other_right = other.right();
565 const QAbstractItemModel *model = range.model();
567 if (other_top > top) {
568 QModelIndex tl = model->index(top, left, parent);
569 QModelIndex br = model->index(other_top - 1, right, parent);
570 result->append(QItemSelectionRange(tl, br));
573 if (other_bottom < bottom) {
574 QModelIndex tl = model->index(other_bottom + 1, left, parent);
575 QModelIndex br = model->index(bottom, right, parent);
576 result->append(QItemSelectionRange(tl, br));
577 bottom = other_bottom;
579 if (other_left > left) {
580 QModelIndex tl = model->index(top, left, parent);
581 QModelIndex br = model->index(bottom, other_left - 1, parent);
582 result->append(QItemSelectionRange(tl, br));
585 if (other_right < right) {
586 QModelIndex tl = model->index(top, other_right + 1, parent);
587 QModelIndex br = model->index(bottom, right, parent);
588 result->append(QItemSelectionRange(tl, br));
596void QItemSelectionModelPrivate::initModel(QAbstractItemModel *m)
598 Q_Q(QItemSelectionModel);
599 const QAbstractItemModel *oldModel = model.valueBypassingBindings();
609 model.setValueBypassingBindings(m);
612 connections = std::array<QMetaObject::Connection, 12> {
613 QObjectPrivate::connect(m, &QAbstractItemModel::rowsAboutToBeRemoved,
614 this, &QItemSelectionModelPrivate::rowsAboutToBeRemoved),
615 QObjectPrivate::connect(m, &QAbstractItemModel::columnsAboutToBeRemoved,
616 this, &QItemSelectionModelPrivate::columnsAboutToBeRemoved),
617 QObjectPrivate::connect(m, &QAbstractItemModel::rowsAboutToBeInserted,
618 this, &QItemSelectionModelPrivate::rowsAboutToBeInserted),
619 QObjectPrivate::connect(m, &QAbstractItemModel::columnsAboutToBeInserted,
620 this, &QItemSelectionModelPrivate::columnsAboutToBeInserted),
621 QObjectPrivate::connect(m, &QAbstractItemModel::rowsAboutToBeMoved,
622 this, &QItemSelectionModelPrivate::triggerLayoutToBeChanged),
623 QObjectPrivate::connect(m, &QAbstractItemModel::columnsAboutToBeMoved,
624 this, &QItemSelectionModelPrivate::triggerLayoutToBeChanged),
625 QObjectPrivate::connect(m, &QAbstractItemModel::rowsMoved,
626 this, &QItemSelectionModelPrivate::triggerLayoutChanged),
627 QObjectPrivate::connect(m, &QAbstractItemModel::columnsMoved,
628 this, &QItemSelectionModelPrivate::triggerLayoutChanged),
629 QObjectPrivate::connect(m, &QAbstractItemModel::layoutAboutToBeChanged,
630 this, &QItemSelectionModelPrivate::layoutAboutToBeChanged),
631 QObjectPrivate::connect(m, &QAbstractItemModel::layoutChanged,
632 this, &QItemSelectionModelPrivate::layoutChanged),
633 QObject::connect(m, &QAbstractItemModel::modelReset,
634 q, &QItemSelectionModel::reset),
635 QObjectPrivate::connect(m, &QAbstractItemModel::destroyed,
636 this, &QItemSelectionModelPrivate::modelDestroyed)
655QItemSelection QItemSelectionModelPrivate::expandSelection(
const QItemSelection &selection,
656 QItemSelectionModel::SelectionFlags command)
const
658 if (selection.isEmpty() && !((command & QItemSelectionModel::Rows) ||
659 (command & QItemSelectionModel::Columns)))
662 QItemSelection expanded;
663 if (command & QItemSelectionModel::Rows) {
664 for (
int i = 0; i < selection.size(); ++i) {
665 QModelIndex parent = selection.at(i).parent();
666 int colCount = model->columnCount(parent);
667 QModelIndex tl = model->index(selection.at(i).top(), 0, parent);
668 QModelIndex br = model->index(selection.at(i).bottom(), colCount - 1, parent);
670 expanded.merge(QItemSelection(tl, br), QItemSelectionModel::Select);
673 if (command & QItemSelectionModel::Columns) {
674 for (
int i = 0; i < selection.size(); ++i) {
675 QModelIndex parent = selection.at(i).parent();
676 int rowCount = model->rowCount(parent);
677 QModelIndex tl = model->index(0, selection.at(i).left(), parent);
678 QModelIndex br = model->index(rowCount - 1, selection.at(i).right(), parent);
680 expanded.merge(QItemSelection(tl, br), QItemSelectionModel::Select);
689void QItemSelectionModelPrivate::rowsAboutToBeRemoved(
const QModelIndex &parent,
692 Q_Q(QItemSelectionModel);
693 Q_ASSERT(start <= end);
697 if (currentIndex.isValid() && parent == currentIndex.parent()
698 && currentIndex.row() >= start && currentIndex.row() <= end) {
699 QModelIndex old = currentIndex;
702 currentIndex = model->index(start - 1, old.column(), parent);
703 }
else if (model.value() && end < model->rowCount(parent) - 1) {
705 currentIndex = model->index(end + 1, old.column(), parent);
708 currentIndex = QModelIndex();
710 emit q->currentChanged(currentIndex, old);
711 emit q->currentRowChanged(currentIndex, old);
712 if (currentIndex.column() != old.column())
713 emit q->currentColumnChanged(currentIndex, old);
716 QItemSelection deselected;
717 QItemSelection newParts;
718 bool indexesOfSelectionChanged =
false;
719 QItemSelection::iterator it = ranges.begin();
720 while (it != ranges.end()) {
721 if (it->topLeft().parent() != parent) {
722 QModelIndex itParent = it->topLeft().parent();
723 while (itParent.isValid() && itParent.parent() != parent)
724 itParent = itParent.parent();
726 if (itParent.isValid() && start <= itParent.row() && itParent.row() <= end) {
727 deselected.append(*it);
728 it = ranges.erase(it);
730 if (itParent.isValid() && end < itParent.row())
731 indexesOfSelectionChanged =
true;
734 }
else if (start <= it->bottom() && it->bottom() <= end
735 && start <= it->top() && it->top() <= end) {
736 deselected.append(*it);
737 it = ranges.erase(it);
738 }
else if (start <= it->top() && it->top() <= end) {
739 deselected.append(QItemSelectionRange(it->topLeft(), model->index(end, it->right(), it->parent())));
740 *it = QItemSelectionRange(model->index(end + 1, it->left(), it->parent()), it->bottomRight());
742 }
else if (start <= it->bottom() && it->bottom() <= end) {
743 deselected.append(QItemSelectionRange(model->index(start, it->left(), it->parent()), it->bottomRight()));
744 *it = QItemSelectionRange(it->topLeft(), model->index(start - 1, it->right(), it->parent()));
746 }
else if (it->top() < start && end < it->bottom()) {
751 const QItemSelectionRange removedRange(model->index(start, it->left(), it->parent()),
752 model->index(end, it->right(), it->parent()));
753 deselected.append(removedRange);
754 QItemSelection::split(*it, removedRange, &newParts);
755 it = ranges.erase(it);
756 }
else if (end < it->top()) {
757 indexesOfSelectionChanged =
true;
763 ranges.append(newParts);
765 if (!deselected.isEmpty() || indexesOfSelectionChanged)
766 emit q->selectionChanged(QItemSelection(), deselected);
772void QItemSelectionModelPrivate::columnsAboutToBeRemoved(
const QModelIndex &parent,
775 Q_Q(QItemSelectionModel);
778 if (currentIndex.isValid() && parent == currentIndex.parent()
779 && currentIndex.column() >= start && currentIndex.column() <= end) {
780 QModelIndex old = currentIndex;
783 currentIndex = model->index(old.row(), start - 1, parent);
784 }
else if (model.value() && end < model->columnCount() - 1) {
786 currentIndex = model->index(old.row(), end + 1, parent);
789 currentIndex = QModelIndex();
791 emit q->currentChanged(currentIndex, old);
792 if (currentIndex.row() != old.row())
793 emit q->currentRowChanged(currentIndex, old);
794 emit q->currentColumnChanged(currentIndex, old);
798 QModelIndex tl = model->index(0, start, parent);
799 QModelIndex br = model->index(model->rowCount(parent) - 1, end, parent);
800 q->select(QItemSelection(tl, br), QItemSelectionModel::Deselect);
809void QItemSelectionModelPrivate::columnsAboutToBeInserted(
const QModelIndex &parent,
814 QList<QItemSelectionRange> split;
815 QList<QItemSelectionRange>::iterator it = ranges.begin();
816 for (; it != ranges.end(); ) {
817 const QModelIndex &itParent = it->parent();
818 if ((*it).isValid() && itParent == parent
819 && (*it).left() < start && (*it).right() >= start) {
820 QModelIndex bottomMiddle = model->index((*it).bottom(), start - 1, itParent);
822 QModelIndex topMiddle = model->index((*it).top(), start, itParent);
824 it = ranges.erase(it);
839void QItemSelectionModelPrivate::rowsAboutToBeInserted(
const QModelIndex &parent,
842 Q_Q(QItemSelectionModel);
845 QList<QItemSelectionRange> split;
846 QList<QItemSelectionRange>::iterator it = ranges.begin();
847 bool indexesOfSelectionChanged =
false;
848 for (; it != ranges.end(); ) {
849 const QModelIndex &itParent = it->parent();
850 if ((*it).isValid() && itParent == parent
851 && (*it).top() < start && (*it).bottom() >= start) {
852 QModelIndex middleRight = model->index(start - 1, (*it).right(), itParent);
854 QModelIndex middleLeft = model->index(start, (*it).left(), itParent);
856 it = ranges.erase(it);
858 split.append(bottom);
859 }
else if ((*it).isValid() && itParent == parent
860 && (*it).top() >= start) {
861 indexesOfSelectionChanged =
true;
869 if (indexesOfSelectionChanged)
870 emit q->selectionChanged(QItemSelection(), QItemSelection());
880void QItemSelectionModelPrivate::layoutAboutToBeChanged(
const QList<QPersistentModelIndex> &,
881 QAbstractItemModel::LayoutChangeHint hint)
883 savedPersistentIndexes.clear();
884 savedPersistentCurrentIndexes.clear();
885 savedPersistentRowLengths.clear();
886 savedPersistentCurrentRowLengths.clear();
890 if (ranges.isEmpty() && currentSelection.size() == 1) {
892 QModelIndex parent = range.parent();
893 tableRowCount = model->rowCount(parent);
894 tableColCount = model->columnCount(parent);
895 if (tableRowCount * tableColCount > 1000
898 && range.bottom() == tableRowCount - 1
899 && range.right() == tableColCount - 1) {
900 tableSelected =
true;
901 tableParent = parent;
905 tableSelected =
false;
907 if (hint == QAbstractItemModel::VerticalSortHint) {
913 savedPersistentRowLengths = qSelectionPersistentRowLengths(ranges);
914 savedPersistentCurrentRowLengths = qSelectionPersistentRowLengths(currentSelection);
916 savedPersistentIndexes = qSelectionIndexes<QList<QPersistentModelIndex>>(ranges);
917 savedPersistentCurrentIndexes = qSelectionIndexes<QList<QPersistentModelIndex>>(currentSelection);
923static QItemSelection
mergeRowLengths(
const QList<std::pair<QPersistentModelIndex, uint>> &rowLengths)
925 if (rowLengths.isEmpty())
926 return QItemSelection();
928 QItemSelection result;
930 while (i < rowLengths.size()) {
931 const QPersistentModelIndex &tl = rowLengths.at(i).first;
936 QPersistentModelIndex br = tl;
937 const uint length = rowLengths.at(i).second;
938 while (++i < rowLengths.size()) {
939 const QPersistentModelIndex &next = rowLengths.at(i).first;
942 const uint nextLength = rowLengths.at(i).second;
943 if ((nextLength == length)
944 && (next.row() == br.row() + 1)
945 && (next.column() == br.column())
946 && (next.parent() == br.parent())) {
952 result.append(QItemSelectionRange(tl, br.sibling(br.row(), br.column() + length - 1)));
963static QItemSelection
mergeIndexes(
const QList<QPersistentModelIndex> &indexes)
965 QItemSelection colSpans;
968 while (i < indexes.size()) {
969 const QPersistentModelIndex &tl = indexes.at(i);
974 QPersistentModelIndex br = tl;
975 QModelIndex brParent = br.parent();
976 int brRow = br.row();
977 int brColumn = br.column();
978 while (++i < indexes.size()) {
979 const QPersistentModelIndex &next = indexes.at(i);
982 const QModelIndex nextParent = next.parent();
983 const int nextRow = next.row();
984 const int nextColumn = next.column();
985 if ((nextParent == brParent)
986 && (nextRow == brRow)
987 && (nextColumn == brColumn + 1)) {
989 brParent = nextParent;
991 brColumn = nextColumn;
996 colSpans.append(QItemSelectionRange(tl, br));
999 QItemSelection rowSpans;
1001 while (i < colSpans.size()) {
1002 QModelIndex tl = colSpans.at(i).topLeft();
1003 QModelIndex br = colSpans.at(i).bottomRight();
1004 QModelIndex prevTl = tl;
1005 while (++i < colSpans.size()) {
1006 QModelIndex nextTl = colSpans.at(i).topLeft();
1007 QModelIndex nextBr = colSpans.at(i).bottomRight();
1009 if (nextTl.parent() != tl.parent())
1012 if ((nextTl.column() == prevTl.column()) && (nextBr.column() == br.column())
1013 && (nextTl.row() == prevTl.row() + 1) && (nextBr.row() == br.row() + 1)) {
1020 rowSpans.append(QItemSelectionRange(tl, br));
1046void QItemSelectionModelPrivate::layoutChanged(
const QList<QPersistentModelIndex> &, QAbstractItemModel::LayoutChangeHint hint)
1049 if (tableSelected && tableColCount == model->columnCount(tableParent)
1050 && tableRowCount == model->rowCount(tableParent)) {
1052 currentSelection.clear();
1053 int bottom = tableRowCount - 1;
1054 int right = tableColCount - 1;
1055 QModelIndex tl = model->index(0, 0, tableParent);
1056 QModelIndex br = model->index(bottom, right, tableParent);
1057 currentSelection << QItemSelectionRange(tl, br);
1058 tableParent = QModelIndex();
1059 tableSelected =
false;
1063 if ((hint != QAbstractItemModel::VerticalSortHint && savedPersistentCurrentIndexes.isEmpty() && savedPersistentIndexes.isEmpty())
1064 || (hint == QAbstractItemModel::VerticalSortHint && savedPersistentRowLengths.isEmpty() && savedPersistentCurrentRowLengths.isEmpty())) {
1072 currentSelection.clear();
1074 if (hint != QAbstractItemModel::VerticalSortHint) {
1076 std::stable_sort(savedPersistentIndexes.begin(), savedPersistentIndexes.end(),
1077 qt_PersistentModelIndexLessThan);
1078 std::stable_sort(savedPersistentCurrentIndexes.begin(), savedPersistentCurrentIndexes.end(),
1079 qt_PersistentModelIndexLessThan);
1082 ranges = mergeIndexes(savedPersistentIndexes);
1083 currentSelection = mergeIndexes(savedPersistentCurrentIndexes);
1086 savedPersistentIndexes.clear();
1087 savedPersistentCurrentIndexes.clear();
1090 std::stable_sort(savedPersistentRowLengths.begin(), savedPersistentRowLengths.end());
1091 std::stable_sort(savedPersistentCurrentRowLengths.begin(), savedPersistentCurrentRowLengths.end());
1094 ranges = mergeRowLengths(savedPersistentRowLengths);
1095 currentSelection = mergeRowLengths(savedPersistentCurrentRowLengths);
1098 savedPersistentRowLengths.clear();
1099 savedPersistentCurrentRowLengths.clear();
1327void QItemSelectionModel::select(
const QItemSelection &selection, QItemSelectionModel::SelectionFlags command)
1329 Q_D(QItemSelectionModel);
1330 if (!d->model.value()) {
1331 qWarning(
"QItemSelectionModel: Selecting when no model has been set will result in a no-op.");
1334 if (command == NoUpdate)
1338 QItemSelection sel = selection;
1344 d->ranges.removeIf(QtFunctionObjects::IsNotValid());
1346 QItemSelection old = d->ranges;
1347 old.merge(d->currentSelection, d->currentCommand);
1350 if (command & Rows || command & Columns)
1351 sel = d->expandSelection(sel, command);
1354 if (command & Clear) {
1356 d->currentSelection.clear();
1360 if (!(command & Current))
1364 if (command & Toggle || command & Select || command & Deselect) {
1365 d->currentCommand = command;
1366 d->currentSelection = sel;
1370 QItemSelection newSelection = d->ranges;
1371 newSelection.merge(d->currentSelection, d->currentCommand);
1372 emitSelectionChanged(newSelection, old);
1387void QItemSelectionModel::clearCurrentIndex()
1389 Q_D(QItemSelectionModel);
1390 QModelIndex previous = d->currentIndex;
1391 d->currentIndex = QModelIndex();
1392 if (previous.isValid()) {
1393 emit currentChanged(d->currentIndex, previous);
1394 emit currentRowChanged(d->currentIndex, previous);
1395 emit currentColumnChanged(d->currentIndex, previous);
1432void QItemSelectionModel::setCurrentIndex(
const QModelIndex &index, QItemSelectionModel::SelectionFlags command)
1434 Q_D(QItemSelectionModel);
1435 if (!d->model.value()) {
1436 qWarning(
"QItemSelectionModel: Setting the current index when no model has been set will result in a no-op.");
1439 if (index == d->currentIndex) {
1440 if (command != NoUpdate)
1441 select(index, command);
1444 QPersistentModelIndex previous = d->currentIndex;
1445 d->currentIndex = index;
1446 if (command != NoUpdate)
1447 select(d->currentIndex, command);
1448 emit currentChanged(d->currentIndex, previous);
1449 if (d->currentIndex.row() != previous.row() ||
1450 d->currentIndex.parent() != previous.parent())
1451 emit currentRowChanged(d->currentIndex, previous);
1452 if (d->currentIndex.column() != previous.column() ||
1453 d->currentIndex.parent() != previous.parent())
1454 emit currentColumnChanged(d->currentIndex, previous);
1469bool QItemSelectionModel::isSelected(
const QModelIndex &index)
const
1471 Q_D(
const QItemSelectionModel);
1472 if (d->model != index.model() || !index.isValid())
1476 auto contains = [](
const auto &index) {
1477 return [&index](
const auto &range) {
return range.contains(index); };
1479 bool selected = std::any_of(d->ranges.begin(), d->ranges.end(), contains(index));
1482 if (d->currentSelection.size()) {
1483 if ((d->currentCommand & Deselect) && selected)
1484 selected = !d->currentSelection.contains(index);
1485 else if (d->currentCommand & Toggle)
1486 selected ^= d->currentSelection.contains(index);
1487 else if ((d->currentCommand & Select) && !selected)
1488 selected = d->currentSelection.contains(index);
1492 return isSelectableAndEnabled(d->model->flags(index));
1508bool QItemSelectionModel::isRowSelected(
int row,
const QModelIndex &parent)
const
1510 Q_D(
const QItemSelectionModel);
1511 if (!d->model.value())
1513 if (parent.isValid() && d->model != parent.model())
1517 if (d->currentCommand & Deselect) {
1518 const auto matches = [](
auto row,
const auto &parent) {
1519 return [row, &parent](
const auto &selection) {
1520 return row >= selection.top() &&
1521 row <= selection.bottom() &&
1522 parent == selection.parent();
1525 if (std::any_of(d->currentSelection.cbegin(), d->currentSelection.cend(), matches(row, parent)))
1530 if (d->currentCommand & Toggle) {
1531 for (
const auto &selection : d->currentSelection) {
1532 if (row >= selection.top() && row <= selection.bottom()) {
1533 const auto intersects = [](
auto row,
const auto &selection) {
1534 return [row, &selection](
const auto &range) {
1535 return row >= range.top() &&
1536 row <= range.bottom() &&
1537 selection.intersected(range).isValid();
1540 if (std::any_of(d->ranges.cbegin(), d->ranges.cend(), intersects(row, selection)))
1546 auto isSelectable = [&](
int row,
int column) {
1547 return isSelectableAndEnabled(d->model->index(row, column, parent).flags());
1550 const int colCount = d->model->columnCount(parent);
1551 int unselectable = 0;
1552 std::vector<QItemSelectionRangeRefCache> cache;
1553 cache.reserve(d->currentSelection.size() + d->ranges.size());
1554 std::copy(d->currentSelection.begin(), d->currentSelection.end(), std::back_inserter(cache));
1555 std::copy(d->ranges.begin(), d->ranges.end(), std::back_inserter(cache));
1558 for (
int column = 0; column < colCount; ++column) {
1559 if (!isSelectable(row, column)) {
1563 bool foundSelection =
false;
1564 for (
auto &curSel : cache) {
1565 if (curSel.contains(row, column, parent)) {
1566 const auto right = curSel.right();
1567 for (
int i = column + 1; i <= right; ++i) {
1568 if (!isSelectable(row, i))
1572 foundSelection =
true;
1573 curSel.invalidate();
1577 if (!foundSelection)
1580 return unselectable < colCount;
1594bool QItemSelectionModel::isColumnSelected(
int column,
const QModelIndex &parent)
const
1596 Q_D(
const QItemSelectionModel);
1597 if (!d->model.value())
1599 if (parent.isValid() && d->model != parent.model())
1603 if (d->currentCommand & Deselect) {
1604 const auto matches = [](
auto column,
const auto &parent) {
1605 return [column, &parent](
const auto &selection) {
1606 return column >= selection.left() &&
1607 column <= selection.right() &&
1608 parent == selection.parent();
1611 if (std::any_of(d->currentSelection.cbegin(), d->currentSelection.cend(), matches(column, parent)))
1616 if (d->currentCommand & Toggle) {
1617 for (
const auto &selection : d->currentSelection) {
1618 if (column >= selection.left() && column <= selection.right()) {
1619 const auto intersects = [](
auto column,
const auto &selection) {
1620 return [column, &selection](
const auto &range) {
1621 return column >= range.left() &&
1622 column <= range.right() &&
1623 selection.intersected(range).isValid();
1626 if (std::any_of(d->ranges.cbegin(), d->ranges.cend(), intersects(column, selection)))
1632 auto isSelectable = [&](
int row,
int column) {
1633 return isSelectableAndEnabled(d->model->index(row, column, parent).flags());
1636 const int rowCount = d->model->rowCount(parent);
1637 int unselectable = 0;
1638 std::vector<QItemSelectionRangeRefCache> cache;
1639 cache.reserve(d->currentSelection.size() + d->ranges.size());
1640 std::copy(d->currentSelection.begin(), d->currentSelection.end(), std::back_inserter(cache));
1641 std::copy(d->ranges.begin(), d->ranges.end(), std::back_inserter(cache));
1644 for (
int row = 0; row < rowCount; ++row) {
1645 if (!isSelectable(row, column)) {
1649 bool foundSelection =
false;
1650 for (
auto &curSel : cache) {
1651 if (curSel.contains(row, column, parent)) {
1652 const auto bottom = curSel.bottom();
1653 for (
int i = row + 1; i <= bottom; ++i) {
1654 if (!isSelectable(i, column))
1658 foundSelection =
true;
1659 curSel.invalidate();
1663 if (!foundSelection)
1666 return unselectable < rowCount;
1676bool QItemSelectionModel::rowIntersectsSelection(
int row,
const QModelIndex &parent)
const
1678 Q_D(
const QItemSelectionModel);
1679 if (!d->model.value())
1681 if (parent.isValid() && d->model != parent.model())
1684 QItemSelection sel = d->ranges;
1685 sel.merge(d->currentSelection, d->currentCommand);
1686 if (sel.isEmpty() || sel.constFirst().parent() != parent)
1689 for (
const QItemSelectionRange &range : std::as_const(sel)) {
1690 int top = range.top();
1691 int bottom = range.bottom();
1692 if (top <= row && bottom >= row) {
1693 int left = range.left();
1694 int right = range.right();
1695 for (
int j = left; j <= right; j++) {
1696 if (isSelectableAndEnabled(d->model->index(row, j, parent).flags()))
1712bool QItemSelectionModel::columnIntersectsSelection(
int column,
const QModelIndex &parent)
const
1714 Q_D(
const QItemSelectionModel);
1715 if (!d->model.value())
1717 if (parent.isValid() && d->model != parent.model())
1720 QItemSelection sel = d->ranges;
1721 sel.merge(d->currentSelection, d->currentCommand);
1722 if (sel.isEmpty() || sel.constFirst().parent() != parent)
1725 for (
const QItemSelectionRange &range : std::as_const(sel)) {
1726 int left = range.left();
1727 int right = range.right();
1728 if (left <= column && right >= column) {
1729 int top = range.top();
1730 int bottom = range.bottom();
1731 for (
int j = top; j <= bottom; j++) {
1732 if (isSelectableAndEnabled(d->model->index(j, column, parent).flags()))
1760bool QItemSelectionModel::hasSelection()
const
1762 Q_D(
const QItemSelectionModel);
1771 const QAbstractItemModel *model = QItemSelectionModel::model();
1772 if (model !=
nullptr) {
1773 auto model_p =
static_cast<
const QAbstractItemModelPrivate *>(QObjectPrivate::get(model));
1774 model_p->executePendingOperations();
1777 if (d->currentCommand & (Toggle | Deselect)) {
1778 QItemSelection sel = d->ranges;
1779 sel.merge(d->currentSelection, d->currentCommand);
1780 return !selectionIsEmpty(sel);
1782 return !(selectionIsEmpty(d->ranges) && selectionIsEmpty(d->currentSelection));
1824QModelIndexList QItemSelectionModel::selectedRows(
int column)
const
1826 QModelIndexList indexes;
1828 QDuplicateTracker<RowOrColumnDefinition> rowsSeen;
1830 const QItemSelection ranges = selection();
1831 for (
int i = 0; i < ranges.size(); ++i) {
1832 const QItemSelectionRange &range = ranges.at(i);
1833 QModelIndex parent = range.parent();
1834 for (
int row = range.top(); row <= range.bottom(); row++) {
1835 if (!rowsSeen.hasSeen({parent, row})) {
1836 if (isRowSelected(row, parent)) {
1837 indexes.append(model()->index(row, column, parent));
1853QModelIndexList QItemSelectionModel::selectedColumns(
int row)
const
1855 QModelIndexList indexes;
1857 QDuplicateTracker<RowOrColumnDefinition> columnsSeen;
1859 const QItemSelection ranges = selection();
1860 for (
int i = 0; i < ranges.size(); ++i) {
1861 const QItemSelectionRange &range = ranges.at(i);
1862 QModelIndex parent = range.parent();
1863 for (
int column = range.left(); column <= range.right(); column++) {
1864 if (!columnsSeen.hasSeen({parent, column})) {
1865 if (isColumnSelected(column, parent)) {
1866 indexes.append(model()->index(row, column, parent));
1963void QItemSelectionModel::emitSelectionChanged(
const QItemSelection &newSelection,
1964 const QItemSelection &oldSelection)
1967 if ((oldSelection.isEmpty() && newSelection.isEmpty()) ||
1968 oldSelection == newSelection)
1972 if (oldSelection.isEmpty() || newSelection.isEmpty()) {
1973 emit selectionChanged(newSelection, oldSelection);
1977 QItemSelection deselected = oldSelection;
1978 QItemSelection selected = newSelection;
1982 for (
int o = 0; o < deselected.size(); ++o) {
1984 for (
int s = 0; s < selected.size() && o < deselected.size();) {
1985 if (deselected.at(o) == selected.at(s)) {
1986 deselected.removeAt(o);
1987 selected.removeAt(s);
1998 QItemSelection intersections;
1999 for (
int o = 0; o < deselected.size(); ++o) {
2000 for (
int s = 0; s < selected.size(); ++s) {
2001 if (deselected.at(o).intersects(selected.at(s)))
2002 intersections.append(deselected.at(o).intersected(selected.at(s)));
2007 for (
int i = 0; i < intersections.size(); ++i) {
2009 for (
int o = 0; o < deselected.size();) {
2010 if (deselected.at(o).intersects(intersections.at(i))) {
2011 QItemSelection::split(deselected.at(o), intersections.at(i), &deselected);
2012 deselected.removeAt(o);
2018 for (
int s = 0; s < selected.size();) {
2019 if (selected.at(s).intersects(intersections.at(i))) {
2020 QItemSelection::split(selected.at(s), intersections.at(i), &selected);
2021 selected.removeAt(s);
2028 if (!selected.isEmpty() || !deselected.isEmpty())
2029 emit selectionChanged(selected, deselected);