Qt
Internal/Contributor docs for the Qt SDK. <b>Note:</b> These are NOT official API docs; those are found <a href='https://doc.qt.io/'>here</a>.
Loading...
Searching...
No Matches
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
501#if QT_CONFIG(accessibility)
502
506QAccessibleInterface::~QAccessibleInterface()
507{
508}
509
517/* accessible widgets plugin discovery stuff */
519 (QAccessibleFactoryInterface_iid, "/accessible"_L1))
520typedef QHash<QString, QAccessiblePlugin*> QAccessiblePluginsHash;
521Q_GLOBAL_STATIC(QAccessiblePluginsHash, qAccessiblePlugins)
522
523// FIXME turn this into one global static struct
524Q_GLOBAL_STATIC(QList<QAccessible::InterfaceFactory>, qAccessibleFactories)
525Q_GLOBAL_STATIC(QList<QAccessible::ActivationObserver *>, qAccessibleActivationObservers)
526
527QAccessible::UpdateHandler QAccessible::updateHandler = nullptr;
528QAccessible::RootObjectHandler QAccessible::rootObjectHandler = nullptr;
529
530static bool cleanupAdded = false;
531
532static QPlatformAccessibility *platformAccessibility()
533{
535 return pfIntegration ? pfIntegration->accessibility() : nullptr;
536}
537
550void QAccessible::cleanup()
551{
552 if (QPlatformAccessibility *pfAccessibility = platformAccessibility())
553 pfAccessibility->cleanup();
554}
555
556static void qAccessibleCleanup()
557{
558 qAccessibleActivationObservers()->clear();
559 qAccessibleFactories()->clear();
560}
561
609void QAccessible::installFactory(InterfaceFactory factory)
610{
611 if (!factory)
612 return;
613
614 if (!cleanupAdded) {
615 qAddPostRoutine(qAccessibleCleanup);
616 cleanupAdded = true;
617 }
618 if (qAccessibleFactories()->contains(factory))
619 return;
620 qAccessibleFactories()->append(factory);
621}
622
626void QAccessible::removeFactory(InterfaceFactory factory)
627{
628 qAccessibleFactories()->removeAll(factory);
629}
630
638QAccessible::UpdateHandler QAccessible::installUpdateHandler(UpdateHandler handler)
639{
640 UpdateHandler old = updateHandler;
641 updateHandler = handler;
642 return old;
643}
644
651QAccessible::RootObjectHandler QAccessible::installRootObjectHandler(RootObjectHandler handler)
652{
653 RootObjectHandler old = rootObjectHandler;
654 rootObjectHandler = handler;
655 return old;
656}
657
666QAccessible::ActivationObserver::~ActivationObserver()
667{
668}
669
675void QAccessible::installActivationObserver(QAccessible::ActivationObserver *observer)
676{
677 if (!observer)
678 return;
679
680 if (!cleanupAdded) {
681 qAddPostRoutine(qAccessibleCleanup);
682 cleanupAdded = true;
683 }
684 if (qAccessibleActivationObservers()->contains(observer))
685 return;
686 qAccessibleActivationObservers()->append(observer);
687}
688
695void QAccessible::removeActivationObserver(ActivationObserver *observer)
696{
697 qAccessibleActivationObservers()->removeAll(observer);
698}
699
718QAccessibleInterface *QAccessible::queryAccessibleInterface(QObject *object)
719{
720 if (!object)
721 return nullptr;
722
723 if (Id id = QAccessibleCache::instance()->idForObject(object))
724 return QAccessibleCache::instance()->interfaceForId(id);
725
726 // Create a QAccessibleInterface for the object class. Start by the most
727 // derived class and walk up the class hierarchy.
728 const QMetaObject *mo = object->metaObject();
729 const auto *objectPriv = QObjectPrivate::get(object);
730 /*
731 We do not want to cache each and every QML metaobject (Button_QMLTYPE_124,
732 Button_QMLTYPE_125, etc.). Those dynamic metaobjects shouldn't have an
733 accessible interface in any case. Instead, we start the whole checking
734 with the first non-dynamic meta-object. To avoid potential regressions
735 in other areas of Qt that also use dynamic metaobjects, we only do this
736 for objects that are QML-related (approximated by checking whether they
737 have ddata set).
738 */
739 const bool qmlRelated = !objectPriv->isDeletingChildren &&
740 objectPriv->declarativeData;
741 while (qmlRelated && mo) {
742 auto mop = QMetaObjectPrivate::get(mo);
743 if (!mop || !(mop->flags & DynamicMetaObject))
744 break;
745
746 mo = mo->superClass();
747 };
748 while (mo) {
749 const QString cn = QLatin1StringView(mo->className());
750
751 // Check if the class has a InterfaceFactory installed.
752 for (int i = qAccessibleFactories()->size(); i > 0; --i) {
753 InterfaceFactory factory = qAccessibleFactories()->at(i - 1);
754 if (QAccessibleInterface *iface = factory(cn, object)) {
755 QAccessibleCache::instance()->insert(object, iface);
756 Q_ASSERT(QAccessibleCache::instance()->containsObject(object));
757 return iface;
758 }
759 }
760 // Find a QAccessiblePlugin (factory) for the class name. If there's
761 // no entry in the cache try to create it using the plugin loader.
762 if (!qAccessiblePlugins()->contains(cn)) {
763 QAccessiblePlugin *factory = nullptr; // 0 means "no plugin found". This is cached as well.
764 const int index = acLoader()->indexOf(cn);
765 if (index != -1)
766 factory = qobject_cast<QAccessiblePlugin *>(acLoader()->instance(index));
767 qAccessiblePlugins()->insert(cn, factory);
768 }
769
770 // At this point the cache should contain a valid factory pointer or 0:
771 Q_ASSERT(qAccessiblePlugins()->contains(cn));
772 QAccessiblePlugin *factory = qAccessiblePlugins()->value(cn);
773 if (factory) {
774 QAccessibleInterface *result = factory->create(cn, object);
775 if (result) {
776 QAccessibleCache::instance()->insert(object, result);
777 Q_ASSERT(QAccessibleCache::instance()->containsObject(object));
778 }
779 return result;
780 }
781 mo = mo->superClass();
782 }
783
784 if (object == qApp) {
785 QAccessibleInterface *appInterface = new QAccessibleApplication;
786 QAccessibleCache::instance()->insert(object, appInterface);
787 Q_ASSERT(QAccessibleCache::instance()->containsObject(qApp));
788 return appInterface;
789 }
790
791 return nullptr;
792}
793
808QAccessible::Id QAccessible::registerAccessibleInterface(QAccessibleInterface *iface)
809{
810 Q_ASSERT(iface);
811 return QAccessibleCache::instance()->insert(iface->object(), iface);
812}
813
819void QAccessible::deleteAccessibleInterface(Id id)
820{
821 QAccessibleCache::instance()->deleteInterface(id);
822}
823
827QAccessible::Id QAccessible::uniqueId(QAccessibleInterface *iface)
828{
829 Id id = QAccessibleCache::instance()->idForInterface(iface);
830 if (!id)
831 id = registerAccessibleInterface(iface);
832 return id;
833}
834
840QAccessibleInterface *QAccessible::accessibleInterface(Id id)
841{
842 return QAccessibleCache::instance()->interfaceForId(id);
843}
844
845
857bool QAccessible::isActive()
858{
859 if (QPlatformAccessibility *pfAccessibility = platformAccessibility())
860 return pfAccessibility->isActive();
861 return false;
862}
863
867void QAccessible::setActive(bool active)
868{
869 for (int i = 0; i < qAccessibleActivationObservers()->size() ;++i)
870 qAccessibleActivationObservers()->at(i)->accessibilityActiveChanged(active);
871}
872
873
888void QAccessible::setRootObject(QObject *object)
889{
890 if (rootObjectHandler) {
891 rootObjectHandler(object);
892 return;
893 }
894
895 if (QPlatformAccessibility *pfAccessibility = platformAccessibility())
896 pfAccessibility->setRootObject(object);
897}
898
918void QAccessible::updateAccessibility(QAccessibleEvent *event)
919{
920 // NOTE: Querying for the accessibleInterface below will result in
921 // resolving and caching the interface, which in some cases will
922 // cache the wrong information as updateAccessibility is called
923 // during construction of widgets. If you see cases where the
924 // cache seems wrong, this call is "to blame", but the code that
925 // caches dynamic data should be updated to handle change events.
926 QAccessibleInterface *iface = event->accessibleInterface();
927 if (isActive() && iface) {
928 if (event->type() == QAccessible::TableModelChanged) {
929 if (iface->tableInterface())
930 iface->tableInterface()->modelChange(static_cast<QAccessibleTableModelChangeEvent*>(event));
931 }
932 }
933
934 if (updateHandler) {
935 updateHandler(event);
936 return;
937 }
938
939 if (QPlatformAccessibility *pfAccessibility = platformAccessibility())
940 pfAccessibility->notifyAccessibilityUpdate(event);
941}
942
950QPair< int, int > QAccessible::qAccessibleTextBoundaryHelper(const QTextCursor &offsetCursor, TextBoundaryType boundaryType)
951{
952 Q_ASSERT(!offsetCursor.isNull());
953
954 QTextCursor endCursor = offsetCursor;
956 int characterCount = endCursor.position();
957
958 QPair<int, int> result;
959 QTextCursor cursor = offsetCursor;
960 switch (boundaryType) {
961 case CharBoundary:
962 result.first = cursor.position();
964 result.second = cursor.position();
965 break;
966 case WordBoundary:
968 result.first = cursor.position();
970 result.second = cursor.position();
971 break;
972 case SentenceBoundary: {
973 // QCursor does not provide functionality to move to next sentence.
974 // We therefore find the current block, then go through the block using
975 // QTextBoundaryFinder and find the sentence the \offset represents
977 result.first = cursor.position();
979 result.second = cursor.position();
980 QString blockText = cursor.selectedText();
981 const int offsetWithinBlockText = offsetCursor.position() - result.first;
982 QTextBoundaryFinder sentenceFinder(QTextBoundaryFinder::Sentence, blockText);
983 sentenceFinder.setPosition(offsetWithinBlockText);
984 int prevBoundary = offsetWithinBlockText;
985 int nextBoundary = offsetWithinBlockText;
986 if (!(sentenceFinder.boundaryReasons() & QTextBoundaryFinder::StartOfItem))
987 prevBoundary = sentenceFinder.toPreviousBoundary();
988 nextBoundary = sentenceFinder.toNextBoundary();
989 if (nextBoundary != -1)
990 result.second = result.first + nextBoundary;
991 if (prevBoundary != -1)
992 result.first += prevBoundary;
993 break; }
994 case LineBoundary:
996 result.first = cursor.position();
998 result.second = cursor.position();
999 break;
1000 case ParagraphBoundary:
1002 result.first = cursor.position();
1004 result.second = cursor.position();
1005 break;
1006 case NoBoundary:
1007 result.first = 0;
1008 result.second = characterCount;
1009 break;
1010 }
1011 return result;
1012}
1013
1158QList<QPair<QAccessibleInterface*, QAccessible::Relation>>
1159QAccessibleInterface::relations(QAccessible::Relation match) const
1160{
1161 Q_UNUSED(match);
1162 return { };
1163}
1164
1170QAccessibleInterface *QAccessibleInterface::focusChild() const
1171{
1172 return nullptr;
1173}
1174
1309QColor QAccessibleInterface::foregroundColor() const
1310{
1311 return QColor();
1312}
1313
1319QColor QAccessibleInterface::backgroundColor() const
1320{
1321 return QColor();
1322}
1323
1396QAccessibleEvent::~QAccessibleEvent()
1397{
1398}
1399
1423QAccessible::Id QAccessibleEvent::uniqueId() const
1424{
1425 if (!m_object)
1426 return m_uniqueId;
1427 QAccessibleInterface *iface = QAccessible::queryAccessibleInterface(m_object);
1428 if (!iface)
1429 return 0;
1430 if (m_child != -1) {
1431 iface = iface->child(m_child);
1432 if (Q_UNLIKELY(!iface)) {
1433 qCWarning(lcAccessibilityCore) << "Invalid child in QAccessibleEvent:" << m_object << "child:" << m_child;
1434 return 0;
1435 }
1436 }
1437 return QAccessible::uniqueId(iface);
1438}
1439
1475QAccessibleValueChangeEvent::~QAccessibleValueChangeEvent()
1476{
1477}
1478
1518QAccessibleStateChangeEvent::~QAccessibleStateChangeEvent()
1519{
1520}
1521
1597QAccessibleTableModelChangeEvent::~QAccessibleTableModelChangeEvent()
1598{
1599}
1625QAccessibleTextCursorEvent::~QAccessibleTextCursorEvent()
1626{
1627}
1628
1629
1665QAccessibleTextInsertEvent::~QAccessibleTextInsertEvent()
1666{
1667}
1668
1669
1707QAccessibleTextRemoveEvent::~QAccessibleTextRemoveEvent()
1708{
1709}
1710
1768QAccessibleTextUpdateEvent::~QAccessibleTextUpdateEvent()
1769{
1770}
1771
1772
1802QAccessibleTextSelectionEvent::~QAccessibleTextSelectionEvent()
1803{
1804}
1805
1853QAccessibleAnnouncementEvent::~QAccessibleAnnouncementEvent()
1854{
1855}
1856
1860QAccessibleInterface *QAccessibleEvent::accessibleInterface() const
1861{
1862 if (m_object == nullptr)
1863 return QAccessible::accessibleInterface(m_uniqueId);
1864
1865 QAccessibleInterface *iface = QAccessible::queryAccessibleInterface(m_object);
1866 if (!iface || !iface->isValid())
1867 return nullptr;
1868
1869 if (m_child >= 0) {
1870 QAccessibleInterface *child = iface->child(m_child);
1871 if (child) {
1872 iface = child;
1873 } else {
1874 qCWarning(lcAccessibilityCore) << "Cannot create accessible child interface for object: " << m_object << " index: " << m_child;
1875 }
1876 }
1877 return iface;
1878}
1879
1893QWindow *QAccessibleInterface::window() const
1894{
1895 return nullptr;
1896}
1897
1906void QAccessibleInterface::virtual_hook(int /*id*/, void * /*data*/)
1907{
1908}
1909
1927const char *qAccessibleRoleString(QAccessible::Role role)
1928{
1929 if (role >= QAccessible::UserRole)
1930 role = QAccessible::UserRole;
1931 static int roleEnum = QAccessible::staticMetaObject.indexOfEnumerator("Role");
1932 return QAccessible::staticMetaObject.enumerator(roleEnum).valueToKey(role);
1933}
1934
1936const char *qAccessibleEventString(QAccessible::Event event)
1937{
1938 static int eventEnum = QAccessible::staticMetaObject.indexOfEnumerator("Event");
1939 return QAccessible::staticMetaObject.enumerator(eventEnum).valueToKey(event);
1940}
1941
1942#ifndef QT_NO_DEBUG_STREAM
1944Q_GUI_EXPORT QDebug operator<<(QDebug d, const QAccessibleInterface *iface)
1945{
1946 QDebugStateSaver saver(d);
1947 if (!iface) {
1948 d << "QAccessibleInterface(null)";
1949 return d;
1950 }
1951 d.nospace();
1952 d << "QAccessibleInterface(" << Qt::hex << (const void *) iface << Qt::dec;
1953 if (iface->isValid()) {
1954 d << " name=" << iface->text(QAccessible::Name) << ' ';
1955 d << "role=" << qAccessibleRoleString(iface->role()) << ' ';
1956 if (iface->childCount())
1957 d << "childc=" << iface->childCount() << ' ';
1958 if (iface->object()) {
1959 d << "obj=" << iface->object();
1960 }
1961 QStringList stateStrings;
1962 QAccessible::State st = iface->state();
1963 if (st.focusable)
1964 stateStrings << u"focusable"_s;
1965 if (st.focused)
1966 stateStrings << u"focused"_s;
1967 if (st.selected)
1968 stateStrings << u"selected"_s;
1969 if (st.invisible)
1970 stateStrings << u"invisible"_s;
1971
1972 if (!stateStrings.isEmpty())
1973 d << stateStrings.join(u'|');
1974
1975 if (!st.invisible)
1976 d << "rect=" << iface->rect();
1977
1978 } else {
1979 d << " invalid";
1980 }
1981 d << ')';
1982 return d;
1983}
1984
1986QDebug operator<<(QDebug d, const QAccessibleEvent &ev)
1987{
1988 QDebugStateSaver saver(d);
1989 d.nospace() << "QAccessibleEvent(";
1990 if (ev.object()) {
1991 d.nospace() << "object=" << Qt::hex << ev.object() << Qt::dec;
1992 d.nospace() << "child=" << ev.child();
1993 } else {
1994 d.nospace() << "no object, uniqueId=" << ev.uniqueId();
1995 }
1996 d << " event=" << qAccessibleEventString(ev.type());
1997 if (ev.type() == QAccessible::StateChanged) {
1998 QAccessible::State changed = static_cast<const QAccessibleStateChangeEvent*>(&ev)->changedStates();
1999 d << "State changed:";
2000 if (changed.disabled) d << "disabled";
2001 if (changed.selected) d << "selected";
2002 if (changed.focusable) d << "focusable";
2003 if (changed.focused) d << "focused";
2004 if (changed.pressed) d << "pressed";
2005 if (changed.checkable) d << "checkable";
2006 if (changed.checked) d << "checked";
2007 if (changed.checkStateMixed) d << "checkStateMixed";
2008 if (changed.readOnly) d << "readOnly";
2009 if (changed.hotTracked) d << "hotTracked";
2010 if (changed.defaultButton) d << "defaultButton";
2011 if (changed.expanded) d << "expanded";
2012 if (changed.collapsed) d << "collapsed";
2013 if (changed.busy) d << "busy";
2014 if (changed.expandable) d << "expandable";
2015 if (changed.marqueed) d << "marqueed";
2016 if (changed.animated) d << "animated";
2017 if (changed.invisible) d << "invisible";
2018 if (changed.offscreen) d << "offscreen";
2019 if (changed.sizeable) d << "sizeable";
2020 if (changed.movable) d << "movable";
2021 if (changed.selfVoicing) d << "selfVoicing";
2022 if (changed.selectable) d << "selectable";
2023 if (changed.linked) d << "linked";
2024 if (changed.traversed) d << "traversed";
2025 if (changed.multiSelectable) d << "multiSelectable";
2026 if (changed.extSelectable) d << "extSelectable";
2027 if (changed.passwordEdit) d << "passwordEdit"; // used to be Protected
2028 if (changed.hasPopup) d << "hasPopup";
2029 if (changed.modal) d << "modal";
2030
2031 // IA2 - we chose to not add some IA2 states for now
2032 // Below the ones that seem helpful
2033 if (changed.active) d << "active";
2034 if (changed.invalid) d << "invalid"; // = defunct
2035 if (changed.editable) d << "editable";
2036 if (changed.multiLine) d << "multiLine";
2037 if (changed.selectableText) d << "selectableText";
2038 if (changed.supportsAutoCompletion) d << "supportsAutoCompletion";
2039
2040 }
2041 d << ')';
2042 return d;
2043}
2044#endif // QT_NO_DEBUGSTREAM
2045
2069QAccessibleTextInterface::~QAccessibleTextInterface()
2070{
2071}
2072
2140static QString textLineBoundary(int beforeAtAfter, const QString &text, int offset, int *startOffset, int *endOffset)
2141{
2142 Q_ASSERT(beforeAtAfter >= -1 && beforeAtAfter <= 1);
2143 Q_ASSERT(*startOffset == -1 && *endOffset == -1);
2144 int length = text.size();
2145 Q_ASSERT(offset >= 0 && offset <= length);
2146
2147 // move offset into the right range (if asking for line before or after
2148 if (beforeAtAfter == 1) {
2149 offset = text.indexOf(QChar::LineFeed, qMin(offset, length - 1));
2150 if (offset < 0)
2151 return QString(); // after the last line comes nothing
2152 ++offset; // move after the newline
2153 } else if (beforeAtAfter == -1) {
2154 offset = text.lastIndexOf(QChar::LineFeed, qMax(offset - 1, 0));
2155 if (offset < 0)
2156 return QString(); // before first line comes nothing
2157 }
2158
2159 if (offset > 0)
2160 *startOffset = text.lastIndexOf(QChar::LineFeed, offset - 1);
2161 ++*startOffset; // move to the char after the newline (0 if lastIndexOf returned -1)
2162
2163 *endOffset = text.indexOf(QChar::LineFeed, qMin(offset, length - 1)) + 1; // include newline char
2164 if (*endOffset <= 0 || *endOffset > length)
2165 *endOffset = length; // if the text doesn't end with a newline it ends at length
2166
2167 return text.mid(*startOffset, *endOffset - *startOffset);
2168}
2169
2187QString QAccessibleTextInterface::textBeforeOffset(int offset, QAccessible::TextBoundaryType boundaryType,
2188 int *startOffset, int *endOffset) const
2189{
2190 const QString txt = text(0, characterCount());
2191
2192 if (offset == -1)
2193 offset = txt.size();
2194
2195 *startOffset = *endOffset = -1;
2196 if (txt.isEmpty() || offset <= 0 || offset > txt.size())
2197 return QString();
2198
2199 // type initialized just to silence a compiler warning [-Werror=maybe-uninitialized]
2201 switch (boundaryType) {
2202 case QAccessible::CharBoundary:
2204 break;
2205 case QAccessible::WordBoundary:
2207 break;
2208 case QAccessible::SentenceBoundary:
2210 break;
2211 case QAccessible::LineBoundary:
2212 case QAccessible::ParagraphBoundary:
2213 // Lines can not use QTextBoundaryFinder since Line there means any potential line-break.
2214 return textLineBoundary(-1, txt, offset, startOffset, endOffset);
2215 case QAccessible::NoBoundary:
2216 // return empty, this function currently only supports single lines, so there can be no line before
2217 return QString();
2218 default:
2219 Q_UNREACHABLE();
2220 }
2221
2222 // keep behavior in sync with QTextCursor::movePosition()!
2223
2224 QTextBoundaryFinder boundary(type, txt);
2225 boundary.setPosition(offset);
2226
2227 do {
2228 if ((boundary.boundaryReasons() & (QTextBoundaryFinder::StartOfItem | QTextBoundaryFinder::EndOfItem)))
2229 break;
2230 } while (boundary.toPreviousBoundary() > 0);
2231 Q_ASSERT(boundary.position() >= 0);
2232 *endOffset = boundary.position();
2233
2234 while (boundary.toPreviousBoundary() > 0) {
2235 if ((boundary.boundaryReasons() & (QTextBoundaryFinder::StartOfItem | QTextBoundaryFinder::EndOfItem)))
2236 break;
2237 }
2238 Q_ASSERT(boundary.position() >= 0);
2239 *startOffset = boundary.position();
2240
2241 return txt.mid(*startOffset, *endOffset - *startOffset);
2242}
2243
2261QString QAccessibleTextInterface::textAfterOffset(int offset, QAccessible::TextBoundaryType boundaryType,
2262 int *startOffset, int *endOffset) const
2263{
2264 const QString txt = text(0, characterCount());
2265
2266 if (offset == -1)
2267 offset = txt.size();
2268
2269 *startOffset = *endOffset = -1;
2270 if (txt.isEmpty() || offset < 0 || offset >= txt.size())
2271 return QString();
2272
2273 // type initialized just to silence a compiler warning [-Werror=maybe-uninitialized]
2275 switch (boundaryType) {
2276 case QAccessible::CharBoundary:
2278 break;
2279 case QAccessible::WordBoundary:
2281 break;
2282 case QAccessible::SentenceBoundary:
2284 break;
2285 case QAccessible::LineBoundary:
2286 case QAccessible::ParagraphBoundary:
2287 // Lines can not use QTextBoundaryFinder since Line there means any potential line-break.
2288 return textLineBoundary(1, txt, offset, startOffset, endOffset);
2289 case QAccessible::NoBoundary:
2290 // return empty, this function currently only supports single lines, so there can be no line after
2291 return QString();
2292 default:
2293 Q_UNREACHABLE();
2294 }
2295
2296 // keep behavior in sync with QTextCursor::movePosition()!
2297
2298 QTextBoundaryFinder boundary(type, txt);
2299 boundary.setPosition(offset);
2300
2301 while (true) {
2302 int toNext = boundary.toNextBoundary();
2303 if ((boundary.boundaryReasons() & (QTextBoundaryFinder::StartOfItem | QTextBoundaryFinder::EndOfItem)))
2304 break;
2305 if (toNext < 0 || toNext >= txt.size())
2306 break; // not found, the boundary might not exist
2307 }
2308 Q_ASSERT(boundary.position() <= txt.size());
2309 *startOffset = boundary.position();
2310
2311 while (true) {
2312 int toNext = boundary.toNextBoundary();
2313 if ((boundary.boundaryReasons() & (QTextBoundaryFinder::StartOfItem | QTextBoundaryFinder::EndOfItem)))
2314 break;
2315 if (toNext < 0 || toNext >= txt.size())
2316 break; // not found, the boundary might not exist
2317 }
2318 Q_ASSERT(boundary.position() <= txt.size());
2319 *endOffset = boundary.position();
2320
2321 if ((*startOffset == -1) || (*endOffset == -1) || (*startOffset == *endOffset)) {
2322 *endOffset = -1;
2323 *startOffset = -1;
2324 }
2325
2326 return txt.mid(*startOffset, *endOffset - *startOffset);
2327}
2328
2346QString QAccessibleTextInterface::textAtOffset(int offset, QAccessible::TextBoundaryType boundaryType,
2347 int *startOffset, int *endOffset) const
2348{
2349 const QString txt = text(0, characterCount());
2350
2351 if (offset == -1)
2352 offset = txt.size();
2353
2354 *startOffset = *endOffset = -1;
2355 if (txt.isEmpty() || offset < 0 || offset > txt.size())
2356 return QString();
2357
2358 if (offset == txt.size() && boundaryType == QAccessible::CharBoundary)
2359 return QString();
2360
2361 // type initialized just to silence a compiler warning [-Werror=maybe-uninitialized]
2363 switch (boundaryType) {
2364 case QAccessible::CharBoundary:
2366 break;
2367 case QAccessible::WordBoundary:
2369 break;
2370 case QAccessible::SentenceBoundary:
2372 break;
2373 case QAccessible::LineBoundary:
2374 case QAccessible::ParagraphBoundary:
2375 // Lines can not use QTextBoundaryFinder since Line there means any potential line-break.
2376 return textLineBoundary(0, txt, offset, startOffset, endOffset);
2377 case QAccessible::NoBoundary:
2378 *startOffset = 0;
2379 *endOffset = txt.size();
2380 return txt;
2381 default:
2382 Q_UNREACHABLE();
2383 }
2384
2385 // keep behavior in sync with QTextCursor::movePosition()!
2386
2387 QTextBoundaryFinder boundary(type, txt);
2388 boundary.setPosition(offset);
2389
2390 do {
2391 if ((boundary.boundaryReasons() & (QTextBoundaryFinder::StartOfItem | QTextBoundaryFinder::EndOfItem)))
2392 break;
2393 } while (boundary.toPreviousBoundary() > 0);
2394 Q_ASSERT(boundary.position() >= 0);
2395 *startOffset = boundary.position();
2396
2397 while (boundary.toNextBoundary() < txt.size()) {
2398 if ((boundary.boundaryReasons() & (QTextBoundaryFinder::StartOfItem | QTextBoundaryFinder::EndOfItem)))
2399 break;
2400 }
2401 Q_ASSERT(boundary.position() <= txt.size());
2402 *endOffset = boundary.position();
2403
2404 return txt.mid(*startOffset, *endOffset - *startOffset);
2405}
2406
2457QAccessibleEditableTextInterface::~QAccessibleEditableTextInterface()
2458{
2459}
2460
2501QAccessibleValueInterface::~QAccessibleValueInterface()
2502{
2503}
2504
2564QAccessibleImageInterface::~QAccessibleImageInterface()
2565{
2566}
2567
2583QAccessibleTableCellInterface::~QAccessibleTableCellInterface()
2584{
2585}
2586
2651QAccessibleTableInterface::~QAccessibleTableInterface()
2652{
2653}
2654
2827QAccessibleActionInterface::~QAccessibleActionInterface()
2828{
2829}
2830
2895struct QAccessibleActionStrings
2896{
2897 QAccessibleActionStrings() :
2898 pressAction(QStringLiteral(QT_TRANSLATE_NOOP("QAccessibleActionInterface", "Press"))),
2899 increaseAction(QStringLiteral(QT_TRANSLATE_NOOP("QAccessibleActionInterface", "Increase"))),
2900 decreaseAction(QStringLiteral(QT_TRANSLATE_NOOP("QAccessibleActionInterface", "Decrease"))),
2901 showMenuAction(QStringLiteral(QT_TRANSLATE_NOOP("QAccessibleActionInterface", "ShowMenu"))),
2902 setFocusAction(QStringLiteral(QT_TRANSLATE_NOOP("QAccessibleActionInterface", "SetFocus"))),
2903 toggleAction(QStringLiteral(QT_TRANSLATE_NOOP("QAccessibleActionInterface", "Toggle"))),
2904 scrollLeftAction(QStringLiteral(QT_TRANSLATE_NOOP("QAccessibleActionInterface", "Scroll Left"))),
2905 scrollRightAction(QStringLiteral(QT_TRANSLATE_NOOP("QAccessibleActionInterface", "Scroll Right"))),
2906 scrollUpAction(QStringLiteral(QT_TRANSLATE_NOOP("QAccessibleActionInterface", "Scroll Up"))),
2907 scrollDownAction(QStringLiteral(QT_TRANSLATE_NOOP("QAccessibleActionInterface", "Scroll Down"))),
2908 previousPageAction(QStringLiteral(QT_TRANSLATE_NOOP("QAccessibleActionInterface", "Previous Page"))),
2909 nextPageAction(QStringLiteral(QT_TRANSLATE_NOOP("QAccessibleActionInterface", "Next Page")))
2910 {}
2911
2912 const QString pressAction;
2913 const QString increaseAction;
2914 const QString decreaseAction;
2915 const QString showMenuAction;
2916 const QString setFocusAction;
2917 const QString toggleAction;
2918 const QString scrollLeftAction;
2919 const QString scrollRightAction;
2920 const QString scrollUpAction;
2921 const QString scrollDownAction;
2922 const QString previousPageAction;
2923 const QString nextPageAction;
2924
2925 QString localizedDescription(const QString &actionName)
2926 {
2927 if (actionName == pressAction)
2928 return QAccessibleActionInterface::tr("Triggers the action");
2929 else if (actionName == increaseAction)
2930 return QAccessibleActionInterface::tr("Increase the value");
2931 else if (actionName == decreaseAction)
2932 return QAccessibleActionInterface::tr("Decrease the value");
2933 else if (actionName == showMenuAction)
2934 return QAccessibleActionInterface::tr("Shows the menu");
2935 else if (actionName == setFocusAction)
2936 return QAccessibleActionInterface::tr("Sets the focus");
2937 else if (actionName == toggleAction)
2938 return QAccessibleActionInterface::tr("Toggles the state");
2939 else if (actionName == scrollLeftAction)
2940 return QAccessibleActionInterface::tr("Scrolls to the left");
2941 else if (actionName == scrollRightAction)
2942 return QAccessibleActionInterface::tr("Scrolls to the right");
2943 else if (actionName == scrollUpAction)
2944 return QAccessibleActionInterface::tr("Scrolls up");
2945 else if (actionName == scrollDownAction)
2946 return QAccessibleActionInterface::tr("Scrolls down");
2947 else if (actionName == previousPageAction)
2948 return QAccessibleActionInterface::tr("Goes back a page");
2949 else if (actionName == nextPageAction)
2950 return QAccessibleActionInterface::tr("Goes to the next page");
2951
2952
2953 return QString();
2954 }
2955};
2956
2957Q_GLOBAL_STATIC(QAccessibleActionStrings, accessibleActionStrings)
2958
2959QString QAccessibleActionInterface::localizedActionName(const QString &actionName) const
2960{
2961 return QAccessibleActionInterface::tr(qPrintable(actionName));
2962}
2963
2964QString QAccessibleActionInterface::localizedActionDescription(const QString &actionName) const
2965{
2966 return accessibleActionStrings()->localizedDescription(actionName);
2967}
2968
2973const QString &QAccessibleActionInterface::pressAction()
2974{
2975 return accessibleActionStrings()->pressAction;
2976}
2977
2982const QString &QAccessibleActionInterface::increaseAction()
2983{
2984 return accessibleActionStrings()->increaseAction;
2985}
2986
2991const QString &QAccessibleActionInterface::decreaseAction()
2992{
2993 return accessibleActionStrings()->decreaseAction;
2994}
2995
3000const QString &QAccessibleActionInterface::showMenuAction()
3001{
3002 return accessibleActionStrings()->showMenuAction;
3003}
3004
3009const QString &QAccessibleActionInterface::setFocusAction()
3010{
3011 return accessibleActionStrings()->setFocusAction;
3012}
3013
3018const QString &QAccessibleActionInterface::toggleAction()
3019{
3020 return accessibleActionStrings()->toggleAction;
3021}
3022
3027QString QAccessibleActionInterface::scrollLeftAction()
3028{
3029 return accessibleActionStrings()->scrollLeftAction;
3030}
3031
3036QString QAccessibleActionInterface::scrollRightAction()
3037{
3038 return accessibleActionStrings()->scrollRightAction;
3039}
3040
3045QString QAccessibleActionInterface::scrollUpAction()
3046{
3047 return accessibleActionStrings()->scrollUpAction;
3048}
3049
3054QString QAccessibleActionInterface::scrollDownAction()
3055{
3056 return accessibleActionStrings()->scrollDownAction;
3057}
3058
3063QString QAccessibleActionInterface::previousPageAction()
3064{
3065 return accessibleActionStrings()->previousPageAction;
3066}
3067
3072QString QAccessibleActionInterface::nextPageAction()
3073{
3074 return accessibleActionStrings()->nextPageAction;
3075}
3076
3077
3097QAccessibleSelectionInterface::~QAccessibleSelectionInterface()
3098{
3099}
3100
3126QAccessibleInterface* QAccessibleSelectionInterface::selectedItem(int selectionIndex) const
3127{
3128 QList<QAccessibleInterface*> items = selectedItems();
3129 if (selectionIndex < 0 || selectionIndex > items.length() -1) {
3130 qCWarning(lcAccessibilityCore) << "Selection index" << selectionIndex << "out of range.";
3131 return nullptr;
3132 }
3133
3134 return items.at(selectionIndex);
3135}
3136
3143bool QAccessibleSelectionInterface::isSelected(QAccessibleInterface *childItem) const
3144{
3145 return selectedItems().contains(childItem);
3146}
3147
3212QAccessibleAttributesInterface::~QAccessibleAttributesInterface()
3213{
3214}
3215
3233QString qAccessibleLocalizedActionDescription(const QString &actionName)
3234{
3235 return accessibleActionStrings()->localizedDescription(actionName);
3236}
3237
3271QAccessibleHyperlinkInterface::~QAccessibleHyperlinkInterface()
3272{
3273
3274}
3275
3276#endif // QT_CONFIG(accessibility)
3277
3279
3280#include "moc_qaccessible_base.cpp"
bool isActive
\inmodule QtGui
The QColor class provides colors based on RGB, HSV or CMYK values.
Definition qcolor.h:31
\inmodule QtCore
\inmodule QtCore
static QPlatformIntegration * platformIntegration()
qsizetype length() const noexcept
Definition qlist.h:399
const_reference at(qsizetype i) const noexcept
Definition qlist.h:446
static QObjectPrivate * get(QObject *o)
Definition qobject_p.h:150
\inmodule QtCore
Definition qobject.h:103
The QPlatformIntegration class is the entry for WindowSystem specific functionality.
\inmodule QtCore
\macro QT_RESTRICTED_CAST_FROM_ASCII
Definition qstring.h:129
qsizetype indexOf(QLatin1StringView s, qsizetype from=0, Qt::CaseSensitivity cs=Qt::CaseSensitive) const
Definition qstring.cpp:4517
qsizetype lastIndexOf(QChar c, Qt::CaseSensitivity cs=Qt::CaseSensitive) const noexcept
Definition qstring.h:296
QString mid(qsizetype position, qsizetype n=-1) const &
Definition qstring.cpp:5300
qsizetype size() const noexcept
Returns the number of characters in this string.
Definition qstring.h:186
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,...
\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:666
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)
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:1531
#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