252QItemSelectionRange QItemSelectionRange::intersected(
const QItemSelectionRange &other)
const
254 if (model() == other.model() && parent() == other.parent()) {
255 QModelIndex topLeft = model()->index(qMax(top(), other.top()),
256 qMax(left(), other.left()),
258 QModelIndex bottomRight = model()->index(qMin(bottom(), other.bottom()),
259 qMin(right(), other.right()),
261 return QItemSelectionRange(topLeft, bottomRight);
263 return QItemSelectionRange();
289static void rowLengthsFromRange(
const QItemSelectionRange &range, QList<std::pair<QPersistentModelIndex, uint>> &result)
291 if (range.isValid() && range.model()) {
292 const QModelIndex topLeft = range.topLeft();
293 const int bottom = range.bottom();
294 const uint width = range.width();
295 const int column = topLeft.column();
296 for (
int row = topLeft.row(); row <= bottom; ++row) {
300 result.emplace_back(topLeft.sibling(row, column), width);
313 if (range.isValid() && range.model()) {
314 const QModelIndex topLeft = range.topLeft();
315 const int bottom = range.bottom();
316 const int right = range.right();
317 for (
int row = topLeft.row(); row <= bottom; ++row) {
318 const QModelIndex columnLeader = topLeft.sibling(row, topLeft.column());
319 for (
int column = topLeft.column(); column <= right; ++column) {
320 QModelIndex index = columnLeader.sibling(row, column);
321 if (isSelectableAndEnabled(range.model()->flags(index)))
322 result.push_back(index);
435void QItemSelection::select(
const QModelIndex &topLeft,
const QModelIndex &bottomRight)
437 if (!topLeft.isValid() || !bottomRight.isValid())
440 if ((topLeft.model() != bottomRight.model())
441 || topLeft.parent() != bottomRight.parent()) {
442 qWarning(
"Can't select indexes from different model or with different parents");
445 if (topLeft.row() > bottomRight.row() || topLeft.column() > bottomRight.column()) {
446 int top = qMin(topLeft.row(), bottomRight.row());
447 int bottom = qMax(topLeft.row(), bottomRight.row());
448 int left = qMin(topLeft.column(), bottomRight.column());
449 int right = qMax(topLeft.column(), bottomRight.column());
450 QModelIndex tl = topLeft.sibling(top, left);
451 QModelIndex br = bottomRight.sibling(bottom, right);
452 append(QItemSelectionRange(tl, br));
455 append(QItemSelectionRange(topLeft, bottomRight));
497void QItemSelection::merge(
const QItemSelection &other, QItemSelectionModel::SelectionFlags command)
499 if (other.isEmpty() ||
500 !(command & QItemSelectionModel::Select ||
501 command & QItemSelectionModel::Deselect ||
502 command & QItemSelectionModel::Toggle))
505 QItemSelection newSelection;
506 newSelection.reserve(other.size());
508 QItemSelection intersections;
509 for (
const auto &range : other) {
510 if (!range.isValid())
512 newSelection.push_back(range);
513 for (
int t = 0; t < size(); ++t) {
514 if (range.intersects(at(t)))
515 intersections.append(at(t).intersected(range));
520 for (
int i = 0; i < intersections.size(); ++i) {
521 for (
int t = 0; t < size();) {
522 if (at(t).intersects(intersections.at(i))) {
523 split(at(t), intersections.at(i),
this);
530 for (
int n = 0; (command & QItemSelectionModel::Toggle) && n < newSelection.size();) {
531 if (newSelection.at(n).intersects(intersections.at(i))) {
532 split(newSelection.at(n), intersections.at(i), &newSelection);
533 newSelection.removeAt(n);
540 if (!(command & QItemSelectionModel::Deselect))
541 operator+=(newSelection);
551void QItemSelection::split(
const QItemSelectionRange &range,
552 const QItemSelectionRange &other, QItemSelection *result)
554 if (range.parent() != other.parent() || range.model() != other.model())
557 QModelIndex parent = other.parent();
558 int top = range.top();
559 int left = range.left();
560 int bottom = range.bottom();
561 int right = range.right();
562 int other_top = other.top();
563 int other_left = other.left();
564 int other_bottom = other.bottom();
565 int other_right = other.right();
566 const QAbstractItemModel *model = range.model();
568 if (other_top > top) {
569 QModelIndex tl = model->index(top, left, parent);
570 QModelIndex br = model->index(other_top - 1, right, parent);
571 result->append(QItemSelectionRange(tl, br));
574 if (other_bottom < bottom) {
575 QModelIndex tl = model->index(other_bottom + 1, left, parent);
576 QModelIndex br = model->index(bottom, right, parent);
577 result->append(QItemSelectionRange(tl, br));
578 bottom = other_bottom;
580 if (other_left > left) {
581 QModelIndex tl = model->index(top, left, parent);
582 QModelIndex br = model->index(bottom, other_left - 1, parent);
583 result->append(QItemSelectionRange(tl, br));
586 if (other_right < right) {
587 QModelIndex tl = model->index(top, other_right + 1, parent);
588 QModelIndex br = model->index(bottom, right, parent);
589 result->append(QItemSelectionRange(tl, br));
597void QItemSelectionModelPrivate::initModel(QAbstractItemModel *m)
599 Q_Q(QItemSelectionModel);
600 const QAbstractItemModel *oldModel = model.valueBypassingBindings();
610 model.setValueBypassingBindings(m);
613 connections = std::array<QMetaObject::Connection, 12> {
614 QObjectPrivate::connect(m, &QAbstractItemModel::rowsAboutToBeRemoved,
615 this, &QItemSelectionModelPrivate::rowsAboutToBeRemoved),
616 QObjectPrivate::connect(m, &QAbstractItemModel::columnsAboutToBeRemoved,
617 this, &QItemSelectionModelPrivate::columnsAboutToBeRemoved),
618 QObjectPrivate::connect(m, &QAbstractItemModel::rowsAboutToBeInserted,
619 this, &QItemSelectionModelPrivate::rowsAboutToBeInserted),
620 QObjectPrivate::connect(m, &QAbstractItemModel::columnsAboutToBeInserted,
621 this, &QItemSelectionModelPrivate::columnsAboutToBeInserted),
622 QObjectPrivate::connect(m, &QAbstractItemModel::rowsAboutToBeMoved,
623 this, &QItemSelectionModelPrivate::triggerLayoutToBeChanged),
624 QObjectPrivate::connect(m, &QAbstractItemModel::columnsAboutToBeMoved,
625 this, &QItemSelectionModelPrivate::triggerLayoutToBeChanged),
626 QObjectPrivate::connect(m, &QAbstractItemModel::rowsMoved,
627 this, &QItemSelectionModelPrivate::triggerLayoutChanged),
628 QObjectPrivate::connect(m, &QAbstractItemModel::columnsMoved,
629 this, &QItemSelectionModelPrivate::triggerLayoutChanged),
630 QObjectPrivate::connect(m, &QAbstractItemModel::layoutAboutToBeChanged,
631 this, &QItemSelectionModelPrivate::layoutAboutToBeChanged),
632 QObjectPrivate::connect(m, &QAbstractItemModel::layoutChanged,
633 this, &QItemSelectionModelPrivate::layoutChanged),
634 QObject::connect(m, &QAbstractItemModel::modelReset,
635 q, &QItemSelectionModel::reset),
636 QObjectPrivate::connect(m, &QAbstractItemModel::destroyed,
637 this, &QItemSelectionModelPrivate::modelDestroyed)
656QItemSelection QItemSelectionModelPrivate::expandSelection(
const QItemSelection &selection,
657 QItemSelectionModel::SelectionFlags command)
const
659 if (selection.isEmpty() && !((command & QItemSelectionModel::Rows) ||
660 (command & QItemSelectionModel::Columns)))
663 QItemSelection expanded;
664 if (command & QItemSelectionModel::Rows) {
665 for (
int i = 0; i < selection.size(); ++i) {
666 QModelIndex parent = selection.at(i).parent();
667 int colCount = model->columnCount(parent);
668 QModelIndex tl = model->index(selection.at(i).top(), 0, parent);
669 QModelIndex br = model->index(selection.at(i).bottom(), colCount - 1, parent);
671 expanded.merge(QItemSelection(tl, br), QItemSelectionModel::Select);
674 if (command & QItemSelectionModel::Columns) {
675 for (
int i = 0; i < selection.size(); ++i) {
676 QModelIndex parent = selection.at(i).parent();
677 int rowCount = model->rowCount(parent);
678 QModelIndex tl = model->index(0, selection.at(i).left(), parent);
679 QModelIndex br = model->index(rowCount - 1, selection.at(i).right(), parent);
681 expanded.merge(QItemSelection(tl, br), QItemSelectionModel::Select);
690void QItemSelectionModelPrivate::rowsAboutToBeRemoved(
const QModelIndex &parent,
693 Q_Q(QItemSelectionModel);
694 Q_ASSERT(start <= end);
698 if (currentIndex.isValid() && parent == currentIndex.parent()
699 && currentIndex.row() >= start && currentIndex.row() <= end) {
700 QModelIndex old = currentIndex;
703 currentIndex = model->index(start - 1, old.column(), parent);
704 }
else if (model.value() && end < model->rowCount(parent) - 1) {
706 currentIndex = model->index(end + 1, old.column(), parent);
709 currentIndex = QModelIndex();
711 emit q->currentChanged(currentIndex, old);
712 emit q->currentRowChanged(currentIndex, old);
713 if (currentIndex.column() != old.column())
714 emit q->currentColumnChanged(currentIndex, old);
717 QItemSelection deselected;
718 QItemSelection newParts;
719 bool indexesOfSelectionChanged =
false;
720 QItemSelection::iterator it = ranges.begin();
721 while (it != ranges.end()) {
722 if (it->topLeft().parent() != parent) {
723 QModelIndex itParent = it->topLeft().parent();
724 while (itParent.isValid() && itParent.parent() != parent)
725 itParent = itParent.parent();
727 if (itParent.isValid() && start <= itParent.row() && itParent.row() <= end) {
728 deselected.append(*it);
729 it = ranges.erase(it);
731 if (itParent.isValid() && end < itParent.row())
732 indexesOfSelectionChanged =
true;
735 }
else if (start <= it->bottom() && it->bottom() <= end
736 && start <= it->top() && it->top() <= end) {
737 deselected.append(*it);
738 it = ranges.erase(it);
739 }
else if (start <= it->top() && it->top() <= end) {
740 deselected.append(QItemSelectionRange(it->topLeft(), model->index(end, it->right(), it->parent())));
741 *it = QItemSelectionRange(model->index(end + 1, it->left(), it->parent()), it->bottomRight());
743 }
else if (start <= it->bottom() && it->bottom() <= end) {
744 deselected.append(QItemSelectionRange(model->index(start, it->left(), it->parent()), it->bottomRight()));
745 *it = QItemSelectionRange(it->topLeft(), model->index(start - 1, it->right(), it->parent()));
747 }
else if (it->top() < start && end < it->bottom()) {
752 const QItemSelectionRange removedRange(model->index(start, it->left(), it->parent()),
753 model->index(end, it->right(), it->parent()));
754 deselected.append(removedRange);
755 QItemSelection::split(*it, removedRange, &newParts);
756 it = ranges.erase(it);
757 }
else if (end < it->top()) {
758 indexesOfSelectionChanged =
true;
764 ranges.append(newParts);
766 if (!deselected.isEmpty() || indexesOfSelectionChanged)
767 emit q->selectionChanged(QItemSelection(), deselected);
773void QItemSelectionModelPrivate::columnsAboutToBeRemoved(
const QModelIndex &parent,
776 Q_Q(QItemSelectionModel);
779 if (currentIndex.isValid() && parent == currentIndex.parent()
780 && currentIndex.column() >= start && currentIndex.column() <= end) {
781 QModelIndex old = currentIndex;
784 currentIndex = model->index(old.row(), start - 1, parent);
785 }
else if (model.value() && end < model->columnCount() - 1) {
787 currentIndex = model->index(old.row(), end + 1, parent);
790 currentIndex = QModelIndex();
792 emit q->currentChanged(currentIndex, old);
793 if (currentIndex.row() != old.row())
794 emit q->currentRowChanged(currentIndex, old);
795 emit q->currentColumnChanged(currentIndex, old);
799 QModelIndex tl = model->index(0, start, parent);
800 QModelIndex br = model->index(model->rowCount(parent) - 1, end, parent);
801 q->select(QItemSelection(tl, br), QItemSelectionModel::Deselect);
810void QItemSelectionModelPrivate::columnsAboutToBeInserted(
const QModelIndex &parent,
815 QList<QItemSelectionRange> split;
816 QList<QItemSelectionRange>::iterator it = ranges.begin();
817 for (; it != ranges.end(); ) {
818 const QModelIndex &itParent = it->parent();
819 if ((*it).isValid() && itParent == parent
820 && (*it).left() < start && (*it).right() >= start) {
821 QModelIndex bottomMiddle = model->index((*it).bottom(), start - 1, itParent);
823 QModelIndex topMiddle = model->index((*it).top(), start, itParent);
825 it = ranges.erase(it);
840void QItemSelectionModelPrivate::rowsAboutToBeInserted(
const QModelIndex &parent,
843 Q_Q(QItemSelectionModel);
846 QList<QItemSelectionRange> split;
847 QList<QItemSelectionRange>::iterator it = ranges.begin();
848 bool indexesOfSelectionChanged =
false;
849 for (; it != ranges.end(); ) {
850 const QModelIndex &itParent = it->parent();
851 if ((*it).isValid() && itParent == parent
852 && (*it).top() < start && (*it).bottom() >= start) {
853 QModelIndex middleRight = model->index(start - 1, (*it).right(), itParent);
855 QModelIndex middleLeft = model->index(start, (*it).left(), itParent);
857 it = ranges.erase(it);
859 split.append(bottom);
860 }
else if ((*it).isValid() && itParent == parent
861 && (*it).top() >= start) {
862 indexesOfSelectionChanged =
true;
870 if (indexesOfSelectionChanged)
871 emit q->selectionChanged(QItemSelection(), QItemSelection());
881void QItemSelectionModelPrivate::layoutAboutToBeChanged(
const QList<QPersistentModelIndex> &,
882 QAbstractItemModel::LayoutChangeHint hint)
884 savedPersistentIndexes.clear();
885 savedPersistentCurrentIndexes.clear();
886 savedPersistentRowLengths.clear();
887 savedPersistentCurrentRowLengths.clear();
891 if (ranges.isEmpty() && currentSelection.size() == 1) {
893 QModelIndex parent = range.parent();
894 tableRowCount = model->rowCount(parent);
895 tableColCount = model->columnCount(parent);
896 if (tableRowCount * tableColCount > 1000
899 && range.bottom() == tableRowCount - 1
900 && range.right() == tableColCount - 1) {
901 tableSelected =
true;
902 tableParent = parent;
906 tableSelected =
false;
908 if (hint == QAbstractItemModel::VerticalSortHint) {
914 savedPersistentRowLengths = qSelectionPersistentRowLengths(ranges);
915 savedPersistentCurrentRowLengths = qSelectionPersistentRowLengths(currentSelection);
917 savedPersistentIndexes = qSelectionIndexes<QList<QPersistentModelIndex>>(ranges);
918 savedPersistentCurrentIndexes = qSelectionIndexes<QList<QPersistentModelIndex>>(currentSelection);
924static QItemSelection
mergeRowLengths(
const QList<std::pair<QPersistentModelIndex, uint>> &rowLengths)
926 if (rowLengths.isEmpty())
927 return QItemSelection();
929 QItemSelection result;
931 while (i < rowLengths.size()) {
932 const QPersistentModelIndex &tl = rowLengths.at(i).first;
937 QPersistentModelIndex br = tl;
938 const uint length = rowLengths.at(i).second;
939 while (++i < rowLengths.size()) {
940 const QPersistentModelIndex &next = rowLengths.at(i).first;
943 const uint nextLength = rowLengths.at(i).second;
944 if ((nextLength == length)
945 && (next.row() == br.row() + 1)
946 && (next.column() == br.column())
947 && (next.parent() == br.parent())) {
953 result.append(QItemSelectionRange(tl, br.sibling(br.row(), br.column() + length - 1)));
964static QItemSelection
mergeIndexes(
const QList<QPersistentModelIndex> &indexes)
966 QItemSelection colSpans;
969 while (i < indexes.size()) {
970 const QPersistentModelIndex &tl = indexes.at(i);
975 QPersistentModelIndex br = tl;
976 QModelIndex brParent = br.parent();
977 int brRow = br.row();
978 int brColumn = br.column();
979 while (++i < indexes.size()) {
980 const QPersistentModelIndex &next = indexes.at(i);
983 const QModelIndex nextParent = next.parent();
984 const int nextRow = next.row();
985 const int nextColumn = next.column();
986 if ((nextParent == brParent)
987 && (nextRow == brRow)
988 && (nextColumn == brColumn + 1)) {
990 brParent = nextParent;
992 brColumn = nextColumn;
997 colSpans.append(QItemSelectionRange(tl, br));
1000 QItemSelection rowSpans;
1002 while (i < colSpans.size()) {
1003 QModelIndex tl = colSpans.at(i).topLeft();
1004 QModelIndex br = colSpans.at(i).bottomRight();
1005 QModelIndex prevTl = tl;
1006 while (++i < colSpans.size()) {
1007 QModelIndex nextTl = colSpans.at(i).topLeft();
1008 QModelIndex nextBr = colSpans.at(i).bottomRight();
1010 if (nextTl.parent() != tl.parent())
1013 if ((nextTl.column() == prevTl.column()) && (nextBr.column() == br.column())
1014 && (nextTl.row() == prevTl.row() + 1) && (nextBr.row() == br.row() + 1)) {
1021 rowSpans.append(QItemSelectionRange(tl, br));
1047void QItemSelectionModelPrivate::layoutChanged(
const QList<QPersistentModelIndex> &, QAbstractItemModel::LayoutChangeHint hint)
1050 if (tableSelected && tableColCount == model->columnCount(tableParent)
1051 && tableRowCount == model->rowCount(tableParent)) {
1053 currentSelection.clear();
1054 int bottom = tableRowCount - 1;
1055 int right = tableColCount - 1;
1056 QModelIndex tl = model->index(0, 0, tableParent);
1057 QModelIndex br = model->index(bottom, right, tableParent);
1058 currentSelection << QItemSelectionRange(tl, br);
1059 tableParent = QModelIndex();
1060 tableSelected =
false;
1064 if ((hint != QAbstractItemModel::VerticalSortHint && savedPersistentCurrentIndexes.isEmpty() && savedPersistentIndexes.isEmpty())
1065 || (hint == QAbstractItemModel::VerticalSortHint && savedPersistentRowLengths.isEmpty() && savedPersistentCurrentRowLengths.isEmpty())) {
1073 currentSelection.clear();
1075 if (hint != QAbstractItemModel::VerticalSortHint) {
1077 std::stable_sort(savedPersistentIndexes.begin(), savedPersistentIndexes.end(),
1078 qt_PersistentModelIndexLessThan);
1079 std::stable_sort(savedPersistentCurrentIndexes.begin(), savedPersistentCurrentIndexes.end(),
1080 qt_PersistentModelIndexLessThan);
1083 ranges = mergeIndexes(savedPersistentIndexes);
1084 currentSelection = mergeIndexes(savedPersistentCurrentIndexes);
1087 savedPersistentIndexes.clear();
1088 savedPersistentCurrentIndexes.clear();
1091 std::stable_sort(savedPersistentRowLengths.begin(), savedPersistentRowLengths.end());
1092 std::stable_sort(savedPersistentCurrentRowLengths.begin(), savedPersistentCurrentRowLengths.end());
1095 ranges = mergeRowLengths(savedPersistentRowLengths);
1096 currentSelection = mergeRowLengths(savedPersistentCurrentRowLengths);
1099 savedPersistentRowLengths.clear();
1100 savedPersistentCurrentRowLengths.clear();
1335void QItemSelectionModel::select(
const QItemSelection &selection, QItemSelectionModel::SelectionFlags command)
1337 Q_D(QItemSelectionModel);
1338 if (!d->model.value()) {
1339 qWarning(
"QItemSelectionModel: Selecting when no model has been set will result in a no-op.");
1342 if (command == NoUpdate)
1346 QItemSelection sel = selection;
1352 d->ranges.removeIf(QtFunctionObjects::IsNotValid());
1354 QItemSelection old = d->ranges;
1355 old.merge(d->currentSelection, d->currentCommand);
1358 if (command & Rows || command & Columns)
1359 sel = d->expandSelection(sel, command);
1362 if (command & Clear) {
1364 d->currentSelection.clear();
1368 if (!(command & Current))
1372 if (command & Toggle || command & Select || command & Deselect) {
1373 d->currentCommand = command;
1374 d->currentSelection = sel;
1378 QItemSelection newSelection = d->ranges;
1379 newSelection.merge(d->currentSelection, d->currentCommand);
1380 emitSelectionChanged(newSelection, old);
1395void QItemSelectionModel::clearCurrentIndex()
1397 Q_D(QItemSelectionModel);
1398 QModelIndex previous = d->currentIndex;
1399 d->currentIndex = QModelIndex();
1400 if (previous.isValid()) {
1401 emit currentChanged(d->currentIndex, previous);
1402 emit currentRowChanged(d->currentIndex, previous);
1403 emit currentColumnChanged(d->currentIndex, previous);
1440void QItemSelectionModel::setCurrentIndex(
const QModelIndex &index, QItemSelectionModel::SelectionFlags command)
1442 Q_D(QItemSelectionModel);
1443 if (!d->model.value()) {
1444 qWarning(
"QItemSelectionModel: Setting the current index when no model has been set will result in a no-op.");
1447 if (index == d->currentIndex) {
1448 if (command != NoUpdate)
1449 select(index, command);
1452 QPersistentModelIndex previous = d->currentIndex;
1453 d->currentIndex = index;
1454 if (command != NoUpdate)
1455 select(d->currentIndex, command);
1456 emit currentChanged(d->currentIndex, previous);
1457 if (d->currentIndex.row() != previous.row() ||
1458 d->currentIndex.parent() != previous.parent())
1459 emit currentRowChanged(d->currentIndex, previous);
1460 if (d->currentIndex.column() != previous.column() ||
1461 d->currentIndex.parent() != previous.parent())
1462 emit currentColumnChanged(d->currentIndex, previous);
1477bool QItemSelectionModel::isSelected(
const QModelIndex &index)
const
1479 Q_D(
const QItemSelectionModel);
1480 if (d->model != index.model() || !index.isValid())
1484 auto contains = [](
const auto &index) {
1485 return [&index](
const auto &range) {
return range.contains(index); };
1487 bool selected = std::any_of(d->ranges.begin(), d->ranges.end(), contains(index));
1490 if (d->currentSelection.size()) {
1491 if ((d->currentCommand & Deselect) && selected)
1492 selected = !d->currentSelection.contains(index);
1493 else if (d->currentCommand & Toggle)
1494 selected ^= d->currentSelection.contains(index);
1495 else if ((d->currentCommand & Select) && !selected)
1496 selected = d->currentSelection.contains(index);
1500 return isSelectableAndEnabled(d->model->flags(index));
1516bool QItemSelectionModel::isRowSelected(
int row,
const QModelIndex &parent)
const
1518 Q_D(
const QItemSelectionModel);
1519 if (!d->model.value())
1521 if (parent.isValid() && d->model != parent.model())
1525 if (d->currentCommand & Deselect) {
1526 const auto matches = [](
auto row,
const auto &parent) {
1527 return [row, &parent](
const auto &selection) {
1528 return row >= selection.top() &&
1529 row <= selection.bottom() &&
1530 parent == selection.parent();
1533 if (std::any_of(d->currentSelection.cbegin(), d->currentSelection.cend(), matches(row, parent)))
1538 if (d->currentCommand & Toggle) {
1539 for (
const auto &selection : d->currentSelection) {
1540 if (row >= selection.top() && row <= selection.bottom()) {
1541 const auto intersects = [](
auto row,
const auto &selection) {
1542 return [row, &selection](
const auto &range) {
1543 return row >= range.top() &&
1544 row <= range.bottom() &&
1545 selection.intersected(range).isValid();
1548 if (std::any_of(d->ranges.cbegin(), d->ranges.cend(), intersects(row, selection)))
1554 auto isSelectable = [&](
int row,
int column) {
1555 return isSelectableAndEnabled(d->model->index(row, column, parent).flags());
1558 const int colCount = d->model->columnCount(parent);
1559 int unselectable = 0;
1560 std::vector<QItemSelectionRangeRefCache> cache;
1561 cache.reserve(d->currentSelection.size() + d->ranges.size());
1562 std::copy(d->currentSelection.begin(), d->currentSelection.end(), std::back_inserter(cache));
1563 std::copy(d->ranges.begin(), d->ranges.end(), std::back_inserter(cache));
1566 for (
int column = 0; column < colCount; ++column) {
1567 if (!isSelectable(row, column)) {
1571 bool foundSelection =
false;
1572 for (
auto &curSel : cache) {
1573 if (curSel.contains(row, column, parent)) {
1574 const auto right = curSel.right();
1575 for (
int i = column + 1; i <= right; ++i) {
1576 if (!isSelectable(row, i))
1580 foundSelection =
true;
1581 curSel.invalidate();
1585 if (!foundSelection)
1588 return unselectable < colCount;
1602bool QItemSelectionModel::isColumnSelected(
int column,
const QModelIndex &parent)
const
1604 Q_D(
const QItemSelectionModel);
1605 if (!d->model.value())
1607 if (parent.isValid() && d->model != parent.model())
1611 if (d->currentCommand & Deselect) {
1612 const auto matches = [](
auto column,
const auto &parent) {
1613 return [column, &parent](
const auto &selection) {
1614 return column >= selection.left() &&
1615 column <= selection.right() &&
1616 parent == selection.parent();
1619 if (std::any_of(d->currentSelection.cbegin(), d->currentSelection.cend(), matches(column, parent)))
1624 if (d->currentCommand & Toggle) {
1625 for (
const auto &selection : d->currentSelection) {
1626 if (column >= selection.left() && column <= selection.right()) {
1627 const auto intersects = [](
auto column,
const auto &selection) {
1628 return [column, &selection](
const auto &range) {
1629 return column >= range.left() &&
1630 column <= range.right() &&
1631 selection.intersected(range).isValid();
1634 if (std::any_of(d->ranges.cbegin(), d->ranges.cend(), intersects(column, selection)))
1640 auto isSelectable = [&](
int row,
int column) {
1641 return isSelectableAndEnabled(d->model->index(row, column, parent).flags());
1644 const int rowCount = d->model->rowCount(parent);
1645 int unselectable = 0;
1646 std::vector<QItemSelectionRangeRefCache> cache;
1647 cache.reserve(d->currentSelection.size() + d->ranges.size());
1648 std::copy(d->currentSelection.begin(), d->currentSelection.end(), std::back_inserter(cache));
1649 std::copy(d->ranges.begin(), d->ranges.end(), std::back_inserter(cache));
1652 for (
int row = 0; row < rowCount; ++row) {
1653 if (!isSelectable(row, column)) {
1657 bool foundSelection =
false;
1658 for (
auto &curSel : cache) {
1659 if (curSel.contains(row, column, parent)) {
1660 const auto bottom = curSel.bottom();
1661 for (
int i = row + 1; i <= bottom; ++i) {
1662 if (!isSelectable(i, column))
1666 foundSelection =
true;
1667 curSel.invalidate();
1671 if (!foundSelection)
1674 return unselectable < rowCount;
1684bool QItemSelectionModel::rowIntersectsSelection(
int row,
const QModelIndex &parent)
const
1686 Q_D(
const QItemSelectionModel);
1687 if (!d->model.value())
1689 if (parent.isValid() && d->model != parent.model())
1692 QItemSelection sel = d->ranges;
1693 sel.merge(d->currentSelection, d->currentCommand);
1694 if (sel.isEmpty() || sel.constFirst().parent() != parent)
1697 for (
const QItemSelectionRange &range : std::as_const(sel)) {
1698 int top = range.top();
1699 int bottom = range.bottom();
1700 if (top <= row && bottom >= row) {
1701 int left = range.left();
1702 int right = range.right();
1703 for (
int j = left; j <= right; j++) {
1704 if (isSelectableAndEnabled(d->model->index(row, j, parent).flags()))
1720bool QItemSelectionModel::columnIntersectsSelection(
int column,
const QModelIndex &parent)
const
1722 Q_D(
const QItemSelectionModel);
1723 if (!d->model.value())
1725 if (parent.isValid() && d->model != parent.model())
1728 QItemSelection sel = d->ranges;
1729 sel.merge(d->currentSelection, d->currentCommand);
1730 if (sel.isEmpty() || sel.constFirst().parent() != parent)
1733 for (
const QItemSelectionRange &range : std::as_const(sel)) {
1734 int left = range.left();
1735 int right = range.right();
1736 if (left <= column && right >= column) {
1737 int top = range.top();
1738 int bottom = range.bottom();
1739 for (
int j = top; j <= bottom; j++) {
1740 if (isSelectableAndEnabled(d->model->index(j, column, parent).flags()))
1768bool QItemSelectionModel::hasSelection()
const
1770 Q_D(
const QItemSelectionModel);
1779 const QAbstractItemModel *model = QItemSelectionModel::model();
1780 if (model !=
nullptr) {
1781 auto model_p =
static_cast<
const QAbstractItemModelPrivate *>(QObjectPrivate::get(model));
1782 model_p->executePendingOperations();
1785 if (d->currentCommand & (Toggle | Deselect)) {
1786 QItemSelection sel = d->ranges;
1787 sel.merge(d->currentSelection, d->currentCommand);
1788 return !selectionIsEmpty(sel);
1790 return !(selectionIsEmpty(d->ranges) && selectionIsEmpty(d->currentSelection));
1829QModelIndexList QItemSelectionModel::selectedRows(
int column)
const
1831 QModelIndexList indexes;
1833 QDuplicateTracker<RowOrColumnDefinition> rowsSeen;
1835 const QItemSelection ranges = selection();
1836 for (
int i = 0; i < ranges.size(); ++i) {
1837 const QItemSelectionRange &range = ranges.at(i);
1838 QModelIndex parent = range.parent();
1839 for (
int row = range.top(); row <= range.bottom(); row++) {
1840 if (!rowsSeen.hasSeen({parent, row})) {
1841 if (isRowSelected(row, parent)) {
1842 indexes.append(model()->index(row, column, parent));
1858QModelIndexList QItemSelectionModel::selectedColumns(
int row)
const
1860 QModelIndexList indexes;
1862 QDuplicateTracker<RowOrColumnDefinition> columnsSeen;
1864 const QItemSelection ranges = selection();
1865 for (
int i = 0; i < ranges.size(); ++i) {
1866 const QItemSelectionRange &range = ranges.at(i);
1867 QModelIndex parent = range.parent();
1868 for (
int column = range.left(); column <= range.right(); column++) {
1869 if (!columnsSeen.hasSeen({parent, column})) {
1870 if (isColumnSelected(column, parent)) {
1871 indexes.append(model()->index(row, column, parent));
1968void QItemSelectionModel::emitSelectionChanged(
const QItemSelection &newSelection,
1969 const QItemSelection &oldSelection)
1972 if ((oldSelection.isEmpty() && newSelection.isEmpty()) ||
1973 oldSelection == newSelection)
1977 if (oldSelection.isEmpty() || newSelection.isEmpty()) {
1978 emit selectionChanged(newSelection, oldSelection);
1982 QItemSelection deselected = oldSelection;
1983 QItemSelection selected = newSelection;
1987 for (
int o = 0; o < deselected.size(); ++o) {
1989 for (
int s = 0; s < selected.size() && o < deselected.size();) {
1990 if (deselected.at(o) == selected.at(s)) {
1991 deselected.removeAt(o);
1992 selected.removeAt(s);
2003 QItemSelection intersections;
2004 for (
int o = 0; o < deselected.size(); ++o) {
2005 for (
int s = 0; s < selected.size(); ++s) {
2006 if (deselected.at(o).intersects(selected.at(s)))
2007 intersections.append(deselected.at(o).intersected(selected.at(s)));
2012 for (
int i = 0; i < intersections.size(); ++i) {
2014 for (
int o = 0; o < deselected.size();) {
2015 if (deselected.at(o).intersects(intersections.at(i))) {
2016 QItemSelection::split(deselected.at(o), intersections.at(i), &deselected);
2017 deselected.removeAt(o);
2023 for (
int s = 0; s < selected.size();) {
2024 if (selected.at(s).intersects(intersections.at(i))) {
2025 QItemSelection::split(selected.at(s), intersections.at(i), &selected);
2026 selected.removeAt(s);
2033 if (!selected.isEmpty() || !deselected.isEmpty())
2034 emit selectionChanged(selected, deselected);