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];
219+ (
void)removeElementsFromCache:(NSArray *)array {
220 for (uint i = 0; i < array.count; ++i) {
221 QMacAccessibilityElement *cell = [array objectAtIndex:i];
223 QAccessibleCache::instance()->deleteInterface(cell->axid);
232 [QMacAccessibilityElement removeElementsFromCache:rows];
237 [QMacAccessibilityElement removeElementsFromCache:columns];
238 [columns autorelease];
241 synthesizedRole = nil;
243 NSAccessibilityPostNotification(self, NSAccessibilityUIElementDestroyedNotification);
247
248
249
250
251
252
253
254
255
256
259 [QMacAccessibilityElement removeElementsFromCache:rows];
263 [QMacAccessibilityElement removeElementsFromCache:columns];
266 QAccessibleCache::instance()->deleteInterface(axid);
270- (BOOL)isEqual:(id)object {
271 if ([object isKindOfClass:[QMacAccessibilityElement
class]]) {
272 QMacAccessibilityElement *other = object;
273 return other->axid == axid && other->synthesizedRole == synthesizedRole;
283- (BOOL)isManagedByParent {
284 return synthesizedRole != nil;
287- (NSMutableArray *)populateTableArray:(NSAccessibilityRole)role count:(
int)count
289 if (self.qtInterface) {
290 auto *array = [NSMutableArray<QMacAccessibilityElement *> arrayWithCapacity:count];
292 for (
int n = 0; n < count; ++n) {
294 QMacAccessibilityElement *element =
295 [[QMacAccessibilityElement alloc] initWithId:axid role:role];
297 if (role == NSAccessibilityRowRole)
298 element->m_rowIndex = n;
299 else if (role == NSAccessibilityColumnRole)
300 element->m_columnIndex = n;
301 [array addObject:element];
304 qWarning(
"QCocoaAccessibility: invalid child");
312- (NSMutableArray *)populateTableRow:(
int)count
314 Q_ASSERT(synthesizedRole == NSAccessibilityRowRole);
315 qCDebug(lcAccessibilityTable) <<
"Populating table row" << m_rowIndex
316 <<
"with" << count <<
"placeholder cells";
325 auto *array = [NSMutableArray<QMacAccessibilityElement *> arrayWithCapacity:count];
328 for (
int n = 0; n < count; ++n) {
330 QMacAccessibilityElement *cell =
331 [[QMacAccessibilityElement alloc] initWithId:axid role:NSAccessibilityCellRole];
333 cell->m_rowIndex = m_rowIndex;
334 cell->m_columnIndex = n;
335 [array addObject:cell];
342- (
void)updateTableModel
344 if (QAccessibleInterface *iface = self.qtInterface) {
345 if (QAccessibleTableInterface *table = iface->tableInterface()) {
346 Q_ASSERT(!self.isManagedByParent);
347 qCDebug(lcAccessibilityTable) <<
"Updating table representation with"
348 << table->rowCount() << table->columnCount();
353 rows = [self populateTableArray:NSAccessibilityRowRole count:table->rowCount()];
356 [columns autorelease];
359 columns = [self populateTableArray:NSAccessibilityColumnRole count:table->columnCount()];
365- (QAccessibleInterface *)qtInterface
367 QAccessibleInterface *iface = QAccessible::accessibleInterface(axid);
368 if (!iface || !iface->isValid())
374 if (synthesizedRole == NSAccessibilityCellRole) {
376 QAccessibleTableInterface *table = iface->tableInterface();
378 QAccessibleInterface *cell = table->cellAt(m_rowIndex, m_columnIndex);
381 Q_ASSERT(cell->isValid());
385 axid = QAccessible::uniqueId(cell);
386 synthesizedRole = nil;
388 QAccessibleCache *cache = QAccessibleCache::instance();
389 if (QMacAccessibilityElement *cellElement = cache->elementForId(axid)) {
391 Q_ASSERT(cellElement->synthesizedRole == nil);
393 if (cellElement != self) {
395 Q_ASSERT(cellElement->m_rowIndex == m_rowIndex && cellElement->m_columnIndex == m_columnIndex);
399 cache->insertElement(axid, self);
408- (BOOL)isAccessibilityFocused
411 id focusedElement = NSApp.accessibilityApplicationFocusedUIElement;
412 return [focusedElement isEqual:self];
417+ (id) lineNumberForIndex: (
int)index forText:(
const QString &)text
419 auto textBefore = QStringView(text).left(index);
420 qsizetype newlines = textBefore.count(u'\n');
424- (BOOL) accessibilityNotifiesWhenDestroyed {
428- (NSString *) accessibilityRole {
431 return synthesizedRole;
432 if (QAccessibleInterface *iface = self.qtInterface)
433 return QCocoaAccessible::macRole(iface);
434 return NSAccessibilityUnknownRole;
437- (NSString *) accessibilitySubRole {
438 if (QAccessibleInterface *iface = self.qtInterface)
439 return QCocoaAccessible::macSubrole(iface);
440 return NSAccessibilityUnknownRole;
443- (NSString *) accessibilityRoleDescription {
444 if (self.qtInterface)
445 return NSAccessibilityRoleDescription(self.accessibilityRole, self.accessibilitySubRole);
446 return NSAccessibilityUnknownRole;
449- (NSArray *) accessibilityChildren {
451 if (synthesizedRole == NSAccessibilityCellRole)
454 QAccessibleInterface *iface = self.qtInterface;
457 if (QAccessibleTableInterface *table = iface->tableInterface()) {
459 if (!synthesizedRole) {
462
463
464
465
466
467
468
469
470
471
472
473
474
475
476
477
478
479
480
481
482
483
484
485
486
487
488
489
490
491
492 NSArray *rs = [self accessibilityRows];
493 NSArray *cs = [self accessibilityColumns];
494 const int rCount =
int([rs count]);
495 const int cCount =
int([cs count]);
496 int childCount = rCount + cCount;
497 NSMutableArray<QMacAccessibilityElement *> *tableChildren =
498 [NSMutableArray<QMacAccessibilityElement *> arrayWithCapacity:childCount];
499 for (
int i = 0; i < rCount; ++i) {
500 [tableChildren addObject:[rs objectAtIndex:i]];
502 for (
int i = 0; i < cCount; ++i) {
503 [tableChildren addObject:[cs objectAtIndex:i]];
505 return NSAccessibilityUnignoredChildren(tableChildren);
506 }
else if (synthesizedRole == NSAccessibilityColumnRole) {
508 }
else if (synthesizedRole == NSAccessibilityRowRole) {
511 Q_ASSERT(m_rowIndex >= 0);
512 Q_ASSERT(rows == nil);
513 const unsigned int numColumns = table->columnCount();
514 if (!columns || columns.count != numColumns) {
516 [columns autorelease];
519 columns = [self populateTableRow:numColumns];
522 return NSAccessibilityUnignoredChildren(columns);
525 return QCocoaAccessible::unignoredChildren(iface);
528- (NSArray *) accessibilitySelectedChildren {
529 QAccessibleInterface *iface = QAccessible::accessibleInterface(axid);
530 if (!iface || !iface->isValid())
533 QAccessibleSelectionInterface *selection = iface->selectionInterface();
537 const QList<QAccessibleInterface *> selectedList = selection->selectedItems();
538 const qsizetype numSelected = selectedList.size();
539 NSMutableArray<QMacAccessibilityElement *> *selectedChildren =
540 [NSMutableArray<QMacAccessibilityElement *> arrayWithCapacity:numSelected];
541 for (QAccessibleInterface *selectedChild : selectedList) {
542 if (selectedChild && selectedChild->isValid()) {
543 QAccessible::Id id = QAccessible::uniqueId(selectedChild);
544 QMacAccessibilityElement *element = [QMacAccessibilityElement elementWithId:id];
546 [selectedChildren addObject:element];
549 return NSAccessibilityUnignoredChildren(selectedChildren);
552- (id) accessibilityWindow {
554 NSAccessibilityElement *parent = self.accessibilityParent;
555 if (parent && parent.accessibilityRole == NSAccessibilityWindowRole)
557 return [parent accessibilityWindow];
560- (id) accessibilityTopLevelUIElementAttribute {
562 return [self.accessibilityParent accessibilityTopLevelUIElementAttribute];
565- (NSString *) accessibilityTitle {
566 if (QAccessibleInterface *iface = self.qtInterface) {
567 if (iface->role() == QAccessible::StaticText)
569 if (self.isManagedByParent)
571 return iface->text(QAccessible::Name).toNSString();
576- (id) accessibilityTitleUIElement {
577 QAccessibleInterface *iface = self.qtInterface;
581 const auto labelRelations = iface->relations(QAccessible::Label);
582 if (labelRelations.empty())
585 QAccessibleInterface *label = labelRelations.first().first;
589 QMacAccessibilityElement *accessibleElement = [QMacAccessibilityElement elementWithInterface:label];
590 if (!accessibleElement)
593 return NSAccessibilityUnignoredAncestor(accessibleElement);
596- (NSString*) accessibilityIdentifier {
597 if (QAccessibleInterface *iface = self.qtInterface)
598 return QAccessibleBridgeUtils::accessibleId(iface).toNSString();
602- (BOOL) isAccessibilityEnabled {
603 if (QAccessibleInterface *iface = self.qtInterface)
604 return !iface->state().disabled;
608- (id)accessibilityParent {
609 if (synthesizedRole == NSAccessibilityCellRole) {
611 QMacAccessibilityElement *tableElement =
612 [QMacAccessibilityElement elementWithId:axid];
613 Q_ASSERT(tableElement && tableElement->rows);
614 Q_ASSERT(
int(tableElement->rows.count) > m_rowIndex);
615 QMacAccessibilityElement *rowElement = tableElement->rows[m_rowIndex];
619 QAccessibleInterface *iface = self.qtInterface;
623 if (self.isManagedByParent) {
625 return NSAccessibilityUnignoredAncestor([QMacAccessibilityElement elementWithId:axid]);
628 if (QAccessibleInterface *parent = iface->parent()) {
629 if (parent->tableInterface()) {
630 QMacAccessibilityElement *tableElement =
631 [QMacAccessibilityElement elementWithInterface:parent];
635 if (m_rowIndex >= 0 && m_columnIndex >= 0)
636 rowIndex = m_rowIndex;
637 else if (QAccessibleTableCellInterface *cell = iface->tableCellInterface())
638 rowIndex = cell->rowIndex();
639 Q_ASSERT(tableElement->rows);
640 if (rowIndex >
int([tableElement->rows count]) || rowIndex == -1)
642 QMacAccessibilityElement *rowElement = tableElement->rows[rowIndex];
643 return NSAccessibilityUnignoredAncestor(rowElement);
648 if (!QCocoaAccessible::isRepresentedByAppKit(parent))
649 return NSAccessibilityUnignoredAncestor([QMacAccessibilityElement elementWithInterface: parent]);
652 if (QWindow *window = iface->window()) {
653 QPlatformWindow *platformWindow = window->handle();
654 if (platformWindow) {
655 QCocoaWindow *win =
static_cast<QCocoaWindow*>(platformWindow);
656 return NSAccessibilityUnignoredAncestor(qnsview_cast(win->view()));
662- (NSRect)accessibilityFrame {
663 QAccessibleInterface *iface = self.qtInterface;
668 if (self.isManagedByParent) {
669 if (QAccessibleTableInterface *table = iface->tableInterface()) {
676 const bool isRow = synthesizedRole == NSAccessibilityRowRole;
678 int &row = isRow ? cellPos.ry() : cellPos.rx();
679 int &col = isRow ? cellPos.rx() : cellPos.ry();
681 NSUInteger trackIndex = self.accessibilityIndex;
682 if (trackIndex != NSNotFound) {
683 row =
int(trackIndex);
684 if (QAccessibleInterface *firstCell = table->cellAt(cellPos.y(), cellPos.x())) {
685 rect = firstCell->rect();
686 col = isRow ? table->columnCount() : table->rowCount();
689 if (QAccessibleInterface *lastCell =
690 table->cellAt(cellPos.y(), cellPos.x()))
691 rect = rect.united(lastCell->rect());
697 rect = iface->rect();
700 return QCocoaScreen::mapToNative(rect);
703- (NSString*)accessibilityLabel {
704 if (QAccessibleInterface *iface = self.qtInterface)
705 return iface->text(QAccessible::Description).toNSString();
706 qWarning() <<
"Called accessibilityLabel on invalid object: " << axid;
710- (
void)setAccessibilityLabel:(NSString*)label{
711 if (QAccessibleInterface *iface = self.qtInterface)
712 iface->setText(QAccessible::Description, QString::fromNSString(label));
715- (NSAccessibilityOrientation)accessibilityOrientation {
716 QAccessibleInterface *iface = self.qtInterface;
718 return NSAccessibilityOrientationUnknown;
720 NSAccessibilityOrientation nsOrientation = NSAccessibilityOrientationUnknown;
721 if (QAccessibleAttributesInterface *attributesIface = iface->attributesInterface()) {
722 const QVariant orientationVariant =
723 attributesIface->attributeValue(QAccessible::Attribute::Orientation);
724 if (orientationVariant.isValid()) {
725 Q_ASSERT(orientationVariant.canConvert<Qt::Orientation>());
726 const Qt::Orientation orientation = orientationVariant.value<Qt::Orientation>();
727 nsOrientation = orientation == Qt::Horizontal ? NSAccessibilityOrientationHorizontal
728 : NSAccessibilityOrientationVertical;
731 return nsOrientation;
734- (id) accessibilityValue {
735 if (QAccessibleInterface *iface = self.qtInterface) {
738 if (QCocoaAccessible::hasValueAttribute(iface))
739 return QCocoaAccessible::getValueAttribute(iface);
745- (id) accessibilityMinValue {
746 if (QAccessibleInterface *iface = self.qtInterface) {
747 if (iface->valueInterface()) {
748 return iface->valueInterface()->minimumValue().toString().toNSString();
755- (id) accessibilityMaxValue {
756 if (QAccessibleInterface *iface = self.qtInterface) {
757 if (iface->valueInterface()) {
758 return iface->valueInterface()->maximumValue().toString().toNSString();
764- (NSInteger) accessibilityNumberOfCharacters {
765 if (QAccessibleInterface *iface = self.qtInterface) {
766 if (QAccessibleTextInterface *text = iface->textInterface())
767 return text->characterCount();
772- (NSString *) accessibilitySelectedText {
773 if (QAccessibleInterface *iface = self.qtInterface) {
774 if (QAccessibleTextInterface *text = iface->textInterface()) {
777 text->selection(0, &start, &end);
778 return text->text(start, end).toNSString();
784- (NSRange) accessibilitySelectedTextRange {
785 QAccessibleInterface *iface = self.qtInterface;
788 if (QAccessibleTextInterface *text = iface->textInterface()) {
791 if (text->selectionCount() > 0) {
792 text->selection(0, &start, &end);
794 start = text->cursorPosition();
797 return NSMakeRange(quint32(start), quint32(end - start));
799 return NSMakeRange(0, 0);
802- (NSInteger)accessibilityLineForIndex:(NSInteger)index {
803 QAccessibleInterface *iface = self.qtInterface;
806 if (QAccessibleTextInterface *text = iface->textInterface()) {
807 QString textToPos = text->text(0, index);
808 return textToPos.count(
'\n');
813- (NSRange)accessibilityVisibleCharacterRange {
814 QAccessibleInterface *iface = self.qtInterface;
818 if (QAccessibleTextInterface *text = iface->textInterface())
819 return NSMakeRange(0,
static_cast<uint>(text->characterCount()));
820 return NSMakeRange(0,
static_cast<uint>(iface->text(QAccessible::Name).length()));
823- (NSInteger) accessibilityInsertionPointLineNumber {
824 QAccessibleInterface *iface = self.qtInterface;
827 if (QAccessibleTextInterface *text = iface->textInterface()) {
828 int position = text->cursorPosition();
829 return [self accessibilityLineForIndex:position];
834- (NSArray *)accessibilityAttributeNames {
835 NSMutableArray *attributes = [[NSMutableArray
new] autorelease];
837#if QT_APPLE_SDK_EQUAL_OR_ABOVE(MACOS(26
))
838 if (@available(macOS 26, *))
839 [attributes addObject:NSAccessibilityLanguageAttribute];
842 QAccessibleInterface *iface = self.qtInterface;
843 if (iface && iface->state().expandable)
844 [attributes addObject:NSAccessibilityExpandedAttribute];
849- (id)accessibilityAttributeValue:(NSString *)attribute {
850 QAccessibleInterface *iface = self.qtInterface;
852 qWarning() <<
"Called attribute on invalid object: " << axid;
856#if QT_APPLE_SDK_EQUAL_OR_ABOVE(MACOS(26
))
857 if (@available(macOS 26, *)) {
858 if ([attribute isEqualToString:NSAccessibilityLanguageAttribute]) {
859 QAccessibleAttributesInterface *attributesIface = iface->attributesInterface();
861 || !attributesIface->attributeKeys().contains(QAccessible::Attribute::Locale))
864 const auto &localeVariant =
865 attributesIface->attributeValue(QAccessible::Attribute::Locale);
866 return localeVariant.toLocale().bcp47Name().toNSString();
871 if ([attribute isEqualToString:NSAccessibilityExpandedAttribute])
872 return iface->state().expanded ? @YES : @NO;
877- (NSArray *)accessibilityParameterizedAttributeNames {
879 QAccessibleInterface *iface = self.qtInterface;
881 qWarning() <<
"Called attribute on invalid object: " << axid;
885 if (iface->textInterface()) {
887 NSAccessibilityStringForRangeParameterizedAttribute,
888 NSAccessibilityLineForIndexParameterizedAttribute,
889 NSAccessibilityRangeForLineParameterizedAttribute,
890 NSAccessibilityRangeForPositionParameterizedAttribute,
892 NSAccessibilityBoundsForRangeParameterizedAttribute,
894 NSAccessibilityStyleRangeForIndexParameterizedAttribute,
895 NSAccessibilityAttributedStringForRangeParameterizedAttribute
902- (id)accessibilityAttributeValue:(NSString *)attribute forParameter:(id)parameter {
903 QAccessibleInterface *iface = self.qtInterface;
905 qWarning() <<
"Called attribute on invalid object: " << axid;
909 if (!iface->textInterface())
912 if ([attribute isEqualToString: NSAccessibilityStringForRangeParameterizedAttribute]) {
913 NSRange range = [parameter rangeValue];
914 QString text = iface->textInterface()->text(range.location, range.location + range.length);
915 return text.toNSString();
917 if ([attribute isEqualToString: NSAccessibilityLineForIndexParameterizedAttribute]) {
918 int index = [parameter intValue];
919 if (index < 0 || index > iface->textInterface()->characterCount())
922 if (iface->state().multiLine) {
924 convertLineOffset(iface->textInterface(), &line, &index);
928 if ([attribute isEqualToString: NSAccessibilityRangeForLineParameterizedAttribute]) {
929 int line = [parameter intValue];
933 NSUInteger startOffset = 0;
934 NSUInteger endOffset = 0;
935 convertLineOffset(iface->textInterface(), &line, &lineOffset, &startOffset, &endOffset);
936 return [NSValue valueWithRange:NSMakeRange(startOffset, endOffset - startOffset)];
938 if ([attribute isEqualToString: NSAccessibilityBoundsForRangeParameterizedAttribute]) {
939 NSRange range = [parameter rangeValue];
940 QRect firstRect = iface->textInterface()->characterRect(range.location);
942 if (range.length > 0) {
943 NSUInteger position = range.location + range.length - 1;
944 if (position > range.location && iface->textInterface()->text(position, position + 1) ==
"\n"_L1)
946 QRect lastRect = iface->textInterface()->characterRect(position);
947 rect = firstRect.united(lastRect);
952 return [NSValue valueWithRect:QCocoaScreen::mapToNative(rect)];
954 if ([attribute isEqualToString: NSAccessibilityAttributedStringForRangeParameterizedAttribute]) {
955 NSRange range = [parameter rangeValue];
956 QString text = iface->textInterface()->text(range.location, range.location + range.length);
957 return [[NSAttributedString alloc] initWithString:text.toNSString()];
958 }
else if ([attribute isEqualToString: NSAccessibilityRangeForPositionParameterizedAttribute]) {
959 QPoint point = QCocoaScreen::mapFromNative([parameter pointValue]).toPoint();
960 int offset = iface->textInterface()->offsetAtPoint(point);
961 return [NSValue valueWithRange:NSMakeRange(
static_cast<NSUInteger>(offset), 1)];
962 }
else if ([attribute isEqualToString: NSAccessibilityStyleRangeForIndexParameterizedAttribute]) {
965 iface->textInterface()->attributes([parameter intValue], &start, &end);
966 return [NSValue valueWithRange:NSMakeRange(
static_cast<NSUInteger>(start),
static_cast<NSUInteger>(end - start))];
971- (BOOL)accessibilityIsAttributeSettable:(NSString *)attribute {
972 QAccessibleInterface *iface = self.qtInterface;
976 if ([attribute isEqualToString:NSAccessibilityFocusedAttribute]) {
977 return iface->state().focusable ? YES : NO;
978 }
else if ([attribute isEqualToString:NSAccessibilityValueAttribute]) {
979 if (iface->textInterface() && iface->state().editable)
981 if (iface->valueInterface())
984 }
else if ([attribute isEqualToString:NSAccessibilitySelectedTextRangeAttribute]) {
985 return iface->textInterface() ? YES : NO;
990- (
void)accessibilitySetValue:(id)value forAttribute:(NSString *)attribute {
991 QAccessibleInterface *iface = self.qtInterface;
994 if ([attribute isEqualToString:NSAccessibilityFocusedAttribute]) {
995 if (QAccessibleActionInterface *action = iface->actionInterface())
996 action->doAction(QAccessibleActionInterface::setFocusAction());
997 }
else if ([attribute isEqualToString:NSAccessibilityValueAttribute]) {
998 if (iface->textInterface()) {
999 QString text = QString::fromNSString((NSString *)value);
1000 iface->setText(QAccessible::Value, text);
1001 }
else if (QAccessibleValueInterface *valueIface = iface->valueInterface()) {
1002 double val = [value doubleValue];
1003 valueIface->setCurrentValue(val);
1005 }
else if ([attribute isEqualToString:NSAccessibilitySelectedTextRangeAttribute]) {
1006 if (QAccessibleTextInterface *text = iface->textInterface()) {
1007 NSRange range = [value rangeValue];
1008 if (range.length > 0)
1009 text->setSelection(0, range.location, range.location + range.length);
1011 text->setCursorPosition(range.location);
1018- (NSArray *)accessibilityActionNames {
1019 NSMutableArray *nsActions = [[NSMutableArray
new] autorelease];
1020 QAccessibleInterface *iface = self.qtInterface;
1024 const QStringList &supportedActionNames = QAccessibleBridgeUtils::effectiveActionNames(iface);
1025 for (
const QString &qtAction : supportedActionNames) {
1026 NSString *nsAction = QCocoaAccessible::getTranslatedAction(qtAction);
1028 [nsActions addObject : nsAction];
1034- (NSString *)accessibilityActionDescription:(NSString *)action {
1035 QAccessibleInterface *iface = self.qtInterface;
1038 QString qtAction = QCocoaAccessible::translateAction(action, iface);
1039 QString description;
1041 if (qtAction.isEmpty()) {
1042 if (QAccessibleActionInterface *actionInterface = iface->actionInterface()) {
1043 qtAction = QString::fromNSString((NSString *)action);
1044 description = actionInterface->localizedActionDescription(qtAction);
1047 description = qAccessibleLocalizedActionDescription(qtAction);
1049 return description.toNSString();
1052- (
void)accessibilityPerformAction:(NSString *)action {
1053 if (QAccessibleInterface *iface = self.qtInterface) {
1054 const QString qtAction = QCocoaAccessible::translateAction(action, iface);
1055 QAccessibleBridgeUtils::performEffectiveAction(iface, qtAction);
1061- (BOOL)accessibilityIsIgnored {
1065 if (self.isManagedByParent)
1068 if (QAccessibleInterface *iface = self.qtInterface)
1069 return QCocoaAccessible::shouldBeIgnored(iface);
1073- (id)accessibilityHitTest:(NSPoint)point
1075 QAccessibleInterface *iface = self.qtInterface;
1077 return NSAccessibilityUnignoredAncestor(self);
1079 QPointF screenPoint = QCocoaScreen::mapFromNative(point);
1080 QWindow *window = QAccessibleBridgeUtils::windowFor(iface);
1084 QAccessibleInterface *childInterface = iface;
1085 while (QAccessibleInterface *child = childInterface->childAt(screenPoint.x(), screenPoint.y())) {
1086 if (!child->isValid())
1089 QWindow *childWindow = QAccessibleBridgeUtils::windowFor(child, childInterface, window);
1090 if (childWindow != window) {
1091 if (
auto *view = QCocoaAccessible::accessibleViewFor(childWindow))
1092 return [view accessibilityHitTest:point];
1095 childInterface = child;
1099 if (childInterface == iface)
1100 return NSAccessibilityUnignoredAncestor(self);
1103 QMacAccessibilityElement *accessibleElement = [QMacAccessibilityElement elementWithInterface:childInterface];
1104 if (accessibleElement)
1105 return NSAccessibilityUnignoredAncestor(accessibleElement);
1106 return NSAccessibilityUnignoredAncestor(self);
1109- (id)accessibilityFocusedUIElement {
1110 QAccessibleInterface *iface = self.qtInterface;
1112 qWarning(
"FocusedUIElement for INVALID");
1116 QAccessibleInterface *focusInterface = iface->focusChild();
1117 if (focusInterface && focusInterface->isValid()) {
1124 QWindow *window = QAccessibleBridgeUtils::windowFor(iface);
1125 QWindow *focusWindow = QAccessibleBridgeUtils::windowFor(focusInterface, iface, window);
1126 if (focusWindow != window) {
1127 if (
auto *view = QCocoaAccessible::accessibleViewFor(focusWindow))
1128 return [view accessibilityFocusedUIElement];
1131 QMacAccessibilityElement *accessibleElement = [QMacAccessibilityElement elementWithInterface:focusInterface];
1132 return NSAccessibilityUnignoredAncestor(accessibleElement);
1135 return NSAccessibilityUnignoredAncestor(self);
1138- (NSString *) accessibilityHelp {
1139 if (QAccessibleInterface *iface = self.qtInterface) {
1140 const QString helpText = iface->text(QAccessible::Help);
1141 if (!helpText.isEmpty())
1142 return helpText.toNSString();
1148
1149
1150- (NSInteger) accessibilityIndex {
1151 NSInteger index = 0;
1152 if (synthesizedRole == NSAccessibilityCellRole)
1153 return m_columnIndex;
1154 if (QAccessibleInterface *iface = self.qtInterface) {
1155 if (self.isManagedByParent) {
1158 if (iface->tableInterface()) {
1159 if (m_rowIndex >= 0)
1160 index = NSInteger(m_rowIndex);
1161 else if (m_columnIndex >= 0)
1162 index = NSInteger(m_columnIndex);
1169- (NSArray *) accessibilityRows {
1170 if (!synthesizedRole && rows) {
1171 QAccessibleInterface *iface = self.qtInterface;
1172 QAccessibleTableInterface *tableInterface = iface ? iface->tableInterface() :
nullptr;
1173 if (tableInterface) {
1174 const unsigned int rowCount = tableInterface->rowCount();
1175 if (rows.count != rowCount) {
1176 qCDebug(lcAccessibilityTable) <<
"Updating table rows with" << rowCount <<
"rows";
1181 rows = [self populateTableArray:NSAccessibilityRowRole
1185 return NSAccessibilityUnignoredChildren(rows);
1191- (NSArray *) accessibilityColumns {
1193 if (!synthesizedRole && columns) {
1194 QAccessibleInterface *iface = self.qtInterface;
1195 if (iface && iface->tableInterface())
1196 return NSAccessibilityUnignoredChildren(columns);
1203- (NSArray *) accessibilityTabs {
1204 QAccessibleInterface *iface = self.qtInterface;
1205 if (iface && iface->role() == QAccessible::PageTabList) {
1206 return QCocoaAccessible::unignoredChildren(iface, [](QAccessibleInterface *child){
1207 return QCocoaAccessible::defaultUnignored(child)
1208 && child->role() == QAccessible::PageTab;