diff options
-rw-r--r-- | src/quick/items/qquickitemsmodule.cpp | 2 | ||||
-rw-r--r-- | src/quick/items/qquickitemview.cpp | 26 | ||||
-rw-r--r-- | src/quick/items/qquickitemview_p.h | 5 | ||||
-rw-r--r-- | src/quick/items/qquickitemview_p_p.h | 2 | ||||
-rw-r--r-- | src/quick/items/qquicklistview.cpp | 21 | ||||
-rw-r--r-- | tests/auto/quick/qquicklistview/tst_qquicklistview.cpp | 68 |
6 files changed, 123 insertions, 1 deletions
diff --git a/src/quick/items/qquickitemsmodule.cpp b/src/quick/items/qquickitemsmodule.cpp index 62e0adcb0a..fcb52bdcb5 100644 --- a/src/quick/items/qquickitemsmodule.cpp +++ b/src/quick/items/qquickitemsmodule.cpp @@ -274,6 +274,8 @@ static void qt_quickitems_defineModule(const char *uri, int major, int minor) qmlRegisterUncreatableType<QQuickEnterKeyAttached, 6>(uri, 2, 6, "EnterKey", QQuickEnterKeyAttached::tr("EnterKey is only available via attached properties")); qmlRegisterType<QQuickShaderEffectSource, 1>(uri, 2, 6, "ShaderEffectSource"); + + qmlRegisterType<QQuickListView, 7>(uri, 2, 7, "ListView"); } static void initResources() diff --git a/src/quick/items/qquickitemview.cpp b/src/quick/items/qquickitemview.cpp index b618daf64b..1cc3046b60 100644 --- a/src/quick/items/qquickitemview.cpp +++ b/src/quick/items/qquickitemview.cpp @@ -448,6 +448,29 @@ void QQuickItemView::setWrapEnabled(bool wrap) emit keyNavigationWrapsChanged(); } +bool QQuickItemView::isKeyNavigationEnabled() const +{ + Q_D(const QQuickItemView); + return d->explicitKeyNavigationEnabled ? d->keyNavigationEnabled : d->interactive; +} + +void QQuickItemView::setKeyNavigationEnabled(bool keyNavigationEnabled) +{ + // TODO: default binding to "interactive" can be removed in Qt 6; it only exists for compatibility reasons. + Q_D(QQuickItemView); + const bool wasImplicit = !d->explicitKeyNavigationEnabled; + if (wasImplicit) + QObject::disconnect(this, &QQuickFlickable::interactiveChanged, this, &QQuickItemView::keyNavigationEnabledChanged); + + d->explicitKeyNavigationEnabled = true; + + // Ensure that we emit the change signal in case there is no different in value. + if (d->keyNavigationEnabled != keyNavigationEnabled || wasImplicit) { + d->keyNavigationEnabled = keyNavigationEnabled; + emit keyNavigationEnabledChanged(); + } +} + int QQuickItemView::cacheBuffer() const { Q_D(const QQuickItemView); @@ -1526,6 +1549,8 @@ QQuickItemViewPrivate::QQuickItemViewPrivate() , transitioner(0) , minExtent(0), maxExtent(0) , ownModel(false), wrap(false) + , keyNavigationEnabled(true) + , explicitKeyNavigationEnabled(false) , inLayout(false), inViewportMoved(false), forceLayout(false), currentIndexCleared(false) , haveHighlightRange(false), autoHighlight(true), highlightRangeStartValid(false), highlightRangeEndValid(false) , fillCacheBuffer(false), inRequest(false) @@ -1654,6 +1679,7 @@ void QQuickItemViewPrivate::init() Q_Q(QQuickItemView); q->setFlag(QQuickItem::ItemIsFocusScope); QObject::connect(q, SIGNAL(movementEnded()), q, SLOT(animStopped())); + QObject::connect(q, &QQuickFlickable::interactiveChanged, q, &QQuickItemView::keyNavigationEnabledChanged); q->setFlickableDirection(QQuickFlickable::VerticalFlick); } diff --git a/src/quick/items/qquickitemview_p.h b/src/quick/items/qquickitemview_p.h index d5c4f59ed2..0541ec44b2 100644 --- a/src/quick/items/qquickitemview_p.h +++ b/src/quick/items/qquickitemview_p.h @@ -69,6 +69,7 @@ class Q_QUICK_PRIVATE_EXPORT QQuickItemView : public QQuickFlickable Q_PROPERTY(QQuickItem *currentItem READ currentItem NOTIFY currentItemChanged) Q_PROPERTY(bool keyNavigationWraps READ isWrapEnabled WRITE setWrapEnabled NOTIFY keyNavigationWrapsChanged) + Q_PROPERTY(bool keyNavigationEnabled READ isKeyNavigationEnabled WRITE setKeyNavigationEnabled NOTIFY keyNavigationEnabledChanged REVISION 7) Q_PROPERTY(int cacheBuffer READ cacheBuffer WRITE setCacheBuffer NOTIFY cacheBufferChanged) Q_PROPERTY(int displayMarginBeginning READ displayMarginBeginning WRITE setDisplayMarginBeginning NOTIFY displayMarginBeginningChanged REVISION 2) Q_PROPERTY(int displayMarginEnd READ displayMarginEnd WRITE setDisplayMarginEnd NOTIFY displayMarginEndChanged REVISION 2) @@ -136,6 +137,9 @@ public: bool isWrapEnabled() const; void setWrapEnabled(bool); + bool isKeyNavigationEnabled() const; + void setKeyNavigationEnabled(bool); + int cacheBuffer() const; void setCacheBuffer(int); @@ -231,6 +235,7 @@ Q_SIGNALS: void currentItemChanged(); void keyNavigationWrapsChanged(); + Q_REVISION(7) void keyNavigationEnabledChanged(); void cacheBufferChanged(); void displayMarginBeginningChanged(); void displayMarginEndChanged(); diff --git a/src/quick/items/qquickitemview_p_p.h b/src/quick/items/qquickitemview_p_p.h index 8af703eb03..3b6407a9f5 100644 --- a/src/quick/items/qquickitemview_p_p.h +++ b/src/quick/items/qquickitemview_p_p.h @@ -308,6 +308,8 @@ public: bool ownModel : 1; bool wrap : 1; + bool keyNavigationEnabled : 1; + bool explicitKeyNavigationEnabled : 1; bool inLayout : 1; bool inViewportMoved : 1; bool forceLayout : 1; diff --git a/src/quick/items/qquicklistview.cpp b/src/quick/items/qquicklistview.cpp index 8384d5b58c..59ecc0b893 100644 --- a/src/quick/items/qquicklistview.cpp +++ b/src/quick/items/qquicklistview.cpp @@ -2174,6 +2174,24 @@ void QQuickListView::setOrientation(QQuickListView::Orientation orientation) By default, key navigation is not wrapped. */ +/*! + \qmlproperty bool QtQuick::ListView::keyNavigationEnabled + \since 5.7 + + This property holds whether the key navigation of the list is enabled. + + If this is \c true, the user can navigate the view with a keyboard. + It is useful for applications that need to selectively enable or + disable mouse and keyboard interaction. + + By default, the value of this property is bound to + \l {Flickable::}{interactive} to ensure behavior compatibility for + existing applications. When explicitly set, it will cease to be bound to + the interactive property. + + \sa \l {Flickable::}{interactive} +*/ + /*! \qmlproperty int QtQuick::ListView::cacheBuffer @@ -2952,7 +2970,8 @@ void QQuickListView::viewportMoved(Qt::Orientations orient) void QQuickListView::keyPressEvent(QKeyEvent *event) { Q_D(QQuickListView); - if (d->model && d->model->count() && d->interactive) { + if (d->model && d->model->count() && ((d->interactive && !d->explicitKeyNavigationEnabled) + || (d->explicitKeyNavigationEnabled && d->keyNavigationEnabled))) { if ((d->orient == QQuickListView::Horizontal && !d->isRightToLeft() && event->key() == Qt::Key_Left) || (d->orient == QQuickListView::Horizontal && d->isRightToLeft() && event->key() == Qt::Key_Right) || (d->orient == QQuickListView::Vertical && !d->isBottomToTop() && event->key() == Qt::Key_Up) diff --git a/tests/auto/quick/qquicklistview/tst_qquicklistview.cpp b/tests/auto/quick/qquicklistview/tst_qquicklistview.cpp index a5de266636..ad6c6ec12d 100644 --- a/tests/auto/quick/qquicklistview/tst_qquicklistview.cpp +++ b/tests/auto/quick/qquicklistview/tst_qquicklistview.cpp @@ -250,6 +250,8 @@ private slots: void QTBUG_48044_currentItemNotVisibleAfterTransition(); + void keyNavigationEnabled(); + private: template <class T> void items(const QUrl &source); template <class T> void changed(const QUrl &source); @@ -8295,6 +8297,72 @@ void tst_QQuickListView::QTBUG_48044_currentItemNotVisibleAfterTransition() QVERIFY(!currentPriv->culled); } +void tst_QQuickListView::keyNavigationEnabled() +{ + QScopedPointer<QQuickView> window(createView()); + window->setSource(testFileUrl("simplelistview.qml")); + window->show(); + window->requestActivate(); + QVERIFY(QTest::qWaitForWindowActive(window.data())); + + QQuickListView *listView = qobject_cast<QQuickListView *>(window->rootObject()); + QVERIFY(listView); + QCOMPARE(listView->isKeyNavigationEnabled(), true); + + listView->setFocus(true); + QVERIFY(listView->hasActiveFocus()); + + listView->setHighlightMoveDuration(0); + + // If keyNavigationEnabled is not explicitly set to true, respect the original behavior + // of disabling both mouse and keyboard interaction. + QSignalSpy enabledSpy(listView, SIGNAL(keyNavigationEnabledChanged())); + listView->setInteractive(false); + QCOMPARE(enabledSpy.count(), 1); + QCOMPARE(listView->isKeyNavigationEnabled(), false); + + flick(window.data(), QPoint(200, 200), QPoint(200, 50), 100); + QVERIFY(!listView->isMoving()); + QCOMPARE(listView->contentY(), 0.0); + QCOMPARE(listView->currentIndex(), 0); + + QTest::keyClick(window.data(), Qt::Key_Down); + QCOMPARE(listView->currentIndex(), 0); + + // Check that isKeyNavigationEnabled implicitly follows the value of interactive. + listView->setInteractive(true); + QCOMPARE(enabledSpy.count(), 2); + QCOMPARE(listView->isKeyNavigationEnabled(), true); + + // Change it back again for the next check. + listView->setInteractive(false); + QCOMPARE(enabledSpy.count(), 3); + QCOMPARE(listView->isKeyNavigationEnabled(), false); + + // Setting keyNavigationEnabled to true shouldn't enable mouse interaction. + listView->setKeyNavigationEnabled(true); + QCOMPARE(enabledSpy.count(), 4); + flick(window.data(), QPoint(200, 200), QPoint(200, 50), 100); + QVERIFY(!listView->isMoving()); + QCOMPARE(listView->contentY(), 0.0); + QCOMPARE(listView->currentIndex(), 0); + + // Should now work. + QTest::keyClick(window.data(), Qt::Key_Down); + QCOMPARE(listView->currentIndex(), 1); + // contentY won't change for one index change in a view this high. + + // Changing interactive now shouldn't result in keyNavigationEnabled changing, + // since we broke the "binding". + listView->setInteractive(true); + QCOMPARE(enabledSpy.count(), 4); + + // Keyboard interaction shouldn't work now. + listView->setKeyNavigationEnabled(false); + QTest::keyClick(window.data(), Qt::Key_Down); + QCOMPARE(listView->currentIndex(), 1); +} + QTEST_MAIN(tst_QQuickListView) #include "tst_qquicklistview.moc" |