diff --git a/src/mumble/CMakeLists.txt b/src/mumble/CMakeLists.txt index e0bb39234..75a63bcf9 100644 --- a/src/mumble/CMakeLists.txt +++ b/src/mumble/CMakeLists.txt @@ -289,6 +289,8 @@ set(MUMBLE_SOURCES "XMLTools.cpp" "XMLTools.h" + "widgets/AccessibleQGroupBox.cpp" + "widgets/AccessibleQGroupBox.h" "widgets/CompletablePage.cpp" "widgets/CompletablePage.h" "widgets/EventFilters.cpp" diff --git a/src/mumble/Cert.cpp b/src/mumble/Cert.cpp index 886e87b99..580e4739a 100644 --- a/src/mumble/Cert.cpp +++ b/src/mumble/Cert.cpp @@ -18,6 +18,7 @@ #include "Utils.h" #include "Global.h" +#include #include #include #include @@ -29,7 +30,7 @@ #define SSL_STRING(x) QString::fromLatin1(x).toUtf8().data() -CertView::CertView(QWidget *p) : QGroupBox(p) { +CertView::CertView(QWidget *p) : AccessibleQGroupBox(p) { QGridLayout *grid = new QGridLayout(this); QLabel *l; @@ -65,6 +66,8 @@ CertView::CertView(QWidget *p) : QGroupBox(p) { grid->addWidget(qlExpiry, 3, 1, 1, 1); grid->setColumnStretch(1, 1); + + updateAccessibleText(); } void CertView::setCert(const QList< QSslCertificate > &cert) { @@ -116,6 +119,8 @@ void CertView::setCert(const QList< QSslCertificate > &cert) { qlIssuerName->setText((issuerName == name) ? tr("Self-signed") : issuerName); } + + updateAccessibleText(); } CertWizard::CertWizard(QWidget *p) : QWizard(p) { @@ -144,6 +149,8 @@ CertWizard::CertWizard(QWidget *p) : QWizard(p) { installEventFilter(m_overrideFilter); connect(this, &CertWizard::currentIdChanged, this, &CertWizard::showPage); + + QTimer::singleShot(0, [this] { this->showPage(0); }); } int CertWizard::nextId() const { diff --git a/src/mumble/Cert.h b/src/mumble/Cert.h index 94f7182d1..cd4b78e86 100644 --- a/src/mumble/Cert.h +++ b/src/mumble/Cert.h @@ -14,12 +14,13 @@ #include #include "Settings.h" +#include "widgets/AccessibleQGroupBox.h" #include "widgets/EventFilters.h" class QLabel; class QWidget; -class CertView : public QGroupBox { +class CertView : public AccessibleQGroupBox { private: Q_OBJECT Q_DISABLE_COPY(CertView) diff --git a/src/mumble/widgets/AccessibleQGroupBox.cpp b/src/mumble/widgets/AccessibleQGroupBox.cpp new file mode 100644 index 000000000..68de27189 --- /dev/null +++ b/src/mumble/widgets/AccessibleQGroupBox.cpp @@ -0,0 +1,90 @@ +// 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 . + +#include "AccessibleQGroupBox.h" + +#include +#include +#include + +AccessibleQGroupBox::AccessibleQGroupBox(QWidget *parent) : QGroupBox(parent) { + setFocusPolicy(Qt::TabFocus); + updateAccessibleText(); +} + +void AccessibleQGroupBox::updateAccessibleText() { + QString text; + + // If we have a grid layout, we iterate over it top-to-bottom left-to-right + // and concat all the label contents. + QGridLayout *gridLayout = qobject_cast< QGridLayout * >(layout()); + if (gridLayout) { + for (int y = 0; y < gridLayout->rowCount(); y++) { + for (int x = 0; x < gridLayout->columnCount(); x++) { + QLabel *label = qobject_cast< QLabel * >(gridLayout->itemAtPosition(y, x)->widget()); + if (!label) { + continue; + } + + text += " "; + + QString content = label->text(); + if (content.trimmed().isEmpty()) { + content = tr("empty"); + } + text += content; + } + text += ","; + } + setAccessibleDescription(text); + return; + } + + // Form layouts contain rows with 1 or 2 items. It can either contain a + // "spanning role", or a label with a field. + QFormLayout *formLayout = qobject_cast< QFormLayout * >(layout()); + if (formLayout) { + for (int y = 0; y < formLayout->rowCount(); y++) { + QLabel *label; + + label = qobject_cast< QLabel * >(formLayout->itemAt(y, QFormLayout::SpanningRole)->widget()); + if (label) { + text += label->text() + ", "; + continue; + } + + label = qobject_cast< QLabel * >(formLayout->itemAt(y, QFormLayout::LabelRole)->widget()); + if (label) { + text += label->text(); + } + + label = qobject_cast< QLabel * >(formLayout->itemAt(y, QFormLayout::FieldRole)->widget()); + if (label) { + QString content = label->text(); + if (content.trimmed().isEmpty()) { + content = tr("empty"); + } + text += " " + content; + } + + text += ", "; + } + setAccessibleDescription(text); + return; + } + + // There is no layout we can easily parse, so just concat all + // child label texts. + QObjectList childObjects = children(); + for (int i = 0; i < childObjects.length(); i++) { + QLabel *label = qobject_cast< QLabel * >(childObjects[i]); + if (!label) { + continue; + } + + text += label->text() + ","; + } + setAccessibleDescription(text); +} diff --git a/src/mumble/widgets/AccessibleQGroupBox.h b/src/mumble/widgets/AccessibleQGroupBox.h new file mode 100644 index 000000000..9e9a5de75 --- /dev/null +++ b/src/mumble/widgets/AccessibleQGroupBox.h @@ -0,0 +1,20 @@ +// 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 . + +#ifndef MUMBLE_MUMBLE_ACCESSIBLEQGROUPBOX_H_ +#define MUMBLE_MUMBLE_ACCESSIBLEQGROUPBOX_H_ + +#include + +class AccessibleQGroupBox : public QGroupBox { + Q_OBJECT + +public: + AccessibleQGroupBox(QWidget *parent); + + void updateAccessibleText(); +}; + +#endif