source: trunk/src/gui/accessible/qaccessible_mac.mm@ 651

Last change on this file since 651 was 651, checked in by Dmitry A. Kuminov, 15 years ago

trunk: Merged in qt 4.6.2 sources.

File size: 92.9 KB
Line 
1/****************************************************************************
2**
3** Copyright (C) 2010 Nokia Corporation and/or its subsidiary(-ies).
4** All rights reserved.
5** Contact: Nokia Corporation ([email protected])
6**
7** This file is part of the QtGui module of the Qt Toolkit.
8**
9** $QT_BEGIN_LICENSE:LGPL$
10** Commercial Usage
11** Licensees holding valid Qt Commercial licenses may use this file in
12** accordance with the Qt Commercial License Agreement provided with the
13** Software or, alternatively, in accordance with the terms contained in
14** a written agreement between you and Nokia.
15**
16** GNU Lesser General Public License Usage
17** Alternatively, this file may be used under the terms of the GNU Lesser
18** General Public License version 2.1 as published by the Free Software
19** Foundation and appearing in the file LICENSE.LGPL included in the
20** packaging of this file. Please review the following information to
21** ensure the GNU Lesser General Public License version 2.1 requirements
22** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
23**
24** In addition, as a special exception, Nokia gives you certain additional
25** rights. These rights are described in the Nokia Qt LGPL Exception
26** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
27**
28** GNU General Public License Usage
29** Alternatively, this file may be used under the terms of the GNU
30** General Public License version 3.0 as published by the Free Software
31** Foundation and appearing in the file LICENSE.GPL included in the
32** packaging of this file. Please review the following information to
33** ensure the GNU General Public License version 3.0 requirements will be
34** met: http://www.gnu.org/copyleft/gpl.html.
35**
36** If you have questions regarding the use of this file, please contact
37** Nokia at [email protected].
38** $QT_END_LICENSE$
39**
40****************************************************************************/
41
42#include "qaccessible.h"
43
44#ifndef QT_NO_ACCESSIBILITY
45#include "qaccessible_mac_p.h"
46#include "qhash.h"
47#include "qset.h"
48#include "qpointer.h"
49#include "qapplication.h"
50#include "qmainwindow.h"
51#include "qtextdocument.h"
52#include "qdebug.h"
53#include "qabstractslider.h"
54#include "qsplitter.h"
55#include "qtabwidget.h"
56#include "qlistview.h"
57#include "qtableview.h"
58#include "qdockwidget.h"
59
60#include <private/qt_mac_p.h>
61#include <private/qwidget_p.h>
62#include <CoreFoundation/CoreFoundation.h>
63
64QT_BEGIN_NAMESPACE
65
66/*
67 Set up platform defines. There is a one-to-one correspondence between the
68 Carbon and Cocoa roles and attributes, but the prefix and type changes.
69*/
70#ifdef QT_MAC_USE_COCOA
71typedef NSString * const QAXRoleType;
72#define QAXApplicationRole NSAccessibilityApplicationRole
73#define QAXButtonRole NSAccessibilityButtonRole
74#define QAXCancelAction NSAccessibilityCancelAction
75#define QAXCheckBoxRole NSAccessibilityCheckBoxRole
76#define QAXChildrenAttribute NSAccessibilityChildrenAttribute
77#define QAXCloseButtonAttribute NSAccessibilityCloseButtonAttribute
78#define QAXCloseButtonAttribute NSAccessibilityCloseButtonAttribute
79#define QAXColumnRole NSAccessibilityColumnRole
80#define QAXConfirmAction NSAccessibilityConfirmAction
81#define QAXContentsAttribute NSAccessibilityContentsAttribute
82#define QAXDecrementAction NSAccessibilityDecrementAction
83#define QAXDecrementArrowSubrole NSAccessibilityDecrementArrowSubrole
84#define QAXDecrementPageSubrole NSAccessibilityDecrementPageSubrole
85#define QAXDescriptionAttribute NSAccessibilityDescriptionAttribute
86#define QAXEnabledAttribute NSAccessibilityEnabledAttribute
87#define QAXExpandedAttribute NSAccessibilityExpandedAttribute
88#define QAXFocusedAttribute NSAccessibilityFocusedAttribute
89#define QAXFocusedUIElementChangedNotification NSAccessibilityFocusedUIElementChangedNotification
90#define QAXFocusedWindowChangedNotification NSAccessibilityFocusedWindowChangedNotification
91#define QAXGroupRole NSAccessibilityGroupRole
92#define QAXGrowAreaAttribute NSAccessibilityGrowAreaAttribute
93#define QAXGrowAreaRole NSAccessibilityGrowAreaRole
94#define QAXHelpAttribute NSAccessibilityHelpAttribute
95#define QAXHorizontalOrientationValue NSAccessibilityHorizontalOrientationValue
96#define QAXHorizontalScrollBarAttribute NSAccessibilityHorizontalScrollBarAttribute
97#define QAXIncrementAction NSAccessibilityIncrementAction
98#define QAXIncrementArrowSubrole NSAccessibilityIncrementArrowSubrole
99#define QAXIncrementPageSubrole NSAccessibilityIncrementPageSubrole
100#define QAXIncrementorRole NSAccessibilityIncrementorRole
101#define QAXLinkedUIElementsAttribute NSAccessibilityLinkedUIElementsAttribute
102#define QAXListRole NSAccessibilityListRole
103#define QAXMainAttribute NSAccessibilityMainAttribute
104#define QAXMaxValueAttribute NSAccessibilityMaxValueAttribute
105#define QAXMenuBarRole NSAccessibilityMenuBarRole
106#define QAXMenuButtonRole NSAccessibilityMenuButtonRole
107#define QAXMenuClosedNotification NSAccessibilityMenuClosedNotification
108#define QAXMenuItemRole NSAccessibilityMenuItemRole
109#define QAXMenuOpenedNotification NSAccessibilityMenuOpenedNotification
110#define QAXMenuRole NSAccessibilityMenuRole
111#define QAXMinValueAttribute NSAccessibilityMinValueAttribute
112#define QAXMinimizeButtonAttribute NSAccessibilityMinimizeButtonAttribute
113#define QAXMinimizedAttribute NSAccessibilityMinimizedAttribute
114#define QAXNextContentsAttribute NSAccessibilityNextContentsAttribute
115#define QAXOrientationAttribute NSAccessibilityOrientationAttribute
116#define QAXParentAttribute NSAccessibilityParentAttribute
117#define QAXPickAction NSAccessibilityPickAction
118#define QAXPopUpButtonRole NSAccessibilityPopUpButtonRole
119#define QAXPositionAttribute NSAccessibilityPositionAttribute
120#define QAXPressAction NSAccessibilityPressAction
121#define QAXPreviousContentsAttribute NSAccessibilityPreviousContentsAttribute
122#define QAXProgressIndicatorRole NSAccessibilityProgressIndicatorRole
123#define QAXRadioButtonRole NSAccessibilityRadioButtonRole
124#define QAXRoleAttribute NSAccessibilityRoleAttribute
125#define QAXRoleDescriptionAttribute NSAccessibilityRoleDescriptionAttribute
126#define QAXRowRole NSAccessibilityRowRole
127#define QAXRowsAttribute NSAccessibilityRowsAttribute
128#define QAXScrollAreaRole NSAccessibilityScrollAreaRole
129#define QAXScrollBarRole NSAccessibilityScrollBarRole
130#define QAXSelectedAttribute NSAccessibilitySelectedAttribute
131#define QAXSelectedChildrenAttribute NSAccessibilitySelectedChildrenAttribute
132#define QAXSelectedRowsAttribute NSAccessibilitySelectedRowsAttribute
133#define QAXSizeAttribute NSAccessibilitySizeAttribute
134#define QAXSliderRole NSAccessibilitySliderRole
135#define QAXSplitGroupRole NSAccessibilitySplitGroupRole
136#define QAXSplitterRole NSAccessibilitySplitterRole
137#define QAXSplittersAttribute NSAccessibilitySplittersAttribute
138#define QAXStaticTextRole NSAccessibilityStaticTextRole
139#define QAXSubroleAttribute NSAccessibilitySubroleAttribute
140#define QAXSubroleAttribute NSAccessibilitySubroleAttribute
141#define QAXTabGroupRole NSAccessibilityTabGroupRole
142#define QAXTableRole NSAccessibilityTableRole
143#define QAXTabsAttribute NSAccessibilityTabsAttribute
144#define QAXTextFieldRole NSAccessibilityTextFieldRole
145#define QAXTitleAttribute NSAccessibilityTitleAttribute
146#define QAXTitleUIElementAttribute NSAccessibilityTitleUIElementAttribute
147#define QAXToolbarButtonAttribute NSAccessibilityToolbarButtonAttribute
148#define QAXToolbarRole NSAccessibilityToolbarRole
149#define QAXTopLevelUIElementAttribute NSAccessibilityTopLevelUIElementAttribute
150#define QAXUnknownRole NSAccessibilityUnknownRole
151#define QAXValueAttribute NSAccessibilityValueAttribute
152#define QAXValueChangedNotification NSAccessibilityValueChangedNotification
153#define QAXValueIndicatorRole NSAccessibilityValueIndicatorRole
154#define QAXVerticalOrientationValue NSAccessibilityVerticalOrientationValue
155#define QAXVerticalScrollBarAttribute NSAccessibilityVerticalScrollBarAttribute
156#define QAXVisibleRowsAttribute NSAccessibilityVisibleRowsAttribute
157#define QAXWindowAttribute NSAccessibilityWindowAttribute
158#define QAXWindowCreatedNotification NSAccessibilityWindowCreatedNotification
159#define QAXWindowMovedNotification NSAccessibilityWindowMovedNotification
160#define QAXWindowRole NSAccessibilityWindowRole
161#define QAXZoomButtonAttribute NSAccessibilityZoomButtonAttribute
162#else
163typedef CFStringRef const QAXRoleType;
164#define QAXApplicationRole kAXApplicationRole
165#define QAXButtonRole kAXButtonRole
166#define QAXCancelAction kAXCancelAction
167#define QAXCheckBoxRole kAXCheckBoxRole
168#define QAXChildrenAttribute kAXChildrenAttribute
169#define QAXCloseButtonAttribute kAXCloseButtonAttribute
170#define QAXColumnRole kAXColumnRole
171#define QAXConfirmAction kAXConfirmAction
172#define QAXContentsAttribute kAXContentsAttribute
173#define QAXDecrementAction kAXDecrementAction
174#define QAXDecrementArrowSubrole kAXDecrementArrowSubrole
175#define QAXDecrementPageSubrole kAXDecrementPageSubrole
176#define QAXDescriptionAttribute kAXDescriptionAttribute
177#define QAXEnabledAttribute kAXEnabledAttribute
178#define QAXExpandedAttribute kAXExpandedAttribute
179#define QAXFocusedAttribute kAXFocusedAttribute
180#define QAXFocusedUIElementChangedNotification kAXFocusedUIElementChangedNotification
181#define QAXFocusedWindowChangedNotification kAXFocusedWindowChangedNotification
182#define QAXGroupRole kAXGroupRole
183#define QAXGrowAreaAttribute kAXGrowAreaAttribute
184#define QAXGrowAreaRole kAXGrowAreaRole
185#define QAXHelpAttribute kAXHelpAttribute
186#define QAXHorizontalOrientationValue kAXHorizontalOrientationValue
187#define QAXHorizontalScrollBarAttribute kAXHorizontalScrollBarAttribute
188#define QAXIncrementAction kAXIncrementAction
189#define QAXIncrementArrowSubrole kAXIncrementArrowSubrole
190#define QAXIncrementPageSubrole kAXIncrementPageSubrole
191#define QAXIncrementorRole kAXIncrementorRole
192#define QAXLinkedUIElementsAttribute kAXLinkedUIElementsAttribute
193#define QAXListRole kAXListRole
194#define QAXMainAttribute kAXMainAttribute
195#define QAXMaxValueAttribute kAXMaxValueAttribute
196#define QAXMenuBarRole kAXMenuBarRole
197#define QAXMenuButtonRole kAXMenuButtonRole
198#define QAXMenuClosedNotification kAXMenuClosedNotification
199#define QAXMenuItemRole kAXMenuItemRole
200#define QAXMenuOpenedNotification kAXMenuOpenedNotification
201#define QAXMenuRole kAXMenuRole
202#define QAXMinValueAttribute kAXMinValueAttribute
203#define QAXMinimizeButtonAttribute kAXMinimizeButtonAttribute
204#define QAXMinimizedAttribute kAXMinimizedAttribute
205#define QAXNextContentsAttribute kAXNextContentsAttribute
206#define QAXOrientationAttribute kAXOrientationAttribute
207#define QAXParentAttribute kAXParentAttribute
208#define QAXPickAction kAXPickAction
209#define QAXPopUpButtonRole kAXPopUpButtonRole
210#define QAXPositionAttribute kAXPositionAttribute
211#define QAXPressAction kAXPressAction
212#define QAXPreviousContentsAttribute kAXPreviousContentsAttribute
213#define QAXProgressIndicatorRole kAXProgressIndicatorRole
214#define QAXRadioButtonRole kAXRadioButtonRole
215#define QAXRoleAttribute kAXRoleAttribute
216#define QAXRoleDescriptionAttribute kAXRoleDescriptionAttribute
217#define QAXRowRole kAXRowRole
218#define QAXRowsAttribute kAXRowsAttribute
219#define QAXScrollAreaRole kAXScrollAreaRole
220#define QAXScrollBarRole kAXScrollBarRole
221#define QAXSelectedAttribute kAXSelectedAttribute
222#define QAXSelectedChildrenAttribute kAXSelectedChildrenAttribute
223#define QAXSelectedRowsAttribute kAXSelectedRowsAttribute
224#define QAXSizeAttribute kAXSizeAttribute
225#define QAXSliderRole kAXSliderRole
226#define QAXSplitGroupRole kAXSplitGroupRole
227#define QAXSplitterRole kAXSplitterRole
228#define QAXSplittersAttribute kAXSplittersAttribute
229#define QAXStaticTextRole kAXStaticTextRole
230#define QAXSubroleAttribute kAXSubroleAttribute
231#define QAXTabGroupRole kAXTabGroupRole
232#define QAXTableRole kAXTableRole
233#define QAXTabsAttribute kAXTabsAttribute
234#define QAXTextFieldRole kAXTextFieldRole
235#define QAXTitleAttribute kAXTitleAttribute
236#define QAXTitleUIElementAttribute kAXTitleUIElementAttribute
237#define QAXToolbarButtonAttribute kAXToolbarButtonAttribute
238#define QAXToolbarRole kAXToolbarRole
239#define QAXTopLevelUIElementAttribute kAXTopLevelUIElementAttribute
240#define QAXUnknownRole kAXUnknownRole
241#define QAXValueAttribute kAXValueAttribute
242#define QAXValueChangedNotification kAXValueChangedNotification
243#define QAXValueIndicatorRole kAXValueIndicatorRole
244#define QAXVerticalOrientationValue kAXVerticalOrientationValue
245#define QAXVerticalScrollBarAttribute kAXVerticalScrollBarAttribute
246#define QAXVisibleRowsAttribute kAXVisibleRowsAttribute
247#define QAXWindowAttribute kAXWindowAttribute
248#define QAXWindowCreatedNotification kAXWindowCreatedNotification
249#define QAXWindowMovedNotification kAXWindowMovedNotification
250#define QAXWindowRole kAXWindowRole
251#define QAXZoomButtonAttribute kAXZoomButtonAttribute
252#endif
253
254
255/*****************************************************************************
256 Externals
257 *****************************************************************************/
258extern bool qt_mac_is_macsheet(const QWidget *w); //qwidget_mac.cpp
259extern bool qt_mac_is_macdrawer(const QWidget *w); //qwidget_mac.cpp
260
261/*****************************************************************************
262 QAccessible Bindings
263 *****************************************************************************/
264//hardcoded bindings between control info and (known) QWidgets
265struct QAccessibleTextBinding {
266 int qt;
267 QAXRoleType mac;
268 bool settable;
269} text_bindings[][10] = {
270 { { QAccessible::MenuItem, QAXMenuItemRole, false },
271 { -1, 0, false }
272 },
273 { { QAccessible::MenuBar, QAXMenuBarRole, false },
274 { -1, 0, false }
275 },
276 { { QAccessible::ScrollBar, QAXScrollBarRole, false },
277 { -1, 0, false }
278 },
279 { { QAccessible::Grip, QAXGrowAreaRole, false },
280 { -1, 0, false }
281 },
282 { { QAccessible::Window, QAXWindowRole, false },
283 { -1, 0, false }
284 },
285 { { QAccessible::Dialog, QAXWindowRole, false },
286 { -1, 0, false }
287 },
288 { { QAccessible::AlertMessage, QAXWindowRole, false },
289 { -1, 0, false }
290 },
291 { { QAccessible::ToolTip, QAXWindowRole, false },
292 { -1, 0, false }
293 },
294 { { QAccessible::HelpBalloon, QAXWindowRole, false },
295 { -1, 0, false }
296 },
297 { { QAccessible::PopupMenu, QAXMenuRole, false },
298 { -1, 0, false }
299 },
300 { { QAccessible::Application, QAXApplicationRole, false },
301 { -1, 0, false }
302 },
303 { { QAccessible::Pane, QAXGroupRole, false },
304 { -1, 0, false }
305 },
306 { { QAccessible::Grouping, QAXGroupRole, false },
307 { -1, 0, false }
308 },
309 { { QAccessible::Separator, QAXSplitterRole, false },
310 { -1, 0, false }
311 },
312 { { QAccessible::ToolBar, QAXToolbarRole, false },
313 { -1, 0, false }
314 },
315 { { QAccessible::PageTab, QAXRadioButtonRole, false },
316 { -1, 0, false }
317 },
318 { { QAccessible::ButtonMenu, QAXMenuButtonRole, false },
319 { -1, 0, false }
320 },
321 { { QAccessible::ButtonDropDown, QAXPopUpButtonRole, false },
322 { -1, 0, false }
323 },
324 { { QAccessible::SpinBox, QAXIncrementorRole, false },
325 { -1, 0, false }
326 },
327 { { QAccessible::Slider, QAXSliderRole, false },
328 { -1, 0, false }
329 },
330 { { QAccessible::ProgressBar, QAXProgressIndicatorRole, false },
331 { -1, 0, false }
332 },
333 { { QAccessible::ComboBox, QAXPopUpButtonRole, false },
334 { -1, 0, false }
335 },
336 { { QAccessible::RadioButton, QAXRadioButtonRole, false },
337 { -1, 0, false }
338 },
339 { { QAccessible::CheckBox, QAXCheckBoxRole, false },
340 { -1, 0, false }
341 },
342 { { QAccessible::StaticText, QAXStaticTextRole, false },
343 { QAccessible::Name, QAXValueAttribute, false },
344 { -1, 0, false }
345 },
346 { { QAccessible::Table, QAXTableRole, false },
347 { -1, 0, false }
348 },
349 { { QAccessible::StatusBar, QAXStaticTextRole, false },
350 { -1, 0, false }
351 },
352 { { QAccessible::Column, QAXColumnRole, false },
353 { -1, 0, false }
354 },
355 { { QAccessible::ColumnHeader, QAXColumnRole, false },
356 { -1, 0, false }
357 },
358 { { QAccessible::Row, QAXRowRole, false },
359 { -1, 0, false }
360 },
361 { { QAccessible::RowHeader, QAXRowRole, false },
362 { -1, 0, false }
363 },
364 { { QAccessible::Cell, QAXTextFieldRole, false },
365 { -1, 0, false }
366 },
367 { { QAccessible::PushButton, QAXButtonRole, false },
368 { -1, 0, false }
369 },
370 { { QAccessible::EditableText, QAXTextFieldRole, true },
371 { -1, 0, false }
372 },
373 { { QAccessible::Link, QAXTextFieldRole, false },
374 { -1, 0, false }
375 },
376 { { QAccessible::Indicator, QAXValueIndicatorRole, false },
377 { -1, 0, false }
378 },
379 { { QAccessible::Splitter, QAXSplitGroupRole, false },
380 { -1, 0, false }
381 },
382 { { QAccessible::List, QAXListRole, false },
383 { -1, 0, false }
384 },
385 { { QAccessible::ListItem, QAXStaticTextRole, false },
386 { -1, 0, false }
387 },
388 { { QAccessible::Cell, QAXStaticTextRole, false },
389 { -1, 0, false }
390 },
391 { { -1, 0, false } }
392};
393
394class QAInterface;
395static CFStringRef macRole(const QAInterface &interface);
396
397QDebug operator<<(QDebug debug, const QAInterface &interface)
398{
399 if (interface.isValid() == false)
400 debug << "invalid interface";
401 else
402 debug << interface.object() << "id" << interface.id() << "role" << hex << interface.role();
403 return debug;
404}
405
406// The root of the Qt accessible hiearchy.
407static QObject *rootObject = 0;
408
409
410bool QAInterface::operator==(const QAInterface &other) const
411{
412 if (isValid() == false || other.isValid() == false)
413 return (isValid() && other.isValid());
414
415 // walk up the parent chain, comparing child indexes, until we reach
416 // an interface that has a QObject.
417 QAInterface currentThis = *this;
418 QAInterface currentOther = other;
419
420 while (currentThis.object() == 0) {
421 if (currentOther.object() != 0)
422 return false;
423
424 // fail if the child indexes in the two hirearchies don't match.
425 if (currentThis.parent().indexOfChild(currentThis) !=
426 currentOther.parent().indexOfChild(currentOther))
427 return false;
428
429 currentThis = currentThis.parent();
430 currentOther = currentOther.parent();
431 }
432
433 return (currentThis.object() == currentOther.object() && currentThis.id() == currentOther.id());
434}
435
436bool QAInterface::operator!=(const QAInterface &other) const
437{
438 return !operator==(other);
439}
440
441uint qHash(const QAInterface &item)
442{
443 if (item.isValid())
444 return qHash(item.object()) + qHash(item.id());
445 else
446 return qHash(item.cachedObject()) + qHash(item.id());
447}
448
449QAInterface QAInterface::navigate(RelationFlag relation, int entry) const
450{
451 if (!checkValid())
452 return QAInterface();
453
454 // On a QAccessibleInterface that handles its own children we can short-circut
455 // the navigation if this QAInterface refers to one of the children:
456 if (child != 0) {
457 // The Ancestor interface will always be the same QAccessibleInterface with
458 // a child value of 0.
459 if (relation == QAccessible::Ancestor)
460 return QAInterface(*this, 0);
461
462 // The child hiearchy is only one level deep, so navigating to a child
463 // of a child is not possible.
464 if (relation == QAccessible::Child) {
465 return QAInterface();
466 }
467 }
468 QAccessibleInterface *child_iface = 0;
469
470 const int status = base.interface->navigate(relation, entry, &child_iface);
471
472 if (status == -1)
473 return QAInterface(); // not found;
474
475 // Check if target is a child of this interface.
476 if (!child_iface) {
477 return QAInterface(*this, status);
478 } else {
479 // Target is child_iface or a child of that (status decides).
480 return QAInterface(child_iface, status);
481 }
482}
483
484QAElement::QAElement()
485:elementRef(0)
486{}
487
488QAElement::QAElement(AXUIElementRef elementRef)
489:elementRef(elementRef)
490{
491 if (elementRef != 0) {
492 CFRetain(elementRef);
493 CFRetain(object());
494 }
495}
496
497QAElement::QAElement(const QAElement &element)
498:elementRef(element.elementRef)
499{
500 if (elementRef != 0) {
501 CFRetain(elementRef);
502 CFRetain(object());
503 }
504}
505
506QAElement::QAElement(HIObjectRef object, int child)
507{
508#ifndef QT_MAC_USE_COCOA
509 if (object == 0) {
510 elementRef = 0; // Create invalid QAElement.
511 } else {
512 elementRef = AXUIElementCreateWithHIObjectAndIdentifier(object, child);
513 CFRetain(object);
514 }
515#else
516 Q_UNUSED(object);
517 Q_UNUSED(child);
518#endif
519}
520
521QAElement::~QAElement()
522{
523 if (elementRef != 0) {
524 CFRelease(object());
525 CFRelease(elementRef);
526 }
527}
528
529void QAElement::operator=(const QAElement &other)
530{
531 if (*this == other)
532 return;
533
534 if (elementRef != 0) {
535 CFRelease(object());
536 CFRelease(elementRef);
537 }
538
539 elementRef = other.elementRef;
540
541 if (elementRef != 0) {
542 CFRetain(elementRef);
543 CFRetain(object());
544 }
545}
546
547bool QAElement::operator==(const QAElement &other) const
548{
549 if (elementRef == 0 || other.elementRef == 0)
550 return (elementRef == other.elementRef);
551
552 return CFEqual(elementRef, other.elementRef);
553}
554
555uint qHash(QAElement element)
556{
557 return qHash(element.object()) + qHash(element.id());
558}
559
560#ifndef QT_MAC_USE_COCOA
561static QInterfaceFactory *createFactory(const QAInterface &interface);
562#endif
563Q_GLOBAL_STATIC(QAccessibleHierarchyManager, accessibleHierarchyManager);
564
565/*
566 Reomves all accessibility info accosiated with the sender object.
567*/
568void QAccessibleHierarchyManager::objectDestroyed(QObject *object)
569{
570 HIObjectRef hiObject = qobjectHiobjectHash.value(object);
571 delete qobjectElementHash.value(object);
572 qobjectElementHash.remove(object);
573 hiobjectInterfaceHash.remove(hiObject);
574}
575
576/*
577 Removes all stored items.
578*/
579void QAccessibleHierarchyManager::reset()
580{
581 qDeleteAll(qobjectElementHash);
582 qobjectElementHash.clear();
583 hiobjectInterfaceHash.clear();
584 qobjectHiobjectHash.clear();
585}
586
587QAccessibleHierarchyManager *QAccessibleHierarchyManager::instance()
588{
589 return accessibleHierarchyManager();
590}
591
592#ifndef QT_MAC_USE_COCOA
593static bool isItemView(const QAInterface &interface)
594{
595 QObject *object = interface.object();
596 return (interface.role() == QAccessible::List || interface.role() == QAccessible::Table
597 || (object && qobject_cast<QAbstractItemView *>(interface.object()))
598 || (object && object->objectName() == QLatin1String("qt_scrollarea_viewport")
599 && qobject_cast<QAbstractItemView *>(object->parent())));
600}
601#endif
602
603static bool isTabWidget(const QAInterface &interface)
604{
605 if (QObject *object = interface.object())
606 return (object->inherits("QTabWidget") && interface.id() == 0);
607 return false;
608}
609
610static bool isStandaloneTabBar(const QAInterface &interface)
611{
612 QObject *object = interface.object();
613 if (interface.role() == QAccessible::PageTabList && object)
614 return (qobject_cast<QTabWidget *>(object->parent()) == 0);
615
616 return false;
617}
618
619static bool isEmbeddedTabBar(const QAInterface &interface)
620{
621 QObject *object = interface.object();
622 if (interface.role() == QAccessible::PageTabList && object)
623 return (qobject_cast<QTabWidget *>(object->parent()));
624
625 return false;
626}
627
628/*
629 Decides if a QAInterface is interesting from an accessibility users point of view.
630*/
631bool isItInteresting(const QAInterface &interface)
632{
633 // Mac accessibility does not have an attribute that corresponds to the Invisible/Offscreen
634 // state, so we disable the interface here.
635 const QAccessible::State state = interface.state();
636 if (state & QAccessible::Invisible ||
637 state & QAccessible::Offscreen )
638 return false;
639
640 const QAccessible::Role role = interface.role();
641
642 if (QObject * const object = interface.object()) {
643 const QString className = QLatin1String(object->metaObject()->className());
644
645 // VoiceOver focusing on tool tips can be confusing. The contents of the
646 // tool tip is avalible through the description attribute anyway, so
647 // we disable accessibility for tool tips.
648 if (className == QLatin1String("QTipLabel"))
649 return false;
650
651 // Hide TabBars that has a QTabWidget parent (the tab widget handles the accessibility)
652 if (isEmbeddedTabBar(interface))
653 return false;
654
655 // Hide docked dockwidgets. ### causes infinitie loop in the apple accessibility code.
656 /* if (QDockWidget *dockWidget = qobject_cast<QDockWidget *>(object)) {
657 if (dockWidget->isFloating() == false)
658 return false;
659 }
660 */
661 }
662
663 // Client is a generic role returned by plain QWidgets or other
664 // widgets that does not have separate QAccessible interface, such
665 // as the TabWidget. Return false unless macRole gives the interface
666 // a special role.
667 if (role == QAccessible::Client && macRole(interface) == CFStringRef(QAXUnknownRole))
668 return false;
669
670 // Some roles are not interesting:
671 if (role == QAccessible::Border || // QFrame
672 role == QAccessible::Application || // We use the system-provided application element.
673 role == QAccessible::MenuItem) // The system also provides the menu items.
674 return false;
675
676 // It is probably better to access the toolbar buttons directly than having
677 // to navigate through the toolbar.
678 if (role == QAccessible::ToolBar)
679 return false;
680
681 return true;
682}
683
684QAElement QAccessibleHierarchyManager::registerInterface(QObject *object, int child)
685{
686#ifndef QT_MAC_USE_COCOA
687 return registerInterface(QAInterface(QAccessible::queryAccessibleInterface(object), child));
688#else
689 Q_UNUSED(object);
690 Q_UNUSED(child);
691 return QAElement();
692#endif
693}
694
695/*
696 Creates a QAXUIelement that corresponds to the given QAInterface.
697*/
698QAElement QAccessibleHierarchyManager::registerInterface(const QAInterface &interface)
699{
700#ifndef QT_MAC_USE_COCOA
701 if (interface.isValid() == false)
702 return QAElement();
703 QAInterface objectInterface = interface.objectInterface();
704
705 QObject * qobject = objectInterface.object();
706 HIObjectRef hiobject = objectInterface.hiObject();
707 if (qobject == 0 || hiobject == 0)
708 return QAElement();
709
710 if (qobjectElementHash.contains(qobject) == false) {
711 registerInterface(qobject, hiobject, createFactory(interface));
712 HIObjectSetAccessibilityIgnored(hiobject, !isItInteresting(interface));
713 }
714
715 return QAElement(hiobject, interface.id());
716#else
717 Q_UNUSED(interface);
718 return QAElement();
719#endif
720}
721
722#ifndef QT_MAC_USE_COCOA
723#include "qaccessible_mac_carbon.cpp"
724#endif
725
726void QAccessibleHierarchyManager::registerInterface(QObject * qobject, HIObjectRef hiobject, QInterfaceFactory *interfaceFactory)
727{
728#ifndef QT_MAC_USE_COCOA
729 if (qobjectElementHash.contains(qobject) == false) {
730 qobjectElementHash.insert(qobject, interfaceFactory);
731 qobjectHiobjectHash.insert(qobject, hiobject);
732 connect(qobject, SIGNAL(destroyed(QObject *)), SLOT(objectDestroyed(QObject *)));
733 }
734
735 if (hiobjectInterfaceHash.contains(hiobject) == false) {
736 hiobjectInterfaceHash.insert(hiobject, interfaceFactory);
737 installAcessibilityEventHandler(hiobject);
738 }
739#else
740 Q_UNUSED(qobject);
741 Q_UNUSED(hiobject);
742 Q_UNUSED(interfaceFactory);
743#endif
744}
745
746void QAccessibleHierarchyManager::registerChildren(const QAInterface &interface)
747{
748 QObject * const object = interface.object();
749 if (object == 0)
750 return;
751
752 QInterfaceFactory *interfaceFactory = qobjectElementHash.value(object);
753
754 if (interfaceFactory == 0)
755 return;
756
757 interfaceFactory->registerChildren();
758}
759
760QAInterface QAccessibleHierarchyManager::lookup(const AXUIElementRef &element)
761{
762 if (element == 0)
763 return QAInterface();
764#ifndef QT_MAC_USE_COCOA
765 HIObjectRef hiObject = AXUIElementGetHIObject(element);
766
767 QInterfaceFactory *factory = hiobjectInterfaceHash.value(hiObject);
768 if (factory == 0) {
769 return QAInterface();
770 }
771
772 UInt64 id;
773 AXUIElementGetIdentifier(element, &id);
774 return factory->interface(id);
775#else
776 return QAInterface();
777#endif;
778}
779
780QAInterface QAccessibleHierarchyManager::lookup(const QAElement &element)
781{
782 return lookup(element.element());
783}
784
785QAElement QAccessibleHierarchyManager::lookup(const QAInterface &interface)
786{
787 if (interface.isValid() == false)
788 return QAElement();
789
790 QInterfaceFactory *factory = qobjectElementHash.value(interface.objectInterface().object());
791 if (factory == 0)
792 return QAElement();
793
794 return factory->element(interface);
795}
796
797QAElement QAccessibleHierarchyManager::lookup(QObject * const object, int id)
798{
799 QInterfaceFactory *factory = qobjectElementHash.value(object);
800 if (factory == 0)
801 return QAElement();
802
803 return factory->element(id);
804}
805
806/*
807 Standard interface mapping, return the stored interface
808 or HIObjectRef, and there is an one-to-one mapping between
809 the identifier and child.
810*/
811class QStandardInterfaceFactory : public QInterfaceFactory
812{
813public:
814 QStandardInterfaceFactory(const QAInterface &interface)
815 : m_interface(interface), object(interface.hiObject())
816 {
817 CFRetain(object);
818 }
819
820 ~QStandardInterfaceFactory()
821 {
822 CFRelease(object);
823 }
824
825
826 QAInterface interface(UInt64 identifier)
827 {
828 const int child = identifier;
829 return QAInterface(m_interface, child);
830 }
831
832 QAElement element(int id)
833 {
834 return QAElement(object, id);
835 }
836
837 QAElement element(const QAInterface &interface)
838 {
839 if (interface.object() == 0)
840 return QAElement();
841 return QAElement(object, interface.id());
842 }
843
844 void registerChildren()
845 {
846 const int childCount = m_interface.childCount();
847 for (int i = 1; i <= childCount; ++i) {
848 accessibleHierarchyManager()->registerInterface(m_interface.navigate(QAccessible::Child, i));
849 }
850 }
851
852private:
853 QAInterface m_interface;
854 HIObjectRef object;
855};
856
857/*
858 Interface mapping where that creates one HIObject for each interface child.
859*/
860class QMultipleHIObjectFactory : public QInterfaceFactory
861{
862public:
863 QMultipleHIObjectFactory(const QAInterface &interface)
864 : m_interface(interface)
865 { }
866
867 ~QMultipleHIObjectFactory()
868 {
869 foreach (HIObjectRef object, objects) {
870 CFRelease(object);
871 }
872 }
873
874 QAInterface interface(UInt64 identifier)
875 {
876 const int child = identifier;
877 return QAInterface(m_interface, child);
878 }
879
880 QAElement element(int child)
881 {
882 if (child == 0)
883 return QAElement(m_interface.hiObject(), 0);
884
885 if (child > objects.count())
886 return QAElement();
887
888 return QAElement(objects.at(child - 1), child);
889 }
890
891 void registerChildren()
892 {
893#ifndef QT_MAC_USE_COCOA
894 const int childCount = m_interface.childCount();
895 for (int i = 1; i <= childCount; ++i) {
896 HIObjectRef hiobject;
897 HIObjectCreate(kObjectQtAccessibility, 0, &hiobject);
898 objects.append(hiobject);
899 accessibleHierarchyManager()->registerInterface(m_interface.object(), hiobject, this);
900 HIObjectSetAccessibilityIgnored(hiobject, !isItInteresting(m_interface.navigate(QAccessible::Child, i)));
901 }
902#endif
903 }
904
905private:
906 QAInterface m_interface;
907 QList<HIObjectRef> objects;
908};
909
910class QItemViewInterfaceFactory : public QInterfaceFactory
911{
912public:
913 QItemViewInterfaceFactory(const QAInterface &interface)
914 : m_interface(interface), object(interface.hiObject())
915 {
916 CFRetain(object);
917 columnCount = 0;
918 if (QTableView * tableView = qobject_cast<QTableView *>(interface.parent().object())) {
919 if (tableView->model())
920 columnCount = tableView->model()->columnCount();
921 if (tableView->verticalHeader())
922 ++columnCount;
923 }
924 }
925
926 ~QItemViewInterfaceFactory()