FIX(a11y): Make plugin config accessible

This commit switches the plugin config tree to a new
MultiColumnTreeWidget and makes it keyboard navigatable.
It also makes screen readers read actual column values.
This commit is contained in:
Hartmnt 2024-01-07 13:49:44 +00:00
parent ed988e646a
commit 4bc60e9d11
6 changed files with 105 additions and 1 deletions

View File

@ -299,6 +299,8 @@ set(MUMBLE_SOURCES
"widgets/MUComboBox.h"
"widgets/MultiStyleWidgetWrapper.cpp"
"widgets/MultiStyleWidgetWrapper.h"
"widgets/MultiColumnTreeWidget.cpp"
"widgets/MultiColumnTreeWidget.h"
"widgets/RichTextItemDelegate.cpp"
"widgets/RichTextItemDelegate.h"
"widgets/SearchDialogItemDelegate.cpp"

View File

@ -38,6 +38,12 @@ PluginConfig::PluginConfig(Settings &st) : ConfigWidget(st) {
qtwPlugins->header()->setSectionResizeMode(2, QHeaderView::ResizeToContents);
qtwPlugins->header()->setSectionResizeMode(3, QHeaderView::ResizeToContents);
qtwPlugins->headerItem()->setData(0, Qt::AccessibleTextRole, tr("Plugin name"));
qtwPlugins->headerItem()->setData(1, Qt::AccessibleTextRole, tr("Plugin enabled checkbox"));
qtwPlugins->headerItem()->setData(2, Qt::AccessibleTextRole, tr("Plugin positional audio permission checkbox"));
qtwPlugins->headerItem()->setData(3, Qt::AccessibleTextRole,
tr("Plugin keyboard event listen permission checkbox"));
qpbUnload->setEnabled(false);
refillPluginList();
@ -230,6 +236,10 @@ void PluginConfig::refillPluginList() {
i->setToolTip(0, currentPlugin->getDescription().toHtmlEscaped());
i->setToolTip(1, tr("Whether this plugin should be enabled"));
i->setData(0, Qt::UserRole, currentPlugin->getID());
on_qtwPlugins_itemChanged(i, 1);
on_qtwPlugins_itemChanged(i, 2);
on_qtwPlugins_itemChanged(i, 3);
}
qtwPlugins->setCurrentItem(qtwPlugins->topLevelItem(0));
@ -251,3 +261,27 @@ void PluginConfig::on_qtwPlugins_currentItemChanged(QTreeWidgetItem *current, QT
qpbUnload->setEnabled(false);
}
}
void PluginConfig::on_qtwPlugins_itemChanged(QTreeWidgetItem *item, int column) {
const_plugin_ptr_t plugin = pluginForItem(item);
if (!plugin) {
return;
}
switch (column) {
case 1:
case 3:
item->setData(column, Qt::AccessibleDescriptionRole,
item->checkState(column) == Qt::Checked ? tr("checked") : tr("unchecked"));
break;
case 2:
if (plugin->getFeatures() & MUMBLE_FEATURE_POSITIONAL) {
item->setData(column, Qt::AccessibleDescriptionRole,
item->checkState(column) == Qt::Checked ? tr("checked") : tr("unchecked"));
} else {
item->setData(column, Qt::AccessibleDescriptionRole, tr("Not available"));
}
break;
}
}

View File

@ -62,6 +62,9 @@ public slots:
/// @param current The currently selected item
/// @param old The previously selected item (if applicable - otherwise NULL/nullptr)
void on_qtwPlugins_currentItemChanged(QTreeWidgetItem *current, QTreeWidgetItem *old);
/// @param item The changed item
/// @param column The column that has changed
void on_qtwPlugins_itemChanged(QTreeWidgetItem *item, int column);
};
#endif

View File

@ -43,10 +43,16 @@
</property>
<layout class="QVBoxLayout">
<item>
<widget class="QTreeWidget" name="qtwPlugins">
<widget class="MultiColumnTreeWidget" name="qtwPlugins">
<property name="accessibleName">
<string>List of plugins</string>
</property>
<property name="accessibleDescription">
<string>Use up and down keys to navigate through plugins. Use left and right keys to navigate between single plugin permissions.</string>
</property>
<property name="tabKeyNavigation">
<bool>false</bool>
</property>
<property name="rootIsDecorated">
<bool>false</bool>
</property>
@ -159,6 +165,13 @@
</item>
</layout>
</widget>
<customwidgets>
<customwidget>
<class>MultiColumnTreeWidget</class>
<extends>QTreeWidget</extends>
<header>widgets/MultiColumnTreeWidget.h</header>
</customwidget>
</customwidgets>
<resources/>
<connections/>
</ui>

View File

@ -0,0 +1,30 @@
// Copyright 2024 The Mumble Developers. All rights reserved.
// Use of this source code is governed by a BSD-style license
// that can be found in the LICENSE file at the root of the
// Mumble source tree or at <https://www.mumble.info/LICENSE>.
#include "MultiColumnTreeWidget.h"
#include <algorithm>
MultiColumnTreeWidget::MultiColumnTreeWidget(QWidget *parent) : QTreeWidget(parent) {
}
QModelIndex MultiColumnTreeWidget::moveCursor(QAbstractItemView::CursorAction cursorAction,
Qt::KeyboardModifiers modifiers) {
QModelIndex mi = QTreeWidget::moveCursor(cursorAction, modifiers);
if (cursorAction == QAbstractItemView::MoveLeft) {
mi = model()->index(mi.row(), std::max(0, mi.column() - 1));
}
if (cursorAction == QAbstractItemView::MoveRight) {
mi = model()->index(mi.row(), std::min(model()->columnCount() - 1, mi.column() + 1));
}
if (cursorAction == QAbstractItemView::MoveUp || cursorAction == QAbstractItemView::MoveDown) {
mi = model()->index(mi.row(), 0);
}
return mi;
}

View File

@ -0,0 +1,22 @@
// Copyright 2024 The Mumble Developers. All rights reserved.
// Use of this source code is governed by a BSD-style license
// that can be found in the LICENSE file at the root of the
// Mumble source tree or at <https://www.mumble.info/LICENSE>.
#ifndef MUMBLE_MUMBLE_WIDGETS_MULTICOLUMNTREEWIDGET_H_
#define MUMBLE_MUMBLE_WIDGETS_MULTICOLUMNTREEWIDGET_H_
#include <QAbstractItemView>
#include <QModelIndex>
#include <QTreeWidget>
class MultiColumnTreeWidget : public QTreeWidget {
Q_OBJECT
public:
MultiColumnTreeWidget(QWidget *parent = nullptr);
QModelIndex moveCursor(QAbstractItemView::CursorAction cursorAction, Qt::KeyboardModifiers modifiers) override;
};
#endif