From 807185d250fd8f5152cafdb416f28abe4438275f Mon Sep 17 00:00:00 2001 From: Frank Reininghaus Date: Mon, 7 Sep 2009 12:57:50 +0200 Subject: Fix some issues with Shift-selection in QAbstractItemView This commit fixes some issues which occur when pressing the Shift key while selecting items (new unit tests included): 1. The offset of the visible area is missing at one point in QAbstractItemView::keyPressEvent, causing Shift-Arrow selection to fail if the view is scrolled down. 2. Shift-click and Shift-Arrow selection fail after a rubberband selection because d->pressedPosition does not correspond to a valid QModelIndex. The problems have been found in Dolphin: http://bugs.kde.org/show_bug.cgi?id=163451 Merge-request: 1426 Reviewed-by: Olivier Goffart --- src/gui/itemviews/qabstractitemview.cpp | 7 +- .../qabstractitemview/tst_qabstractitemview.cpp | 111 +++++++++++++++++++++ 2 files changed, 114 insertions(+), 4 deletions(-) diff --git a/src/gui/itemviews/qabstractitemview.cpp b/src/gui/itemviews/qabstractitemview.cpp index ea98cb2..52529ff 100644 --- a/src/gui/itemviews/qabstractitemview.cpp +++ b/src/gui/itemviews/qabstractitemview.cpp @@ -1537,8 +1537,7 @@ void QAbstractItemView::mousePressEvent(QMouseEvent *event) QPoint offset = d->offset(); if ((command & QItemSelectionModel::Current) == 0) d->pressedPosition = pos + offset; - - if (d->pressedPosition == QPoint(-1, -1)) + else if (!indexAt(d->pressedPosition).isValid()) d->pressedPosition = visualRect(currentIndex()).center() + offset; if (edit(index, NoEditTriggers, event)) @@ -2089,8 +2088,8 @@ void QAbstractItemView::keyPressEvent(QKeyEvent *event) // note that we don't check if the new current index is enabled because moveCursor() makes sure it is if (command & QItemSelectionModel::Current) { d->selectionModel->setCurrentIndex(newCurrent, QItemSelectionModel::NoUpdate); - if (d->pressedPosition == QPoint(-1, -1)) - d->pressedPosition = visualRect(oldCurrent).center(); + if (!indexAt(d->pressedPosition).isValid()) + d->pressedPosition = visualRect(oldCurrent).center() + d->offset(); QRect rect(d->pressedPosition - d->offset(), visualRect(newCurrent).center()); setSelection(rect, command); } else { diff --git a/tests/auto/qabstractitemview/tst_qabstractitemview.cpp b/tests/auto/qabstractitemview/tst_qabstractitemview.cpp index a43b727..eae830f 100644 --- a/tests/auto/qabstractitemview/tst_qabstractitemview.cpp +++ b/tests/auto/qabstractitemview/tst_qabstractitemview.cpp @@ -217,6 +217,8 @@ private slots: void task250754_fontChange(); void task200665_itemEntered(); void task257481_emptyEditor(); + void shiftArrowSelectionAfterScrolling(); + void shiftSelectionAfterRubberbandSelection(); }; class MyAbstractItemDelegate : public QAbstractItemDelegate @@ -1261,6 +1263,115 @@ void tst_QAbstractItemView::task257481_emptyEditor() QVERIFY(!lineEditors.first()->size().isEmpty()); } +void tst_QAbstractItemView::shiftArrowSelectionAfterScrolling() +{ + QStandardItemModel model; + for (int i=0; i<10; ++i) { + QStandardItem *item = new QStandardItem(QString("%1").arg(i)); + model.setItem(i, 0, item); + } + + QListView view; + view.setFixedSize(150, 250); + view.setFlow(QListView::LeftToRight); + view.setGridSize(QSize(100, 100)); + view.setSelectionMode(QListView::ExtendedSelection); + view.setViewMode(QListView::IconMode); + view.setModel(&model); + view.show(); + QTest::qWait(30); + + QModelIndex index0 = model.index(0, 0); + QModelIndex index1 = model.index(1, 0); + QModelIndex index9 = model.index(9, 0); + + view.selectionModel()->setCurrentIndex(index0, QItemSelectionModel::NoUpdate); + QCOMPARE(view.currentIndex(), index0); + + view.scrollTo(index9); + QTest::keyClick(&view, Qt::Key_Down, Qt::ShiftModifier); + + QCOMPARE(view.currentIndex(), index1); + QModelIndexList selected = view.selectionModel()->selectedIndexes(); + QCOMPARE(selected.count(), 2); + QVERIFY(selected.contains(index0)); + QVERIFY(selected.contains(index1)); +} + +void tst_QAbstractItemView::shiftSelectionAfterRubberbandSelection() +{ + QStandardItemModel model; + for (int i=0; i<3; ++i) { + QStandardItem *item = new QStandardItem(QString("%1").arg(i)); + model.setItem(i, 0, item); + } + + QListView view; + view.setFixedSize(150, 450); + view.setFlow(QListView::LeftToRight); + view.setGridSize(QSize(100, 100)); + view.setSelectionMode(QListView::ExtendedSelection); + view.setViewMode(QListView::IconMode); + view.setModel(&model); + view.show(); + QTest::qWait(30); + + QModelIndex index0 = model.index(0, 0); + QModelIndex index1 = model.index(1, 0); + QModelIndex index2 = model.index(2, 0); + + view.setCurrentIndex(index0); + QCOMPARE(view.currentIndex(), index0); + + // Determine the points where the rubberband selection starts and ends + QPoint pressPos = view.visualRect(index1).bottomRight() + QPoint(1, 1); + QPoint releasePos = view.visualRect(index1).center(); + QVERIFY(!view.indexAt(pressPos).isValid()); + QCOMPARE(view.indexAt(releasePos), index1); + + // Select item 1 using a rubberband selection + // The mouse move event has to be created manually because the QTest framework does not + // contain a function for mouse moves with buttons pressed + QTest::mousePress(view.viewport(), Qt::LeftButton, Qt::NoModifier, pressPos); + QMouseEvent moveEvent(QEvent::MouseMove, releasePos, Qt::NoButton, Qt::LeftButton, Qt::NoModifier); + bool moveEventReceived = qApp->notify(view.viewport(), &moveEvent); + QVERIFY(moveEventReceived); + QTest::mouseRelease(view.viewport(), Qt::LeftButton, Qt::NoModifier, releasePos); + QCOMPARE(view.currentIndex(), index1); + + // Shift-click item 2 + QPoint item2Pos = view.visualRect(index2).center(); + QTest::mouseClick(view.viewport(), Qt::LeftButton, Qt::ShiftModifier, item2Pos); + QCOMPARE(view.currentIndex(), index2); + + // Verify that the selection worked OK + QModelIndexList selected = view.selectionModel()->selectedIndexes(); + QCOMPARE(selected.count(), 2); + QVERIFY(selected.contains(index1)); + QVERIFY(selected.contains(index2)); + + // Select item 0 to revert the selection + view.setCurrentIndex(index0); + QCOMPARE(view.currentIndex(), index0); + + // Repeat the same steps as above, but with a Shift-Arrow selection + QTest::mousePress(view.viewport(), Qt::LeftButton, Qt::NoModifier, pressPos); + QMouseEvent moveEvent2(QEvent::MouseMove, releasePos, Qt::NoButton, Qt::LeftButton, Qt::NoModifier); + moveEventReceived = qApp->notify(view.viewport(), &moveEvent2); + QVERIFY(moveEventReceived); + QTest::mouseRelease(view.viewport(), Qt::LeftButton, Qt::NoModifier, releasePos); + QCOMPARE(view.currentIndex(), index1); + + // Press Shift-Down + QTest::keyClick(&view, Qt::Key_Down, Qt::ShiftModifier); + QCOMPARE(view.currentIndex(), index2); + + // Verify that the selection worked OK + selected = view.selectionModel()->selectedIndexes(); + QCOMPARE(selected.count(), 2); + QVERIFY(selected.contains(index1)); + QVERIFY(selected.contains(index2)); +} QTEST_MAIN(tst_QAbstractItemView) #include "tst_qabstractitemview.moc" -- cgit v0.12