mirror of
https://invent.kde.org/system/dolphin
synced 2024-10-02 14:45:04 +00:00
Fix focus chain
Prior to this commit pressing Tab repeatedly would bring the focus to the end of the status bar but not further. This commit makes sure the tab focus doesn't get stuck on the invisible tab bar by explicitly removing the DolphinTabBar from the focus chain while it is hidden. I don't understand why pressing Tab doesn't do anything for the invisible tab bar, but removing an invisible and currently useless widget from the focus chain seems sensible in any case. Improve the accessibility autotest to prevent regressions concerning this.
This commit is contained in:
parent
65ba5a58c0
commit
a4efbfbfa6
|
@ -13,6 +13,28 @@
|
||||||
#include <QMimeData>
|
#include <QMimeData>
|
||||||
#include <QTimer>
|
#include <QTimer>
|
||||||
|
|
||||||
|
class PreventFocusWhileHidden : public QObject
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
PreventFocusWhileHidden(QObject *parent)
|
||||||
|
: QObject(parent){};
|
||||||
|
|
||||||
|
protected:
|
||||||
|
bool eventFilter(QObject *obj, QEvent *ev) override
|
||||||
|
{
|
||||||
|
switch (ev->type()) {
|
||||||
|
case QEvent::Hide:
|
||||||
|
static_cast<QWidget *>(obj)->setFocusPolicy(Qt::NoFocus);
|
||||||
|
return false;
|
||||||
|
case QEvent::Show:
|
||||||
|
static_cast<QWidget *>(obj)->setFocusPolicy(Qt::TabFocus);
|
||||||
|
return false;
|
||||||
|
default:
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
};
|
||||||
|
};
|
||||||
|
|
||||||
DolphinTabBar::DolphinTabBar(QWidget *parent)
|
DolphinTabBar::DolphinTabBar(QWidget *parent)
|
||||||
: QTabBar(parent)
|
: QTabBar(parent)
|
||||||
, m_autoActivationIndex(-1)
|
, m_autoActivationIndex(-1)
|
||||||
|
@ -23,6 +45,9 @@ DolphinTabBar::DolphinTabBar(QWidget *parent)
|
||||||
setMovable(true);
|
setMovable(true);
|
||||||
setTabsClosable(true);
|
setTabsClosable(true);
|
||||||
|
|
||||||
|
setFocusPolicy(Qt::NoFocus);
|
||||||
|
installEventFilter(new PreventFocusWhileHidden(this));
|
||||||
|
|
||||||
m_autoActivationTimer = new QTimer(this);
|
m_autoActivationTimer = new QTimer(this);
|
||||||
m_autoActivationTimer->setSingleShot(true);
|
m_autoActivationTimer->setSingleShot(true);
|
||||||
m_autoActivationTimer->setInterval(800);
|
m_autoActivationTimer->setInterval(800);
|
||||||
|
|
|
@ -539,29 +539,47 @@ void DolphinMainWindowTest::testAccessibilityAncestorTree()
|
||||||
QVERIFY(QTest::qWaitForWindowExposed(m_mainWindow.data()));
|
QVERIFY(QTest::qWaitForWindowExposed(m_mainWindow.data()));
|
||||||
QVERIFY(m_mainWindow->isVisible());
|
QVERIFY(m_mainWindow->isVisible());
|
||||||
|
|
||||||
std::set<const QObject *> testedObjects; // Makes sure we stop testing if we arrive at an item that was already tested.
|
|
||||||
QAccessibleInterface *accessibleInterfaceOfMainWindow = QAccessible::queryAccessibleInterface(m_mainWindow.get());
|
QAccessibleInterface *accessibleInterfaceOfMainWindow = QAccessible::queryAccessibleInterface(m_mainWindow.get());
|
||||||
Q_CHECK_PTR(accessibleInterfaceOfMainWindow);
|
Q_CHECK_PTR(accessibleInterfaceOfMainWindow);
|
||||||
|
|
||||||
// We will do accessibility checks for every object that gets focus. Focus will be changed using the Tab key.
|
// We will test the accessibility of objects traversing forwards and backwards.
|
||||||
while (qApp->focusObject() && !testedObjects.count(qApp->focusObject())) {
|
int testedObjectsSizeAfterTraversingForwards = 0;
|
||||||
const auto currentlyFocusedObject = qApp->focusObject();
|
for (int i = 0; i < 2; i++) {
|
||||||
QAccessibleInterface *accessibleInterface = QAccessible::queryAccessibleInterface(currentlyFocusedObject);
|
std::tuple<Qt::Key, Qt::KeyboardModifier> focusChainTraversalKeyCombination = {Qt::Key::Key_Tab, Qt::NoModifier};
|
||||||
|
if (i) {
|
||||||
// The accessibleInterfaces of focused objects might themselves have children.
|
focusChainTraversalKeyCombination = {Qt::Key::Key_Tab, Qt::ShiftModifier};
|
||||||
// We go down that hierarchy as far as possible and then test the ancestor tree from there.
|
|
||||||
while (accessibleInterface->childCount() > 0) {
|
|
||||||
accessibleInterface = accessibleInterface->child(0);
|
|
||||||
}
|
|
||||||
while (accessibleInterface != accessibleInterfaceOfMainWindow) {
|
|
||||||
QVERIFY2(accessibleInterface,
|
|
||||||
qPrintable(QString("%1's accessibleInterface or one of its accessible children doesn't have the main window as an ancestor.")
|
|
||||||
.arg(currentlyFocusedObject->metaObject()->className())));
|
|
||||||
accessibleInterface = accessibleInterface->parent();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
testedObjects.insert(currentlyFocusedObject); // Add it to testedObjects so we won't test it again later.
|
// We will do accessibility checks for every object that gets focus. Focus will be changed using the focusChainTraversalKeyCombination.
|
||||||
QTest::keyClick(m_mainWindow.get(), Qt::Key::Key_Tab, Qt::ShiftModifier); // ShiftModifier because the Tab cycle is currently broken going forward.
|
std::set<const QObject *> testedObjects; // Makes sure we stop testing when we arrive at an item that was already tested.
|
||||||
|
while (qApp->focusObject() && !testedObjects.count(qApp->focusObject())) {
|
||||||
|
const auto currentlyFocusedObject = qApp->focusObject();
|
||||||
|
|
||||||
|
QAccessibleInterface *accessibleInterface = QAccessible::queryAccessibleInterface(currentlyFocusedObject);
|
||||||
|
// The accessibleInterfaces of focused objects might themselves have children.
|
||||||
|
// We go down that hierarchy as far as possible and then test the ancestor tree from there.
|
||||||
|
while (accessibleInterface->childCount() > 0) {
|
||||||
|
accessibleInterface = accessibleInterface->child(0);
|
||||||
|
}
|
||||||
|
while (accessibleInterface != accessibleInterfaceOfMainWindow) {
|
||||||
|
QVERIFY2(accessibleInterface,
|
||||||
|
qPrintable(QString("%1's accessibleInterface or one of its accessible children doesn't have the main window as an ancestor.")
|
||||||
|
.arg(currentlyFocusedObject->metaObject()->className())));
|
||||||
|
accessibleInterface = accessibleInterface->parent();
|
||||||
|
}
|
||||||
|
|
||||||
|
testedObjects.insert(currentlyFocusedObject); // Add it to testedObjects so we won't test it again later.
|
||||||
|
QTest::keyClick(m_mainWindow.get(), std::get<0>(focusChainTraversalKeyCombination), std::get<1>(focusChainTraversalKeyCombination));
|
||||||
|
QVERIFY2(currentlyFocusedObject != qApp->focusObject(),
|
||||||
|
"The focus chain is broken. The focused object should have changed after pressing the focusChainTraversalKeyCombination.");
|
||||||
|
}
|
||||||
|
|
||||||
|
if (i == 0) {
|
||||||
|
testedObjectsSizeAfterTraversingForwards = testedObjects.size();
|
||||||
|
} else {
|
||||||
|
QCOMPARE(testedObjects.size(), testedObjectsSizeAfterTraversingForwards); // The size after traversing backwards is different than
|
||||||
|
// after going forwards which is probably not intended.
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
Loading…
Reference in a new issue