From 305616a60462b668c4d0b3d19302fa90469aceb5 Mon Sep 17 00:00:00 2001 From: Liang Qi Date: Tue, 7 May 2013 08:41:50 +0200 Subject: [PATCH] Mac: respect the system settings in Full Keyboard Access Iterate all or not in nextPrevItemInTabFocusChain function. Change-Id: I14d40dbeda01ca470efe23886789383ff1d30c0f Reviewed-by: Gabriel de Dietrich --- src/quick/items/qquickitem.cpp | 35 +++++- src/quick/items/qquickitem_p.h | 3 + .../quick/qquickitem2/data/activeFocusOnTab6.qml | 144 ++++++++++++++++++++ tests/auto/quick/qquickitem2/tst_qquickitem.cpp | 132 ++++++++++++++++++ 4 files changed, 313 insertions(+), 1 deletions(-) create mode 100644 tests/auto/quick/qquickitem2/data/activeFocusOnTab6.qml diff --git a/src/quick/items/qquickitem.cpp b/src/quick/items/qquickitem.cpp index 733e26a..b4732c3 100644 --- a/src/quick/items/qquickitem.cpp +++ b/src/quick/items/qquickitem.cpp @@ -58,6 +58,7 @@ #include #include #include +#include #include #include @@ -2034,6 +2035,35 @@ QQuickItem::~QQuickItem() /*! \internal +*/ +bool QQuickItemPrivate::qt_tab_all_widgets() +{ + if (const QPlatformTheme *theme = QGuiApplicationPrivate::platformTheme()) + return theme->themeHint(QPlatformTheme::TabAllWidgets).toBool(); + return true; +} + +/*! + \internal +*/ +bool QQuickItemPrivate::canAcceptTabFocus(QQuickItem *item) +{ + bool result = true; + +#ifndef QT_NO_ACCESSIBILITY + result = false; + if (QObject *acc = qmlAttachedPropertiesObject(item, false)) { + int role = acc->property("role").toInt(); + if (role == QAccessible::EditableText || role == QAccessible::Table || role == QAccessible::List) + result = true; + } +#endif + + return result; +} + +/*! + \internal \brief QQuickItemPrivate::focusNextPrev focuses the next/prev item in the tab-focus-chain \param item The item that currently has the focus \param forward The direction @@ -2059,6 +2089,8 @@ QQuickItem* QQuickItemPrivate::nextPrevItemInTabFocusChain(QQuickItem *item, boo Q_ASSERT(item); Q_ASSERT(item->activeFocusOnTab()); + bool all = QQuickItemPrivate::qt_tab_all_widgets(); + QQuickItem *from = 0; if (forward) { from = item->parentItem(); @@ -2121,7 +2153,8 @@ QQuickItem* QQuickItemPrivate::nextPrevItemInTabFocusChain(QQuickItem *item, boo } from = last; - } while (skip || !current->activeFocusOnTab() || !current->isEnabled() || !current->isVisible()); + } while (skip || !current->activeFocusOnTab() || !current->isEnabled() || !current->isVisible() + || !(all || QQuickItemPrivate::canAcceptTabFocus(current))); return current; } diff --git a/src/quick/items/qquickitem_p.h b/src/quick/items/qquickitem_p.h index 3602b57..4c2df99 100644 --- a/src/quick/items/qquickitem_p.h +++ b/src/quick/items/qquickitem_p.h @@ -487,6 +487,9 @@ public: static bool focusNextPrev(QQuickItem *item, bool forward); static QQuickItem *nextPrevItemInTabFocusChain(QQuickItem *item, bool forward); + static bool qt_tab_all_widgets(); //todo: move to QGuiApplication? + static bool canAcceptTabFocus(QQuickItem *item); + qreal x; qreal y; qreal width; diff --git a/tests/auto/quick/qquickitem2/data/activeFocusOnTab6.qml b/tests/auto/quick/qquickitem2/data/activeFocusOnTab6.qml new file mode 100644 index 0000000..22b4d24 --- /dev/null +++ b/tests/auto/quick/qquickitem2/data/activeFocusOnTab6.qml @@ -0,0 +1,144 @@ +import QtQuick 2.1 + +Item { + id: main + objectName: "main" + width: 800 + height: 600 + focus: true + Component.onCompleted: button12.focus = true + Item { + id: sub1 + objectName: "sub1" + width: 230 + height: 600 + anchors.top: parent.top + anchors.left: parent.left + Item { + id: button11 + objectName: "button11" + width: 100 + height: 50 + activeFocusOnTab: true + Accessible.role: Accessible.Table + Rectangle { + anchors.fill: parent + color: parent.activeFocus ? "red" : "black" + } + + anchors.top: parent.top + anchors.topMargin: 100 + } + Item { + id: button12 + objectName: "button12" + activeFocusOnTab: true + Accessible.role: Accessible.List + Rectangle { + anchors.fill: parent + color: parent.activeFocus ? "red" : "black" + } + width: 100 + height: 50 + + anchors.top: button11.bottom + anchors.bottomMargin: 100 + } + Item { + id: button13 + objectName: "button13" + enabled: false + activeFocusOnTab: true + Accessible.role: Accessible.Table + Rectangle { + anchors.fill: parent + color: parent.activeFocus ? "red" : "black" + } + width: 100 + height: 50 + + anchors.top: button12.bottom + anchors.bottomMargin: 100 + } + Item { + id: button14 + objectName: "button14" + visible: false + activeFocusOnTab: true + Accessible.role: Accessible.List + Rectangle { + anchors.fill: parent + color: parent.activeFocus ? "red" : "black" + } + width: 100 + height: 50 + + anchors.top: button12.bottom + anchors.bottomMargin: 100 + } + } + Item { + id: sub2 + objectName: "sub2" + activeFocusOnTab: true + Accessible.role: Accessible.Row + width: 230 + height: 600 + anchors.top: parent.top + anchors.left: sub1.right + Item { + id: button21 + objectName: "button21" + width: 100 + height: 50 + activeFocusOnTab: true + Accessible.role: Accessible.PushButton + Rectangle { + anchors.fill: parent + color: parent.activeFocus ? "red" : "black" + } + + anchors.top: parent.top + anchors.topMargin: 100 + } + Item { + id: button22 + objectName: "button22" + width: 100 + height: 50 + activeFocusOnTab: true + Accessible.role: Accessible.RadioButton + Rectangle { + anchors.fill: parent + color: parent.activeFocus ? "red" : "black" + } + + anchors.top: button21.bottom + anchors.bottomMargin: 100 + } + } + Item { + id: sub3 + objectName: "sub3" + width: 230 + height: 600 + anchors.top: parent.top + anchors.left: sub2.right + TextEdit { + id: edit + objectName: "edit" + width: 230 + height: 400 + readOnly: false + activeFocusOnTab: true + Accessible.role: Accessible.EditableText + wrapMode: TextEdit.Wrap + textFormat: TextEdit.RichText + + text: "aaa\n" + +"bbb\n" + +"ccc\n" + +"ddd\n" + } + } +} diff --git a/tests/auto/quick/qquickitem2/tst_qquickitem.cpp b/tests/auto/quick/qquickitem2/tst_qquickitem.cpp index 3ec77ce..18ab581 100644 --- a/tests/auto/quick/qquickitem2/tst_qquickitem.cpp +++ b/tests/auto/quick/qquickitem2/tst_qquickitem.cpp @@ -47,6 +47,7 @@ #include #include #include +#include #include #include "../../shared/util.h" #include "../shared/visualtestutil.h" @@ -69,8 +70,10 @@ private slots: void activeFocusOnTab3(); void activeFocusOnTab4(); void activeFocusOnTab5(); + void activeFocusOnTab6(); void nextItemInFocusChain(); + void nextItemInFocusChain2(); void keys(); void keysProcessingOrder(); @@ -110,6 +113,11 @@ private slots: private: QQmlEngine engine; + bool qt_tab_all_widgets() { + if (const QPlatformTheme *theme = QGuiApplicationPrivate::platformTheme()) + return theme->themeHint(QPlatformTheme::TabAllWidgets).toBool(); + return true; + } }; class KeysTestObject : public QObject @@ -283,6 +291,9 @@ void tst_QQuickItem::cleanup() void tst_QQuickItem::activeFocusOnTab() { + if (!qt_tab_all_widgets()) + QSKIP("This function doesn't support NOT iterating all."); + QQuickView *window = new QQuickView(0); window->setBaseSize(QSize(800,600)); @@ -392,6 +403,9 @@ void tst_QQuickItem::activeFocusOnTab() void tst_QQuickItem::activeFocusOnTab2() { + if (!qt_tab_all_widgets()) + QSKIP("This function doesn't support NOT iterating all."); + QQuickView *window = new QQuickView(0); window->setBaseSize(QSize(800,600)); @@ -429,6 +443,9 @@ void tst_QQuickItem::activeFocusOnTab2() void tst_QQuickItem::activeFocusOnTab3() { + if (!qt_tab_all_widgets()) + QSKIP("This function doesn't support NOT iterating all."); + QQuickView *window = new QQuickView(0); window->setBaseSize(QSize(800,600)); @@ -608,6 +625,9 @@ void tst_QQuickItem::activeFocusOnTab3() void tst_QQuickItem::activeFocusOnTab4() { + if (!qt_tab_all_widgets()) + QSKIP("This function doesn't support NOT iterating all."); + QQuickView *window = new QQuickView(0); window->setBaseSize(QSize(800,600)); @@ -637,6 +657,9 @@ void tst_QQuickItem::activeFocusOnTab4() void tst_QQuickItem::activeFocusOnTab5() { + if (!qt_tab_all_widgets()) + QSKIP("This function doesn't support NOT iterating all."); + QQuickView *window = new QQuickView(0); window->setBaseSize(QSize(800,600)); @@ -666,8 +689,69 @@ void tst_QQuickItem::activeFocusOnTab5() delete window; } +void tst_QQuickItem::activeFocusOnTab6() +{ + if (qt_tab_all_widgets()) + QSKIP("This function doesn't support iterating all."); + + QQuickView *window = new QQuickView(0); + window->setBaseSize(QSize(800,600)); + + window->setSource(testFileUrl("activeFocusOnTab6.qml")); + window->show(); + window->requestActivate(); + QVERIFY(QTest::qWaitForWindowActive(window)); + QVERIFY(QGuiApplication::focusWindow() == window); + + // original: button12 + QQuickItem *item = findItem(window->rootObject(), "button12"); + QVERIFY(item); + QVERIFY(item->hasActiveFocus()); + + // Tab: button12->edit + QKeyEvent key(QEvent::KeyPress, Qt::Key_Tab, Qt::NoModifier, "", false, 1); + QGuiApplication::sendEvent(window, &key); + QVERIFY(key.isAccepted()); + + item = findItem(window->rootObject(), "edit"); + QVERIFY(item); + QVERIFY(item->hasActiveFocus()); + + // BackTab: edit->button12 + key = QKeyEvent(QEvent::KeyPress, Qt::Key_Tab, Qt::ShiftModifier, "", false, 1); + QGuiApplication::sendEvent(window, &key); + QVERIFY(key.isAccepted()); + + item = findItem(window->rootObject(), "button12"); + QVERIFY(item); + QVERIFY(item->hasActiveFocus()); + + // BackTab: button12->button11 + key = QKeyEvent(QEvent::KeyPress, Qt::Key_Tab, Qt::ShiftModifier, "", false, 1); + QGuiApplication::sendEvent(window, &key); + QVERIFY(key.isAccepted()); + + item = findItem(window->rootObject(), "button11"); + QVERIFY(item); + QVERIFY(item->hasActiveFocus()); + + // BackTab: button11->edit + key = QKeyEvent(QEvent::KeyPress, Qt::Key_Tab, Qt::ShiftModifier, "", false, 1); + QGuiApplication::sendEvent(window, &key); + QVERIFY(key.isAccepted()); + + item = findItem(window->rootObject(), "edit"); + QVERIFY(item); + QVERIFY(item->hasActiveFocus()); + + delete window; +} + void tst_QQuickItem::nextItemInFocusChain() { + if (!qt_tab_all_widgets()) + QSKIP("This function doesn't support NOT iterating all."); + QQuickView *window = new QQuickView(0); window->setBaseSize(QSize(800,600)); @@ -739,6 +823,54 @@ void tst_QQuickItem::nextItemInFocusChain() delete window; } +void tst_QQuickItem::nextItemInFocusChain2() +{ + if (qt_tab_all_widgets()) + QSKIP("This function doesn't support iterating all."); + + QQuickView *window = new QQuickView(0); + window->setBaseSize(QSize(800,600)); + + window->setSource(testFileUrl("activeFocusOnTab6.qml")); + window->show(); + window->requestActivate(); + QVERIFY(QTest::qWaitForWindowActive(window)); + QVERIFY(QGuiApplication::focusWindow() == window); + + QQuickItem *button11 = findItem(window->rootObject(), "button11"); + QVERIFY(button11); + QQuickItem *button12 = findItem(window->rootObject(), "button12"); + QVERIFY(button12); + + QQuickItem *edit = findItem(window->rootObject(), "edit"); + QVERIFY(edit); + + QQuickItem *next, *prev; + + next = button11->nextItemInFocusChain(true); + QVERIFY(next); + QCOMPARE(next, button12); + prev = button11->nextItemInFocusChain(false); + QVERIFY(prev); + QCOMPARE(prev, edit); + + next = button12->nextItemInFocusChain(); + QVERIFY(next); + QCOMPARE(next, edit); + prev = button12->nextItemInFocusChain(false); + QVERIFY(prev); + QCOMPARE(prev, button11); + + next = edit->nextItemInFocusChain(); + QVERIFY(next); + QCOMPARE(next, button11); + prev = edit->nextItemInFocusChain(false); + QVERIFY(prev); + QCOMPARE(prev, button12); + + delete window; +} + void tst_QQuickItem::keys() { QQuickView *window = new QQuickView(0); -- 1.7.2.5