diff options
Diffstat (limited to 'src/gui/accessible/qaccessible.cpp')
-rw-r--r-- | src/gui/accessible/qaccessible.cpp | 381 |
1 files changed, 292 insertions, 89 deletions
diff --git a/src/gui/accessible/qaccessible.cpp b/src/gui/accessible/qaccessible.cpp index 2fdcbfdd27..46bca16dad 100644 --- a/src/gui/accessible/qaccessible.cpp +++ b/src/gui/accessible/qaccessible.cpp @@ -1,41 +1,5 @@ -/**************************************************************************** -** -** Copyright (C) 2020 The Qt Company Ltd. -** Contact: https://www.qt.io/licensing/ -** -** This file is part of the QtGui module of the Qt Toolkit. -** -** $QT_BEGIN_LICENSE:LGPL$ -** Commercial License Usage -** Licensees holding valid commercial Qt licenses may use this file in -** accordance with the commercial license agreement provided with the -** Software or, alternatively, in accordance with the terms contained in -** a written agreement between you and The Qt Company. For licensing terms -** and conditions see https://www.qt.io/terms-conditions. For further -** information use the contact form at https://www.qt.io/contact-us. -** -** GNU Lesser General Public License Usage -** Alternatively, this file may be used under the terms of the GNU Lesser -** General Public License version 3 as published by the Free Software -** Foundation and appearing in the file LICENSE.LGPL3 included in the -** packaging of this file. Please review the following information to -** ensure the GNU Lesser General Public License version 3 requirements -** will be met: https://www.gnu.org/licenses/lgpl-3.0.html. -** -** GNU General Public License Usage -** Alternatively, this file may be used under the terms of the GNU -** General Public License version 2.0 or (at your option) the GNU General -** Public license version 3 or any later version approved by the KDE Free -** Qt Foundation. The licenses are as published by the Free Software -** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3 -** included in the packaging of this file. Please review the following -** information to ensure the GNU General Public License requirements will -** be met: https://www.gnu.org/licenses/gpl-2.0.html and -** https://www.gnu.org/licenses/gpl-3.0.html. -** -** $QT_END_LICENSE$ -** -****************************************************************************/ +// Copyright (C) 2020 The Qt Company Ltd. +// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only #include "qaccessible.h" @@ -54,11 +18,14 @@ #include <QtCore/qdebug.h> #include <QtCore/qloggingcategory.h> #include <QtCore/qmetaobject.h> +#include <QtCore/private/qmetaobject_p.h> #include <QtCore/qhash.h> #include <private/qfactoryloader_p.h> QT_BEGIN_NAMESPACE +using namespace Qt::StringLiterals; + Q_LOGGING_CATEGORY(lcAccessibilityCore, "qt.accessibility.core"); /*! @@ -162,7 +129,6 @@ Q_LOGGING_CATEGORY(lcAccessibilityCore, "qt.accessibility.core"); \value hasPopup The object opens a popup. \value hotTracked The object's appearance is sensitive to the mouse cursor position. \value invalid The object is no longer valid (because it has been deleted). - \value invalidEntry Input validation current input invalid. \value invisible The object is not visible to the user. \value linked The object is linked to another object, e.g. a hyperlink. \value marqueed The object displays scrolling contents, e.g. a log view. @@ -252,7 +218,7 @@ Q_LOGGING_CATEGORY(lcAccessibilityCore, "qt.accessibility.core"); \value ObjectHide An object is hidden; for example, with QWidget::hide(). Any children the object that is hidden has do not send this event. It is not sent when an object is hidden as - it is being obcured by others. + it is being obscured by others. \value ObjectReorder A layout or item view has added, removed, or moved an object (Qt does not use this event). \value ObjectShow An object is displayed; for example, with @@ -309,7 +275,7 @@ Q_LOGGING_CATEGORY(lcAccessibilityCore, "qt.accessibility.core"); \value AlertMessage An object that is used to alert the user. \value Animation An object that displays an animation. \value Application The application's main window. - \value Assistant An object that provids interactive help. + \value Assistant An object that provides interactive help. \value Border An object that represents a border. \value ButtonDropDown A button that drops down a list of items. \value ButtonDropGrid A button that drops down a grid. @@ -388,14 +354,29 @@ Q_LOGGING_CATEGORY(lcAccessibilityCore, "qt.accessibility.core"); \enum QAccessible::RelationFlag This enum type defines bit flags that can be combined to indicate - the relationship between two accessible objects. - - \value Label The first object is the label of the second object. - \value Labelled The first object is labelled by the second object. - \value Controller The first object controls the second object. - \value Controlled The first object is controlled by the second object. - \value AllRelations Used as a mask to specify that we are interesting in information - about all relations + the relationship between two accessible objects. It is used by + the relations() function, which returns a list of all the related + interfaces of the calling object, together with the relations + for each object. + + Each entry in the list is a QPair where the \c second member stores + the relation type(s) between the \c returned object represented by the + \c first member and the \c origin (the caller) interface/object. + + In the table below, the \c returned object refers to the object in + the returned list, and the \c origin object is the one represented + by the calling interface. + + \value Label The \c returned object is the label for the \c origin object. + \value Labelled The \c returned object is labelled by the \c origin object. + \value Controller The \c returned object controls the \c origin object. + \value Controlled The \c returned object is controlled by the \c origin object. + \value [since 6.6] DescriptionFor The \c returned object provides a description for the \c origin object. + \value [since 6.6] Described The \c returned object is described by the \c origin object. + \value [since 6.6] FlowsFrom Content logically flows from the \c returned object to the \c origin object. + \value [since 6.6] FlowsTo Content logically flows to the \c returned object from the \c origin object. + \value AllRelations Used as a mask to specify that we are interesting in information + about all relations Implementations of relations() return a combination of these flags. Some values are mutually exclusive. @@ -431,6 +412,43 @@ Q_LOGGING_CATEGORY(lcAccessibilityCore, "qt.accessibility.core"); \sa QAccessibleTextInterface */ +/*! \enum QAccessible::Attribute + This enum describes different types of attributes used by the + \l QAccessibleAttributesInterface. + \since 6.8 + + These attributes are comparable to the concept of properties/(object) + attributes found in ARIA, AT-SPI2, IAccessible, UIA and NSAccessibility + and are mapped to their platform counterpart where applicable. + + Each attribute is handled as a key-value pair, with the values of this + enumeration being used as keys. + + Attribute values are represented in a \l QVariant. The type of the value + stored in the \l QVariant is fixed and specified below for each of the + attribute types. + + \value Custom value type: \a QHash<QString, QString> + The \a Custom attribute is special in that + it can effectively represent multiple attributes at + once, since it itself is a \l QHash used to represent + key-value pairs. + For platforms supporting custom key-value pairs for + attributes, those set in the \a Custom attribute + are bridged to the platform layer without applying any + translation to platform-specific attributes. In general, + the other, more strongly typed attributes should be used. + This attribute can e.g. be used for prototyping + before officially adding an official new enumeration value + for a specific feature. + \value Level value type: \a int + Defines the hierarchical level of an element within a structure, + e.g. the heading level of a heading. This attribute conceptually + matches the "aria-level" property in ARIA. + + \sa QAccessibleAttributesInterface +*/ + /*! \enum QAccessible::InterfaceType @@ -449,11 +467,13 @@ Q_LOGGING_CATEGORY(lcAccessibilityCore, "qt.accessibility.core"); \value TableInterface For lists, tables and trees. \value TableCellInterface For cells in a TableInterface object. \value HyperlinkInterface For hyperlink nodes (usually embedded as children of text nodes) + \value [since 6.5] SelectionInterface For non-text objects that support selection of child objects. + \value [since 6.8] AttributesInterface For objects that support object-specific attributes. - \sa QAccessibleInterface::interface_cast(), QAccessibleTextInterface, QAccessibleValueInterface, QAccessibleActionInterface, QAccessibleTableInterface, QAccessibleTableCellInterface + \sa QAccessibleInterface::interface_cast(), QAccessibleTextInterface, QAccessibleValueInterface, QAccessibleActionInterface, QAccessibleTableInterface, QAccessibleTableCellInterface, QAccessibleSelectionInterface, QAccessibleAttributesInterface */ -#ifndef QT_NO_ACCESSIBILITY +#if QT_CONFIG(accessibility) /*! Destroys the QAccessibleInterface. @@ -470,8 +490,8 @@ QAccessibleInterface::~QAccessibleInterface() /* accessible widgets plugin discovery stuff */ -Q_GLOBAL_STATIC_WITH_ARGS(QFactoryLoader, loader, - (QAccessibleFactoryInterface_iid, QLatin1String("/accessible"))) +Q_GLOBAL_STATIC_WITH_ARGS(QFactoryLoader, acLoader, + (QAccessibleFactoryInterface_iid, "/accessible"_L1)) typedef QHash<QString, QAccessiblePlugin*> QAccessiblePluginsHash; Q_GLOBAL_STATIC(QAccessiblePluginsHash, qAccessiblePlugins) @@ -681,11 +701,30 @@ QAccessibleInterface *QAccessible::queryAccessibleInterface(QObject *object) // Create a QAccessibleInterface for the object class. Start by the most // derived class and walk up the class hierarchy. const QMetaObject *mo = object->metaObject(); + const auto *objectPriv = QObjectPrivate::get(object); + /* + We do not want to cache each and every QML metaobject (Button_QMLTYPE_124, + Button_QMLTYPE_125, etc.). Those dynamic metaobjects shouldn't have an + accessible interface in any case. Instead, we start the whole checking + with the first non-dynamic meta-object. To avoid potential regressions + in other areas of Qt that also use dynamic metaobjects, we only do this + for objects that are QML-related (approximated by checking whether they + have ddata set). + */ + const bool qmlRelated = !objectPriv->isDeletingChildren && + objectPriv->declarativeData; + while (qmlRelated && mo) { + auto mop = QMetaObjectPrivate::get(mo); + if (!mop || !(mop->flags & DynamicMetaObject)) + break; + + mo = mo->superClass(); + }; while (mo) { - const QString cn = QLatin1String(mo->className()); + const QString cn = QLatin1StringView(mo->className()); // Check if the class has a InterfaceFactory installed. - for (int i = qAccessibleFactories()->count(); i > 0; --i) { + for (int i = qAccessibleFactories()->size(); i > 0; --i) { InterfaceFactory factory = qAccessibleFactories()->at(i - 1); if (QAccessibleInterface *iface = factory(cn, object)) { QAccessibleCache::instance()->insert(object, iface); @@ -696,14 +735,15 @@ QAccessibleInterface *QAccessible::queryAccessibleInterface(QObject *object) // Find a QAccessiblePlugin (factory) for the class name. If there's // no entry in the cache try to create it using the plugin loader. if (!qAccessiblePlugins()->contains(cn)) { - const int index = loader()->indexOf(cn); - if (index != -1) { - QAccessiblePlugin *factory = qobject_cast<QAccessiblePlugin *>(loader()->instance(index)); - qAccessiblePlugins()->insert(cn, factory); - } + QAccessiblePlugin *factory = nullptr; // 0 means "no plugin found". This is cached as well. + const int index = acLoader()->indexOf(cn); + if (index != -1) + factory = qobject_cast<QAccessiblePlugin *>(acLoader()->instance(index)); + qAccessiblePlugins()->insert(cn, factory); } // At this point the cache should contain a valid factory pointer or 0: + Q_ASSERT(qAccessiblePlugins()->contains(cn)); QAccessiblePlugin *factory = qAccessiblePlugins()->value(cn); if (factory) { QAccessibleInterface *result = factory->create(cn, object); @@ -801,7 +841,7 @@ bool QAccessible::isActive() */ void QAccessible::setActive(bool active) { - for (int i = 0; i < qAccessibleActivationObservers()->count() ;++i) + for (int i = 0; i < qAccessibleActivationObservers()->size() ;++i) qAccessibleActivationObservers()->at(i)->accessibilityActiveChanged(active); } @@ -864,11 +904,11 @@ void QAccessible::updateAccessibility(QAccessibleEvent *event) if (iface->tableInterface()) iface->tableInterface()->modelChange(static_cast<QAccessibleTableModelChangeEvent*>(event)); } + } - if (updateHandler) { - updateHandler(event); - return; - } + if (updateHandler) { + updateHandler(event); + return; } if (QPlatformAccessibility *pfAccessibility = platformAccessibility()) @@ -1287,6 +1327,11 @@ QColor QAccessibleInterface::backgroundColor() const */ /*! + \fn QAccessibleSelectionInterface *QAccessibleInterface::selectionInterface() + \since 6.5 +*/ + +/*! \class QAccessibleEvent \ingroup accessibility \inmodule QtGui @@ -1648,8 +1693,8 @@ QAccessibleTextRemoveEvent::~QAccessibleTextRemoveEvent() /*! \fn QAccessibleTextInsertEvent::QAccessibleTextInsertEvent(QAccessibleInterface *iface, int position, const QString &text) - Constructs a new QAccessibleTextInsertEvent event for \a iface. The text has been inserted at - \a position. + Constructs a new QAccessibleTextInsertEvent event for \a iface. The \a text has been inserted + at \a position. */ /*! @@ -1842,16 +1887,16 @@ Q_GUI_EXPORT QDebug operator<<(QDebug d, const QAccessibleInterface *iface) QStringList stateStrings; QAccessible::State st = iface->state(); if (st.focusable) - stateStrings << QLatin1String("focusable"); + stateStrings << u"focusable"_s; if (st.focused) - stateStrings << QLatin1String("focused"); + stateStrings << u"focused"_s; if (st.selected) - stateStrings << QLatin1String("selected"); + stateStrings << u"selected"_s; if (st.invisible) - stateStrings << QLatin1String("invisible"); + stateStrings << u"invisible"_s; if (!stateStrings.isEmpty()) - d << stateStrings.join(QLatin1Char('|')); + d << stateStrings.join(u'|'); if (!st.invisible) d << "rect=" << iface->rect(); @@ -2022,7 +2067,7 @@ static QString textLineBoundary(int beforeAtAfter, const QString &text, int offs { Q_ASSERT(beforeAtAfter >= -1 && beforeAtAfter <= 1); Q_ASSERT(*startOffset == -1 && *endOffset == -1); - int length = text.length(); + int length = text.size(); Q_ASSERT(offset >= 0 && offset <= length); // move offset into the right range (if asking for line before or after @@ -2071,10 +2116,10 @@ QString QAccessibleTextInterface::textBeforeOffset(int offset, QAccessible::Text const QString txt = text(0, characterCount()); if (offset == -1) - offset = txt.length(); + offset = txt.size(); *startOffset = *endOffset = -1; - if (txt.isEmpty() || offset <= 0 || offset > txt.length()) + if (txt.isEmpty() || offset <= 0 || offset > txt.size()) return QString(); // type initialized just to silence a compiler warning [-Werror=maybe-uninitialized] @@ -2145,10 +2190,10 @@ QString QAccessibleTextInterface::textAfterOffset(int offset, QAccessible::TextB const QString txt = text(0, characterCount()); if (offset == -1) - offset = txt.length(); + offset = txt.size(); *startOffset = *endOffset = -1; - if (txt.isEmpty() || offset < 0 || offset >= txt.length()) + if (txt.isEmpty() || offset < 0 || offset >= txt.size()) return QString(); // type initialized just to silence a compiler warning [-Werror=maybe-uninitialized] @@ -2183,20 +2228,20 @@ QString QAccessibleTextInterface::textAfterOffset(int offset, QAccessible::TextB int toNext = boundary.toNextBoundary(); if ((boundary.boundaryReasons() & (QTextBoundaryFinder::StartOfItem | QTextBoundaryFinder::EndOfItem))) break; - if (toNext < 0 || toNext >= txt.length()) + if (toNext < 0 || toNext >= txt.size()) break; // not found, the boundary might not exist } - Q_ASSERT(boundary.position() <= txt.length()); + Q_ASSERT(boundary.position() <= txt.size()); *startOffset = boundary.position(); while (true) { int toNext = boundary.toNextBoundary(); if ((boundary.boundaryReasons() & (QTextBoundaryFinder::StartOfItem | QTextBoundaryFinder::EndOfItem))) break; - if (toNext < 0 || toNext >= txt.length()) + if (toNext < 0 || toNext >= txt.size()) break; // not found, the boundary might not exist } - Q_ASSERT(boundary.position() <= txt.length()); + Q_ASSERT(boundary.position() <= txt.size()); *endOffset = boundary.position(); if ((*startOffset == -1) || (*endOffset == -1) || (*startOffset == *endOffset)) { @@ -2230,13 +2275,13 @@ QString QAccessibleTextInterface::textAtOffset(int offset, QAccessible::TextBoun const QString txt = text(0, characterCount()); if (offset == -1) - offset = txt.length(); + offset = txt.size(); *startOffset = *endOffset = -1; - if (txt.isEmpty() || offset < 0 || offset > txt.length()) + if (txt.isEmpty() || offset < 0 || offset > txt.size()) return QString(); - if (offset == txt.length() && boundaryType == QAccessible::CharBoundary) + if (offset == txt.size() && boundaryType == QAccessible::CharBoundary) return QString(); // type initialized just to silence a compiler warning [-Werror=maybe-uninitialized] @@ -2257,7 +2302,7 @@ QString QAccessibleTextInterface::textAtOffset(int offset, QAccessible::TextBoun return textLineBoundary(0, txt, offset, startOffset, endOffset); case QAccessible::NoBoundary: *startOffset = 0; - *endOffset = txt.length(); + *endOffset = txt.size(); return txt; default: Q_UNREACHABLE(); @@ -2275,11 +2320,11 @@ QString QAccessibleTextInterface::textAtOffset(int offset, QAccessible::TextBoun Q_ASSERT(boundary.position() >= 0); *startOffset = boundary.position(); - while (boundary.toNextBoundary() < txt.length()) { + while (boundary.toNextBoundary() < txt.size()) { if ((boundary.boundaryReasons() & (QTextBoundaryFinder::StartOfItem | QTextBoundaryFinder::EndOfItem))) break; } - Q_ASSERT(boundary.position() <= txt.length()); + Q_ASSERT(boundary.position() <= txt.size()); *endOffset = boundary.position(); return txt.mid(*startOffset, *endOffset - *startOffset); @@ -2516,6 +2561,7 @@ QAccessibleTableCellInterface::~QAccessibleTableCellInterface() /*! \class QAccessibleTableInterface + \inmodule QtGui \ingroup accessibility \brief The QAccessibleTableInterface class implements support for @@ -2601,7 +2647,7 @@ QAccessibleTableInterface::~QAccessibleTableInterface() /*! \fn virtual QList<int> QAccessibleTableInterface::selectedRows() const - Returns the list of currently selected columns. + Returns the list of currently selected rows. */ /*! @@ -2662,6 +2708,7 @@ QAccessibleTableInterface::~QAccessibleTableInterface() /*! \class QAccessibleActionInterface + \inmodule QtGui \ingroup accessibility \brief The QAccessibleActionInterface class implements support for @@ -2953,6 +3000,161 @@ QString QAccessibleActionInterface::nextPageAction() return accessibleActionStrings()->nextPageAction; } + +/*! + \since 6.5 + \class QAccessibleSelectionInterface + \inmodule QtGui + \ingroup accessibility + + \brief The QAccessibleSelectionInterface class implements support for + selection handling. + + It provides methods for both, retrieving the current selection + as well as modifying the selection. + + Only selections of direct children are supported. +*/ + +/*! + + Destroys the QAccessibleSelectionInterface. +*/ +QAccessibleSelectionInterface::~QAccessibleSelectionInterface() +{ +} + +/*! + \fn virtual int QAccessibleSelectionInterface::selectedItemCount() const + + Returns the total number of selected accessible items. +*/ + +/*! + \fn virtual QList<QAccessibleInterface *> QAccessibleSelectionInterface::selectedItems() const + + Returns the list of selected accessible items. +*/ + +/*! + Returns the selected accessible item at index \a selectionIndex in the selection. + + Note that the index refers to the n-th selected accessible item (i.e. the index in the current selection), + which generally differs from the index that would be passed to \l QAccessibleInterface::child() + in order to retrieve the same item. + + The default implementation uses \a selectionIndex to retrieve the item from the list + of selected items retrieved by \l QAccessibleSelectionInterface::selectedItems(). + + In particular for implementations dealing with many selected items, reimplementing + this method in a more efficient way may be desirable for performance reasons. +*/ +QAccessibleInterface* QAccessibleSelectionInterface::selectedItem(int selectionIndex) const +{ + QList<QAccessibleInterface*> items = selectedItems(); + if (selectionIndex < 0 || selectionIndex > items.length() -1) { + qCWarning(lcAccessibilityCore) << "Selection index" << selectionIndex << "out of range."; + return nullptr; + } + + return items.at(selectionIndex); +} + +/*! + Returns whether \a childItem is part of the current selection. + + The default implementation checks whether \a childItem is contained + in the list of items retrieved by \l QAccessibleSelectionInterface::selectedItems. +*/ +bool QAccessibleSelectionInterface::isSelected(QAccessibleInterface *childItem) const +{ + return selectedItems().contains(childItem); +} + +/*! + \fn virtual bool QAccessibleSelectionInterface::select(QAccessibleInterface *childItem) + + Adds \a childItem to the selection. + Returns whether \a childItem has actually been added to the selection. + + For implementations that only allow single selections, + this may replace the current selection. +*/ + +/*! + \fn virtual bool QAccessibleSelectionInterface::unselect(QAccessibleInterface *childItem) + + Removes \a childItem from the selection. + + Returns whether the accessible item has actually been removed from the selection. +*/ + +/*! + \fn virtual bool QAccessibleSelectionInterface::selectAll() + + Selects all accessible child items. + + Returns whether all accessible child items have actually been added to the selection. +*/ + +/*! + \fn virtual bool QAccessibleSelectionInterface::clear() + + Unselects all accessible child items. + + Returns whether all accessible child items have actually been removed from the selection, + i.e. whether the selection is empty after this method has been called. +*/ + + +/*! + \since 6.8 + \class QAccessibleAttributesInterface + \inmodule QtGui + \ingroup accessibility + + \brief The QAccessibleAttributesInterface class implements support for + reporting attributes for an accessible object. + + Attributes are key-value pairs. Values are stored in \l QVariant. + + The \a QAccessible::Attributes enumeration describes the available keys and + documents which type to use for the value of each key. + + While the text-specific attributes handled by \l QAccessibleTextInterface::attributes + are specific to objects implementing text and are specific to a specific text + position/offset, the attributes handled by the \l QAccessibleAttributesInterface + can be used for objects of any role and apply for the whole object. + + Classes already implementing \l QAccessibleTextInterface for text-specific attrtibutes + may want to implement \l QAccessibleAttributesInterface in addition for object-specific + attributes. +*/ + +/*! + + Destroys the QAccessibleAttributesInterface. +*/ +QAccessibleAttributesInterface::~QAccessibleAttributesInterface() +{ +} + +/*! + \fn QList<QAccessible::Attribute> QAccessibleAttributesInterface::attributeKeys() const + + Returns the keys of all attributes the object supports. The \l QAccessible::Attribute + enumeration describes available keys. +*/ + +/*! + \fn QVariant QAccessibleAttributesInterface::attributeValue(QAccessible::Attribute key) const + + Returns the value of the attribute \a key of this object. + + If the specificed attribute is not set for this object, an invalid + \l QVariant is returned. +*/ + /*! \internal */ QString qAccessibleLocalizedActionDescription(const QString &actionName) { @@ -2997,7 +3199,8 @@ QAccessibleHyperlinkInterface::~QAccessibleHyperlinkInterface() } -#endif // QT_NO_ACCESSIBILITY +#endif // QT_CONFIG(accessibility) QT_END_NAMESPACE +#include "moc_qaccessible_base.cpp" |