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);
650 if (parent->role() != QAccessible::Application && parent->role() != QAccessible::Window)
651 return NSAccessibilityUnignoredAncestor([QMacAccessibilityElement elementWithInterface: parent]);
654 if (QWindow *window = iface->window()) {
655 QPlatformWindow *platformWindow = window->handle();
656 if (platformWindow) {
657 QCocoaWindow *win =
static_cast<QCocoaWindow*>(platformWindow);
658 return NSAccessibilityUnignoredAncestor(qnsview_cast(win->view()));
664- (NSRect)accessibilityFrame {
665 QAccessibleInterface *iface = self.qtInterface;
670 if (self.isManagedByParent) {
671 if (QAccessibleTableInterface *table = iface->tableInterface()) {
678 const bool isRow = synthesizedRole == NSAccessibilityRowRole;
680 int &row = isRow ? cellPos.ry() : cellPos.rx();
681 int &col = isRow ? cellPos.rx() : cellPos.ry();
683 NSUInteger trackIndex = self.accessibilityIndex;
684 if (trackIndex != NSNotFound) {
685 row =
int(trackIndex);
686 if (QAccessibleInterface *firstCell = table->cellAt(cellPos.y(), cellPos.x())) {
687 rect = firstCell->rect();
688 col = isRow ? table->columnCount() : table->rowCount();
691 if (QAccessibleInterface *lastCell =
692 table->cellAt(cellPos.y(), cellPos.x()))
693 rect = rect.united(lastCell->rect());
699 rect = iface->rect();
702 return QCocoaScreen::mapToNative(rect);
705- (NSString*)accessibilityLabel {
706 if (QAccessibleInterface *iface = self.qtInterface)
707 return iface->text(QAccessible::Description).toNSString();
708 qWarning() <<
"Called accessibilityLabel on invalid object: " << axid;
712- (
void)setAccessibilityLabel:(NSString*)label{
713 if (QAccessibleInterface *iface = self.qtInterface)
714 iface->setText(QAccessible::Description, QString::fromNSString(label));
717- (NSAccessibilityOrientation)accessibilityOrientation {
718 QAccessibleInterface *iface = self.qtInterface;
720 return NSAccessibilityOrientationUnknown;
722 NSAccessibilityOrientation nsOrientation = NSAccessibilityOrientationUnknown;
723 if (QAccessibleAttributesInterface *attributesIface = iface->attributesInterface()) {
724 const QVariant orientationVariant =
725 attributesIface->attributeValue(QAccessible::Attribute::Orientation);
726 if (orientationVariant.isValid()) {
727 Q_ASSERT(orientationVariant.canConvert<Qt::Orientation>());
728 const Qt::Orientation orientation = orientationVariant.value<Qt::Orientation>();
729 nsOrientation = orientation == Qt::Horizontal ? NSAccessibilityOrientationHorizontal
730 : NSAccessibilityOrientationVertical;
733 return nsOrientation;
736- (id) accessibilityValue {
737 if (QAccessibleInterface *iface = self.qtInterface) {
740 if (QCocoaAccessible::hasValueAttribute(iface))
741 return QCocoaAccessible::getValueAttribute(iface);
747- (id) accessibilityMinValue {
748 if (QAccessibleInterface *iface = self.qtInterface) {
749 if (iface->valueInterface()) {
750 return iface->valueInterface()->minimumValue().toString().toNSString();
757- (id) accessibilityMaxValue {
758 if (QAccessibleInterface *iface = self.qtInterface) {
759 if (iface->valueInterface()) {
760 return iface->valueInterface()->maximumValue().toString().toNSString();
766- (NSInteger) accessibilityNumberOfCharacters {
767 if (QAccessibleInterface *iface = self.qtInterface) {
768 if (QAccessibleTextInterface *text = iface->textInterface())
769 return text->characterCount();
774- (NSString *) accessibilitySelectedText {
775 if (QAccessibleInterface *iface = self.qtInterface) {
776 if (QAccessibleTextInterface *text = iface->textInterface()) {
779 text->selection(0, &start, &end);
780 return text->text(start, end).toNSString();
786- (NSRange) accessibilitySelectedTextRange {
787 QAccessibleInterface *iface = self.qtInterface;
790 if (QAccessibleTextInterface *text = iface->textInterface()) {
793 if (text->selectionCount() > 0) {
794 text->selection(0, &start, &end);
796 start = text->cursorPosition();
799 return NSMakeRange(quint32(start), quint32(end - start));
801 return NSMakeRange(0, 0);
804- (NSInteger)accessibilityLineForIndex:(NSInteger)index {
805 QAccessibleInterface *iface = self.qtInterface;
808 if (QAccessibleTextInterface *text = iface->textInterface()) {
809 QString textToPos = text->text(0, index);
810 return textToPos.count(
'\n');
815- (NSRange)accessibilityVisibleCharacterRange {
816 QAccessibleInterface *iface = self.qtInterface;
820 if (QAccessibleTextInterface *text = iface->textInterface())
821 return NSMakeRange(0,
static_cast<uint>(text->characterCount()));
822 return NSMakeRange(0,
static_cast<uint>(iface->text(QAccessible::Name).length()));
825- (NSInteger) accessibilityInsertionPointLineNumber {
826 QAccessibleInterface *iface = self.qtInterface;
829 if (QAccessibleTextInterface *text = iface->textInterface()) {
830 int position = text->cursorPosition();
831 return [self accessibilityLineForIndex:position];
836- (NSArray *)accessibilityAttributeNames {
837#if QT_MACOS_PLATFORM_SDK_EQUAL_OR_ABOVE(260000
)
838 if (@available(macOS 26, *))
839 return @[ NSAccessibilityLanguageAttribute ];
845- (id)accessibilityAttributeValue:(NSString *)attribute {
846 QAccessibleInterface *iface = self.qtInterface;
848 qWarning() <<
"Called attribute on invalid object: " << axid;
852#if QT_MACOS_PLATFORM_SDK_EQUAL_OR_ABOVE(260000
)
853 if (@available(macOS 26, *)) {
854 if ([attribute isEqualToString:NSAccessibilityLanguageAttribute]) {
855 QAccessibleAttributesInterface *attributesIface = iface->attributesInterface();
857 || !attributesIface->attributeKeys().contains(QAccessible::Attribute::Locale))
860 const auto &localeVariant =
861 attributesIface->attributeValue(QAccessible::Attribute::Locale);
862 return localeVariant.toLocale().bcp47Name().toNSString();
870- (NSArray *)accessibilityParameterizedAttributeNames {
872 QAccessibleInterface *iface = self.qtInterface;
874 qWarning() <<
"Called attribute on invalid object: " << axid;
878 if (iface->textInterface()) {
880 NSAccessibilityStringForRangeParameterizedAttribute,
881 NSAccessibilityLineForIndexParameterizedAttribute,
882 NSAccessibilityRangeForLineParameterizedAttribute,
883 NSAccessibilityRangeForPositionParameterizedAttribute,
885 NSAccessibilityBoundsForRangeParameterizedAttribute,
887 NSAccessibilityStyleRangeForIndexParameterizedAttribute,
888 NSAccessibilityAttributedStringForRangeParameterizedAttribute
895- (id)accessibilityAttributeValue:(NSString *)attribute forParameter:(id)parameter {
896 QAccessibleInterface *iface = self.qtInterface;
898 qWarning() <<
"Called attribute on invalid object: " << axid;
902 if (!iface->textInterface())
905 if ([attribute isEqualToString: NSAccessibilityStringForRangeParameterizedAttribute]) {
906 NSRange range = [parameter rangeValue];
907 QString text = iface->textInterface()->text(range.location, range.location + range.length);
908 return text.toNSString();
910 if ([attribute isEqualToString: NSAccessibilityLineForIndexParameterizedAttribute]) {
911 int index = [parameter intValue];
912 if (index < 0 || index > iface->textInterface()->characterCount())
915 if (iface->state().multiLine) {
917 convertLineOffset(iface->textInterface(), &line, &index);
921 if ([attribute isEqualToString: NSAccessibilityRangeForLineParameterizedAttribute]) {
922 int line = [parameter intValue];
926 NSUInteger startOffset = 0;
927 NSUInteger endOffset = 0;
928 convertLineOffset(iface->textInterface(), &line, &lineOffset, &startOffset, &endOffset);
929 return [NSValue valueWithRange:NSMakeRange(startOffset, endOffset - startOffset)];
931 if ([attribute isEqualToString: NSAccessibilityBoundsForRangeParameterizedAttribute]) {
932 NSRange range = [parameter rangeValue];
933 QRect firstRect = iface->textInterface()->characterRect(range.location);
935 if (range.length > 0) {
936 NSUInteger position = range.location + range.length - 1;
937 if (position > range.location && iface->textInterface()->text(position, position + 1) ==
"\n"_L1)
939 QRect lastRect = iface->textInterface()->characterRect(position);
940 rect = firstRect.united(lastRect);
945 return [NSValue valueWithRect:QCocoaScreen::mapToNative(rect)];
947 if ([attribute isEqualToString: NSAccessibilityAttributedStringForRangeParameterizedAttribute]) {
948 NSRange range = [parameter rangeValue];
949 QString text = iface->textInterface()->text(range.location, range.location + range.length);
950 return [[NSAttributedString alloc] initWithString:text.toNSString()];
951 }
else if ([attribute isEqualToString: NSAccessibilityRangeForPositionParameterizedAttribute]) {
952 QPoint point = QCocoaScreen::mapFromNative([parameter pointValue]).toPoint();
953 int offset = iface->textInterface()->offsetAtPoint(point);
954 return [NSValue valueWithRange:NSMakeRange(
static_cast<NSUInteger>(offset), 1)];
955 }
else if ([attribute isEqualToString: NSAccessibilityStyleRangeForIndexParameterizedAttribute]) {
958 iface->textInterface()->attributes([parameter intValue], &start, &end);
959 return [NSValue valueWithRange:NSMakeRange(
static_cast<NSUInteger>(start),
static_cast<NSUInteger>(end - start))];
964- (BOOL)accessibilityIsAttributeSettable:(NSString *)attribute {
965 QAccessibleInterface *iface = self.qtInterface;
969 if ([attribute isEqualToString:NSAccessibilityFocusedAttribute]) {
970 return iface->state().focusable ? YES : NO;
971 }
else if ([attribute isEqualToString:NSAccessibilityValueAttribute]) {
972 if (iface->textInterface() && iface->state().editable)
974 if (iface->valueInterface())
977 }
else if ([attribute isEqualToString:NSAccessibilitySelectedTextRangeAttribute]) {
978 return iface->textInterface() ? YES : NO;
983- (
void)accessibilitySetValue:(id)value forAttribute:(NSString *)attribute {
984 QAccessibleInterface *iface = self.qtInterface;
987 if ([attribute isEqualToString:NSAccessibilityFocusedAttribute]) {
988 if (QAccessibleActionInterface *action = iface->actionInterface())
989 action->doAction(QAccessibleActionInterface::setFocusAction());
990 }
else if ([attribute isEqualToString:NSAccessibilityValueAttribute]) {
991 if (iface->textInterface()) {
992 QString text = QString::fromNSString((NSString *)value);
993 iface->setText(QAccessible::Value, text);
994 }
else if (QAccessibleValueInterface *valueIface = iface->valueInterface()) {
995 double val = [value doubleValue];
996 valueIface->setCurrentValue(val);
998 }
else if ([attribute isEqualToString:NSAccessibilitySelectedTextRangeAttribute]) {
999 if (QAccessibleTextInterface *text = iface->textInterface()) {
1000 NSRange range = [value rangeValue];
1001 if (range.length > 0)
1002 text->setSelection(0, range.location, range.location + range.length);
1004 text->setCursorPosition(range.location);
1011- (NSArray *)accessibilityActionNames {
1012 NSMutableArray *nsActions = [[NSMutableArray
new] autorelease];
1013 QAccessibleInterface *iface = self.qtInterface;
1017 const QStringList &supportedActionNames = QAccessibleBridgeUtils::effectiveActionNames(iface);
1018 for (
const QString &qtAction : supportedActionNames) {
1019 NSString *nsAction = QCocoaAccessible::getTranslatedAction(qtAction);
1021 [nsActions addObject : nsAction];
1027- (NSString *)accessibilityActionDescription:(NSString *)action {
1028 QAccessibleInterface *iface = self.qtInterface;
1031 QString qtAction = QCocoaAccessible::translateAction(action, iface);
1032 QString description;
1034 if (qtAction.isEmpty()) {
1035 if (QAccessibleActionInterface *actionInterface = iface->actionInterface()) {
1036 qtAction = QString::fromNSString((NSString *)action);
1037 description = actionInterface->localizedActionDescription(qtAction);
1040 description = qAccessibleLocalizedActionDescription(qtAction);
1042 return description.toNSString();
1045- (
void)accessibilityPerformAction:(NSString *)action {
1046 if (QAccessibleInterface *iface = self.qtInterface) {
1047 const QString qtAction = QCocoaAccessible::translateAction(action, iface);
1048 QAccessibleBridgeUtils::performEffectiveAction(iface, qtAction);
1054- (BOOL)accessibilityIsIgnored {
1058 if (self.isManagedByParent)
1061 if (QAccessibleInterface *iface = self.qtInterface)
1062 return QCocoaAccessible::shouldBeIgnored(iface);
1066- (id)accessibilityHitTest:(NSPoint)point {
1067 QAccessibleInterface *iface = self.qtInterface;
1070 return NSAccessibilityUnignoredAncestor(self);
1073 QPointF screenPoint = QCocoaScreen::mapFromNative(point);
1074 QAccessibleInterface *childInterface = iface->childAt(screenPoint.x(), screenPoint.y());
1076 if (!childInterface || !childInterface->isValid())
1077 return NSAccessibilityUnignoredAncestor(self);
1080 QAccessibleInterface *childOfChildInterface =
nullptr;
1082 childOfChildInterface = childInterface->childAt(screenPoint.x(), screenPoint.y());
1083 if (childOfChildInterface && childOfChildInterface->isValid())
1084 childInterface = childOfChildInterface;
1085 }
while (childOfChildInterface && childOfChildInterface->isValid());
1088 QMacAccessibilityElement *accessibleElement = [QMacAccessibilityElement elementWithInterface:childInterface];
1089 if (accessibleElement)
1090 return NSAccessibilityUnignoredAncestor(accessibleElement);
1091 return NSAccessibilityUnignoredAncestor(self);
1094- (id)accessibilityFocusedUIElement {
1095 QAccessibleInterface *iface = self.qtInterface;
1097 qWarning(
"FocusedUIElement for INVALID");
1101 QAccessibleInterface *childInterface = iface->focusChild();
1102 if (childInterface && childInterface->isValid()) {
1103 QMacAccessibilityElement *accessibleElement = [QMacAccessibilityElement elementWithInterface:childInterface];
1104 return NSAccessibilityUnignoredAncestor(accessibleElement);
1107 return NSAccessibilityUnignoredAncestor(self);
1110- (NSString *) accessibilityHelp {
1111 if (QAccessibleInterface *iface = self.qtInterface) {
1112 const QString helpText = iface->text(QAccessible::Help);
1113 if (!helpText.isEmpty())
1114 return helpText.toNSString();
1120
1121
1122- (NSInteger) accessibilityIndex {
1123 NSInteger index = 0;
1124 if (synthesizedRole == NSAccessibilityCellRole)
1125 return m_columnIndex;
1126 if (QAccessibleInterface *iface = self.qtInterface) {
1127 if (self.isManagedByParent) {
1130 if (iface->tableInterface()) {
1131 if (m_rowIndex >= 0)
1132 index = NSInteger(m_rowIndex);
1133 else if (m_columnIndex >= 0)
1134 index = NSInteger(m_columnIndex);
1141- (NSArray *) accessibilityRows {
1142 if (!synthesizedRole && rows) {
1143 QAccessibleInterface *iface = self.qtInterface;
1144 QAccessibleTableInterface *tableInterface = iface ? iface->tableInterface() :
nullptr;
1145 if (tableInterface) {
1146 const unsigned int rowCount = tableInterface->rowCount();
1147 if (rows.count != rowCount) {
1148 qCDebug(lcAccessibilityTable) <<
"Updating table rows with" << rowCount <<
"rows";
1153 rows = [self populateTableArray:NSAccessibilityRowRole
1157 return NSAccessibilityUnignoredChildren(rows);
1163- (NSArray *) accessibilityColumns {
1165 if (!synthesizedRole && columns) {
1166 QAccessibleInterface *iface = self.qtInterface;
1167 if (iface && iface->tableInterface())
1168 return NSAccessibilityUnignoredChildren(columns);
1175- (NSArray *) accessibilityTabs {
1176 QAccessibleInterface *iface = self.qtInterface;
1177 if (iface && iface->role() == QAccessible::PageTabList) {
1178 return QCocoaAccessible::unignoredChildren(iface, [](QAccessibleInterface *child){
1179 return QCocoaAccessible::defaultUnignored(child)
1180 && child->role() == QAccessible::PageTab;