Qt 6.x
The Qt SDK
All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Properties Friends Macros Pages
qaccessible.cpp
Go to the documentation of this file.
1// Copyright (C) 2020 The Qt Company Ltd.
2// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only
3
4#include "qaccessible.h"
5
7#include "qaccessibleplugin.h"
8#include "qaccessibleobject.h"
9#include "qaccessiblebridge.h"
10#include <QtCore/qtextboundaryfinder.h>
11#include <QtGui/qclipboard.h>
12#include <QtGui/qguiapplication.h>
13#include <QtGui/qtextcursor.h>
14#include <private/qguiapplication_p.h>
15#include <qpa/qplatformaccessibility.h>
16#include <qpa/qplatformintegration.h>
17
18#include <QtCore/qdebug.h>
19#include <QtCore/qloggingcategory.h>
20#include <QtCore/qmetaobject.h>
21#include <QtCore/private/qmetaobject_p.h>
22#include <QtCore/qhash.h>
23#include <private/qfactoryloader_p.h>
24
26
27using namespace Qt::StringLiterals;
28
29Q_LOGGING_CATEGORY(lcAccessibilityCore, "qt.accessibility.core");
30
438#if QT_CONFIG(accessibility)
439
443QAccessibleInterface::~QAccessibleInterface()
444{
445}
446
454/* accessible widgets plugin discovery stuff */
456 (QAccessibleFactoryInterface_iid, "/accessible"_L1))
457typedef QHash<QString, QAccessiblePlugin*> QAccessiblePluginsHash;
458Q_GLOBAL_STATIC(QAccessiblePluginsHash, qAccessiblePlugins)
459
460// FIXME turn this into one global static struct
462Q_GLOBAL_STATIC(QList<QAccessible::ActivationObserver *>, qAccessibleActivationObservers)
463
464QAccessible::UpdateHandler QAccessible::updateHandler = nullptr;
465QAccessible::RootObjectHandler QAccessible::rootObjectHandler = nullptr;
466
467static bool cleanupAdded = false;
468
469static QPlatformAccessibility *platformAccessibility()
470{
472 return pfIntegration ? pfIntegration->accessibility() : nullptr;
473}
474
487void QAccessible::cleanup()
488{
489 if (QPlatformAccessibility *pfAccessibility = platformAccessibility())
490 pfAccessibility->cleanup();
491}
492
493static void qAccessibleCleanup()
494{
495 qAccessibleActivationObservers()->clear();
496 qAccessibleFactories()->clear();
497}
498
546void QAccessible::installFactory(InterfaceFactory factory)
547{
548 if (!factory)
549 return;
550
551 if (!cleanupAdded) {
552 qAddPostRoutine(qAccessibleCleanup);
553 cleanupAdded = true;
554 }
555 if (qAccessibleFactories()->contains(factory))
556 return;
557 qAccessibleFactories()->append(factory);
558}
559
563void QAccessible::removeFactory(InterfaceFactory factory)
564{
565 qAccessibleFactories()->removeAll(factory);
566}
567
575QAccessible::UpdateHandler QAccessible::installUpdateHandler(UpdateHandler handler)
576{
577 UpdateHandler old = updateHandler;
578 updateHandler = handler;
579 return old;
580}
581
588QAccessible::RootObjectHandler QAccessible::installRootObjectHandler(RootObjectHandler handler)
589{
590 RootObjectHandler old = rootObjectHandler;
591 rootObjectHandler = handler;
592 return old;
593}
594
603QAccessible::ActivationObserver::~ActivationObserver()
604{
605}
606
612void QAccessible::installActivationObserver(QAccessible::ActivationObserver *observer)
613{
614 if (!observer)
615 return;
616
617 if (!cleanupAdded) {
618 qAddPostRoutine(qAccessibleCleanup);
619 cleanupAdded = true;
620 }
621 if (qAccessibleActivationObservers()->contains(observer))
622 return;
623 qAccessibleActivationObservers()->append(observer);
624}
625
632void QAccessible::removeActivationObserver(ActivationObserver *observer)
633{
634 qAccessibleActivationObservers()->removeAll(observer);
635}
636
655QAccessibleInterface *QAccessible::queryAccessibleInterface(QObject *object)
656{
657 if (!object)
658 return nullptr;
659
660 if (Id id = QAccessibleCache::instance()->idForObject(object))
661 return QAccessibleCache::instance()->interfaceForId(id);
662
663 // Create a QAccessibleInterface for the object class. Start by the most
664 // derived class and walk up the class hierarchy.
665 const QMetaObject *mo = object->metaObject();
666 const auto *objectPriv = QObjectPrivate::get(object);
667 /*
668 We do not want to cache each and every QML metaobject (Button_QMLTYPE_124,
669 Button_QMLTYPE_125, etc.). Those dynamic metaobjects shouldn't have an
670 accessible interface in any case. Instead, we start the whole checking
671 with the first non-dynamic meta-object. To avoid potential regressions
672 in other areas of Qt that also use dynamic metaobjects, we only do this
673 for objects that are QML-related (approximated by checking whether they
674 have ddata set).
675 */
676 const bool qmlRelated = !objectPriv->isDeletingChildren &&
677 objectPriv->declarativeData;
678 while (qmlRelated && mo) {
679 auto mop = QMetaObjectPrivate::get(mo);
680 if (!mop || !(mop->flags & DynamicMetaObject))
681 break;
682
683 mo = mo->superClass();
684 };
685 while (mo) {
686 const QString cn = QLatin1StringView(mo->className());
687
688 // Check if the class has a InterfaceFactory installed.
689 for (int i = qAccessibleFactories()->size(); i > 0; --i) {
690 InterfaceFactory factory = qAccessibleFactories()->at(i - 1);
691 if (QAccessibleInterface *iface = factory(cn, object)) {
692 QAccessibleCache::instance()->insert(object, iface);
693 Q_ASSERT(QAccessibleCache::instance()->containsObject(object));
694 return iface;
695 }
696 }
697 // Find a QAccessiblePlugin (factory) for the class name. If there's
698 // no entry in the cache try to create it using the plugin loader.
699 if (!qAccessiblePlugins()->contains(cn)) {
700 QAccessiblePlugin *factory = nullptr; // 0 means "no plugin found". This is cached as well.
701 const int index = acLoader()->indexOf(cn);
702 if (index != -1)
703 factory = qobject_cast<QAccessiblePlugin *>(acLoader()->instance(index));
704 qAccessiblePlugins()->insert(cn, factory);
705 }
706
707 // At this point the cache should contain a valid factory pointer or 0:
708 Q_ASSERT(qAccessiblePlugins()->contains(cn));
709 QAccessiblePlugin *factory = qAccessiblePlugins()->value(cn);
710 if (factory) {
711 QAccessibleInterface *result = factory->create(cn, object);
712 if (result) {
713 QAccessibleCache::instance()->insert(object, result);
714 Q_ASSERT(QAccessibleCache::instance()->containsObject(object));
715 }
716 return result;
717 }
718 mo = mo->superClass();
719 }
720
721 if (object == qApp) {
722 QAccessibleInterface *appInterface = new QAccessibleApplication;
723 QAccessibleCache::instance()->insert(object, appInterface);
724 Q_ASSERT(QAccessibleCache::instance()->containsObject(qApp));
725 return appInterface;
726 }
727
728 return nullptr;
729}
730
745QAccessible::Id QAccessible::registerAccessibleInterface(QAccessibleInterface *iface)
746{
747 Q_ASSERT(iface);
748 return QAccessibleCache::instance()->insert(iface->object(), iface);
749}
750
756void QAccessible::deleteAccessibleInterface(Id id)
757{
758 QAccessibleCache::instance()->deleteInterface(id);
759}
760
764QAccessible::Id QAccessible::uniqueId(QAccessibleInterface *iface)
765{
766 Id id = QAccessibleCache::instance()->idForInterface(iface);
767 if (!id)
768 id = registerAccessibleInterface(iface);
769 return id;
770}
771
777QAccessibleInterface *QAccessible::accessibleInterface(Id id)
778{
779 return QAccessibleCache::instance()->interfaceForId(id);
780}
781
782
794bool QAccessible::isActive()
795{
796 if (QPlatformAccessibility *pfAccessibility = platformAccessibility())
797 return pfAccessibility->isActive();
798 return false;
799}
800
804void QAccessible::setActive(bool active)
805{
806 for (int i = 0; i < qAccessibleActivationObservers()->size() ;++i)
807 qAccessibleActivationObservers()->at(i)->accessibilityActiveChanged(active);
808}
809
810
825void QAccessible::setRootObject(QObject *object)
826{
827 if (rootObjectHandler) {
828 rootObjectHandler(object);
829 return;
830 }
831
832 if (QPlatformAccessibility *pfAccessibility = platformAccessibility())
833 pfAccessibility->setRootObject(object);
834}
835
855void QAccessible::updateAccessibility(QAccessibleEvent *event)
856{
857 // NOTE: Querying for the accessibleInterface below will result in
858 // resolving and caching the interface, which in some cases will
859 // cache the wrong information as updateAccessibility is called
860 // during construction of widgets. If you see cases where the
861 // cache seems wrong, this call is "to blame", but the code that
862 // caches dynamic data should be updated to handle change events.
863 QAccessibleInterface *iface = event->accessibleInterface();
864 if (isActive() && iface) {
865 if (event->type() == QAccessible::TableModelChanged) {
866 if (iface->tableInterface())
867 iface->tableInterface()->modelChange(static_cast<QAccessibleTableModelChangeEvent*>(event));
868 }
869 }
870
871 if (updateHandler) {
872 updateHandler(event);
873 return;
874 }
875
876 if (QPlatformAccessibility *pfAccessibility = platformAccessibility())
877 pfAccessibility->notifyAccessibilityUpdate(event);
878}
879
887QPair< int, int > QAccessible::qAccessibleTextBoundaryHelper(const QTextCursor &offsetCursor, TextBoundaryType boundaryType)
888{
889 Q_ASSERT(!offsetCursor.isNull());
890
891 QTextCursor endCursor = offsetCursor;
893 int characterCount = endCursor.position();
894
896 QTextCursor cursor = offsetCursor;
897 switch (boundaryType) {
898 case CharBoundary:
899 result.first = cursor.position();
901 result.second = cursor.position();
902 break;
903 case WordBoundary:
905 result.first = cursor.position();
907 result.second = cursor.position();
908 break;
909 case SentenceBoundary: {
910 // QCursor does not provide functionality to move to next sentence.
911 // We therefore find the current block, then go through the block using
912 // QTextBoundaryFinder and find the sentence the \offset represents
914 result.first = cursor.position();
916 result.second = cursor.position();
917 QString blockText = cursor.selectedText();
918 const int offsetWithinBlockText = offsetCursor.position() - result.first;
919 QTextBoundaryFinder sentenceFinder(QTextBoundaryFinder::Sentence, blockText);
920 sentenceFinder.setPosition(offsetWithinBlockText);
921 int prevBoundary = offsetWithinBlockText;
922 int nextBoundary = offsetWithinBlockText;
923 if (!(sentenceFinder.boundaryReasons() & QTextBoundaryFinder::StartOfItem))
924 prevBoundary = sentenceFinder.toPreviousBoundary();
925 nextBoundary = sentenceFinder.toNextBoundary();
926 if (nextBoundary != -1)
927 result.second = result.first + nextBoundary;
928 if (prevBoundary != -1)
929 result.first += prevBoundary;
930 break; }
931 case LineBoundary:
933 result.first = cursor.position();
935 result.second = cursor.position();
936 break;
937 case ParagraphBoundary:
939 result.first = cursor.position();
941 result.second = cursor.position();
942 break;
943 case NoBoundary:
944 result.first = 0;
945 result.second = characterCount;
946 break;
947 }
948 return result;
949}
950
1096QAccessibleInterface::relations(QAccessible::Relation match) const
1097{
1098 Q_UNUSED(match);
1099 return { };
1100}
1101
1107QAccessibleInterface *QAccessibleInterface::focusChild() const
1108{
1109 return nullptr;
1110}
1111
1246QColor QAccessibleInterface::foregroundColor() const
1247{
1248 return QColor();
1249}
1250
1256QColor QAccessibleInterface::backgroundColor() const
1257{
1258 return QColor();
1259}
1260
1333QAccessibleEvent::~QAccessibleEvent()
1334{
1335}
1336
1360QAccessible::Id QAccessibleEvent::uniqueId() const
1361{
1362 if (!m_object)
1363 return m_uniqueId;
1364 QAccessibleInterface *iface = QAccessible::queryAccessibleInterface(m_object);
1365 if (!iface)
1366 return 0;
1367 if (m_child != -1) {
1368 iface = iface->child(m_child);
1369 if (Q_UNLIKELY(!iface)) {
1370 qCWarning(lcAccessibilityCore) << "Invalid child in QAccessibleEvent:" << m_object << "child:" << m_child;
1371 return 0;
1372 }
1373 }
1374 return QAccessible::uniqueId(iface);
1375}
1376
1412QAccessibleValueChangeEvent::~QAccessibleValueChangeEvent()
1413{
1414}
1415
1455QAccessibleStateChangeEvent::~QAccessibleStateChangeEvent()
1456{
1457}
1458
1534QAccessibleTableModelChangeEvent::~QAccessibleTableModelChangeEvent()
1535{
1536}
1562QAccessibleTextCursorEvent::~QAccessibleTextCursorEvent()
1563{
1564}
1565
1566
1602QAccessibleTextInsertEvent::~QAccessibleTextInsertEvent()
1603{
1604}
1605
1606
1644QAccessibleTextRemoveEvent::~QAccessibleTextRemoveEvent()
1645{
1646}
1647
1705QAccessibleTextUpdateEvent::~QAccessibleTextUpdateEvent()
1706{
1707}
1708
1709
1739QAccessibleTextSelectionEvent::~QAccessibleTextSelectionEvent()
1740{
1741}
1742
1743
1744
1748QAccessibleInterface *QAccessibleEvent::accessibleInterface() const
1749{
1750 if (m_object == nullptr)
1751 return QAccessible::accessibleInterface(m_uniqueId);
1752
1753 QAccessibleInterface *iface = QAccessible::queryAccessibleInterface(m_object);
1754 if (!iface || !iface->isValid())
1755 return nullptr;
1756
1757 if (m_child >= 0) {
1758 QAccessibleInterface *child = iface->child(m_child);
1759 if (child) {
1760 iface = child;
1761 } else {
1762 qCWarning(lcAccessibilityCore) << "Cannot create accessible child interface for object: " << m_object << " index: " << m_child;
1763 }
1764 }
1765 return iface;
1766}
1767
1781QWindow *QAccessibleInterface::window() const
1782{
1783 return nullptr;
1784}
1785
1794void QAccessibleInterface::virtual_hook(int /*id*/, void * /*data*/)
1795{
1796}
1797
1815const char *qAccessibleRoleString(QAccessible::Role role)
1816{
1817 if (role >= QAccessible::UserRole)
1818 role = QAccessible::UserRole;
1819 static int roleEnum = QAccessible::staticMetaObject.indexOfEnumerator("Role");
1820 return QAccessible::staticMetaObject.enumerator(roleEnum).valueToKey(role);
1821}
1822
1824const char *qAccessibleEventString(QAccessible::Event event)
1825{
1826 static int eventEnum = QAccessible::staticMetaObject.indexOfEnumerator("Event");
1827 return QAccessible::staticMetaObject.enumerator(eventEnum).valueToKey(event);
1828}
1829
1830#ifndef QT_NO_DEBUG_STREAM
1832Q_GUI_EXPORT QDebug operator<<(QDebug d, const QAccessibleInterface *iface)
1833{
1834 QDebugStateSaver saver(d);
1835 if (!iface) {
1836 d << "QAccessibleInterface(null)";
1837 return d;
1838 }
1839 d.nospace();
1840 d << "QAccessibleInterface(" << Qt::hex << (const void *) iface << Qt::dec;
1841 if (iface->isValid()) {
1842 d << " name=" << iface->text(QAccessible::Name) << ' ';
1843 d << "role=" << qAccessibleRoleString(iface->role()) << ' ';
1844 if (iface->childCount())
1845 d << "childc=" << iface->childCount() << ' ';
1846 if (iface->object()) {
1847 d << "obj=" << iface->object();
1848 }
1849 QStringList stateStrings;
1850 QAccessible::State st = iface->state();
1851 if (st.focusable)
1852 stateStrings << u"focusable"_s;
1853 if (st.focused)
1854 stateStrings << u"focused"_s;
1855 if (st.selected)
1856 stateStrings << u"selected"_s;
1857 if (st.invisible)
1858 stateStrings << u"invisible"_s;
1859
1860 if (!stateStrings.isEmpty())
1861 d << stateStrings.join(u'|');
1862
1863 if (!st.invisible)
1864 d << "rect=" << iface->rect();
1865
1866 } else {
1867 d << " invalid";
1868 }
1869 d << ')';
1870 return d;
1871}
1872
1874QDebug operator<<(QDebug d, const QAccessibleEvent &ev)
1875{
1876 QDebugStateSaver saver(d);
1877 d.nospace() << "QAccessibleEvent(";
1878 if (ev.object()) {
1879 d.nospace() << "object=" << Qt::hex << ev.object() << Qt::dec;
1880 d.nospace() << "child=" << ev.child();
1881 } else {
1882 d.nospace() << "no object, uniqueId=" << ev.uniqueId();
1883 }
1884 d << " event=" << qAccessibleEventString(ev.type());
1885 if (ev.type() == QAccessible::StateChanged) {
1886 QAccessible::State changed = static_cast<const QAccessibleStateChangeEvent*>(&ev)->changedStates();
1887 d << "State changed:";
1888 if (changed.disabled) d << "disabled";
1889 if (changed.selected) d << "selected";
1890 if (changed.focusable) d << "focusable";
1891 if (changed.focused) d << "focused";
1892 if (changed.pressed) d << "pressed";
1893 if (changed.checkable) d << "checkable";
1894 if (changed.checked) d << "checked";
1895 if (changed.checkStateMixed) d << "checkStateMixed";
1896 if (changed.readOnly) d << "readOnly";
1897 if (changed.hotTracked) d << "hotTracked";
1898 if (changed.defaultButton) d << "defaultButton";
1899 if (changed.expanded) d << "expanded";
1900 if (changed.collapsed) d << "collapsed";
1901 if (changed.busy) d << "busy";
1902 if (changed.expandable) d << "expandable";
1903 if (changed.marqueed) d << "marqueed";
1904 if (changed.animated) d << "animated";
1905 if (changed.invisible) d << "invisible";
1906 if (changed.offscreen) d << "offscreen";
1907 if (changed.sizeable) d << "sizeable";
1908 if (changed.movable) d << "movable";
1909 if (changed.selfVoicing) d << "selfVoicing";
1910 if (changed.selectable) d << "selectable";
1911 if (changed.linked) d << "linked";
1912 if (changed.traversed) d << "traversed";
1913 if (changed.multiSelectable) d << "multiSelectable";
1914 if (changed.extSelectable) d << "extSelectable";
1915 if (changed.passwordEdit) d << "passwordEdit"; // used to be Protected
1916 if (changed.hasPopup) d << "hasPopup";
1917 if (changed.modal) d << "modal";
1918
1919 // IA2 - we chose to not add some IA2 states for now
1920 // Below the ones that seem helpful
1921 if (changed.active) d << "active";
1922 if (changed.invalid) d << "invalid"; // = defunct
1923 if (changed.editable) d << "editable";
1924 if (changed.multiLine) d << "multiLine";
1925 if (changed.selectableText) d << "selectableText";
1926 if (changed.supportsAutoCompletion) d << "supportsAutoCompletion";
1927
1928 }
1929 d << ')';
1930 return d;
1931}
1932#endif // QT_NO_DEBUGSTREAM
1933
1957QAccessibleTextInterface::~QAccessibleTextInterface()
1958{
1959}
1960
2028static QString textLineBoundary(int beforeAtAfter, const QString &text, int offset, int *startOffset, int *endOffset)
2029{
2030 Q_ASSERT(beforeAtAfter >= -1 && beforeAtAfter <= 1);
2031 Q_ASSERT(*startOffset == -1 && *endOffset == -1);
2032 int length = text.size();
2033 Q_ASSERT(offset >= 0 && offset <= length);
2034
2035 // move offset into the right range (if asking for line before or after
2036 if (beforeAtAfter == 1) {
2038 if (offset < 0)
2039 return QString(); // after the last line comes nothing
2040 ++offset; // move after the newline
2041 } else if (beforeAtAfter == -1) {
2043 if (offset < 0)
2044 return QString(); // before first line comes nothing
2045 }
2046
2047 if (offset > 0)
2048 *startOffset = text.lastIndexOf(QChar::LineFeed, offset - 1);
2049 ++*startOffset; // move to the char after the newline (0 if lastIndexOf returned -1)
2050
2051 *endOffset = text.indexOf(QChar::LineFeed, qMin(offset, length - 1)) + 1; // include newline char
2052 if (*endOffset <= 0 || *endOffset > length)
2053 *endOffset = length; // if the text doesn't end with a newline it ends at length
2054
2055 return text.mid(*startOffset, *endOffset - *startOffset);
2056}
2057
2075QString QAccessibleTextInterface::textBeforeOffset(int offset, QAccessible::TextBoundaryType boundaryType,
2076 int *startOffset, int *endOffset) const
2077{
2078 const QString txt = text(0, characterCount());
2079
2080 if (offset == -1)
2081 offset = txt.size();
2082
2083 *startOffset = *endOffset = -1;
2084 if (txt.isEmpty() || offset <= 0 || offset > txt.size())
2085 return QString();
2086
2087 // type initialized just to silence a compiler warning [-Werror=maybe-uninitialized]
2089 switch (boundaryType) {
2090 case QAccessible::CharBoundary:
2092 break;
2093 case QAccessible::WordBoundary:
2095 break;
2096 case QAccessible::SentenceBoundary:
2098 break;
2099 case QAccessible::LineBoundary:
2100 case QAccessible::ParagraphBoundary:
2101 // Lines can not use QTextBoundaryFinder since Line there means any potential line-break.
2102 return textLineBoundary(-1, txt, offset, startOffset, endOffset);
2103 case QAccessible::NoBoundary:
2104 // return empty, this function currently only supports single lines, so there can be no line before
2105 return QString();
2106 default:
2107 Q_UNREACHABLE();
2108 }
2109
2110 // keep behavior in sync with QTextCursor::movePosition()!
2111
2112 QTextBoundaryFinder boundary(type, txt);
2113 boundary.setPosition(offset);
2114
2115 do {
2116 if ((boundary.boundaryReasons() & (QTextBoundaryFinder::StartOfItem | QTextBoundaryFinder::EndOfItem)))
2117 break;
2118 } while (boundary.toPreviousBoundary() > 0);
2119 Q_ASSERT(boundary.position() >= 0);
2120 *endOffset = boundary.position();
2121
2122 while (boundary.toPreviousBoundary() > 0) {
2123 if ((boundary.boundaryReasons() & (QTextBoundaryFinder::StartOfItem | QTextBoundaryFinder::EndOfItem)))
2124 break;
2125 }
2126 Q_ASSERT(boundary.position() >= 0);
2127 *startOffset = boundary.position();
2128
2129 return txt.mid(*startOffset, *endOffset - *startOffset);
2130}
2131
2149QString QAccessibleTextInterface::textAfterOffset(int offset, QAccessible::TextBoundaryType boundaryType,
2150 int *startOffset, int *endOffset) const
2151{
2152 const QString txt = text(0, characterCount());
2153
2154 if (offset == -1)
2155 offset = txt.size();
2156
2157 *startOffset = *endOffset = -1;
2158 if (txt.isEmpty() || offset < 0 || offset >= txt.size())
2159 return QString();
2160
2161 // type initialized just to silence a compiler warning [-Werror=maybe-uninitialized]
2163 switch (boundaryType) {
2164 case QAccessible::CharBoundary:
2166 break;
2167 case QAccessible::WordBoundary:
2169 break;
2170 case QAccessible::SentenceBoundary:
2172 break;
2173 case QAccessible::LineBoundary:
2174 case QAccessible::ParagraphBoundary:
2175 // Lines can not use QTextBoundaryFinder since Line there means any potential line-break.
2176 return textLineBoundary(1, txt, offset, startOffset, endOffset);
2177 case QAccessible::NoBoundary:
2178 // return empty, this function currently only supports single lines, so there can be no line after
2179 return QString();
2180 default:
2181 Q_UNREACHABLE();
2182 }
2183
2184 // keep behavior in sync with QTextCursor::movePosition()!
2185
2186 QTextBoundaryFinder boundary(type, txt);
2187 boundary.setPosition(offset);
2188
2189 while (true) {
2190 int toNext = boundary.toNextBoundary();
2191 if ((boundary.boundaryReasons() & (QTextBoundaryFinder::StartOfItem | QTextBoundaryFinder::EndOfItem)))
2192 break;
2193 if (toNext < 0 || toNext >= txt.size())
2194 break; // not found, the boundary might not exist
2195 }
2196 Q_ASSERT(boundary.position() <= txt.size());
2197 *startOffset = boundary.position();
2198
2199 while (true) {
2200 int toNext = boundary.toNextBoundary();
2201 if ((boundary.boundaryReasons() & (QTextBoundaryFinder::StartOfItem | QTextBoundaryFinder::EndOfItem)))
2202 break;
2203 if (toNext < 0 || toNext >= txt.size())
2204 break; // not found, the boundary might not exist
2205 }
2206 Q_ASSERT(boundary.position() <= txt.size());
2207 *endOffset = boundary.position();
2208
2209 if ((*startOffset == -1) || (*endOffset == -1) || (*startOffset == *endOffset)) {
2210 *endOffset = -1;
2211 *startOffset = -1;
2212 }
2213
2214 return txt.mid(*startOffset, *endOffset - *startOffset);
2215}
2216
2234QString QAccessibleTextInterface::textAtOffset(int offset, QAccessible::TextBoundaryType boundaryType,
2235 int *startOffset, int *endOffset) const
2236{
2237 const QString txt = text(0, characterCount());
2238
2239 if (offset == -1)
2240 offset = txt.size();
2241
2242 *startOffset = *endOffset = -1;
2243 if (txt.isEmpty() || offset < 0 || offset > txt.size())
2244 return QString();
2245
2246 if (offset == txt.size() && boundaryType == QAccessible::CharBoundary)
2247 return QString();
2248
2249 // type initialized just to silence a compiler warning [-Werror=maybe-uninitialized]
2251 switch (boundaryType) {
2252 case QAccessible::CharBoundary:
2254 break;
2255 case QAccessible::WordBoundary:
2257 break;
2258 case QAccessible::SentenceBoundary:
2260 break;
2261 case QAccessible::LineBoundary:
2262 case QAccessible::ParagraphBoundary:
2263 // Lines can not use QTextBoundaryFinder since Line there means any potential line-break.
2264 return textLineBoundary(0, txt, offset, startOffset, endOffset);
2265 case QAccessible::NoBoundary:
2266 *startOffset = 0;
2267 *endOffset = txt.size();
2268 return txt;
2269 default:
2270 Q_UNREACHABLE();
2271 }
2272
2273 // keep behavior in sync with QTextCursor::movePosition()!
2274
2275 QTextBoundaryFinder boundary(type, txt);
2276 boundary.setPosition(offset);
2277
2278 do {
2279 if ((boundary.boundaryReasons() & (QTextBoundaryFinder::StartOfItem | QTextBoundaryFinder::EndOfItem)))
2280 break;
2281 } while (boundary.toPreviousBoundary() > 0);
2282 Q_ASSERT(boundary.position() >= 0);
2283 *startOffset = boundary.position();
2284
2285 while (boundary.toNextBoundary() < txt.size()) {
2286 if ((boundary.boundaryReasons() & (QTextBoundaryFinder::StartOfItem | QTextBoundaryFinder::EndOfItem)))
2287 break;
2288 }
2289 Q_ASSERT(boundary.position() <= txt.size());
2290 *endOffset = boundary.position();
2291
2292 return txt.mid(*startOffset, *endOffset - *startOffset);
2293}
2294
2345QAccessibleEditableTextInterface::~QAccessibleEditableTextInterface()
2346{
2347}
2348
2389QAccessibleValueInterface::~QAccessibleValueInterface()
2390{
2391}
2392
2452QAccessibleImageInterface::~QAccessibleImageInterface()
2453{
2454}
2455
2471QAccessibleTableCellInterface::~QAccessibleTableCellInterface()
2472{
2473}
2474
2539QAccessibleTableInterface::~QAccessibleTableInterface()
2540{
2541}
2542
2715QAccessibleActionInterface::~QAccessibleActionInterface()
2716{
2717}
2718
2783struct QAccessibleActionStrings
2784{
2785 QAccessibleActionStrings() :
2786 pressAction(QStringLiteral(QT_TRANSLATE_NOOP("QAccessibleActionInterface", "Press"))),
2787 increaseAction(QStringLiteral(QT_TRANSLATE_NOOP("QAccessibleActionInterface", "Increase"))),
2788 decreaseAction(QStringLiteral(QT_TRANSLATE_NOOP("QAccessibleActionInterface", "Decrease"))),
2789 showMenuAction(QStringLiteral(QT_TRANSLATE_NOOP("QAccessibleActionInterface", "ShowMenu"))),
2790 setFocusAction(QStringLiteral(QT_TRANSLATE_NOOP("QAccessibleActionInterface", "SetFocus"))),
2791 toggleAction(QStringLiteral(QT_TRANSLATE_NOOP("QAccessibleActionInterface", "Toggle"))),
2792 scrollLeftAction(QStringLiteral(QT_TRANSLATE_NOOP("QAccessibleActionInterface", "Scroll Left"))),
2793 scrollRightAction(QStringLiteral(QT_TRANSLATE_NOOP("QAccessibleActionInterface", "Scroll Right"))),
2794 scrollUpAction(QStringLiteral(QT_TRANSLATE_NOOP("QAccessibleActionInterface", "Scroll Up"))),
2795 scrollDownAction(QStringLiteral(QT_TRANSLATE_NOOP("QAccessibleActionInterface", "Scroll Down"))),
2796 previousPageAction(QStringLiteral(QT_TRANSLATE_NOOP("QAccessibleActionInterface", "Previous Page"))),
2797 nextPageAction(QStringLiteral(QT_TRANSLATE_NOOP("QAccessibleActionInterface", "Next Page")))
2798 {}
2799
2800 const QString pressAction;
2801 const QString increaseAction;
2802 const QString decreaseAction;
2803 const QString showMenuAction;
2804 const QString setFocusAction;
2805 const QString toggleAction;
2806 const QString scrollLeftAction;
2807 const QString scrollRightAction;
2808 const QString scrollUpAction;
2809 const QString scrollDownAction;
2810 const QString previousPageAction;
2811 const QString nextPageAction;
2812
2813 QString localizedDescription(const QString &actionName)
2814 {
2815 if (actionName == pressAction)
2816 return QAccessibleActionInterface::tr("Triggers the action");
2817 else if (actionName == increaseAction)
2818 return QAccessibleActionInterface::tr("Increase the value");
2819 else if (actionName == decreaseAction)
2820 return QAccessibleActionInterface::tr("Decrease the value");
2821 else if (actionName == showMenuAction)
2822 return QAccessibleActionInterface::tr("Shows the menu");
2823 else if (actionName == setFocusAction)
2824 return QAccessibleActionInterface::tr("Sets the focus");
2825 else if (actionName == toggleAction)
2826 return QAccessibleActionInterface::tr("Toggles the state");
2827 else if (actionName == scrollLeftAction)
2828 return QAccessibleActionInterface::tr("Scrolls to the left");
2829 else if (actionName == scrollRightAction)
2830 return QAccessibleActionInterface::tr("Scrolls to the right");
2831 else if (actionName == scrollUpAction)
2832 return QAccessibleActionInterface::tr("Scrolls up");
2833 else if (actionName == scrollDownAction)
2834 return QAccessibleActionInterface::tr("Scrolls down");
2835 else if (actionName == previousPageAction)
2836 return QAccessibleActionInterface::tr("Goes back a page");
2837 else if (actionName == nextPageAction)
2838 return QAccessibleActionInterface::tr("Goes to the next page");
2839
2840
2841 return QString();
2842 }
2843};
2844
2845Q_GLOBAL_STATIC(QAccessibleActionStrings, accessibleActionStrings)
2846
2847QString QAccessibleActionInterface::localizedActionName(const QString &actionName) const
2848{
2849 return QAccessibleActionInterface::tr(qPrintable(actionName));
2850}
2851
2852QString QAccessibleActionInterface::localizedActionDescription(const QString &actionName) const
2853{
2854 return accessibleActionStrings()->localizedDescription(actionName);
2855}
2856
2861const QString &QAccessibleActionInterface::pressAction()
2862{
2863 return accessibleActionStrings()->pressAction;
2864}
2865
2870const QString &QAccessibleActionInterface::increaseAction()
2871{
2872 return accessibleActionStrings()->increaseAction;
2873}
2874
2879const QString &QAccessibleActionInterface::decreaseAction()
2880{
2881 return accessibleActionStrings()->decreaseAction;
2882}
2883
2888const QString &QAccessibleActionInterface::showMenuAction()
2889{
2890 return accessibleActionStrings()->showMenuAction;
2891}
2892
2897const QString &QAccessibleActionInterface::setFocusAction()
2898{
2899 return accessibleActionStrings()->setFocusAction;
2900}
2901
2906const QString &QAccessibleActionInterface::toggleAction()
2907{
2908 return accessibleActionStrings()->toggleAction;
2909}
2910
2915QString QAccessibleActionInterface::scrollLeftAction()
2916{
2917 return accessibleActionStrings()->scrollLeftAction;
2918}
2919
2924QString QAccessibleActionInterface::scrollRightAction()
2925{
2926 return accessibleActionStrings()->scrollRightAction;
2927}
2928
2933QString QAccessibleActionInterface::scrollUpAction()
2934{
2935 return accessibleActionStrings()->scrollUpAction;
2936}
2937
2942QString QAccessibleActionInterface::scrollDownAction()
2943{
2944 return accessibleActionStrings()->scrollDownAction;
2945}
2946
2951QString QAccessibleActionInterface::previousPageAction()
2952{
2953 return accessibleActionStrings()->previousPageAction;
2954}
2955
2960QString QAccessibleActionInterface::nextPageAction()
2961{
2962 return accessibleActionStrings()->nextPageAction;
2963}
2964
2965
2986QAccessibleSelectionInterface::~QAccessibleSelectionInterface()
2987{
2988}
2989
3015QAccessibleInterface* QAccessibleSelectionInterface::selectedItem(int selectionIndex) const
3016{
3017 QList<QAccessibleInterface*> items = selectedItems();
3018 if (selectionIndex < 0 || selectionIndex > items.length() -1) {
3019 qCWarning(lcAccessibilityCore) << "Selection index" << selectionIndex << "out of range.";
3020 return nullptr;
3021 }
3022
3023 return items.at(selectionIndex);
3024}
3025
3032bool QAccessibleSelectionInterface::isSelected(QAccessibleInterface *childItem) const
3033{
3034 return selectedItems().contains(childItem);
3035}
3036
3074QString qAccessibleLocalizedActionDescription(const QString &actionName)
3075{
3076 return accessibleActionStrings()->localizedDescription(actionName);
3077}
3078
3112QAccessibleHyperlinkInterface::~QAccessibleHyperlinkInterface()
3113{
3114
3115}
3116
3117#endif // QT_CONFIG(accessibility)
3118
3120
3121#include "moc_qaccessible_base.cpp"
bool isActive
\inmodule QtGui
@ LineFeed
Definition qchar.h:53
The QColor class provides colors based on RGB, HSV or CMYK values.
Definition qcolor.h:31
\inmodule QtCore
\inmodule QtCore
static QPlatformIntegration * platformIntegration()
\inmodule QtCore
Definition qhash.h:818
Definition qlist.h:74
qsizetype length() const noexcept
Definition qlist.h:388
const_reference at(qsizetype i) const noexcept
Definition qlist.h:429
static QObjectPrivate * get(QObject *o)
Definition qobject_p.h:153
\inmodule QtCore
Definition qobject.h:90
The QPlatformIntegration class is the entry for WindowSystem specific functionality.
\inmodule QtCore
\macro QT_RESTRICTED_CAST_FROM_ASCII
Definition qstring.h:127
qsizetype lastIndexOf(QChar c, Qt::CaseSensitivity cs=Qt::CaseSensitive) const noexcept
Definition qstring.h:279
qsizetype size() const
Returns the number of characters in this string.
Definition qstring.h:182
QString mid(qsizetype position, qsizetype n=-1) const
Returns a string that contains n characters of this string, starting at the specified position index.
Definition qstring.cpp:5204
static QString static QString qsizetype indexOf(QChar c, qsizetype from=0, Qt::CaseSensitivity cs=Qt::CaseSensitive) const
Definition qstring.cpp:4420
BoundaryType
\value Grapheme Finds a grapheme which is the smallest boundary.
\reentrant \inmodule QtGui
Definition qtextcursor.h:30
bool movePosition(MoveOperation op, MoveMode=MoveAnchor, int n=1)
Moves the cursor by performing the given operation n times, using the specified mode,...
bool isNull() const
Returns true if the cursor is null; otherwise returns false.
int position() const
Returns the absolute position of the cursor within the document.
\inmodule QtGui
Definition qwindow.h:63
QString text
QCursor cursor
auto mo
[7]
Combined button and popup list for selecting options.
constexpr QBindableInterface iface
Definition qproperty.h:664
QTextStream & hex(QTextStream &stream)
Calls QTextStream::setIntegerBase(16) on stream and returns stream.
QTextStream & dec(QTextStream &stream)
Calls QTextStream::setIntegerBase(10) on stream and returns stream.
#define Q_UNLIKELY(x)
std::pair< T1, T2 > QPair
void qAddPostRoutine(QtCleanUpFunction p)
#define qApp
#define Q_GLOBAL_STATIC_WITH_ARGS(TYPE, NAME, ARGS)
#define Q_GLOBAL_STATIC(TYPE, NAME,...)
#define Q_LOGGING_CATEGORY(name,...)
#define qCWarning(category,...)
@ DynamicMetaObject
constexpr const T & qMin(const T &a, const T &b)
Definition qminmax.h:40
constexpr const T & qMax(const T &a, const T &b)
Definition qminmax.h:42
static bool contains(const QJsonArray &haystack, unsigned needle)
Definition qopengl.cpp:116
GLenum GLuint GLintptr GLsizeiptr size
[1]
GLuint index
[2]
GLenum GLuint GLenum GLsizei length
GLenum GLuint id
[7]
GLenum type
GLenum GLuint GLintptr offset
struct _cl_event * event
GLuint64EXT * result
[6]
#define Q_ASSERT(cond)
Definition qrandom.cpp:47
#define qPrintable(string)
Definition qstring.h:1391
#define QStringLiteral(str)
#define Q_UNUSED(x)
static bool match(const uchar *found, uint foundLen, const char *target, uint targetLen)
#define QT_TRANSLATE_NOOP(scope, x)
QDataStream & operator<<(QDataStream &out, const MyClass &myObj)
[4]
Text files * txt
QItemEditorFactory * factory
QList< QTreeWidgetItem * > items
QLayoutItem * child
[0]
static const QMetaObjectPrivate * get(const QMetaObject *metaobject)
\inmodule QtCore