5#include <AppKit/AppKit.h>
13#include <QtCore/qlogging.h>
14#include <QtGui/private/qaccessiblecache_p.h>
15#include <QtGui/private/qaccessiblebridgeutils_p.h>
16#include <QtGui/qaccessible.h>
20Q_STATIC_LOGGING_CATEGORY(lcAccessibilityTable,
"qt.accessibility.table")
22using namespace Qt::StringLiterals;
24#if QT_CONFIG(accessibility)
27
28
29
30
31
32
33
34
35
36
37
38
39static void convertLineOffset(QAccessibleTextInterface *text,
int *line,
int *offset, NSUInteger *start = 0, NSUInteger *end = 0)
41 Q_ASSERT(*line == -1 || *offset == -1);
42 Q_ASSERT(*line != -1 || *offset != -1);
43 Q_ASSERT(*offset <= text->characterCount());
46 int curStart = 0, curEnd = 0;
50 text->textAtOffset(curStart, QAccessible::LineBoundary, &curStart, &curEnd);
52 if (curStart == -1 || curEnd == -1) {
66 text->textAtOffset(curEnd, QAccessible::LineBoundary, &nextStart, &nextEnd);
67 if (nextEnd == curEnd)
70 }
while ((*line == -1 || curLine < *line) && (*offset == -1 || (curEnd <= *offset)) && curEnd <= text->characterCount());
72 curEnd = qMin(curEnd, text->characterCount());
79 Q_ASSERT(curStart >= 0);
80 Q_ASSERT(curEnd >= 0);
87@implementation QMacAccessibilityElement {
93 NSMutableArray<QMacAccessibilityElement *> *rows;
94 NSMutableArray<QMacAccessibilityElement *> *columns;
102 NSString *synthesizedRole;
105- (instancetype)initWithId:(QAccessible::Id)anId
107 return [self initWithId:anId role:nil];
110- (instancetype)initWithId:(QAccessible::Id)anId role:(NSAccessibilityRole)role
112 Q_ASSERT((
int)anId < 0);
120 synthesizedRole = role;
124 if (!synthesizedRole) {
125 if (QAccessibleInterface *iface = QAccessible::accessibleInterface(axid)) {
126 if (iface->tableInterface()) {
127 [self updateTableModel];
128 }
else if (
const auto *cell = iface->tableCellInterface()) {
131 m_rowIndex = cell->rowIndex();
132 m_columnIndex = cell->columnIndex();
133 QAccessibleInterface *table = cell->table();
135 QAccessibleTableInterface *tableInterface = table->tableInterface();
136 if (tableInterface) {
137 auto *tableElement = [QMacAccessibilityElement elementWithInterface:table];
138 Q_ASSERT(tableElement);
139 if (!tableElement->rows
140 ||
int(tableElement->rows.count) <= m_rowIndex
141 ||
int(tableElement->rows.count) != tableInterface->rowCount()) {
142 qCWarning(lcAccessibilityTable)
143 <<
"Cell requested for row" << m_rowIndex <<
"is out of"
144 <<
"bounds for table with" << (tableElement->rows ?
145 tableElement->rows.count : tableInterface->rowCount())
146 <<
"rows! Resizing table model.";
147 [tableElement updateTableModel];
150 Q_ASSERT(tableElement->rows);
151 Q_ASSERT(
int(tableElement->rows.count) > m_rowIndex);
153 auto *rowElement = tableElement->rows[m_rowIndex];
154 if (!rowElement->columns ||
int(rowElement->columns.count) != tableInterface->columnCount()) {
155 if (rowElement->columns) {
156 qCWarning(lcAccessibilityTable)
157 <<
"Table representation column count is out of sync:"
158 << rowElement->columns.count <<
"!=" << tableInterface->columnCount();
159 [rowElement->columns autorelease];
160 rowElement->columns = nil;
162 rowElement->columns = [rowElement populateTableRow:tableInterface->columnCount()];
163 [rowElement->columns retain];
166 qCDebug(lcAccessibilityTable) <<
"Creating cell representation for"
167 << m_rowIndex << m_columnIndex
169 << tableElement->rows.count <<
"rows and"
170 << rowElement->columns.count <<
"columns";
172 rowElement->columns[m_columnIndex] = self;
183
184
185
186
187
188
189
190
191+ (instancetype)elementWithId:(QAccessible::Id)anId
197 QAccessibleCache *cache = QAccessibleCache::instance();
199 QMacAccessibilityElement *element = cache->elementForId(anId);
201 Q_ASSERT(QAccessible::accessibleInterface(anId));
202 element = [[self alloc] initWithId:anId];
203 if (cache->insertElement(anId, element))
209+ (instancetype)elementWithInterface:(QAccessibleInterface *)iface
215 const QAccessible::Id anId = QAccessible::uniqueId(iface);
216 return [self elementWithId:anId];
227 [columns autorelease];
230 synthesizedRole = nil;
232 NSAccessibilityPostNotification(self, NSAccessibilityUIElementDestroyedNotification);
239 NSAccessibilityPostNotification(self, NSAccessibilityUIElementDestroyedNotification);
247- (BOOL)isEqual:(id)object {
248 if ([object isKindOfClass:[QMacAccessibilityElement
class]]) {
249 QMacAccessibilityElement *other = object;
252 return other == self;
254 return other->axid == axid && other->synthesizedRole == synthesizedRole
256 || (other->m_rowIndex == m_rowIndex && other->m_columnIndex == m_columnIndex));
266- (BOOL)isManagedByParent {
267 return synthesizedRole != nil;
270- (NSMutableArray *)populateTableArray:(NSAccessibilityRole)role count:(
int)count
272 if (self.qtInterface) {
273 auto *array = [NSMutableArray<QMacAccessibilityElement *> arrayWithCapacity:count];
275 for (
int n = 0; n < count; ++n) {
277 QMacAccessibilityElement *element =
278 [[QMacAccessibilityElement alloc] initWithId:axid role:role];
280 if (role == NSAccessibilityRowRole)
281 element->m_rowIndex = n;
282 else if (role == NSAccessibilityColumnRole)
283 element->m_columnIndex = n;
284 [array addObject:element];
287 qWarning(
"QCocoaAccessibility: invalid child");
295- (NSMutableArray *)populateTableRow:(
int)count
297 Q_ASSERT(synthesizedRole == NSAccessibilityRowRole);
298 qCDebug(lcAccessibilityTable) <<
"Populating table row" << m_rowIndex
299 <<
"with" << count <<
"placeholder cells";
308 auto *array = [NSMutableArray<QMacAccessibilityElement *> arrayWithCapacity:count];
311 for (
int n = 0; n < count; ++n) {
313 QMacAccessibilityElement *cell =
314 [[QMacAccessibilityElement alloc] initWithId:axid role:NSAccessibilityCellRole];
316 cell->m_rowIndex = m_rowIndex;
317 cell->m_columnIndex = n;
318 [array addObject:cell];
325- (
void)updateTableModel
327 if (QAccessibleInterface *iface = self.qtInterface) {
328 if (QAccessibleTableInterface *table = iface->tableInterface()) {
329 Q_ASSERT(!self.isManagedByParent);
330 qCDebug(lcAccessibilityTable) <<
"Updating table representation with"
331 << table->rowCount() << table->columnCount();
336 rows = [self populateTableArray:NSAccessibilityRowRole count:table->rowCount()];
339 [columns autorelease];
342 columns = [self populateTableArray:NSAccessibilityColumnRole count:table->columnCount()];
348- (QAccessibleInterface *)qtInterface
350 QAccessibleInterface *iface = QAccessible::accessibleInterface(axid);
351 if (!iface || !iface->isValid())
357 if (synthesizedRole == NSAccessibilityCellRole) {
359 QAccessibleTableInterface *table = iface->tableInterface();
361 QAccessibleInterface *cell = table->cellAt(m_rowIndex, m_columnIndex);
364 Q_ASSERT(cell->isValid());
368 axid = QAccessible::uniqueId(cell);
369 synthesizedRole = nil;
374 QAccessibleCache *cache = QAccessibleCache::instance();
375 Q_ASSERT(!cache->elementForId(axid) || !cache->elementForId(axid)->synthesizedRole);
376 cache->insertElement(axid, self);
385- (BOOL)isAccessibilityFocused
388 id focusedElement = NSApp.accessibilityApplicationFocusedUIElement;
389 return [focusedElement isEqual:self];
394+ (id) lineNumberForIndex: (
int)index forText:(
const QString &)text
396 auto textBefore = QStringView(text).left(index);
397 qsizetype newlines = textBefore.count(u'\n');
401- (BOOL) accessibilityNotifiesWhenDestroyed {
405- (NSString *) accessibilityRole {
408 return synthesizedRole;
409 if (QAccessibleInterface *iface = self.qtInterface)
410 return QCocoaAccessible::macRole(iface);
411 return NSAccessibilityUnknownRole;
414- (NSString *) accessibilitySubRole {
415 if (QAccessibleInterface *iface = self.qtInterface)
416 return QCocoaAccessible::macSubrole(iface);
417 return NSAccessibilityUnknownRole;
420- (NSString *) accessibilityRoleDescription {
421 if (self.qtInterface)
422 return NSAccessibilityRoleDescription(self.accessibilityRole, self.accessibilitySubRole);
423 return NSAccessibilityUnknownRole;
426- (NSArray *) accessibilityChildren {
428 if (synthesizedRole == NSAccessibilityCellRole)
431 QAccessibleInterface *iface = self.qtInterface;
434 if (QAccessibleTableInterface *table = iface->tableInterface()) {
436 if (!synthesizedRole) {
439
440
441
442
443
444
445
446
447
448
449
450
451
452
453
454
455
456
457
458
459
460
461
462
463
464
465
466
467
468
469 NSArray *rs = [self accessibilityRows];
470 NSArray *cs = [self accessibilityColumns];
471 const int rCount =
int([rs count]);
472 const int cCount =
int([cs count]);
473 int childCount = rCount + cCount;
474 NSMutableArray<QMacAccessibilityElement *> *tableChildren =
475 [NSMutableArray<QMacAccessibilityElement *> arrayWithCapacity:childCount];
476 for (
int i = 0; i < rCount; ++i) {
477 [tableChildren addObject:[rs objectAtIndex:i]];
479 for (
int i = 0; i < cCount; ++i) {
480 [tableChildren addObject:[cs objectAtIndex:i]];
482 return NSAccessibilityUnignoredChildren(tableChildren);
483 }
else if (synthesizedRole == NSAccessibilityColumnRole) {
485 }
else if (synthesizedRole == NSAccessibilityRowRole) {
488 Q_ASSERT(m_rowIndex >= 0);
489 Q_ASSERT(rows == nil);
490 const unsigned int numColumns = table->columnCount();
491 if (!columns || columns.count != numColumns) {
493 [columns autorelease];
496 columns = [self populateTableRow:numColumns];
499 return NSAccessibilityUnignoredChildren(columns);
502 return QCocoaAccessible::unignoredChildren(iface);
505- (NSArray *) accessibilitySelectedChildren {
506 QAccessibleInterface *iface = QAccessible::accessibleInterface(axid);
507 if (!iface || !iface->isValid())
510 QAccessibleSelectionInterface *selection = iface->selectionInterface();
514 const QList<QAccessibleInterface *> selectedList = selection->selectedItems();
515 const qsizetype numSelected = selectedList.size();
516 NSMutableArray<QMacAccessibilityElement *> *selectedChildren =
517 [NSMutableArray<QMacAccessibilityElement *> arrayWithCapacity:numSelected];
518 for (QAccessibleInterface *selectedChild : selectedList) {
519 if (selectedChild && selectedChild->isValid()) {
520 QAccessible::Id id = QAccessible::uniqueId(selectedChild);
521 QMacAccessibilityElement *element = [QMacAccessibilityElement elementWithId:id];
523 [selectedChildren addObject:element];
526 return NSAccessibilityUnignoredChildren(selectedChildren);
529- (id) accessibilityWindow {
531 NSAccessibilityElement *parent = self.accessibilityParent;
532 if (parent && parent.accessibilityRole == NSAccessibilityWindowRole)
534 return [parent accessibilityWindow];
537- (id) accessibilityTopLevelUIElementAttribute {
539 return [self.accessibilityParent accessibilityTopLevelUIElementAttribute];
542- (NSString *) accessibilityTitle {
543 if (QAccessibleInterface *iface = self.qtInterface) {
544 if (iface->role() == QAccessible::StaticText)
546 if (self.isManagedByParent)
548 return iface->text(QAccessible::Name).toNSString();
553- (id) accessibilityTitleUIElement {
554 QAccessibleInterface *iface = self.qtInterface;
558 const auto labelRelations = iface->relations(QAccessible::Label);
559 if (labelRelations.empty())
562 QAccessibleInterface *label = labelRelations.first().first;
566 QMacAccessibilityElement *accessibleElement = [QMacAccessibilityElement elementWithInterface:label];
567 if (!accessibleElement)
570 return NSAccessibilityUnignoredAncestor(accessibleElement);
573- (NSString*) accessibilityIdentifier {
574 if (QAccessibleInterface *iface = self.qtInterface)
575 return QAccessibleBridgeUtils::accessibleId(iface).toNSString();
579- (BOOL) isAccessibilityEnabled {
580 if (QAccessibleInterface *iface = self.qtInterface)
581 return !iface->state().disabled;
585- (id)accessibilityParent {
586 if (synthesizedRole == NSAccessibilityCellRole) {
587 QAccessibleInterface *tableInterface = QAccessible::accessibleInterface(axid);
588 if (!tableInterface || !tableInterface->isValid())
590 QMacAccessibilityElement *tableElement =
591 [QMacAccessibilityElement elementWithId:axid];
592 if (!tableElement->rows || m_rowIndex < 0
593 || m_rowIndex >=
int(tableElement->rows.count))
595 QMacAccessibilityElement *rowElement = tableElement->rows[m_rowIndex];
599 QAccessibleInterface *iface = self.qtInterface;
603 if (self.isManagedByParent) {
605 return NSAccessibilityUnignoredAncestor([QMacAccessibilityElement elementWithId:axid]);
608 if (QAccessibleInterface *parent = iface->parent()) {
609 if (parent->tableInterface()) {
610 QMacAccessibilityElement *tableElement =
611 [QMacAccessibilityElement elementWithInterface:parent];
616 if (QAccessibleTableCellInterface *cell = iface->tableCellInterface())
617 rowIndex = cell->rowIndex();
618 else if (m_rowIndex >= 0 && m_columnIndex >= 0)
619 rowIndex = m_rowIndex;
620 if (!tableElement->rows || rowIndex < 0 || rowIndex >=
int(tableElement->rows.count))
622 QMacAccessibilityElement *rowElement = tableElement->rows[rowIndex];
623 return NSAccessibilityUnignoredAncestor(rowElement);
628 if (!QCocoaAccessible::isRepresentedByAppKit(parent))
629 return NSAccessibilityUnignoredAncestor([QMacAccessibilityElement elementWithInterface: parent]);
632 if (QWindow *window = iface->window()) {
633 QPlatformWindow *platformWindow = window->handle();
634 if (platformWindow) {
635 QCocoaWindow *win =
static_cast<QCocoaWindow*>(platformWindow);
636 return NSAccessibilityUnignoredAncestor(qnsview_cast(win->view()));
642- (NSRect)accessibilityFrame {
643 QAccessibleInterface *iface = self.qtInterface;
648 if (self.isManagedByParent) {
649 if (QAccessibleTableInterface *table = iface->tableInterface()) {
656 const bool isRow = synthesizedRole == NSAccessibilityRowRole;
658 int &row = isRow ? cellPos.ry() : cellPos.rx();
659 int &col = isRow ? cellPos.rx() : cellPos.ry();
661 NSUInteger trackIndex = self.accessibilityIndex;
662 if (trackIndex != NSNotFound) {
663 row =
int(trackIndex);
664 if (QAccessibleInterface *firstCell = table->cellAt(cellPos.y(), cellPos.x())) {
665 rect = firstCell->rect();
666 col = isRow ? table->columnCount() : table->rowCount();
669 if (QAccessibleInterface *lastCell =
670 table->cellAt(cellPos.y(), cellPos.x()))
671 rect = rect.united(lastCell->rect());
677 rect = iface->rect();
680 return QCocoaScreen::mapToNative(rect);
683- (NSString*)accessibilityLabel {
684 if (QAccessibleInterface *iface = self.qtInterface)
685 return iface->text(QAccessible::Description).toNSString();
686 qWarning() <<
"Called accessibilityLabel on invalid object: " << axid;
690- (
void)setAccessibilityLabel:(NSString*)label{
691 if (QAccessibleInterface *iface = self.qtInterface)
692 iface->setText(QAccessible::Description, QString::fromNSString(label));
695- (NSAccessibilityOrientation)accessibilityOrientation {
696 QAccessibleInterface *iface = self.qtInterface;
698 return NSAccessibilityOrientationUnknown;
700 NSAccessibilityOrientation nsOrientation = NSAccessibilityOrientationUnknown;
701 if (QAccessibleAttributesInterface *attributesIface = iface->attributesInterface()) {
702 const QVariant orientationVariant =
703 attributesIface->attributeValue(QAccessible::Attribute::Orientation);
704 if (orientationVariant.isValid()) {
705 Q_ASSERT(orientationVariant.canConvert<Qt::Orientation>());
706 const Qt::Orientation orientation = orientationVariant.value<Qt::Orientation>();
707 nsOrientation = orientation == Qt::Horizontal ? NSAccessibilityOrientationHorizontal
708 : NSAccessibilityOrientationVertical;
711 return nsOrientation;
714- (id) accessibilityValue {
715 if (QAccessibleInterface *iface = self.qtInterface) {
718 if (QCocoaAccessible::hasValueAttribute(iface))
719 return QCocoaAccessible::getValueAttribute(iface);
725- (id) accessibilityMinValue {
726 if (QAccessibleInterface *iface = self.qtInterface) {
727 if (iface->valueInterface()) {
728 return iface->valueInterface()->minimumValue().toString().toNSString();
735- (id) accessibilityMaxValue {
736 if (QAccessibleInterface *iface = self.qtInterface) {
737 if (iface->valueInterface()) {
738 return iface->valueInterface()->maximumValue().toString().toNSString();
744- (NSInteger) accessibilityNumberOfCharacters {
745 if (QAccessibleInterface *iface = self.qtInterface) {
746 if (QAccessibleTextInterface *text = iface->textInterface())
747 return text->characterCount();
752- (NSString *) accessibilitySelectedText {
753 if (QAccessibleInterface *iface = self.qtInterface) {
754 if (QAccessibleTextInterface *text = iface->textInterface()) {
757 text->selection(0, &start, &end);
758 return text->text(start, end).toNSString();
764- (NSRange) accessibilitySelectedTextRange {
765 QAccessibleInterface *iface = self.qtInterface;
768 if (QAccessibleTextInterface *text = iface->textInterface()) {
771 if (text->selectionCount() > 0) {
772 text->selection(0, &start, &end);
774 start = text->cursorPosition();
777 return NSMakeRange(quint32(start), quint32(end - start));
779 return NSMakeRange(0, 0);
782- (NSInteger)accessibilityLineForIndex:(NSInteger)index {
783 QAccessibleInterface *iface = self.qtInterface;
786 if (QAccessibleTextInterface *text = iface->textInterface()) {
787 QString textToPos = text->text(0, index);
788 return textToPos.count(
'\n');
793- (NSRange)accessibilityVisibleCharacterRange {
794 QAccessibleInterface *iface = self.qtInterface;
798 if (QAccessibleTextInterface *text = iface->textInterface())
799 return NSMakeRange(0,
static_cast<uint>(text->characterCount()));
800 return NSMakeRange(0,
static_cast<uint>(iface->text(QAccessible::Name).length()));
803- (NSInteger) accessibilityInsertionPointLineNumber {
804 QAccessibleInterface *iface = self.qtInterface;
807 if (QAccessibleTextInterface *text = iface->textInterface()) {
808 int position = text->cursorPosition();
809 return [self accessibilityLineForIndex:position];
814- (NSArray *)accessibilityAttributeNames {
815 NSMutableArray *attributes = [[NSMutableArray
new] autorelease];
816 QAccessibleInterface *iface = self.qtInterface;
818#if QT_APPLE_SDK_EQUAL_OR_ABOVE(MACOS(26
))
819 if (@available(macOS 26, *)) {
820 [attributes addObject:NSAccessibilityLanguageAttribute];
822 if (iface && iface->role() == QAccessible::Heading) {
823 QAccessibleAttributesInterface *attributesIface = iface->attributesInterface();
825 && attributesIface->attributeKeys().contains(QAccessible::Attribute::Level))
826 [attributes addObject:NSAccessibilityHeadingLevelAttribute];
831 if (iface && iface->state().expandable)
832 [attributes addObject:NSAccessibilityExpandedAttribute];
837- (id)accessibilityAttributeValue:(NSString *)attribute {
838 QAccessibleInterface *iface = self.qtInterface;
840 qWarning() <<
"Called attribute on invalid object: " << axid;
844#if QT_APPLE_SDK_EQUAL_OR_ABOVE(MACOS(26
))
845 if (@available(macOS 26, *)) {
846 if ([attribute isEqualToString:NSAccessibilityLanguageAttribute]) {
847 QAccessibleAttributesInterface *attributesIface = iface->attributesInterface();
849 || !attributesIface->attributeKeys().contains(QAccessible::Attribute::Locale))
852 const auto &localeVariant =
853 attributesIface->attributeValue(QAccessible::Attribute::Locale);
854 return localeVariant.toLocale().bcp47Name().toNSString();
857 if ([attribute isEqualToString:NSAccessibilityHeadingLevelAttribute]) {
858 if (iface->role() != QAccessible::Heading)
861 auto attributesIface = iface->attributesInterface();
862 if (!attributesIface)
865 const QVariant levelVariant =
866 attributesIface->attributeValue(QAccessible::Attribute::Level);
867 if (!levelVariant.isValid() || !levelVariant.canConvert<
int>())
870 const int level = levelVariant.toInt();
879 if ([attribute isEqualToString:NSAccessibilityExpandedAttribute])
880 return iface->state().expanded ? @YES : @NO;
885- (NSArray *)accessibilityParameterizedAttributeNames {
887 QAccessibleInterface *iface = self.qtInterface;
889 qWarning() <<
"Called attribute on invalid object: " << axid;
893 if (iface->textInterface()) {
895 NSAccessibilityStringForRangeParameterizedAttribute,
896 NSAccessibilityLineForIndexParameterizedAttribute,
897 NSAccessibilityRangeForLineParameterizedAttribute,
898 NSAccessibilityRangeForPositionParameterizedAttribute,
900 NSAccessibilityBoundsForRangeParameterizedAttribute,
902 NSAccessibilityStyleRangeForIndexParameterizedAttribute,
903 NSAccessibilityAttributedStringForRangeParameterizedAttribute
910- (id)accessibilityAttributeValue:(NSString *)attribute forParameter:(id)parameter {
911 QAccessibleInterface *iface = self.qtInterface;
913 qWarning() <<
"Called attribute on invalid object: " << axid;
917 if (!iface->textInterface())
920 if ([attribute isEqualToString: NSAccessibilityStringForRangeParameterizedAttribute]) {
921 NSRange range = [parameter rangeValue];
922 QString text = iface->textInterface()->text(range.location, range.location + range.length);
923 return text.toNSString();
925 if ([attribute isEqualToString: NSAccessibilityLineForIndexParameterizedAttribute]) {
926 int index = [parameter intValue];
927 if (index < 0 || index > iface->textInterface()->characterCount())
930 if (iface->state().multiLine) {
932 convertLineOffset(iface->textInterface(), &line, &index);
936 if ([attribute isEqualToString: NSAccessibilityRangeForLineParameterizedAttribute]) {
937 int line = [parameter intValue];
941 NSUInteger startOffset = 0;
942 NSUInteger endOffset = 0;
943 convertLineOffset(iface->textInterface(), &line, &lineOffset, &startOffset, &endOffset);
944 return [NSValue valueWithRange:NSMakeRange(startOffset, endOffset - startOffset)];
946 if ([attribute isEqualToString: NSAccessibilityBoundsForRangeParameterizedAttribute]) {
947 NSRange range = [parameter rangeValue];
948 QRect firstRect = iface->textInterface()->characterRect(range.location);
950 if (range.length > 0) {
951 NSUInteger position = range.location + range.length - 1;
952 if (position > range.location && iface->textInterface()->text(position, position + 1) ==
"\n"_L1)
954 QRect lastRect = iface->textInterface()->characterRect(position);
955 rect = firstRect.united(lastRect);
960 return [NSValue valueWithRect:QCocoaScreen::mapToNative(rect)];
962 if ([attribute isEqualToString: NSAccessibilityAttributedStringForRangeParameterizedAttribute]) {
963 NSRange range = [parameter rangeValue];
964 QString text = iface->textInterface()->text(range.location, range.location + range.length);
965 return [[NSAttributedString alloc] initWithString:text.toNSString()];
966 }
else if ([attribute isEqualToString: NSAccessibilityRangeForPositionParameterizedAttribute]) {
967 QPoint point = QCocoaScreen::mapFromNative([parameter pointValue]).toPoint();
968 int offset = iface->textInterface()->offsetAtPoint(point);
969 return [NSValue valueWithRange:NSMakeRange(
static_cast<NSUInteger>(offset), 1)];
970 }
else if ([attribute isEqualToString: NSAccessibilityStyleRangeForIndexParameterizedAttribute]) {
973 iface->textInterface()->attributes([parameter intValue], &start, &end);
974 return [NSValue valueWithRange:NSMakeRange(
static_cast<NSUInteger>(start),
static_cast<NSUInteger>(end - start))];
979- (BOOL)accessibilityIsAttributeSettable:(NSString *)attribute {
980 QAccessibleInterface *iface = self.qtInterface;
984 if ([attribute isEqualToString:NSAccessibilityFocusedAttribute]) {
985 return iface->state().focusable ? YES : NO;
986 }
else if ([attribute isEqualToString:NSAccessibilityValueAttribute]) {
987 if (iface->textInterface() && iface->state().editable)
989 if (iface->valueInterface())
992 }
else if ([attribute isEqualToString:NSAccessibilitySelectedTextRangeAttribute]) {
993 return iface->textInterface() ? YES : NO;
998- (
void)accessibilitySetValue:(id)value forAttribute:(NSString *)attribute {
999 QAccessibleInterface *iface = self.qtInterface;
1002 if ([attribute isEqualToString:NSAccessibilityFocusedAttribute]) {
1003 if (QAccessibleActionInterface *action = iface->actionInterface())
1004 action->doAction(QAccessibleActionInterface::setFocusAction());
1005 }
else if ([attribute isEqualToString:NSAccessibilityValueAttribute]) {
1006 if (iface->textInterface()) {
1007 QString text = QString::fromNSString((NSString *)value);
1008 iface->setText(QAccessible::Value, text);
1009 }
else if (QAccessibleValueInterface *valueIface = iface->valueInterface()) {
1010 double val = [value doubleValue];
1011 valueIface->setCurrentValue(val);
1013 }
else if ([attribute isEqualToString:NSAccessibilitySelectedTextRangeAttribute]) {
1014 if (QAccessibleTextInterface *text = iface->textInterface()) {
1015 NSRange range = [value rangeValue];
1016 if (range.length > 0)
1017 text->setSelection(0, range.location, range.location + range.length);
1019 text->setCursorPosition(range.location);
1026- (NSArray *)accessibilityActionNames {
1027 NSMutableArray *nsActions = [[NSMutableArray
new] autorelease];
1028 QAccessibleInterface *iface = self.qtInterface;
1032 const QStringList &supportedActionNames = QAccessibleBridgeUtils::effectiveActionNames(iface);
1033 for (
const QString &qtAction : supportedActionNames) {
1034 NSString *nsAction = QCocoaAccessible::getTranslatedAction(qtAction);
1036 [nsActions addObject : nsAction];
1042- (NSString *)accessibilityActionDescription:(NSString *)action {
1043 QAccessibleInterface *iface = self.qtInterface;
1046 QString qtAction = QCocoaAccessible::translateAction(action, iface);
1047 QString description;
1049 if (qtAction.isEmpty()) {
1050 if (QAccessibleActionInterface *actionInterface = iface->actionInterface()) {
1051 qtAction = QString::fromNSString((NSString *)action);
1052 description = actionInterface->localizedActionDescription(qtAction);
1055 description = qAccessibleLocalizedActionDescription(qtAction);
1057 return description.toNSString();
1060- (
void)accessibilityPerformAction:(NSString *)action {
1061 if (QAccessibleInterface *iface = self.qtInterface) {
1062 const QString qtAction = QCocoaAccessible::translateAction(action, iface);
1063 QAccessibleBridgeUtils::performEffectiveAction(iface, qtAction);
1069- (BOOL)accessibilityIsIgnored {
1073 if (self.isManagedByParent)
1076 if (QAccessibleInterface *iface = self.qtInterface)
1077 return QCocoaAccessible::shouldBeIgnored(iface);
1081- (id)accessibilityHitTest:(NSPoint)point
1083 QAccessibleInterface *iface = self.qtInterface;
1085 return NSAccessibilityUnignoredAncestor(self);
1087 QPointF screenPoint = QCocoaScreen::mapFromNative(point);
1088 QWindow *window = QAccessibleBridgeUtils::windowFor(iface);
1092 QAccessibleInterface *childInterface = iface;
1093 while (QAccessibleInterface *child = childInterface->childAt(screenPoint.x(), screenPoint.y())) {
1094 if (!child->isValid())
1097 QWindow *childWindow = QAccessibleBridgeUtils::windowFor(child, childInterface, window);
1098 if (childWindow != window) {
1099 if (
auto *view = QCocoaAccessible::accessibleViewFor(childWindow))
1100 return [view accessibilityHitTest:point];
1103 childInterface = child;
1107 if (childInterface == iface)
1108 return NSAccessibilityUnignoredAncestor(self);
1111 QMacAccessibilityElement *accessibleElement = [QMacAccessibilityElement elementWithInterface:childInterface];
1112 if (accessibleElement)
1113 return NSAccessibilityUnignoredAncestor(accessibleElement);
1114 return NSAccessibilityUnignoredAncestor(self);
1117- (id)accessibilityFocusedUIElement {
1118 QAccessibleInterface *iface = self.qtInterface;
1120 qWarning(
"FocusedUIElement for INVALID");
1124 QAccessibleInterface *focusInterface = iface->focusChild();
1125 if (focusInterface && focusInterface->isValid()) {
1132 QWindow *window = QAccessibleBridgeUtils::windowFor(iface);
1133 QWindow *focusWindow = QAccessibleBridgeUtils::windowFor(focusInterface, iface, window);
1134 if (focusWindow != window) {
1135 if (
auto *view = QCocoaAccessible::accessibleViewFor(focusWindow))
1136 return [view accessibilityFocusedUIElement];
1139 QMacAccessibilityElement *accessibleElement = [QMacAccessibilityElement elementWithInterface:focusInterface];
1140 return NSAccessibilityUnignoredAncestor(accessibleElement);
1143 return NSAccessibilityUnignoredAncestor(self);
1146- (NSString *) accessibilityHelp {
1147 if (QAccessibleInterface *iface = self.qtInterface) {
1148 const QString helpText = iface->text(QAccessible::Help);
1149 if (!helpText.isEmpty())
1150 return helpText.toNSString();
1156
1157
1158- (NSInteger) accessibilityIndex {
1159 NSInteger index = 0;
1160 if (synthesizedRole == NSAccessibilityCellRole)
1161 return m_columnIndex;
1162 if (QAccessibleInterface *iface = self.qtInterface) {
1163 if (self.isManagedByParent) {
1166 if (iface->tableInterface()) {
1167 if (m_rowIndex >= 0)
1168 index = NSInteger(m_rowIndex);
1169 else if (m_columnIndex >= 0)
1170 index = NSInteger(m_columnIndex);
1177- (NSArray *) accessibilityRows {
1178 if (!synthesizedRole && rows) {
1179 QAccessibleInterface *iface = self.qtInterface;
1180 QAccessibleTableInterface *tableInterface = iface ? iface->tableInterface() :
nullptr;
1181 if (tableInterface) {
1182 const unsigned int rowCount = tableInterface->rowCount();
1183 if (rows.count != rowCount) {
1184 qCDebug(lcAccessibilityTable) <<
"Updating table rows with" << rowCount <<
"rows";
1189 rows = [self populateTableArray:NSAccessibilityRowRole
1193 return NSAccessibilityUnignoredChildren(rows);
1199- (NSArray *) accessibilityColumns {
1201 if (!synthesizedRole && columns) {
1202 QAccessibleInterface *iface = self.qtInterface;
1203 if (iface && iface->tableInterface())
1204 return NSAccessibilityUnignoredChildren(columns);
1211- (NSArray *) accessibilityTabs {
1212 QAccessibleInterface *iface = self.qtInterface;
1213 if (iface && iface->role() == QAccessible::PageTabList) {
1214 return QCocoaAccessible::unignoredChildren(iface, [](QAccessibleInterface *child){
1215 return QCocoaAccessible::defaultUnignored(child)
1216 && child->role() == QAccessible::PageTab;