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 *)accessibilityParameterizedAttributeNames {
838 QAccessibleInterface *iface = self.qtInterface;
840 qWarning() <<
"Called attribute on invalid object: " << axid;
844 if (iface->textInterface()) {
846 NSAccessibilityStringForRangeParameterizedAttribute,
847 NSAccessibilityLineForIndexParameterizedAttribute,
848 NSAccessibilityRangeForLineParameterizedAttribute,
849 NSAccessibilityRangeForPositionParameterizedAttribute,
851 NSAccessibilityBoundsForRangeParameterizedAttribute,
853 NSAccessibilityStyleRangeForIndexParameterizedAttribute,
854 NSAccessibilityAttributedStringForRangeParameterizedAttribute
861- (id)accessibilityAttributeValue:(NSString *)attribute forParameter:(id)parameter {
862 QAccessibleInterface *iface = self.qtInterface;
864 qWarning() <<
"Called attribute on invalid object: " << axid;
868 if (!iface->textInterface())
871 if ([attribute isEqualToString: NSAccessibilityStringForRangeParameterizedAttribute]) {
872 NSRange range = [parameter rangeValue];
873 QString text = iface->textInterface()->text(range.location, range.location + range.length);
874 return text.toNSString();
876 if ([attribute isEqualToString: NSAccessibilityLineForIndexParameterizedAttribute]) {
877 int index = [parameter intValue];
878 if (index < 0 || index > iface->textInterface()->characterCount())
881 if (iface->state().multiLine) {
883 convertLineOffset(iface->textInterface(), &line, &index);
887 if ([attribute isEqualToString: NSAccessibilityRangeForLineParameterizedAttribute]) {
888 int line = [parameter intValue];
892 NSUInteger startOffset = 0;
893 NSUInteger endOffset = 0;
894 convertLineOffset(iface->textInterface(), &line, &lineOffset, &startOffset, &endOffset);
895 return [NSValue valueWithRange:NSMakeRange(startOffset, endOffset - startOffset)];
897 if ([attribute isEqualToString: NSAccessibilityBoundsForRangeParameterizedAttribute]) {
898 NSRange range = [parameter rangeValue];
899 QRect firstRect = iface->textInterface()->characterRect(range.location);
901 if (range.length > 0) {
902 NSUInteger position = range.location + range.length - 1;
903 if (position > range.location && iface->textInterface()->text(position, position + 1) ==
"\n"_L1)
905 QRect lastRect = iface->textInterface()->characterRect(position);
906 rect = firstRect.united(lastRect);
911 return [NSValue valueWithRect:QCocoaScreen::mapToNative(rect)];
913 if ([attribute isEqualToString: NSAccessibilityAttributedStringForRangeParameterizedAttribute]) {
914 NSRange range = [parameter rangeValue];
915 QString text = iface->textInterface()->text(range.location, range.location + range.length);
916 return [[NSAttributedString alloc] initWithString:text.toNSString()];
917 }
else if ([attribute isEqualToString: NSAccessibilityRangeForPositionParameterizedAttribute]) {
918 QPoint point = QCocoaScreen::mapFromNative([parameter pointValue]).toPoint();
919 int offset = iface->textInterface()->offsetAtPoint(point);
920 return [NSValue valueWithRange:NSMakeRange(
static_cast<NSUInteger>(offset), 1)];
921 }
else if ([attribute isEqualToString: NSAccessibilityStyleRangeForIndexParameterizedAttribute]) {
924 iface->textInterface()->attributes([parameter intValue], &start, &end);
925 return [NSValue valueWithRange:NSMakeRange(
static_cast<NSUInteger>(start),
static_cast<NSUInteger>(end - start))];
930- (BOOL)accessibilityIsAttributeSettable:(NSString *)attribute {
931 QAccessibleInterface *iface = self.qtInterface;
935 if ([attribute isEqualToString:NSAccessibilityFocusedAttribute]) {
936 return iface->state().focusable ? YES : NO;
937 }
else if ([attribute isEqualToString:NSAccessibilityValueAttribute]) {
938 if (iface->textInterface() && iface->state().editable)
940 if (iface->valueInterface())
943 }
else if ([attribute isEqualToString:NSAccessibilitySelectedTextRangeAttribute]) {
944 return iface->textInterface() ? YES : NO;
949- (
void)accessibilitySetValue:(id)value forAttribute:(NSString *)attribute {
950 QAccessibleInterface *iface = self.qtInterface;
953 if ([attribute isEqualToString:NSAccessibilityFocusedAttribute]) {
954 if (QAccessibleActionInterface *action = iface->actionInterface())
955 action->doAction(QAccessibleActionInterface::setFocusAction());
956 }
else if ([attribute isEqualToString:NSAccessibilityValueAttribute]) {
957 if (iface->textInterface()) {
958 QString text = QString::fromNSString((NSString *)value);
959 iface->setText(QAccessible::Value, text);
960 }
else if (QAccessibleValueInterface *valueIface = iface->valueInterface()) {
961 double val = [value doubleValue];
962 valueIface->setCurrentValue(val);
964 }
else if ([attribute isEqualToString:NSAccessibilitySelectedTextRangeAttribute]) {
965 if (QAccessibleTextInterface *text = iface->textInterface()) {
966 NSRange range = [value rangeValue];
967 if (range.length > 0)
968 text->setSelection(0, range.location, range.location + range.length);
970 text->setCursorPosition(range.location);
977- (NSArray *)accessibilityActionNames {
978 NSMutableArray *nsActions = [[NSMutableArray
new] autorelease];
979 QAccessibleInterface *iface = self.qtInterface;
983 const QStringList &supportedActionNames = QAccessibleBridgeUtils::effectiveActionNames(iface);
984 for (
const QString &qtAction : supportedActionNames) {
985 NSString *nsAction = QCocoaAccessible::getTranslatedAction(qtAction);
987 [nsActions addObject : nsAction];
993- (NSString *)accessibilityActionDescription:(NSString *)action {
994 QAccessibleInterface *iface = self.qtInterface;
997 QString qtAction = QCocoaAccessible::translateAction(action, iface);
1000 if (qtAction.isEmpty()) {
1001 if (QAccessibleActionInterface *actionInterface = iface->actionInterface()) {
1002 qtAction = QString::fromNSString((NSString *)action);
1003 description = actionInterface->localizedActionDescription(qtAction);
1006 description = qAccessibleLocalizedActionDescription(qtAction);
1008 return description.toNSString();
1011- (
void)accessibilityPerformAction:(NSString *)action {
1012 if (QAccessibleInterface *iface = self.qtInterface) {
1013 const QString qtAction = QCocoaAccessible::translateAction(action, iface);
1014 QAccessibleBridgeUtils::performEffectiveAction(iface, qtAction);
1020- (BOOL)accessibilityIsIgnored {
1024 if (self.isManagedByParent)
1027 if (QAccessibleInterface *iface = self.qtInterface)
1028 return QCocoaAccessible::shouldBeIgnored(iface);
1032- (id)accessibilityHitTest:(NSPoint)point {
1033 QAccessibleInterface *iface = self.qtInterface;
1036 return NSAccessibilityUnignoredAncestor(self);
1039 QPointF screenPoint = QCocoaScreen::mapFromNative(point);
1040 QAccessibleInterface *childInterface = iface->childAt(screenPoint.x(), screenPoint.y());
1042 if (!childInterface || !childInterface->isValid())
1043 return NSAccessibilityUnignoredAncestor(self);
1046 QAccessibleInterface *childOfChildInterface =
nullptr;
1048 childOfChildInterface = childInterface->childAt(screenPoint.x(), screenPoint.y());
1049 if (childOfChildInterface && childOfChildInterface->isValid())
1050 childInterface = childOfChildInterface;
1051 }
while (childOfChildInterface && childOfChildInterface->isValid());
1054 QMacAccessibilityElement *accessibleElement = [QMacAccessibilityElement elementWithInterface:childInterface];
1055 if (accessibleElement)
1056 return NSAccessibilityUnignoredAncestor(accessibleElement);
1057 return NSAccessibilityUnignoredAncestor(self);
1060- (id)accessibilityFocusedUIElement {
1061 QAccessibleInterface *iface = self.qtInterface;
1063 qWarning(
"FocusedUIElement for INVALID");
1067 QAccessibleInterface *childInterface = iface->focusChild();
1068 if (childInterface && childInterface->isValid()) {
1069 QMacAccessibilityElement *accessibleElement = [QMacAccessibilityElement elementWithInterface:childInterface];
1070 return NSAccessibilityUnignoredAncestor(accessibleElement);
1073 return NSAccessibilityUnignoredAncestor(self);
1076- (NSString *) accessibilityHelp {
1077 if (QAccessibleInterface *iface = self.qtInterface) {
1078 const QString helpText = iface->text(QAccessible::Help);
1079 if (!helpText.isEmpty())
1080 return helpText.toNSString();
1086
1087
1088- (NSInteger) accessibilityIndex {
1089 NSInteger index = 0;
1090 if (synthesizedRole == NSAccessibilityCellRole)
1091 return m_columnIndex;
1092 if (QAccessibleInterface *iface = self.qtInterface) {
1093 if (self.isManagedByParent) {
1096 if (iface->tableInterface()) {
1097 if (m_rowIndex >= 0)
1098 index = NSInteger(m_rowIndex);
1099 else if (m_columnIndex >= 0)
1100 index = NSInteger(m_columnIndex);
1107- (NSArray *) accessibilityRows {
1108 if (!synthesizedRole && rows) {
1109 QAccessibleInterface *iface = self.qtInterface;
1110 QAccessibleTableInterface *tableInterface = iface ? iface->tableInterface() :
nullptr;
1111 if (tableInterface) {
1112 const unsigned int rowCount = tableInterface->rowCount();
1113 if (rows.count != rowCount) {
1114 qCDebug(lcAccessibilityTable) <<
"Updating table rows with" << rowCount <<
"rows";
1119 rows = [self populateTableArray:NSAccessibilityRowRole
1123 return NSAccessibilityUnignoredChildren(rows);
1129- (NSArray *) accessibilityColumns {
1131 if (!synthesizedRole && columns) {
1132 QAccessibleInterface *iface = self.qtInterface;
1133 if (iface && iface->tableInterface())
1134 return NSAccessibilityUnignoredChildren(columns);
1141- (NSArray *) accessibilityTabs {
1142 QAccessibleInterface *iface = self.qtInterface;
1143 if (iface && iface->role() == QAccessible::PageTabList) {
1144 return QCocoaAccessible::unignoredChildren(iface, [](QAccessibleInterface *child){
1145 return QCocoaAccessible::defaultUnignored(child)
1146 && child->role() == QAccessible::PageTab;