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 NSMutableArray *attributes = [[NSMutableArray
new] autorelease];
839#if QT_MACOS_PLATFORM_SDK_EQUAL_OR_ABOVE(260000
)
840 if (@available(macOS 26, *))
841 [attributes addObject:NSAccessibilityLanguageAttribute];
844 QAccessibleInterface *iface = self.qtInterface;
845 if (iface && iface->state().expandable)
846 [attributes addObject:NSAccessibilityExpandedAttribute];
851- (id)accessibilityAttributeValue:(NSString *)attribute {
852 QAccessibleInterface *iface = self.qtInterface;
854 qWarning() <<
"Called attribute on invalid object: " << axid;
858#if QT_MACOS_PLATFORM_SDK_EQUAL_OR_ABOVE(260000
)
859 if (@available(macOS 26, *)) {
860 if ([attribute isEqualToString:NSAccessibilityLanguageAttribute]) {
861 QAccessibleAttributesInterface *attributesIface = iface->attributesInterface();
863 || !attributesIface->attributeKeys().contains(QAccessible::Attribute::Locale))
866 const auto &localeVariant =
867 attributesIface->attributeValue(QAccessible::Attribute::Locale);
868 return localeVariant.toLocale().bcp47Name().toNSString();
873 if ([attribute isEqualToString:NSAccessibilityExpandedAttribute])
874 return iface->state().expanded ? @YES : @NO;
879- (NSArray *)accessibilityParameterizedAttributeNames {
881 QAccessibleInterface *iface = self.qtInterface;
883 qWarning() <<
"Called attribute on invalid object: " << axid;
887 if (iface->textInterface()) {
889 NSAccessibilityStringForRangeParameterizedAttribute,
890 NSAccessibilityLineForIndexParameterizedAttribute,
891 NSAccessibilityRangeForLineParameterizedAttribute,
892 NSAccessibilityRangeForPositionParameterizedAttribute,
894 NSAccessibilityBoundsForRangeParameterizedAttribute,
896 NSAccessibilityStyleRangeForIndexParameterizedAttribute,
897 NSAccessibilityAttributedStringForRangeParameterizedAttribute
904- (id)accessibilityAttributeValue:(NSString *)attribute forParameter:(id)parameter {
905 QAccessibleInterface *iface = self.qtInterface;
907 qWarning() <<
"Called attribute on invalid object: " << axid;
911 if (!iface->textInterface())
914 if ([attribute isEqualToString: NSAccessibilityStringForRangeParameterizedAttribute]) {
915 NSRange range = [parameter rangeValue];
916 QString text = iface->textInterface()->text(range.location, range.location + range.length);
917 return text.toNSString();
919 if ([attribute isEqualToString: NSAccessibilityLineForIndexParameterizedAttribute]) {
920 int index = [parameter intValue];
921 if (index < 0 || index > iface->textInterface()->characterCount())
924 if (iface->state().multiLine) {
926 convertLineOffset(iface->textInterface(), &line, &index);
930 if ([attribute isEqualToString: NSAccessibilityRangeForLineParameterizedAttribute]) {
931 int line = [parameter intValue];
935 NSUInteger startOffset = 0;
936 NSUInteger endOffset = 0;
937 convertLineOffset(iface->textInterface(), &line, &lineOffset, &startOffset, &endOffset);
938 return [NSValue valueWithRange:NSMakeRange(startOffset, endOffset - startOffset)];
940 if ([attribute isEqualToString: NSAccessibilityBoundsForRangeParameterizedAttribute]) {
941 NSRange range = [parameter rangeValue];
942 QRect firstRect = iface->textInterface()->characterRect(range.location);
944 if (range.length > 0) {
945 NSUInteger position = range.location + range.length - 1;
946 if (position > range.location && iface->textInterface()->text(position, position + 1) ==
"\n"_L1)
948 QRect lastRect = iface->textInterface()->characterRect(position);
949 rect = firstRect.united(lastRect);
954 return [NSValue valueWithRect:QCocoaScreen::mapToNative(rect)];
956 if ([attribute isEqualToString: NSAccessibilityAttributedStringForRangeParameterizedAttribute]) {
957 NSRange range = [parameter rangeValue];
958 QString text = iface->textInterface()->text(range.location, range.location + range.length);
959 return [[NSAttributedString alloc] initWithString:text.toNSString()];
960 }
else if ([attribute isEqualToString: NSAccessibilityRangeForPositionParameterizedAttribute]) {
961 QPoint point = QCocoaScreen::mapFromNative([parameter pointValue]).toPoint();
962 int offset = iface->textInterface()->offsetAtPoint(point);
963 return [NSValue valueWithRange:NSMakeRange(
static_cast<NSUInteger>(offset), 1)];
964 }
else if ([attribute isEqualToString: NSAccessibilityStyleRangeForIndexParameterizedAttribute]) {
967 iface->textInterface()->attributes([parameter intValue], &start, &end);
968 return [NSValue valueWithRange:NSMakeRange(
static_cast<NSUInteger>(start),
static_cast<NSUInteger>(end - start))];
973- (BOOL)accessibilityIsAttributeSettable:(NSString *)attribute {
974 QAccessibleInterface *iface = self.qtInterface;
978 if ([attribute isEqualToString:NSAccessibilityFocusedAttribute]) {
979 return iface->state().focusable ? YES : NO;
980 }
else if ([attribute isEqualToString:NSAccessibilityValueAttribute]) {
981 if (iface->textInterface() && iface->state().editable)
983 if (iface->valueInterface())
986 }
else if ([attribute isEqualToString:NSAccessibilitySelectedTextRangeAttribute]) {
987 return iface->textInterface() ? YES : NO;
992- (
void)accessibilitySetValue:(id)value forAttribute:(NSString *)attribute {
993 QAccessibleInterface *iface = self.qtInterface;
996 if ([attribute isEqualToString:NSAccessibilityFocusedAttribute]) {
997 if (QAccessibleActionInterface *action = iface->actionInterface())
998 action->doAction(QAccessibleActionInterface::setFocusAction());
999 }
else if ([attribute isEqualToString:NSAccessibilityValueAttribute]) {
1000 if (iface->textInterface()) {
1001 QString text = QString::fromNSString((NSString *)value);
1002 iface->setText(QAccessible::Value, text);
1003 }
else if (QAccessibleValueInterface *valueIface = iface->valueInterface()) {
1004 double val = [value doubleValue];
1005 valueIface->setCurrentValue(val);
1007 }
else if ([attribute isEqualToString:NSAccessibilitySelectedTextRangeAttribute]) {
1008 if (QAccessibleTextInterface *text = iface->textInterface()) {
1009 NSRange range = [value rangeValue];
1010 if (range.length > 0)
1011 text->setSelection(0, range.location, range.location + range.length);
1013 text->setCursorPosition(range.location);
1020- (NSArray *)accessibilityActionNames {
1021 NSMutableArray *nsActions = [[NSMutableArray
new] autorelease];
1022 QAccessibleInterface *iface = self.qtInterface;
1026 const QStringList &supportedActionNames = QAccessibleBridgeUtils::effectiveActionNames(iface);
1027 for (
const QString &qtAction : supportedActionNames) {
1028 NSString *nsAction = QCocoaAccessible::getTranslatedAction(qtAction);
1030 [nsActions addObject : nsAction];
1036- (NSString *)accessibilityActionDescription:(NSString *)action {
1037 QAccessibleInterface *iface = self.qtInterface;
1040 QString qtAction = QCocoaAccessible::translateAction(action, iface);
1041 QString description;
1043 if (qtAction.isEmpty()) {
1044 if (QAccessibleActionInterface *actionInterface = iface->actionInterface()) {
1045 qtAction = QString::fromNSString((NSString *)action);
1046 description = actionInterface->localizedActionDescription(qtAction);
1049 description = qAccessibleLocalizedActionDescription(qtAction);
1051 return description.toNSString();
1054- (
void)accessibilityPerformAction:(NSString *)action {
1055 if (QAccessibleInterface *iface = self.qtInterface) {
1056 const QString qtAction = QCocoaAccessible::translateAction(action, iface);
1057 QAccessibleBridgeUtils::performEffectiveAction(iface, qtAction);
1063- (BOOL)accessibilityIsIgnored {
1067 if (self.isManagedByParent)
1070 if (QAccessibleInterface *iface = self.qtInterface)
1071 return QCocoaAccessible::shouldBeIgnored(iface);
1075- (id)accessibilityHitTest:(NSPoint)point {
1076 QAccessibleInterface *iface = self.qtInterface;
1079 return NSAccessibilityUnignoredAncestor(self);
1082 QPointF screenPoint = QCocoaScreen::mapFromNative(point);
1083 QAccessibleInterface *childInterface = iface->childAt(screenPoint.x(), screenPoint.y());
1085 if (!childInterface || !childInterface->isValid())
1086 return NSAccessibilityUnignoredAncestor(self);
1089 QAccessibleInterface *childOfChildInterface =
nullptr;
1091 childOfChildInterface = childInterface->childAt(screenPoint.x(), screenPoint.y());
1092 if (childOfChildInterface && childOfChildInterface->isValid())
1093 childInterface = childOfChildInterface;
1094 }
while (childOfChildInterface && childOfChildInterface->isValid());
1097 QMacAccessibilityElement *accessibleElement = [QMacAccessibilityElement elementWithInterface:childInterface];
1098 if (accessibleElement)
1099 return NSAccessibilityUnignoredAncestor(accessibleElement);
1100 return NSAccessibilityUnignoredAncestor(self);
1103- (id)accessibilityFocusedUIElement {
1104 QAccessibleInterface *iface = self.qtInterface;
1106 qWarning(
"FocusedUIElement for INVALID");
1110 QAccessibleInterface *childInterface = iface->focusChild();
1111 if (childInterface && childInterface->isValid()) {
1112 QMacAccessibilityElement *accessibleElement = [QMacAccessibilityElement elementWithInterface:childInterface];
1113 return NSAccessibilityUnignoredAncestor(accessibleElement);
1116 return NSAccessibilityUnignoredAncestor(self);
1119- (NSString *) accessibilityHelp {
1120 if (QAccessibleInterface *iface = self.qtInterface) {
1121 const QString helpText = iface->text(QAccessible::Help);
1122 if (!helpText.isEmpty())
1123 return helpText.toNSString();
1129
1130
1131- (NSInteger) accessibilityIndex {
1132 NSInteger index = 0;
1133 if (synthesizedRole == NSAccessibilityCellRole)
1134 return m_columnIndex;
1135 if (QAccessibleInterface *iface = self.qtInterface) {
1136 if (self.isManagedByParent) {
1139 if (iface->tableInterface()) {
1140 if (m_rowIndex >= 0)
1141 index = NSInteger(m_rowIndex);
1142 else if (m_columnIndex >= 0)
1143 index = NSInteger(m_columnIndex);
1150- (NSArray *) accessibilityRows {
1151 if (!synthesizedRole && rows) {
1152 QAccessibleInterface *iface = self.qtInterface;
1153 QAccessibleTableInterface *tableInterface = iface ? iface->tableInterface() :
nullptr;
1154 if (tableInterface) {
1155 const unsigned int rowCount = tableInterface->rowCount();
1156 if (rows.count != rowCount) {
1157 qCDebug(lcAccessibilityTable) <<
"Updating table rows with" << rowCount <<
"rows";
1162 rows = [self populateTableArray:NSAccessibilityRowRole
1166 return NSAccessibilityUnignoredChildren(rows);
1172- (NSArray *) accessibilityColumns {
1174 if (!synthesizedRole && columns) {
1175 QAccessibleInterface *iface = self.qtInterface;
1176 if (iface && iface->tableInterface())
1177 return NSAccessibilityUnignoredChildren(columns);
1184- (NSArray *) accessibilityTabs {
1185 QAccessibleInterface *iface = self.qtInterface;
1186 if (iface && iface->role() == QAccessible::PageTabList) {
1187 return QCocoaAccessible::unignoredChildren(iface, [](QAccessibleInterface *child){
1188 return QCocoaAccessible::defaultUnignored(child)
1189 && child->role() == QAccessible::PageTab;