aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--src/quick/items/qquickitemsmodule.cpp2
-rw-r--r--src/quick/items/qquickitemview.cpp26
-rw-r--r--src/quick/items/qquickitemview_p.h5
-rw-r--r--src/quick/items/qquickitemview_p_p.h2
-rw-r--r--src/quick/items/qquicklistview.cpp21
-rw-r--r--tests/auto/quick/qquicklistview/tst_qquicklistview.cpp68
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"