1 /****************************************************************************
3 ** Copyright (C) 2012 Nokia Corporation and/or its subsidiary(-ies).
4 ** All rights reserved.
5 ** Contact: Nokia Corporation (qt-info@nokia.com)
7 ** This file is part of the plugins of the Qt Toolkit.
9 ** $QT_BEGIN_LICENSE:LGPL$
10 ** GNU Lesser General Public License Usage
11 ** This file may be used under the terms of the GNU Lesser General Public
12 ** License version 2.1 as published by the Free Software Foundation and
13 ** appearing in the file LICENSE.LGPL included in the packaging of this
14 ** file. Please review the following information to ensure the GNU Lesser
15 ** General Public License version 2.1 requirements will be met:
16 ** http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
18 ** In addition, as a special exception, Nokia gives you certain additional
19 ** rights. These rights are described in the Nokia Qt LGPL Exception
20 ** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
22 ** GNU General Public License Usage
23 ** Alternatively, this file may be used under the terms of the GNU General
24 ** Public License version 3.0 as published by the Free Software Foundation
25 ** and appearing in the file LICENSE.GPL included in the packaging of this
26 ** file. Please review the following information to ensure the GNU General
27 ** Public License version 3.0 requirements will be met:
28 ** http://www.gnu.org/copyleft/gpl.html.
31 ** Alternatively, this file may be used in accordance with the terms and
32 ** conditions contained in a signed written agreement between you and Nokia.
40 ****************************************************************************/
41 #include "qcocoaaccessibilityelement.h"
42 #include "qcocoaaccessibility.h"
43 #include "qcocoahelpers.h"
45 #include <QAccessible>
46 #include "QAccessibleActionInterface"
48 #import <AppKit/NSAccessibility.h>
50 static QAccessibleInterface *acast(void *ptr)
52 return reinterpret_cast<QAccessibleInterface *>(ptr);
55 @implementation QCocoaAccessibleElement
57 - (id)initWithIndex:(int)aIndex parent:(id)aParent accessibleInterface:(void *)anQAccessibleInterface
62 accessibleInterface = anQAccessibleInterface;
63 role = QCocoaAccessible::macRole(acast(accessibleInterface)->role());
71 + (QCocoaAccessibleElement *)elementWithIndex:(int)aIndex parent:(id)aParent accessibleInterface:(void *)anQAccessibleInterface
73 return [[[self alloc] initWithIndex:aIndex parent:aParent accessibleInterface:anQAccessibleInterface] autorelease];
80 - (BOOL)isEqual:(id)object {
81 if ([object isKindOfClass:[QCocoaAccessibleElement class]]) {
82 QCocoaAccessibleElement *other = object;
83 return (index == other->index) && [role isEqualToString:other->role] && [parent isEqual:other->parent];
89 return [parent hash] + index;
97 // accessibility protocol
102 - (NSArray *)accessibilityAttributeNames {
103 static NSArray *attributes = nil;
104 if (attributes == nil) {
105 attributes = [[NSArray alloc] initWithObjects:
106 NSAccessibilityRoleAttribute,
107 NSAccessibilityRoleDescriptionAttribute,
108 NSAccessibilityChildrenAttribute,
109 NSAccessibilityFocusedAttribute,
110 NSAccessibilityParentAttribute,
111 NSAccessibilityWindowAttribute,
112 NSAccessibilityTopLevelUIElementAttribute,
113 NSAccessibilityPositionAttribute,
114 NSAccessibilitySizeAttribute,
115 NSAccessibilityDescriptionAttribute,
121 - (id)accessibilityAttributeValue:(NSString *)attribute {
122 if ([attribute isEqualToString:NSAccessibilityRoleAttribute]) {
124 } else if ([attribute isEqualToString:NSAccessibilityRoleDescriptionAttribute]) {
125 return NSAccessibilityRoleDescription(role, nil);
126 } else if ([attribute isEqualToString:NSAccessibilityChildrenAttribute]) {
127 int numKids = acast(accessibleInterface)->childCount();
129 NSMutableArray *kids = [NSMutableArray arrayWithCapacity:numKids];
130 for (int i = 0; i < numKids; ++i) {
131 QAccessibleInterface *childInterface = acast(accessibleInterface)->child(i);
132 [kids addObject:[QCocoaAccessibleElement elementWithIndex:i parent:self accessibleInterface:(void*)childInterface]];
135 return NSAccessibilityUnignoredChildren(kids);
136 } else if ([attribute isEqualToString:NSAccessibilityFocusedAttribute]) {
137 // Just check if the app thinks we're focused.
138 id focusedElement = [NSApp accessibilityAttributeValue:NSAccessibilityFocusedUIElementAttribute];
139 return [NSNumber numberWithBool:[focusedElement isEqual:self]];
140 } else if ([attribute isEqualToString:NSAccessibilityParentAttribute]) {
141 return NSAccessibilityUnignoredAncestor(parent);
142 } else if ([attribute isEqualToString:NSAccessibilityWindowAttribute]) {
143 // We're in the same window as our parent.
144 return [parent accessibilityAttributeValue:NSAccessibilityWindowAttribute];
145 } else if ([attribute isEqualToString:NSAccessibilityTopLevelUIElementAttribute]) {
146 // We're in the same top level element as our parent.
147 return [parent accessibilityAttributeValue:NSAccessibilityTopLevelUIElementAttribute];
148 } else if ([attribute isEqualToString:NSAccessibilityPositionAttribute]) {
149 QPoint qtPosition = acast(accessibleInterface)->rect().topLeft();
150 QSize qtSize = acast(accessibleInterface)->rect().size();
151 return [NSValue valueWithPoint: NSMakePoint(qtPosition.x(), qt_mac_flipYCoordinate(qtPosition.y() + qtSize.height()))];
152 } else if ([attribute isEqualToString:NSAccessibilitySizeAttribute]) {
153 QSize qtSize = acast(accessibleInterface)->rect().size();
154 return [NSValue valueWithSize: NSMakeSize(qtSize.width(), qtSize.height())];
155 } else if ([attribute isEqualToString:NSAccessibilityDescriptionAttribute]) {
156 return qt_mac_QStringToNSString(acast(accessibleInterface)->text(QAccessible::Name));
162 - (BOOL)accessibilityIsAttributeSettable:(NSString *)attribute {
163 if ([attribute isEqualToString:NSAccessibilityFocusedAttribute]) {
164 return NO; // YES to handle keyboard input
170 - (void)accessibilitySetValue:(id)value forAttribute:(NSString *)attribute {
172 if ([attribute isEqualToString:NSAccessibilityFocusedAttribute]) {
179 - (NSArray *)accessibilityActionNames {
180 NSMutableArray * nsActions = [NSMutableArray new];
182 QAccessibleActionInterface *actionInterface = acast(accessibleInterface)->actionInterface();
183 if (actionInterface) {
184 QStringList supportedActionNames = actionInterface->actionNames();
186 foreach (const QString &qtAction, supportedActionNames) {
187 NSString *nsAction = QCocoaAccessible::getTranslatedAction(qtAction);
189 [nsActions addObject : nsAction];
196 - (NSString *)accessibilityActionDescription:(NSString *)action {
197 QAccessibleActionInterface *actionInterface = acast(accessibleInterface)->actionInterface();
198 if (actionInterface) {
199 QString qtAction = QCocoaAccessible::translateAction(action);
200 QString description = actionInterface->localizedActionDescription(qtAction);
201 if (!description.isEmpty())
202 return qt_mac_QStringToNSString(description);
205 return NSAccessibilityActionDescription(action);
208 - (void)accessibilityPerformAction:(NSString *)action {
209 QAccessibleActionInterface *actionInterface = acast(accessibleInterface)->actionInterface();
210 if (actionInterface) {
211 QString qtAction = QCocoaAccessible::translateAction(action);
212 actionInterface->doAction(QAccessibleActionInterface::pressAction());
218 - (BOOL)accessibilityIsIgnored {
222 - (id)accessibilityHitTest:(NSPoint)point {
224 if (!accessibleInterface)
225 return NSAccessibilityUnignoredAncestor(self);
226 QAccessibleInterface *childInterface = acast(accessibleInterface)->childAt(point.x, qt_mac_flipYCoordinate(point.y));
228 // No child found, meaning we hit this element.
229 if (!childInterface) {
230 return NSAccessibilityUnignoredAncestor(self);
233 // hit a child, forward to child accessible interface.
234 int childIndex = acast(accessibleInterface)->indexOfChild(childInterface);
235 QCocoaAccessibleElement *accessibleElement = [QCocoaAccessibleElement elementWithIndex:childIndex -1 parent:self accessibleInterface: childInterface];
236 return [accessibleElement accessibilityHitTest:point];
239 - (id)accessibilityFocusedUIElement {
240 return NSAccessibilityUnignoredAncestor(self);