From 558718ff4406638410364db7c1310cb38963d6df Mon Sep 17 00:00:00 2001
From: Vyacheslav Grigoryev <armagvvg@gmail.com>
Date: Fri, 6 May 2016 01:29:27 +0300
Subject: [PATCH] QTableView: Fix selection for reordered or hidden
 rows/columns
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit

The old code sometimes made incorrect selections when rows or columns were
hidden or moved. It used logical top left and bottom right indexes to create a
selection rectangle. However on moved or hidden cells a wrong rectangle was
made. This fix calculates a simple rectangle without hidden cells and makes use
of the row/column select functionality provided by the selection model, to make
the right selection.

[ChangeLog][QtWidgets][QTableView] Fixed a selection bug when rows or columns were hidden (QTBUG-50171)

Task-number: QTBUG-50171
Change-Id: Id186012af26da7b2051ff5eb1c13e6b7494cca77
Reviewed-by: Thorbjørn Lund Martsum <tmartsum@gmail.com>
---
 src/widgets/itemviews/qtableview.cpp          | 23 ++++++------
 .../itemviews/qtableview/tst_qtableview.cpp   | 36 +++++++++++++++++++
 2 files changed, 46 insertions(+), 13 deletions(-)

diff --git a/src/widgets/itemviews/qtableview.cpp b/src/widgets/itemviews/qtableview.cpp
index ee0d41ce150..b68c105abaf 100644
--- a/src/widgets/itemviews/qtableview.cpp
+++ b/src/widgets/itemviews/qtableview.cpp
@@ -3249,13 +3249,12 @@ void QTableViewPrivate::selectRow(int row, bool anchor)
                 command |= QItemSelectionModel::Current;
         }
 
-        QModelIndex tl = model->index(qMin(rowSectionAnchor, row), logicalColumn(0), root);
-        QModelIndex br = model->index(qMax(rowSectionAnchor, row), logicalColumn(model->columnCount(root) - 1), root);
-        if ((verticalHeader->sectionsMoved() && tl.row() != br.row())
-            || horizontalHeader->sectionsMoved()) {
-            q->setSelection(q->visualRect(tl)|q->visualRect(br), command);
+        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())) {
+            q->setSelection(q->visualRect(upper) | q->visualRect(lower), command | QItemSelectionModel::Rows);
         } else {
-            selectionModel->select(QItemSelection(tl, br), command);
+            selectionModel->select(QItemSelection(upper, lower), command | QItemSelectionModel::Rows);
         }
     }
 }
@@ -3289,14 +3288,12 @@ void QTableViewPrivate::selectColumn(int column, bool anchor)
                 command |= QItemSelectionModel::Current;
         }
 
-        QModelIndex tl = model->index(logicalRow(0), qMin(columnSectionAnchor, column), root);
-        QModelIndex br = model->index(logicalRow(model->rowCount(root) - 1),
-                                      qMax(columnSectionAnchor, column), root);
-        if ((horizontalHeader->sectionsMoved() && tl.column() != br.column())
-            || verticalHeader->sectionsMoved()) {
-            q->setSelection(q->visualRect(tl)|q->visualRect(br), command);
+        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())) {
+            q->setSelection(q->visualRect(left) | q->visualRect(right), command | QItemSelectionModel::Columns);
         } else {
-            selectionModel->select(QItemSelection(tl, br), command);
+            selectionModel->select(QItemSelection(left, right), command | QItemSelectionModel::Columns);
         }
     }
 }
diff --git a/tests/auto/widgets/itemviews/qtableview/tst_qtableview.cpp b/tests/auto/widgets/itemviews/qtableview/tst_qtableview.cpp
index e5abd6bc463..2bb3f6a1369 100644
--- a/tests/auto/widgets/itemviews/qtableview/tst_qtableview.cpp
+++ b/tests/auto/widgets/itemviews/qtableview/tst_qtableview.cpp
@@ -203,6 +203,7 @@ private slots:
     void taskQTBUG_8777_scrollToSpans();
     void taskQTBUG_10169_sizeHintForRow();
     void taskQTBUG_30653_doItemsLayout();
+    void taskQTBUG_50171_selectRowAfterSwapColumns();
 
 #ifndef QT_NO_WHEELEVENT
     void mouseWheel_data();
@@ -4476,5 +4477,40 @@ void tst_QTableView::taskQTBUG_30653_doItemsLayout()
     QCOMPARE(scrollToBottomOffset, doItemsLayoutOffset);
 }
 
+void tst_QTableView::taskQTBUG_50171_selectRowAfterSwapColumns()
+{
+    {
+        QtTestTableView tableView;
+        QtTestTableModel model(2, 3);
+        tableView.setModel(&model);
+
+        tableView.horizontalHeader()->swapSections(1, 2);
+        tableView.horizontalHeader()->hideSection(0);
+        tableView.selectRow(1);
+
+        QItemSelectionModel* tableSelectionModel = tableView.selectionModel();
+        QCOMPARE(tableSelectionModel->isRowSelected(1, QModelIndex()), true);
+        QCOMPARE(tableSelectionModel->isSelected(tableView.model()->index(0, 0)), false);
+        QCOMPARE(tableSelectionModel->isSelected(tableView.model()->index(0, 1)), false);
+        QCOMPARE(tableSelectionModel->isSelected(tableView.model()->index(0, 2)), false);
+    }
+
+    {
+        QtTestTableView tableView;
+        QtTestTableModel model(3, 2);
+        tableView.setModel(&model);
+
+        tableView.verticalHeader()->swapSections(1, 2);
+        tableView.verticalHeader()->hideSection(0);
+        tableView.selectColumn(1);
+
+        QItemSelectionModel* sModel = tableView.selectionModel();
+        QCOMPARE(sModel->isColumnSelected(1, QModelIndex()), true);
+        QCOMPARE(sModel->isSelected(tableView.model()->index(0, 0)), false);
+        QCOMPARE(sModel->isSelected(tableView.model()->index(1, 0)), false);
+        QCOMPARE(sModel->isSelected(tableView.model()->index(2, 0)), false);
+    }
+}
+
 QTEST_MAIN(tst_QTableView)
 #include "tst_qtableview.moc"
-- 
GitLab