QTableView: fix selection with rows and cells in ExtendedSelection mode

QTableView stored the current row/column selection start in an own
variable instead using currentSelectionStartIndex. This leads to an
inconsistent behavior when the selection is done with a click on the
header and then in a cell (and the other way round)

Fixes: QTBUG-92561
Change-Id: I4c8bda3a938de451b6eff2819141e86a6870fbef
Reviewed-by: Volker Hilsheimer <volker.hilsheimer@qt.io>
(cherry picked from commit e8b3d35a18e7e4cf6543868d89d6060c90314f39)
Reviewed-by: Qt Cherry-pick Bot <cherrypick_bot@qt-project.org>
This commit is contained in:
Christian Ehrlicher 2021-04-21 21:29:19 +02:00 committed by Qt Cherry-pick Bot
parent e8d39c670e
commit 39817d0f3b
3 changed files with 76 additions and 5 deletions

View File

@ -3388,7 +3388,7 @@ void QTableViewPrivate::selectRow(int row, bool anchor)
selectionModel->setCurrentIndex(index, QItemSelectionModel::NoUpdate);
if ((anchor && !(command & QItemSelectionModel::Current))
|| (q->selectionMode() == QTableView::SingleSelection))
rowSectionAnchor = row;
currentSelectionStartIndex = model->index(row, column, root);
if (q->selectionMode() != QTableView::SingleSelection
&& command.testFlag(QItemSelectionModel::Toggle)) {
@ -3401,6 +3401,7 @@ void QTableViewPrivate::selectRow(int row, bool anchor)
command |= QItemSelectionModel::Current;
}
const auto rowSectionAnchor = currentSelectionStartIndex.row();
QModelIndex upper = model->index(qMin(rowSectionAnchor, row), column, root);
QModelIndex lower = model->index(qMax(rowSectionAnchor, row), column, root);
if ((verticalHeader->sectionsMoved() && upper.row() != lower.row())) {
@ -3427,7 +3428,7 @@ void QTableViewPrivate::selectColumn(int column, bool anchor)
selectionModel->setCurrentIndex(index, QItemSelectionModel::NoUpdate);
if ((anchor && !(command & QItemSelectionModel::Current))
|| (q->selectionMode() == QTableView::SingleSelection))
columnSectionAnchor = column;
currentSelectionStartIndex = model->index(row, column, root);
if (q->selectionMode() != QTableView::SingleSelection
&& command.testFlag(QItemSelectionModel::Toggle)) {
@ -3440,6 +3441,7 @@ void QTableViewPrivate::selectColumn(int column, bool anchor)
command |= QItemSelectionModel::Current;
}
const auto columnSectionAnchor = currentSelectionStartIndex.column();
QModelIndex left = model->index(row, qMin(columnSectionAnchor, column), root);
QModelIndex right = model->index(row, qMax(columnSectionAnchor, column), root);
if ((horizontalHeader->sectionsMoved() && left.column() != right.column())) {

View File

@ -136,7 +136,6 @@ class QTableViewPrivate : public QAbstractItemViewPrivate
public:
QTableViewPrivate()
: showGrid(true), gridStyle(Qt::SolidLine),
rowSectionAnchor(-1), columnSectionAnchor(-1),
columnResizeTimerID(0), rowResizeTimerID(0),
horizontalHeader(nullptr), verticalHeader(nullptr),
sortingEnabled(false), geometryRecursionBlock(false),
@ -186,8 +185,6 @@ public:
bool showGrid;
Qt::PenStyle gridStyle;
int rowSectionAnchor;
int columnSectionAnchor;
int columnResizeTimerID;
int rowResizeTimerID;
QList<int> columnsToUpdate;

View File

@ -437,6 +437,8 @@ private slots:
void taskQTBUG_30653_doItemsLayout();
void taskQTBUG_50171_selectRowAfterSwapColumns();
void deselectRow();
void selectRowsAndCells();
void selectColumnsAndCells();
#if QT_CONFIG(wheelevent)
void mouseWheel_data();
@ -4783,6 +4785,76 @@ void tst_QTableView::deselectRow()
QVERIFY(!tw.selectionModel()->isRowSelected(1, QModelIndex()));
}
class QTableViewSelectCells : public QTableView
{
public:
QItemSelectionModel::SelectionFlags selectionCommand(const QModelIndex &index,
const QEvent *) const override
{
return QTableView::selectionCommand(index, shiftPressed ? &mouseEvent : nullptr);
}
QMouseEvent mouseEvent = QMouseEvent(QEvent::MouseButtonPress, QPointF(), Qt::LeftButton, Qt::LeftButton, Qt::ShiftModifier);
bool shiftPressed = false;
};
void tst_QTableView::selectRowsAndCells()
{
const auto checkRows = [](const QModelIndexList &mil)
{
QCOMPARE(mil.size(), 3);
for (const auto &mi : mil)
QVERIFY(mi.row() >= 1 && mi.row() <= 3);
};
QTableViewSelectCells tw;
QtTestTableModel model(5, 1);
tw.setSelectionBehavior(QAbstractItemView::SelectRows);
tw.setSelectionMode(QAbstractItemView::ExtendedSelection);
tw.setModel(&model);
tw.show();
tw.selectRow(1);
tw.shiftPressed = true;
tw.selectRow(2);
tw.shiftPressed = false;
QTest::mouseClick(tw.viewport(), Qt::LeftButton, Qt::ShiftModifier, tw.visualRect(model.index(3, 0)).center());
checkRows(tw.selectionModel()->selectedRows());
tw.clearSelection();
QTest::mouseClick(tw.viewport(), Qt::LeftButton, Qt::NoModifier, tw.visualRect(model.index(3, 0)).center());
tw.shiftPressed = true;
tw.selectRow(1);
checkRows(tw.selectionModel()->selectedRows());
}
void tst_QTableView::selectColumnsAndCells()
{
const auto checkColumns = [](const QModelIndexList &mil)
{
QCOMPARE(mil.size(), 3);
for (const auto &mi : mil)
QVERIFY(mi.column() >= 1 && mi.column() <= 3);
};
QTableViewSelectCells tw;
QtTestTableModel model(1, 5);
tw.setSelectionBehavior(QAbstractItemView::SelectColumns);
tw.setSelectionMode(QAbstractItemView::ExtendedSelection);
tw.setModel(&model);
tw.show();
tw.selectColumn(1);
tw.shiftPressed = true;
tw.selectColumn(2);
tw.shiftPressed = false;
QTest::mouseClick(tw.viewport(), Qt::LeftButton, Qt::ShiftModifier, tw.visualRect(model.index(0, 3)).center());
checkColumns(tw.selectionModel()->selectedColumns());
tw.clearSelection();
QTest::mouseClick(tw.viewport(), Qt::LeftButton, Qt::NoModifier, tw.visualRect(model.index(0, 3)).center());
tw.shiftPressed = true;
tw.selectColumn(1);
checkColumns(tw.selectionModel()->selectedColumns());
}
// This has nothing to do with QTableView, but it's convenient to reuse the QtTestTableModel
#if QT_CONFIG(textmarkdownwriter)