From d025ebb1a8163cd1f03151927486cf62c5e77957 Mon Sep 17 00:00:00 2001 From: Olivier Goffart Date: Fri, 30 Oct 2009 09:55:20 +0100 Subject: Fixes regression in QComboBox with keypad navigation while mouse is over the popup The problem is that is we move the selection with the keyboard in a way that causes the view to scroll, the current selection would jump. This happends since commit 9cb231d773db6deb that fixed the emission of the enter signal when the view is scrolled. We Therefor cannot use the enter signal. Catch manually the mouse move events to update the selection instead. Reviewed-by: Thierry --- src/gui/widgets/qcombobox.cpp | 24 ++++------------ src/gui/widgets/qcombobox_p.h | 1 - tests/auto/qcombobox/tst_qcombobox.cpp | 52 ++++++++++++++++++++++++++++++++++ 3 files changed, 58 insertions(+), 19 deletions(-) diff --git a/src/gui/widgets/qcombobox.cpp b/src/gui/widgets/qcombobox.cpp index 6dbf15a..1879db4 100644 --- a/src/gui/widgets/qcombobox.cpp +++ b/src/gui/widgets/qcombobox.cpp @@ -489,18 +489,6 @@ void QComboBoxPrivateContainer::viewDestroyed() } /* - Sets currentIndex on entered if the LeftButton is not pressed. This - means that if mouseTracking(...) is on, we setCurrentIndex and select - even when LeftButton is not pressed. -*/ -void QComboBoxPrivateContainer::setCurrentIndex(const QModelIndex &index) -{ - if (QComboBoxDelegate::isSeparator(index)) - return; - view->setCurrentIndex(index); -} - -/* Returns the item view used for the combobox popup. */ QAbstractItemView *QComboBoxPrivateContainer::itemView() const @@ -525,8 +513,6 @@ void QComboBoxPrivateContainer::setItemView(QAbstractItemView *itemView) disconnect(view->verticalScrollBar(), SIGNAL(rangeChanged(int,int)), this, SLOT(updateScrollers())); #endif - disconnect(view, SIGNAL(entered(QModelIndex)), - this, SLOT(setCurrentIndex(QModelIndex))); disconnect(view, SIGNAL(destroyed()), this, SLOT(viewDestroyed())); @@ -563,8 +549,6 @@ void QComboBoxPrivateContainer::setItemView(QAbstractItemView *itemView) connect(view->verticalScrollBar(), SIGNAL(rangeChanged(int,int)), this, SLOT(updateScrollers())); #endif - connect(view, SIGNAL(entered(QModelIndex)), - this, SLOT(setCurrentIndex(QModelIndex))); connect(view, SIGNAL(destroyed()), this, SLOT(viewDestroyed())); @@ -655,16 +639,20 @@ bool QComboBoxPrivateContainer::eventFilter(QObject *o, QEvent *e) break; } break; - case QEvent::MouseMove: { + case QEvent::MouseMove: if (isVisible()) { QMouseEvent *m = static_cast(e); QWidget *widget = static_cast(o); QPoint vector = widget->mapToGlobal(m->pos()) - initialClickPosition; if (vector.manhattanLength() > 9 && blockMouseReleaseTimer.isActive()) blockMouseReleaseTimer.stop(); + QModelIndex indexUnderMouse = view->indexAt(m->pos()); + if (indexUnderMouse.isValid() && indexUnderMouse != view->currentIndex() + && !QComboBoxDelegate::isSeparator(indexUnderMouse)) { + view->setCurrentIndex(indexUnderMouse); + } } break; - } case QEvent::MouseButtonRelease: { QMouseEvent *m = static_cast(e); if (isVisible() && view->rect().contains(m->pos()) && view->currentIndex().isValid() diff --git a/src/gui/widgets/qcombobox_p.h b/src/gui/widgets/qcombobox_p.h index 06e51e4..fe42c47 100644 --- a/src/gui/widgets/qcombobox_p.h +++ b/src/gui/widgets/qcombobox_p.h @@ -231,7 +231,6 @@ public: public Q_SLOTS: void scrollItemView(int action); void updateScrollers(); - void setCurrentIndex(const QModelIndex &index); void viewDestroyed(); protected: diff --git a/tests/auto/qcombobox/tst_qcombobox.cpp b/tests/auto/qcombobox/tst_qcombobox.cpp index 8acae7a..51a7ff8 100644 --- a/tests/auto/qcombobox/tst_qcombobox.cpp +++ b/tests/auto/qcombobox/tst_qcombobox.cpp @@ -153,6 +153,7 @@ private slots: void task260974_menuItemRectangleForComboBoxPopup(); void removeItem(); void resetModel(); + void keyBoardNavigationWithMouse(); protected slots: void onEditTextChanged( const QString &newString ); @@ -2448,6 +2449,57 @@ void tst_QComboBox::resetModel() } +void tst_QComboBox::keyBoardNavigationWithMouse() +{ + QComboBox combo; + combo.setEditable(false); + for (int i = 0; i < 80; i++) + combo.addItem( QString::number(i)); + combo.show(); + QApplication::setActiveWindow(&combo); + QTest::qWaitForWindowShown(&combo); + QTRY_COMPARE(QApplication::activeWindow(), static_cast(&combo)); + + QCOMPARE(combo.currentText(), QLatin1String("0")); + + combo.setFocus(); + QTRY_VERIFY(combo.hasFocus()); + + QTest::keyClick(testWidget->lineEdit(), Qt::Key_Space); + QTest::qWait(30); + QTRY_VERIFY(combo.view()); + QTRY_VERIFY(combo.view()->isVisible()); + QTest::qWait(130); + + QCOMPARE(combo.currentText(), QLatin1String("0")); + + QCursor::setPos(combo.view()->mapToGlobal(combo.view()->rect().center())); + QTest::qWait(200); + +#define GET_SELECTION(SEL) \ + QCOMPARE(combo.view()->selectionModel()->selection().count(), 1); \ + QCOMPARE(combo.view()->selectionModel()->selection().indexes().count(), 1); \ + SEL = combo.view()->selectionModel()->selection().indexes().first().row() + + int selection; + GET_SELECTION(selection); + + //since we moved the mouse is in the middle it should even be around 5; + QVERIFY(selection > 3); + + static const int final = 40; + for (int i = selection + 1; i <= final; i++) + { + QTest::keyClick(combo.view(), Qt::Key_Down); + QTest::qWait(20); + GET_SELECTION(selection); + QCOMPARE(selection, i); + } + + QTest::keyClick(combo.view(), Qt::Key_Enter); + QTRY_COMPARE(combo.currentText(), QString::number(final)); +} + QTEST_MAIN(tst_QComboBox) #include "tst_qcombobox.moc" -- cgit v0.12