|
1 /**************************************************************************** |
|
2 ** |
|
3 ** Copyright (C) 2009 Nokia Corporation and/or its subsidiary(-ies). |
|
4 ** All rights reserved. |
|
5 ** Contact: Nokia Corporation (qt-info@nokia.com) |
|
6 ** |
|
7 ** This file is part of the QtGui module of the Qt Toolkit. |
|
8 ** |
|
9 ** $QT_BEGIN_LICENSE:LGPL$ |
|
10 ** No Commercial Usage |
|
11 ** This file contains pre-release code and may not be distributed. |
|
12 ** You may use this file in accordance with the terms and conditions |
|
13 ** contained in the Technology Preview License Agreement accompanying |
|
14 ** this package. |
|
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 ** If you have questions regarding the use of this file, please contact |
|
29 ** Nokia at qt-info@nokia.com. |
|
30 ** |
|
31 ** |
|
32 ** |
|
33 ** |
|
34 ** |
|
35 ** |
|
36 ** |
|
37 ** |
|
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 |
|
64 QT_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 |
|
71 typedef 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 |
|
163 typedef 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 *****************************************************************************/ |
|
258 extern bool qt_mac_is_macsheet(const QWidget *w); //qwidget_mac.cpp |
|
259 extern 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 |
|
265 struct 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 |
|
394 class QAInterface; |
|
395 static CFStringRef macRole(const QAInterface &interface); |
|
396 |
|
397 QDebug 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. |
|
407 static QObject *rootObject = 0; |
|
408 |
|
409 |
|
410 bool 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 |
|
436 bool QAInterface::operator!=(const QAInterface &other) const |
|
437 { |
|
438 return !operator==(other); |
|
439 } |
|
440 |
|
441 uint 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 |
|
449 QAInterface 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 |
|
484 QAElement::QAElement() |
|
485 :elementRef(0) |
|
486 {} |
|
487 |
|
488 QAElement::QAElement(AXUIElementRef elementRef) |
|
489 :elementRef(elementRef) |
|
490 { |
|
491 if (elementRef != 0) { |
|
492 CFRetain(elementRef); |
|
493 CFRetain(object()); |
|
494 } |
|
495 } |
|
496 |
|
497 QAElement::QAElement(const QAElement &element) |
|
498 :elementRef(element.elementRef) |
|
499 { |
|
500 if (elementRef != 0) { |
|
501 CFRetain(elementRef); |
|
502 CFRetain(object()); |
|
503 } |
|
504 } |
|
505 |
|
506 QAElement::QAElement(HIObjectRef object, int child) |
|
507 :elementRef( |
|
508 #ifndef QT_MAC_USE_COCOA |
|
509 AXUIElementCreateWithHIObjectAndIdentifier(object, child) |
|
510 #endif |
|
511 ) |
|
512 { |
|
513 #ifndef QT_MAC_USE_COCOA |
|
514 if (object == 0) { |
|
515 elementRef = 0; // Create invalid QAElement. |
|
516 } else { |
|
517 elementRef = AXUIElementCreateWithHIObjectAndIdentifier(object, child); |
|
518 CFRetain(object); |
|
519 } |
|
520 #else |
|
521 Q_UNUSED(object); |
|
522 Q_UNUSED(child); |
|
523 #endif |
|
524 } |
|
525 |
|
526 QAElement::~QAElement() |
|
527 { |
|
528 if (elementRef != 0) { |
|
529 CFRelease(object()); |
|
530 CFRelease(elementRef); |
|
531 } |
|
532 } |
|
533 |
|
534 void QAElement::operator=(const QAElement &other) |
|
535 { |
|
536 if (*this == other) |
|
537 return; |
|
538 |
|
539 if (elementRef != 0) { |
|
540 CFRelease(object()); |
|
541 CFRelease(elementRef); |
|
542 } |
|
543 |
|
544 elementRef = other.elementRef; |
|
545 |
|
546 if (elementRef != 0) { |
|
547 CFRetain(elementRef); |
|
548 CFRetain(object()); |
|
549 } |
|
550 } |
|
551 |
|
552 bool QAElement::operator==(const QAElement &other) const |
|
553 { |
|
554 if (elementRef == 0 || other.elementRef == 0) |
|
555 return (elementRef == other.elementRef); |
|
556 |
|
557 return CFEqual(elementRef, other.elementRef); |
|
558 } |
|
559 |
|
560 uint qHash(QAElement element) |
|
561 { |
|
562 return qHash(element.object()) + qHash(element.id()); |
|
563 } |
|
564 |
|
565 #ifndef QT_MAC_USE_COCOA |
|
566 static QInterfaceFactory *createFactory(const QAInterface &interface); |
|
567 #endif |
|
568 Q_GLOBAL_STATIC(QAccessibleHierarchyManager, accessibleHierarchyManager); |
|
569 |
|
570 /* |
|
571 Reomves all accessibility info accosiated with the sender object. |
|
572 */ |
|
573 void QAccessibleHierarchyManager::objectDestroyed(QObject *object) |
|
574 { |
|
575 HIObjectRef hiObject = qobjectHiobjectHash.value(object); |
|
576 delete qobjectElementHash.value(object); |
|
577 qobjectElementHash.remove(object); |
|
578 hiobjectInterfaceHash.remove(hiObject); |
|
579 } |
|
580 |
|
581 /* |
|
582 Removes all stored items. |
|
583 */ |
|
584 void QAccessibleHierarchyManager::reset() |
|
585 { |
|
586 qDeleteAll(qobjectElementHash); |
|
587 qobjectElementHash.clear(); |
|
588 hiobjectInterfaceHash.clear(); |
|
589 qobjectHiobjectHash.clear(); |
|
590 } |
|
591 |
|
592 QAccessibleHierarchyManager *QAccessibleHierarchyManager::instance() |
|
593 { |
|
594 return accessibleHierarchyManager(); |
|
595 } |
|
596 |
|
597 #ifndef QT_MAC_USE_COCOA |
|
598 static bool isItemView(const QAInterface &interface) |
|
599 { |
|
600 QObject *object = interface.object(); |
|
601 return (interface.role() == QAccessible::List || interface.role() == QAccessible::Table |
|
602 || (object && qobject_cast<QAbstractItemView *>(interface.object())) |
|
603 || (object && object->objectName() == QLatin1String("qt_scrollarea_viewport") |
|
604 && qobject_cast<QAbstractItemView *>(object->parent()))); |
|
605 } |
|
606 #endif |
|
607 |
|
608 static bool isTabWidget(const QAInterface &interface) |
|
609 { |
|
610 if (QObject *object = interface.object()) |
|
611 return (object->inherits("QTabWidget") && interface.id() == 0); |
|
612 return false; |
|
613 } |
|
614 |
|
615 static bool isStandaloneTabBar(const QAInterface &interface) |
|
616 { |
|
617 QObject *object = interface.object(); |
|
618 if (interface.role() == QAccessible::PageTabList && object) |
|
619 return (qobject_cast<QTabWidget *>(object->parent()) == 0); |
|
620 |
|
621 return false; |
|
622 } |
|
623 |
|
624 static bool isEmbeddedTabBar(const QAInterface &interface) |
|
625 { |
|
626 QObject *object = interface.object(); |
|
627 if (interface.role() == QAccessible::PageTabList && object) |
|
628 return (qobject_cast<QTabWidget *>(object->parent())); |
|
629 |
|
630 return false; |
|
631 } |
|
632 |
|
633 /* |
|
634 Decides if a QAInterface is interesting from an accessibility users point of view. |
|
635 */ |
|
636 bool isItInteresting(const QAInterface &interface) |
|
637 { |
|
638 // Mac accessibility does not have an attribute that corresponds to the Invisible/Offscreen |
|
639 // state, so we disable the interface here. |
|
640 const QAccessible::State state = interface.state(); |
|
641 if (state & QAccessible::Invisible || |
|
642 state & QAccessible::Offscreen ) |
|
643 return false; |
|
644 |
|
645 const QAccessible::Role role = interface.role(); |
|
646 |
|
647 if (QObject * const object = interface.object()) { |
|
648 const QString className = QLatin1String(object->metaObject()->className()); |
|
649 |
|
650 // VoiceOver focusing on tool tips can be confusing. The contents of the |
|
651 // tool tip is avalible through the description attribute anyway, so |
|
652 // we disable accessibility for tool tips. |
|
653 if (className == QLatin1String("QTipLabel")) |
|
654 return false; |
|
655 |
|
656 // Hide TabBars that has a QTabWidget parent (the tab widget handles the accessibility) |
|
657 if (isEmbeddedTabBar(interface)) |
|
658 return false; |
|
659 |
|
660 // Hide docked dockwidgets. ### causes infinitie loop in the apple accessibility code. |
|
661 /* if (QDockWidget *dockWidget = qobject_cast<QDockWidget *>(object)) { |
|
662 if (dockWidget->isFloating() == false) |
|
663 return false; |
|
664 } |
|
665 */ |
|
666 } |
|
667 |
|
668 // Client is a generic role returned by plain QWidgets or other |
|
669 // widgets that does not have separate QAccessible interface, such |
|
670 // as the TabWidget. Return false unless macRole gives the interface |
|
671 // a special role. |
|
672 if (role == QAccessible::Client && macRole(interface) == CFStringRef(QAXUnknownRole)) |
|
673 return false; |
|
674 |
|
675 // Some roles are not interesting: |
|
676 if (role == QAccessible::Border || // QFrame |
|
677 role == QAccessible::Application || // We use the system-provided application element. |
|
678 role == QAccessible::MenuItem) // The system also provides the menu items. |
|
679 return false; |
|
680 |
|
681 // It is probably better to access the toolbar buttons directly than having |
|
682 // to navigate through the toolbar. |
|
683 if (role == QAccessible::ToolBar) |
|
684 return false; |
|
685 |
|
686 return true; |
|
687 } |
|
688 |
|
689 QAElement QAccessibleHierarchyManager::registerInterface(QObject *object, int child) |
|
690 { |
|
691 #ifndef QT_MAC_USE_COCOA |
|
692 return registerInterface(QAInterface(QAccessible::queryAccessibleInterface(object), child)); |
|
693 #else |
|
694 Q_UNUSED(object); |
|
695 Q_UNUSED(child); |
|
696 return QAElement(); |
|
697 #endif |
|
698 } |
|
699 |
|
700 /* |
|
701 Creates a QAXUIelement that corresponds to the given QAInterface. |
|
702 */ |
|
703 QAElement QAccessibleHierarchyManager::registerInterface(const QAInterface &interface) |
|
704 { |
|
705 #ifndef QT_MAC_USE_COCOA |
|
706 if (interface.isValid() == false) |
|
707 return QAElement(); |
|
708 QAInterface objectInterface = interface.objectInterface(); |
|
709 |
|
710 QObject * qobject = objectInterface.object(); |
|
711 HIObjectRef hiobject = objectInterface.hiObject(); |
|
712 if (qobject == 0 || hiobject == 0) |
|
713 return QAElement(); |
|
714 |
|
715 if (qobjectElementHash.contains(qobject) == false) { |
|
716 registerInterface(qobject, hiobject, createFactory(interface)); |
|
717 HIObjectSetAccessibilityIgnored(hiobject, !isItInteresting(interface)); |
|
718 } |
|
719 |
|
720 return QAElement(hiobject, interface.id()); |
|
721 #else |
|
722 Q_UNUSED(interface); |
|
723 return QAElement(); |
|
724 #endif |
|
725 } |
|
726 |
|
727 #ifndef QT_MAC_USE_COCOA |
|
728 #include "qaccessible_mac_carbon.cpp" |
|
729 #endif |
|
730 |
|
731 void QAccessibleHierarchyManager::registerInterface(QObject * qobject, HIObjectRef hiobject, QInterfaceFactory *interfaceFactory) |
|
732 { |
|
733 #ifndef QT_MAC_USE_COCOA |
|
734 if (qobjectElementHash.contains(qobject) == false) { |
|
735 qobjectElementHash.insert(qobject, interfaceFactory); |
|
736 qobjectHiobjectHash.insert(qobject, hiobject); |
|
737 connect(qobject, SIGNAL(destroyed(QObject *)), SLOT(objectDestroyed(QObject *))); |
|
738 } |
|
739 |
|
740 if (hiobjectInterfaceHash.contains(hiobject) == false) { |
|
741 hiobjectInterfaceHash.insert(hiobject, interfaceFactory); |
|
742 installAcessibilityEventHandler(hiobject); |
|
743 } |
|
744 #else |
|
745 Q_UNUSED(qobject); |
|
746 Q_UNUSED(hiobject); |
|
747 Q_UNUSED(interfaceFactory); |
|
748 #endif |
|
749 } |
|
750 |
|
751 void QAccessibleHierarchyManager::registerChildren(const QAInterface &interface) |
|
752 { |
|
753 QObject * const object = interface.object(); |
|
754 if (object == 0) |
|
755 return; |
|
756 |
|
757 QInterfaceFactory *interfaceFactory = qobjectElementHash.value(object); |
|
758 |
|
759 if (interfaceFactory == 0) |
|
760 return; |
|
761 |
|
762 interfaceFactory->registerChildren(); |
|
763 } |
|
764 |
|
765 QAInterface QAccessibleHierarchyManager::lookup(const AXUIElementRef &element) |
|
766 { |
|
767 if (element == 0) |
|
768 return QAInterface(); |
|
769 #ifndef QT_MAC_USE_COCOA |
|
770 HIObjectRef hiObject = AXUIElementGetHIObject(element); |
|
771 |
|
772 QInterfaceFactory *factory = hiobjectInterfaceHash.value(hiObject); |
|
773 if (factory == 0) { |
|
774 return QAInterface(); |
|
775 } |
|
776 |
|
777 UInt64 id; |
|
778 AXUIElementGetIdentifier(element, &id); |
|
779 return factory->interface(id); |
|
780 #else |
|
781 return QAInterface(); |
|
782 #endif; |
|
783 } |
|
784 |
|
785 QAInterface QAccessibleHierarchyManager::lookup(const QAElement &element) |
|
786 { |
|
787 return lookup(element.element()); |
|
788 } |
|
789 |
|
790 QAElement QAccessibleHierarchyManager::lookup(const QAInterface &interface) |
|
791 { |
|
792 if (interface.isValid() == false) |
|
793 return QAElement(); |
|
794 |
|
795 QInterfaceFactory *factory = qobjectElementHash.value(interface.objectInterface().object()); |
|
796 if (factory == 0) |
|
797 return QAElement(); |
|
798 |
|
799 return factory->element(interface); |
|
800 } |
|
801 |
|
802 QAElement QAccessibleHierarchyManager::lookup(QObject * const object, int id) |
|
803 { |
|
804 QInterfaceFactory *factory = qobjectElementHash.value(object); |
|
805 if (factory == 0) |
|
806 return QAElement(); |
|
807 |
|
808 return factory->element(id); |
|
809 } |
|
810 |
|
811 /* |
|
812 Standard interface mapping, return the stored interface |
|
813 or HIObjectRef, and there is an one-to-one mapping between |
|
814 the identifier and child. |
|
815 */ |
|
816 class QStandardInterfaceFactory : public QInterfaceFactory |
|
817 { |
|
818 public: |
|
819 QStandardInterfaceFactory(const QAInterface &interface) |
|
820 : m_interface(interface), object(interface.hiObject()) |
|
821 { |
|
822 CFRetain(object); |
|
823 } |
|
824 |
|
825 ~QStandardInterfaceFactory() |
|
826 { |
|
827 CFRelease(object); |
|
828 } |
|
829 |
|
830 |
|
831 QAInterface interface(UInt64 identifier) |
|
832 { |
|
833 const int child = identifier; |
|
834 return QAInterface(m_interface, child); |
|
835 } |
|
836 |
|
837 QAElement element(int id) |
|
838 { |
|
839 return QAElement(object, id); |
|
840 } |
|
841 |
|
842 QAElement element(const QAInterface &interface) |
|
843 { |
|
844 if (interface.object() == 0) |
|
845 return QAElement(); |
|
846 return QAElement(object, interface.id()); |
|
847 } |
|
848 |
|
849 void registerChildren() |
|
850 { |
|
851 const int childCount = m_interface.childCount(); |
|
852 for (int i = 1; i <= childCount; ++i) { |
|
853 accessibleHierarchyManager()->registerInterface(m_interface.navigate(QAccessible::Child, i)); |
|
854 } |
|
855 } |
|
856 |
|
857 private: |
|
858 QAInterface m_interface; |
|
859 HIObjectRef object; |
|
860 }; |
|
861 |
|
862 /* |
|
863 Interface mapping where that creates one HIObject for each interface child. |
|
864 */ |
|
865 class QMultipleHIObjectFactory : public QInterfaceFactory |
|
866 { |
|
867 public: |
|
868 QMultipleHIObjectFactory(const QAInterface &interface) |
|
869 : m_interface(interface) |
|
870 { } |
|
871 |
|
872 ~QMultipleHIObjectFactory() |
|
873 { |
|
874 foreach (HIObjectRef object, objects) { |
|
875 CFRelease(object); |
|
876 } |
|
877 } |
|
878 |
|
879 QAInterface interface(UInt64 identifier) |
|
880 { |
|
881 const int child = identifier; |
|
882 return QAInterface(m_interface, child); |
|
883 } |
|
884 |
|
885 QAElement element(int child) |
|
886 { |
|
887 if (child == 0) |
|
888 return QAElement(m_interface.hiObject(), 0); |
|
889 |
|
890 if (child > objects.count()) |
|
891 return QAElement(); |
|
892 |
|
893 return QAElement(objects.at(child - 1), child); |
|
894 } |
|
895 |
|
896 void registerChildren() |
|
897 { |
|
898 #ifndef QT_MAC_USE_COCOA |
|
899 const int childCount = m_interface.childCount(); |
|
900 for (int i = 1; i <= childCount; ++i) { |
|
901 HIObjectRef hiobject; |
|
902 HIObjectCreate(kObjectQtAccessibility, 0, &hiobject); |
|
903 objects.append(hiobject); |
|
904 accessibleHierarchyManager()->registerInterface(m_interface.object(), hiobject, this); |
|
905 HIObjectSetAccessibilityIgnored(hiobject, !isItInteresting(m_interface.navigate(QAccessible::Child, i))); |
|
906 } |
|
907 #endif |
|
908 } |
|
909 |
|
910 private: |
|
911 QAInterface m_interface; |
|
912 QList<HIObjectRef> objects; |
|
913 }; |
|
914 |
|
915 class QItemViewInterfaceFactory : public QInterfaceFactory |
|
916 { |
|
917 public: |
|
918 QItemViewInterfaceFactory(const QAInterface &interface) |
|
919 : m_interface(interface), object(interface.hiObject()) |
|
920 { |
|
921 CFRetain(object); |
|
922 columnCount = 0; |
|
923 if (QTableView * tableView = qobject_cast<QTableView *>(interface.parent().object())) { |
|
924 if (tableView->model()) |
|
925 columnCount = tableView->model()->columnCount(); |
|
926 if (tableView->verticalHeader()) |
|
927 ++columnCount; |
|
928 } |
|
929 } |
|
930 |
|
931 ~QItemViewInterfaceFactory() |
|
932 { |
|
933 CFRelease(object); |
|
934 } |
|
935 |
|
936 QAInterface interface(UInt64 identifier) |
|
937 { |
|
938 if (identifier == 0) |
|
939 return m_interface; |
|
940 |
|
941 if (m_interface.role() == QAccessible::List) |
|
942 return m_interface.childAt(identifier); |
|
943 |
|
944 if (m_interface.role() == QAccessible::Table) { |
|
945 const int index = identifier; |
|
946 if (index == 0) |
|
947 return m_interface; // return the item view interface. |
|
948 |
|
949 const int rowIndex = (index - 1) / (columnCount + 1); |
|
950 const int cellIndex = (index - 1) % (columnCount + 1); |
|
951 /* |
|
952 qDebug() << "index" << index; |
|
953 qDebug() << "rowIndex" << rowIndex; |
|
954 qDebug() << "cellIndex" << cellIndex; |
|
955 */ |
|
956 const QAInterface rowInterface = m_interface.childAt(rowIndex + 1); |
|
957 |
|
958 if ((cellIndex) == 0) // Is it a row? |
|
959 return rowInterface; |
|
960 else { |
|
961 return rowInterface.childAt(cellIndex); |
|
962 } |
|
963 } |
|
964 |
|
965 return QAInterface(); |
|
966 } |
|
967 |
|
968 QAElement element(int id) |
|
969 { |
|
970 if (id != 0) { |
|
971 return QAElement(); |
|
972 } |
|
973 return QAElement(object, 0); |
|
974 } |
|
975 |
|
976 QAElement element(const QAInterface &interface) |
|
977 { |
|
978 if (interface.object() && interface.object() == m_interface.object()) { |
|
979 return QAElement(object, 0); |
|
980 } else if (m_interface.role() == QAccessible::List) { |
|
981 if (interface.parent().object() && interface.parent().object() == m_interface.object()) |
|
982 return QAElement(object, m_interface.indexOfChild(interface)); |
|
983 } else if (m_interface.role() == QAccessible::Table) { |
|
984 QAInterface currentInterface = interface; |
|
985 int index = 0; |
|
986 |
|
987 while (currentInterface.isValid() && currentInterface.object() == 0) { |
|
988 const QAInterface parentInterface = currentInterface.parent(); |
|
989 /* |
|
990 qDebug() << "current index" << index; |
|
991 qDebug() << "current interface" << interface; |
|
992 |
|
993 qDebug() << "parent interface" << parentInterface; |
|
994 qDebug() << "grandparent interface" << parentInterface.parent(); |
|
995 qDebug() << "childCount" << interface.childCount(); |
|
996 qDebug() << "index of child" << parentInterface.indexOfChild(currentInterface); |
|
997 */ |
|
998 index += ((parentInterface.indexOfChild(currentInterface) - 1) * (currentInterface.childCount() + 1)) + 1; |
|
999 currentInterface = parentInterface; |
|
1000 // qDebug() << "new current interface" << currentInterface; |
|
1001 } |
|
1002 if (currentInterface.object() == m_interface.object()) |
|
1003 return QAElement(object, index); |
|
1004 |
|
1005 |
|
1006 } |
|
1007 return QAElement(); |
|
1008 } |
|
1009 |
|
1010 void registerChildren() |
|
1011 { |
|
1012 // Item view child interfraces don't have their own qobjects, so there is nothing to register here. |
|
1013 } |
|
1014 |
|
1015 private: |
|
1016 QAInterface m_interface; |
|
1017 HIObjectRef object; |
|
1018 int columnCount; // for table views; |
|
1019 }; |
|
1020 |
|
1021 #ifndef QT_MAC_USE_COCOA |
|
1022 static bool managesChildren(const QAInterface &interface) |
|
1023 { |
|
1024 return (interface.childCount() > 0 && interface.childAt(1).id() > 0); |
|
1025 } |
|
1026 |
|
1027 static QInterfaceFactory *createFactory(const QAInterface &interface) |
|
1028 { |
|
1029 if (isItemView(interface)) { |
|
1030 return new QItemViewInterfaceFactory(interface); |
|
1031 } if (managesChildren(interface)) { |
|
1032 return new QMultipleHIObjectFactory(interface); |
|
1033 } |
|
1034 |
|
1035 return new QStandardInterfaceFactory(interface); |
|
1036 } |
|
1037 #endif |
|
1038 |
|
1039 QList<QAElement> lookup(const QList<QAInterface> &interfaces) |
|
1040 { |
|
1041 QList<QAElement> elements; |
|
1042 foreach (const QAInterface &interface, interfaces) |
|
1043 if (interface.isValid()) { |
|
1044 const QAElement element = accessibleHierarchyManager()->lookup(interface); |
|
1045 if (element.isValid()) |
|
1046 elements.append(element); |
|
1047 } |
|
1048 return elements; |
|
1049 } |
|
1050 |
|
1051 // Debug output helpers: |
|
1052 /* |
|
1053 static QString nameForEventKind(UInt32 kind) |
|
1054 { |
|
1055 switch(kind) { |
|
1056 case kEventAccessibleGetChildAtPoint: return QString("GetChildAtPoint"); break; |
|
1057 case kEventAccessibleGetAllAttributeNames: return QString("GetAllAttributeNames"); break; |
|
1058 case kEventAccessibleGetNamedAttribute: return QString("GetNamedAttribute"); break; |
|
1059 case kEventAccessibleSetNamedAttribute: return QString("SetNamedAttribute"); break; |
|
1060 case kEventAccessibleGetAllActionNames: return QString("GetAllActionNames"); break; |
|
1061 case kEventAccessibleGetFocusedChild: return QString("GetFocusedChild"); break; |
|
1062 default: |
|
1063 return QString("Unknown accessibility event type: %1").arg(kind); |
|
1064 break; |
|
1065 }; |
|
1066 } |
|
1067 */ |
|
1068 #ifndef QT_MAC_USE_COCOA |
|
1069 static bool qt_mac_append_cf_uniq(CFMutableArrayRef array, CFTypeRef value) |
|
1070 { |
|
1071 if (value == 0) |
|
1072 return false; |
|
1073 |
|
1074 CFRange range; |
|
1075 range.location = 0; |
|
1076 range.length = CFArrayGetCount(array); |
|
1077 if(!CFArrayContainsValue(array, range, value)) { |
|
1078 CFArrayAppendValue(array, value); |
|
1079 return true; |
|
1080 } |
|
1081 return false; |
|
1082 } |
|
1083 |
|
1084 static OSStatus setAttributeValue(EventRef event, const QList<QAElement> &elements) |
|
1085 { |
|
1086 CFMutableArrayRef array = CFArrayCreateMutable(0, 0, &kCFTypeArrayCallBacks); |
|
1087 foreach (const QAElement &element, elements) { |
|
1088 if (element.isValid()) |
|
1089 CFArrayAppendValue(array, element.element()); |
|
1090 } |
|
1091 |
|
1092 const OSStatus err = SetEventParameter(event, kEventParamAccessibleAttributeValue, |
|
1093 typeCFTypeRef, sizeof(array), &array); |
|
1094 CFRelease(array); |
|
1095 return err; |
|
1096 } |
|
1097 #endif //QT_MAC_USE_COCOA |
|
1098 |
|
1099 /* |
|
1100 Gets the AccessibleObject parameter from an event. |
|
1101 */ |
|
1102 static inline AXUIElementRef getAccessibleObjectParameter(EventRef event) |
|
1103 { |
|
1104 AXUIElementRef element; |
|
1105 GetEventParameter(event, kEventParamAccessibleObject, typeCFTypeRef, 0, |
|
1106 sizeof(element), 0, &element); |
|
1107 return element; |
|
1108 } |
|
1109 |
|
1110 /* |
|
1111 The application event handler makes sure that all top-level qt windows are registered |
|
1112 before any accessibility events are handeled. |
|
1113 */ |
|
1114 #ifndef QT_MAC_USE_COCOA |
|
1115 static OSStatus applicationEventHandler(EventHandlerCallRef next_ref, EventRef event, void *) |
|
1116 { |
|
1117 QAInterface rootInterface(QAccessible::queryAccessibleInterface(rootObject ? rootObject : qApp), 0); |
|
1118 accessibleHierarchyManager()->registerChildren(rootInterface); |
|
1119 |
|
1120 return CallNextEventHandler(next_ref, event); |
|
1121 } |
|
1122 |
|
1123 /* |
|
1124 Returns the value for element by combining the QAccessibility::Checked and |
|
1125 QAccessibility::Mixed flags into an int value that the Mac accessibilty |
|
1126 system understands. This works for check boxes, radio buttons, and the like. |
|
1127 The return values are: |
|
1128 0: unchecked |
|
1129 1: checked |
|
1130 2: undecided |
|
1131 */ |
|
1132 static int buttonValue(QAInterface element) |
|
1133 { |
|
1134 const QAccessible::State state = element.state(); |
|
1135 if (state & QAccessible::Mixed) |
|
1136 return 2; |
|
1137 else if(state & QAccessible::Checked) |
|
1138 return 1; |
|
1139 else |
|
1140 return 0; |
|
1141 } |
|
1142 |
|
1143 static QString getValue(const QAInterface &interface) |
|
1144 { |
|
1145 const QAccessible::Role role = interface.role(); |
|
1146 if (role == QAccessible::RadioButton || role == QAccessible::CheckBox) |
|
1147 return QString::number(buttonValue(interface)); |
|
1148 else |
|
1149 return interface.text(QAccessible::Value); |
|
1150 } |
|
1151 #endif //QT_MAC_USE_COCOA |
|
1152 |
|
1153 /* |
|
1154 Translates a QAccessible::Role into a mac accessibility role. |
|
1155 */ |
|
1156 static CFStringRef macRole(const QAInterface &interface) |
|
1157 { |
|
1158 const QAccessible::Role qtRole = interface.role(); |
|
1159 |
|
1160 // qDebug() << "role for" << interface.object() << "interface role" << hex << qtRole; |
|
1161 |
|
1162 // Qt accessibility: QAccessible::Splitter contains QAccessible::Grip. |
|
1163 // Mac accessibility: AXSplitGroup contains AXSplitter. |
|
1164 if (qtRole == QAccessible::Grip) { |
|
1165 const QAInterface parent = interface.parent(); |
|
1166 if (parent.isValid() && parent.role() == QAccessible::Splitter) |
|
1167 return CFStringRef(QAXSplitterRole); |
|
1168 } |
|
1169 |
|
1170 // Tab widgets and standalone tab bars get the kAXTabGroupRole. Accessibility |
|
1171 // for tab bars emebedded in a tab widget is handled by the tab widget. |
|
1172 if (isTabWidget(interface) || isStandaloneTabBar(interface)) |
|
1173 return kAXTabGroupRole; |
|
1174 |
|
1175 if (QObject *object = interface.object()) { |
|
1176 // ### The interface for an abstract scroll area returns the generic "Client" |
|
1177 // role, so we have to to an extra detect on the QObject here. |
|
1178 if (object->inherits("QAbstractScrollArea") && interface.id() == 0) |
|
1179 return CFStringRef(QAXScrollAreaRole); |
|
1180 |
|
1181 if (object->inherits("QDockWidget")) |
|
1182 return CFStringRef(QAXUnknownRole); |
|
1183 } |
|
1184 |
|
1185 int i = 0; |
|
1186 int testRole = text_bindings[i][0].qt; |
|
1187 while (testRole != -1) { |
|
1188 if (testRole == qtRole) |
|
1189 return CFStringRef(text_bindings[i][0].mac); |
|
1190 ++i; |
|
1191 testRole = text_bindings[i][0].qt; |
|
1192 } |
|
1193 |
|
1194 // qDebug() << "got unknown role!" << interface << interface.parent(); |
|
1195 |
|
1196 return CFStringRef(QAXUnknownRole); |
|
1197 } |
|
1198 |
|
1199 /* |
|
1200 Translates a QAccessible::Role and an attribute name into a QAccessible::Text, taking into |
|
1201 account execptions listed in text_bindings. |
|
1202 */ |
|
1203 #ifndef QT_MAC_USE_COCOA |
|
1204 static int textForRoleAndAttribute(QAccessible::Role role, CFStringRef attribute) |
|
1205 { |
|
1206 // Search for exception, return it if found. |
|
1207 int testRole = text_bindings[0][0].qt; |
|
1208 int i = 0; |
|
1209 while (testRole != -1) { |
|
1210 if (testRole == role) { |
|
1211 int j = 1; |
|
1212 int qtRole = text_bindings[i][j].qt; |
|
1213 CFStringRef testAttribute = CFStringRef(text_bindings[i][j].mac); |
|
1214 while (qtRole != -1) { |
|
1215 if (CFStringCompare(attribute, testAttribute, 0) == kCFCompareEqualTo) { |
|
1216 return (QAccessible::Text)qtRole; |
|
1217 } |
|
1218 ++j; |
|
1219 testAttribute = CFStringRef(text_bindings[i][j].mac); /// ### custom compare |
|
1220 qtRole = text_bindings[i][j].qt; /// ### custom compare |
|
1221 } |
|
1222 break; |
|
1223 } |
|
1224 ++i; |
|
1225 testRole = text_bindings[i][0].qt; |
|
1226 } |
|
1227 |
|
1228 // Return default mappping |
|
1229 if (CFStringCompare(attribute, CFStringRef(QAXTitleAttribute), 0) == kCFCompareEqualTo) |
|
1230 return QAccessible::Name; |
|
1231 else if (CFStringCompare(attribute, CFStringRef(QAXValueAttribute), 0) == kCFCompareEqualTo) |
|
1232 return QAccessible::Value; |
|
1233 else if (CFStringCompare(attribute, CFStringRef(QAXHelpAttribute), 0) == kCFCompareEqualTo) |
|
1234 return QAccessible::Help; |
|
1235 else if (CFStringCompare(attribute, CFStringRef(QAXDescriptionAttribute), 0) == kCFCompareEqualTo) |
|
1236 return QAccessible::Description; |
|
1237 else |
|
1238 return -1; |
|
1239 } |
|
1240 |
|
1241 /* |
|
1242 Returns the subrole string constant for the interface if it has one, |
|
1243 else returns an empty string. |
|
1244 */ |
|
1245 static QCFString subrole(const QAInterface &interface) |
|
1246 { |
|
1247 const QAInterface parent = interface.parent(); |
|
1248 if (parent.isValid() == false) |
|
1249 return QCFString(); |
|
1250 |
|
1251 if (parent.role() == QAccessible::ScrollBar) { |
|
1252 QCFString subrole; |
|
1253 switch(interface.id()) { |
|
1254 case 1: subrole = CFStringRef(QAXDecrementArrowSubrole); break; |
|
1255 case 2: subrole = CFStringRef(QAXDecrementPageSubrole); break; |
|
1256 case 4: subrole = CFStringRef(QAXIncrementPageSubrole); break; |
|
1257 case 5: subrole = CFStringRef(QAXIncrementArrowSubrole); break; |
|
1258 default: |
|
1259 break; |
|
1260 } |
|
1261 return subrole; |
|
1262 } |
|
1263 return QCFString(); |
|
1264 } |
|
1265 |
|
1266 // Gets the scroll bar orientation by asking the QAbstractSlider object directly. |
|
1267 static Qt::Orientation scrollBarOrientation(const QAInterface &scrollBar) |
|
1268 { |
|
1269 QObject *const object = scrollBar.object(); |
|
1270 if (QAbstractSlider * const sliderObject = qobject_cast<QAbstractSlider * const>(object)) |
|
1271 return sliderObject->orientation(); |
|
1272 |
|
1273 return Qt::Vertical; // D'oh! The interface wasn't a scroll bar. |
|
1274 } |
|
1275 |
|
1276 static QAInterface scrollAreaGetScrollBarInterface(const QAInterface &scrollArea, Qt::Orientation orientation) |
|
1277 { |
|
1278 if (macRole(scrollArea) != CFStringRef(CFStringRef(QAXScrollAreaRole))) |
|
1279 return QAInterface(); |
|
1280 |
|
1281 // Child 1 is the contents widget, 2 and 3 are the scroll bar containers wich contains possible scroll bars. |
|
1282 for (int i = 2; i <= 3; ++i) { |
|
1283 QAInterface scrollBarContainer = scrollArea.childAt(i); |
|
1284 for (int i = 1; i <= scrollBarContainer.childCount(); ++i) { |
|
1285 QAInterface scrollBar = scrollBarContainer.childAt(i); |
|
1286 if (scrollBar.isValid() && |
|
1287 scrollBar.role() == QAccessible::ScrollBar && |
|
1288 scrollBarOrientation(scrollBar) == orientation) |
|
1289 return scrollBar; |
|
1290 } |
|
1291 } |
|
1292 |
|
1293 return QAInterface(); |
|
1294 } |
|
1295 |
|
1296 static bool scrollAreaHasScrollBar(const QAInterface &scrollArea, Qt::Orientation orientation) |
|
1297 { |
|
1298 return scrollAreaGetScrollBarInterface(scrollArea, orientation).isValid(); |
|
1299 } |
|
1300 |
|
1301 static QAElement scrollAreaGetScrollBar(const QAInterface &scrollArea, Qt::Orientation orientation) |
|
1302 { |
|
1303 return accessibleHierarchyManager()->lookup(scrollAreaGetScrollBarInterface(scrollArea, orientation)); |
|
1304 } |
|
1305 |
|
1306 static QAElement scrollAreaGetContents(const QAInterface &scrollArea) |
|
1307 { |
|
1308 // Child 1 is the contents widget, |
|
1309 return accessibleHierarchyManager()->lookup(scrollArea.navigate(QAccessible::Child, 1)); |
|
1310 } |
|
1311 |
|
1312 static QAElement tabWidgetGetContents(const QAInterface &interface) |
|
1313 { |
|
1314 // A kAXTabGroup has a kAXContents attribute, which consists of the |
|
1315 // ui elements for the current tab page. Get the current tab page |
|
1316 // from the QStackedWidget, where the current visible page can |
|
1317 // be found at index 1. |
|
1318 QAInterface stackedWidget = interface.childAt(1); |
|
1319 accessibleHierarchyManager()->registerChildren(stackedWidget); |
|
1320 QAInterface tabPageInterface = stackedWidget.childAt(1); |
|
1321 return accessibleHierarchyManager()->lookup(tabPageInterface); |
|
1322 } |
|
1323 |
|
1324 static QList<QAElement> tabBarGetTabs(const QAInterface &interface) |
|
1325 { |
|
1326 // Get the tabs by searching for children with the "PageTab" role. |
|
1327 // This filters out the left/right navigation buttons. |
|
1328 accessibleHierarchyManager()->registerChildren(interface); |
|
1329 QList<QAElement> tabs; |
|
1330 const int numChildren = interface.childCount(); |
|
1331 for (int i = 1; i < numChildren + 1; ++i) { |
|
1332 QAInterface child = interface.navigate(QAccessible::Child, i); |
|
1333 if (child.isValid() && child.role() == QAccessible::PageTab) { |
|
1334 tabs.append(accessibleHierarchyManager()->lookup(child)); |
|
1335 } |
|
1336 } |
|
1337 return tabs; |
|
1338 } |
|
1339 |
|
1340 static QList<QAElement> tabWidgetGetTabs(const QAInterface &interface) |
|
1341 { |
|
1342 // Each QTabWidget has two children, a QStackedWidget and a QTabBar. |
|
1343 // Get the tabs from the QTabBar. |
|
1344 return tabBarGetTabs(interface.childAt(2)); |
|
1345 } |
|
1346 |
|
1347 static QList<QAElement> tabWidgetGetChildren(const QAInterface &interface) |
|
1348 { |
|
1349 // The children for a kAXTabGroup should consist of the tabs and the |
|
1350 // contents of the current open tab page. |
|
1351 QList<QAElement> children = tabWidgetGetTabs(interface); |
|
1352 children += tabWidgetGetContents(interface); |
|
1353 return children; |
|
1354 } |
|
1355 #endif //QT_MAC_USE_COCOA |
|
1356 |
|
1357 /* |
|
1358 Returns the label (buddy) interface for interface, or 0 if it has none. |
|
1359 */ |
|
1360 /* |
|
1361 static QAInterface findLabel(const QAInterface &interface) |
|
1362 { |
|
1363 return interface.navigate(QAccessible::Label, 1); |
|
1364 } |
|
1365 */ |
|
1366 /* |
|
1367 Returns a list of interfaces this interface labels, or an empty list if it doesn't label any. |
|
1368 */ |
|
1369 /* |
|
1370 static QList<QAInterface> findLabelled(const QAInterface &interface) |
|
1371 { |
|
1372 QList<QAInterface> interfaceList; |
|
1373 |
|
1374 int count = 1; |
|
1375 const QAInterface labelled = interface.navigate(QAccessible::Labelled, count); |
|
1376 while (labelled.isValid()) { |
|
1377 interfaceList.append(labelled); |
|
1378 ++count; |
|
1379 } |
|
1380 return interfaceList; |
|
1381 } |
|
1382 */ |
|
1383 /* |
|
1384 Tests if the given QAInterface has data for a mac attribute. |
|
1385 */ |
|
1386 #ifndef QT_MAC_USE_COCOA |
|
1387 static bool supportsAttribute(CFStringRef attribute, const QAInterface &interface) |
|
1388 { |
|
1389 const int text = textForRoleAndAttribute(interface.role(), attribute); |
|
1390 |
|
1391 // Special case: Static texts don't have a title. |
|
1392 if (interface.role() == QAccessible::StaticText && attribute == CFStringRef(QAXTitleAttribute)) |
|
1393 return false; |
|
1394 |
|
1395 // Return true if we the attribute matched a QAccessible::Role and we get text for that role from the interface. |
|
1396 if (text != -1) { |
|
1397 if (text == QAccessible::Value) // Special case for Value, see getValue() |
|
1398 return !getValue(interface).isEmpty(); |
|
1399 else |
|
1400 return !interface.text((QAccessible::Text)text).isEmpty(); |
|
1401 } |
|
1402 |
|
1403 if (CFStringCompare(attribute, CFStringRef(QAXChildrenAttribute), 0) == kCFCompareEqualTo) { |
|
1404 if (interface.childCount() > 0) |
|
1405 return true; |
|
1406 } |
|
1407 |
|
1408 if (CFStringCompare(attribute, CFStringRef(QAXSubroleAttribute), 0) == kCFCompareEqualTo) { |
|
1409 return (subrole(interface) != QCFString()); |
|
1410 } |
|
1411 |
|
1412 return false; |
|
1413 } |
|
1414 |
|
1415 static void appendIfSupported(CFMutableArrayRef array, CFStringRef attribute, const QAInterface &interface) |
|
1416 { |
|
1417 if (supportsAttribute(attribute, interface)) |
|
1418 qt_mac_append_cf_uniq(array, attribute); |
|
1419 } |
|
1420 |
|
1421 /* |
|
1422 Returns the names of the attributes the give QAInterface supports. |
|
1423 */ |
|
1424 static OSStatus getAllAttributeNames(EventRef event, const QAInterface &interface, EventHandlerCallRef next_ref) |
|
1425 { |
|
1426 // Call system event handler. |
|
1427 OSStatus err = CallNextEventHandler(next_ref, event); |
|
1428 if(err != noErr && err != eventNotHandledErr) |
|
1429 return err; |
|
1430 CFMutableArrayRef attrs = 0; |
|
1431 GetEventParameter(event, kEventParamAccessibleAttributeNames, typeCFMutableArrayRef, 0, |
|
1432 sizeof(attrs), 0, &attrs); |
|
1433 |
|
1434 if (!attrs) |
|
1435 return eventNotHandledErr; |
|
1436 |
|
1437 // Append attribute names that are always supported. |
|
1438 qt_mac_append_cf_uniq(attrs, CFStringRef(QAXPositionAttribute)); |
|
1439 qt_mac_append_cf_uniq(attrs, CFStringRef(QAXSizeAttribute)); |
|
1440 qt_mac_append_cf_uniq(attrs, CFStringRef(QAXRoleAttribute)); |
|
1441 qt_mac_append_cf_uniq(attrs, CFStringRef(QAXEnabledAttribute)); |
|
1442 qt_mac_append_cf_uniq(attrs, CFStringRef(QAXWindowAttribute)); |
|
1443 qt_mac_append_cf_uniq(attrs, CFStringRef(QAXTopLevelUIElementAttribute)); |
|
1444 |
|
1445 // Append these names if the QInterafceItem returns any data for them. |
|
1446 appendIfSupported(attrs, CFStringRef(QAXTitleAttribute), interface); |
|
1447 appendIfSupported(attrs, CFStringRef(QAXValueAttribute), interface); |
|
1448 appendIfSupported(attrs, CFStringRef(QAXDescriptionAttribute), interface); |
|
1449 appendIfSupported(attrs, CFStringRef(QAXLinkedUIElementsAttribute), interface); |
|
1450 appendIfSupported(attrs, CFStringRef(QAXHelpAttribute), interface); |
|
1451 appendIfSupported(attrs, CFStringRef(QAXTitleUIElementAttribute), interface); |
|
1452 appendIfSupported(attrs, CFStringRef(QAXChildrenAttribute), interface); |
|
1453 appendIfSupported(attrs, CFStringRef(QAXSubroleAttribute), interface); |
|
1454 |
|
1455 // Append attribute names based on the interaface role. |
|
1456 switch (interface.role()) { |
|
1457 case QAccessible::Window: |
|
1458 qt_mac_append_cf_uniq(attrs, CFStringRef(QAXMainAttribute)); |
|
1459 qt_mac_append_cf_uniq(attrs, CFStringRef(QAXMinimizedAttribute)); |
|
1460 qt_mac_append_cf_uniq(attrs, CFStringRef(QAXCloseButtonAttribute)); |
|
1461 qt_mac_append_cf_uniq(attrs, CFStringRef(QAXZoomButtonAttribute)); |
|
1462 qt_mac_append_cf_uniq(attrs, CFStringRef(QAXMinimizeButtonAttribute)); |
|
1463 qt_mac_append_cf_uniq(attrs, CFStringRef(QAXToolbarButtonAttribute)); |
|
1464 qt_mac_append_cf_uniq(attrs, CFStringRef(QAXGrowAreaAttribute)); |
|
1465 break; |
|
1466 case QAccessible::RadioButton: |
|
1467 case QAccessible::CheckBox: |
|
1468 qt_mac_append_cf_uniq(attrs, CFStringRef(QAXMinValueAttribute)); |
|
1469 qt_mac_append_cf_uniq(attrs, CFStringRef(QAXMaxValueAttribute)); |
|
1470 break; |
|
1471 case QAccessible::ScrollBar: |
|
1472 qt_mac_append_cf_uniq(attrs, CFStringRef(QAXOrientationAttribute)); |
|
1473 break; |
|
1474 case QAccessible::Splitter: |
|
1475 qt_mac_append_cf_uniq(attrs, CFStringRef(QAXSplittersAttribute)); |
|
1476 break; |
|
1477 case QAccessible::Table: |
|
1478 qt_mac_append_cf_uniq(attrs, CFStringRef(QAXRowsAttribute)); |
|
1479 qt_mac_append_cf_uniq(attrs, CFStringRef(QAXVisibleRowsAttribute)); |
|
1480 qt_mac_append_cf_uniq(attrs, CFStringRef(QAXSelectedRowsAttribute)); |
|
1481 break; |
|
1482 default: |
|
1483 break; |
|
1484 } |
|
1485 |
|
1486 // Append attribute names based on the mac accessibility role. |
|
1487 const QCFString mac_role = macRole(interface); |
|
1488 if (mac_role == CFStringRef(QAXSplitterRole)) { |
|
1489 qt_mac_append_cf_uniq(attrs, CFStringRef(QAXPreviousContentsAttribute)); |
|
1490 qt_mac_append_cf_uniq(attrs, CFStringRef(QAXNextContentsAttribute)); |
|
1491 qt_mac_append_cf_uniq(attrs, CFStringRef(QAXOrientationAttribute)); |
|
1492 } else if (mac_role == CFStringRef(QAXScrollAreaRole)) { |
|
1493 if (scrollAreaHasScrollBar(interface, Qt::Horizontal)) |
|
1494 qt_mac_append_cf_uniq(attrs, CFStringRef(QAXHorizontalScrollBarAttribute)); |
|
1495 if (scrollAreaHasScrollBar(interface, Qt::Vertical)) |
|
1496 qt_mac_append_cf_uniq(attrs, CFStringRef(QAXVerticalScrollBarAttribute)); |
|
1497 qt_mac_append_cf_uniq(attrs, CFStringRef(QAXContentsAttribute)); |
|
1498 } else if (mac_role == CFStringRef(QAXTabGroupRole)) { |
|
1499 qt_mac_append_cf_uniq(attrs, CFStringRef(QAXTabsAttribute)); |
|
1500 // Only tab widgets can have the contents attribute, there is no way of getting |
|
1501 // the contents from a QTabBar. |
|
1502 if (isTabWidget(interface)) |
|
1503 qt_mac_append_cf_uniq(attrs, CFStringRef(QAXContentsAttribute)); |
|
1504 } |
|
1505 |
|
1506 return noErr; |
|
1507 } |
|
1508 |
|
1509 static void handleStringAttribute(EventRef event, QAccessible::Text text, const QAInterface &interface) |
|
1510 { |
|
1511 QString str = interface.text(text); |
|
1512 if (str.isEmpty()) |
|
1513 return; |
|
1514 |
|
1515 // Remove any html markup from the text string, or VoiceOver will read the html tags. |
|
1516 static QTextDocument document; |
|
1517 document.setHtml(str); |
|
1518 str = document.toPlainText(); |
|
1519 |
|
1520 CFStringRef cfstr = QCFString::toCFStringRef(str); |
|
1521 SetEventParameter(event, kEventParamAccessibleAttributeValue, typeCFStringRef, sizeof(cfstr), &cfstr); |
|
1522 } |
|
1523 |
|
1524 /* |
|
1525 Handles the parent attribute for a interface. |
|
1526 There are basically three cases here: |
|
1527 1. interface is a HIView and has only HIView children. |
|
1528 2. interface is a HIView but has children that is not a HIView |
|
1529 3. interface is not a HIView. |
|
1530 */ |
|
1531 static OSStatus handleChildrenAttribute(EventHandlerCallRef next_ref, EventRef event, QAInterface &interface) |
|
1532 { |
|
1533 // Add the children for this interface to the global QAccessibelHierachyManager. |
|
1534 accessibleHierarchyManager()->registerChildren(interface); |
|
1535 |
|
1536 if (isTabWidget(interface)) { |
|
1537 QList<QAElement> children = tabWidgetGetChildren(interface); |
|
1538 const int childCount = children.count(); |
|
1539 |
|
1540 CFMutableArrayRef array = 0; |
|
1541 array = CFArrayCreateMutable(0, 0, &kCFTypeArrayCallBacks); |
|
1542 for (int i = 0; i < childCount; ++i) { |
|
1543 qt_mac_append_cf_uniq(array, children.at(i).element()); |
|
1544 } |
|
1545 |
|
1546 OSStatus err; |
|
1547 err = SetEventParameter(event, kEventParamAccessibleAttributeValue, typeCFArrayRef, sizeof(array), &array); |
|
1548 if (err != noErr) |
|
1549 qWarning("Qt:Internal error (%s:%d)", __FILE__, __LINE__); |
|
1550 |
|
1551 return noErr; |
|
1552 } |
|
1553 |
|
1554 const QList<QAElement> children = lookup(interface.children()); |
|
1555 const int childCount = children.count(); |
|
1556 |
|
1557 OSStatus err = eventNotHandledErr; |
|
1558 if (interface.isHIView()) |
|
1559 err = CallNextEventHandler(next_ref, event); |
|
1560 |
|
1561 CFMutableArrayRef array = 0; |
|
1562 int arraySize = 0; |
|
1563 if (err == noErr) { |
|
1564 CFTypeRef obj = 0; |
|
1565 err = GetEventParameter(event, kEventParamAccessibleAttributeValue, typeCFTypeRef, NULL , sizeof(obj), NULL, &obj); |
|
1566 if (err == noErr && obj != 0) { |
|
1567 array = (CFMutableArrayRef)obj; |
|
1568 arraySize = CFArrayGetCount(array); |
|
1569 } |
|
1570 } |
|
1571 |
|
1572 if (array) { |
|
1573 CFArrayRemoveAllValues(array); |
|
1574 for (int i = 0; i < childCount; ++i) { |
|
1575 qt_mac_append_cf_uniq(array, children.at(i).element()); |
|
1576 } |
|
1577 } else { |
|
1578 array = CFArrayCreateMutable(0, 0, &kCFTypeArrayCallBacks); |
|
1579 for (int i = 0; i < childCount; ++i) { |
|
1580 qt_mac_append_cf_uniq(array, children.at(i).element()); |
|
1581 } |
|
1582 |
|
1583 err = SetEventParameter(event, kEventParamAccessibleAttributeValue, typeCFArrayRef, sizeof(array), &array); |
|
1584 if (err != noErr) |
|
1585 qWarning("Qt:Internal error (%s:%d)", __FILE__, __LINE__); |
|
1586 } |
|
1587 |
|
1588 return noErr; |
|
1589 } |
|
1590 |
|
1591 /* |
|
1592 |
|
1593 */ |
|
1594 static OSStatus handleParentAttribute(EventHandlerCallRef next_ref, EventRef event, const QAInterface &interface) |
|
1595 { |
|
1596 OSStatus err = eventNotHandledErr; |
|
1597 if (interface.isHIView()) { |
|
1598 err = CallNextEventHandler(next_ref, event); |
|
1599 } |
|
1600 if (err == noErr) |
|
1601 return err; |
|
1602 |
|
1603 const QAInterface parentInterface = interface.navigate(QAccessible::Ancestor, 1); |
|
1604 const QAElement parentElement = accessibleHierarchyManager()->lookup(parentInterface); |
|
1605 |
|
1606 if (parentElement.isValid() == false) |
|
1607 return eventNotHandledErr; |
|
1608 |
|
1609 AXUIElementRef elementRef = parentElement.element(); |
|
1610 SetEventParameter(event, kEventParamAccessibleAttributeValue, typeCFTypeRef, sizeof(elementRef), &elementRef); |
|
1611 return noErr; |
|
1612 } |
|
1613 #endif |
|
1614 |
|
1615 struct IsWindowTest |
|
1616 { |
|
1617 static inline bool test(const QAInterface &interface) |
|
1618 { |
|
1619 return (interface.role() == QAccessible::Window); |
|
1620 } |
|
1621 }; |
|
1622 |
|
1623 struct IsWindowAndNotDrawerOrSheetTest |
|
1624 { |
|
1625 static inline bool test(const QAInterface &interface) |
|
1626 { |
|
1627 QWidget * const widget = qobject_cast<QWidget*>(interface.object()); |
|
1628 return (interface.role() == QAccessible::Window && |
|
1629 widget && widget->isWindow() && |
|
1630 !qt_mac_is_macdrawer(widget) && |
|
1631 !qt_mac_is_macsheet(widget)); |
|
1632 } |
|
1633 }; |
|
1634 |
|
1635 /* |
|
1636 Navigates up the iterfaces ancestor hierachy until a QAccessibleInterface that |
|
1637 passes the Test is found. If we reach a interface that is a HIView we stop the |
|
1638 search and call AXUIElementCopyAttributeValue. |
|
1639 */ |
|
1640 template <typename TestType> |
|
1641 OSStatus navigateAncestors(EventHandlerCallRef next_ref, EventRef event, const QAInterface &interface, CFStringRef attribute) |
|
1642 { |
|
1643 if (interface.isHIView()) |
|
1644 return CallNextEventHandler(next_ref, event); |
|
1645 |
|
1646 QAInterface current = interface; |
|
1647 QAElement element; |
|
1648 while (current.isValid()) { |
|
1649 if (TestType::test(interface)) { |
|
1650 element = accessibleHierarchyManager()->lookup(current); |
|
1651 break; |
|
1652 } |
|
1653 |
|
1654 // If we reach an InterfaceItem that is a HiView we can hand of the search to |
|
1655 // the system event handler. This is the common case. |
|
1656 if (current.isHIView()) { |
|
1657 CFTypeRef value = 0; |
|
1658 const QAElement currentElement = accessibleHierarchyManager()->lookup(current); |
|
1659 AXError err = AXUIElementCopyAttributeValue(currentElement.element(), attribute, &value); |
|
1660 AXUIElementRef newElement = (AXUIElementRef)value; |
|
1661 |
|
1662 if (err == noErr) |
|
1663 element = QAElement(newElement); |
|
1664 |
|
1665 if (newElement != 0) |
|
1666 CFRelease(newElement); |
|
1667 break; |
|
1668 } |
|
1669 |
|
1670 QAInterface next = current.parent(); |
|
1671 if (next.isValid() == false) |
|
1672 break; |
|
1673 if (next == current) |
|
1674 break; |
|
1675 current = next; |
|
1676 } |
|
1677 |
|
1678 if (element.isValid() == false) |
|
1679 return eventNotHandledErr; |
|
1680 |
|
1681 |
|
1682 AXUIElementRef elementRef = element.element(); |
|
1683 SetEventParameter(event, kEventParamAccessibleAttributeValue, typeCFTypeRef, |
|
1684 sizeof(elementRef), &elementRef); |
|
1685 return noErr; |
|
1686 } |
|
1687 |
|
1688 /* |
|
1689 Returns the top-level window for an interface, which is the closest ancestor interface that |
|
1690 has the Window role, but is not a sheet or a drawer. |
|
1691 */ |
|
1692 #ifndef QT_MAC_USE_COCOA |
|
1693 static OSStatus handleWindowAttribute(EventHandlerCallRef next_ref, EventRef event, const QAInterface &interface) |
|
1694 { |
|
1695 return navigateAncestors<IsWindowAndNotDrawerOrSheetTest>(next_ref, event, interface, CFStringRef(QAXWindowAttribute)); |
|
1696 } |
|
1697 |
|
1698 /* |
|
1699 Returns the top-level window for an interface, which is the closest ancestor interface that |
|
1700 has the Window role. (Can also be a sheet or a drawer) |
|
1701 */ |
|
1702 static OSStatus handleTopLevelUIElementAttribute(EventHandlerCallRef next_ref, EventRef event, const QAInterface &interface) |
|
1703 { |
|
1704 return navigateAncestors<IsWindowTest>(next_ref, event, interface, CFStringRef(QAXTopLevelUIElementAttribute)); |
|
1705 } |
|
1706 |
|
1707 /* |
|
1708 Returns the tab buttons for an interface. |
|
1709 */ |
|
1710 static OSStatus handleTabsAttribute(EventHandlerCallRef next_ref, EventRef event, QAInterface &interface) |
|
1711 { |
|
1712 Q_UNUSED(next_ref); |
|
1713 if (isTabWidget(interface)) |
|
1714 return setAttributeValue(event, tabWidgetGetTabs(interface)); |
|
1715 else |
|
1716 return setAttributeValue(event, tabBarGetTabs(interface)); |
|
1717 } |
|
1718 |
|
1719 static OSStatus handlePositionAttribute(EventHandlerCallRef, EventRef event, const QAInterface &interface) |
|
1720 { |
|
1721 QPoint qpoint(interface.rect().topLeft()); |
|
1722 HIPoint point; |
|
1723 point.x = qpoint.x(); |
|
1724 point.y = qpoint.y(); |
|
1725 SetEventParameter(event, kEventParamAccessibleAttributeValue, typeHIPoint, sizeof(point), &point); |
|
1726 return noErr; |
|
1727 } |
|
1728 |
|
1729 static OSStatus handleSizeAttribute(EventHandlerCallRef, EventRef event, const QAInterface &interface) |
|
1730 { |
|
1731 QSize qSize(interface.rect().size()); |
|
1732 HISize size; |
|
1733 size.width = qSize.width(); |
|
1734 size.height = qSize.height(); |
|
1735 SetEventParameter(event, kEventParamAccessibleAttributeValue, typeHISize, sizeof(size), &size); |
|
1736 return noErr; |
|
1737 } |
|
1738 |
|
1739 static OSStatus handleSubroleAttribute(EventHandlerCallRef, EventRef event, const QAInterface &interface) |
|
1740 { |
|
1741 const QCFString role = subrole(interface); |
|
1742 CFStringRef rolestr = (CFStringRef)role; |
|
1743 SetEventParameter(event, kEventParamAccessibleAttributeValue, typeCFTypeRef, sizeof(rolestr), &rolestr); |
|
1744 return noErr; |
|
1745 } |
|
1746 |
|
1747 static OSStatus handleOrientationAttribute(EventHandlerCallRef next_ref, EventRef event, const QAInterface &interface) |
|
1748 { |
|
1749 QObject *const object = interface.object(); |
|
1750 Qt::Orientation orientation; |
|
1751 if (interface.role() == QAccessible::ScrollBar) { |
|
1752 orientation = scrollBarOrientation(interface); |
|
1753 } else if (QSplitterHandle * const splitter = qobject_cast<QSplitterHandle * const>(object)) { |
|
1754 // Qt reports the layout orientation, but we want the splitter handle orientation. |
|
1755 orientation = (splitter->orientation() == Qt::Horizontal) ? Qt::Vertical : Qt::Horizontal; |
|
1756 } else { |
|
1757 return CallNextEventHandler(next_ref, event); |
|
1758 } |
|
1759 const CFStringRef orientationString = (orientation == Qt::Vertical) |
|
1760 ? CFStringRef(QAXVerticalOrientationValue) : CFStringRef(QAXHorizontalOrientationValue); |
|
1761 SetEventParameter(event, kEventParamAccessibleAttributeValue, typeCFStringRef, sizeof(orientationString), &orientationString); |
|
1762 return noErr; |
|
1763 } |
|
1764 |
|
1765 /* |
|
1766 Figures out the next or previous contents for a splitter. |
|
1767 */ |
|
1768 static OSStatus handleSplitterContentsAttribute(EventHandlerCallRef next_ref, EventRef event, const QAInterface &interface, QCFString nextOrPrev) |
|
1769 { |
|
1770 if (interface.isValid() == false || interface.role() != QAccessible::Grip) |
|
1771 return eventNotHandledErr; |
|
1772 |
|
1773 const QAInterface parent = interface.parent(); |
|
1774 if (parent.isValid() == false) |
|
1775 return CallNextEventHandler(next_ref, event); |
|
1776 |
|
1777 if (parent.role() != QAccessible::Splitter) |
|
1778 return CallNextEventHandler(next_ref, event); |
|
1779 |
|
1780 const QSplitter * const splitter = qobject_cast<const QSplitter * const>(parent.object()); |
|
1781 if (splitter == 0) |
|
1782 return CallNextEventHandler(next_ref, event); |
|
1783 |
|
1784 QWidget * const splitterHandle = qobject_cast<QWidget * const>(interface.object()); |
|
1785 const int splitterHandleIndex = splitter->indexOf(splitterHandle); |
|
1786 const int widgetIndex = (nextOrPrev == QCFString(CFStringRef(QAXPreviousContentsAttribute))) ? splitterHandleIndex - 1 : splitterHandleIndex; |
|
1787 const QAElement contentsElement = accessibleHierarchyManager()->lookup(splitter->widget(widgetIndex), 0); |
|
1788 return setAttributeValue(event, QList<QAElement>() << contentsElement); |
|
1789 } |
|
1790 |
|
1791 /* |
|
1792 Creates a list of all splitter handles the splitter contains. |
|
1793 */ |
|
1794 static OSStatus handleSplittersAttribute(EventHandlerCallRef next_ref, EventRef event, QAInterface &interface) |
|
1795 { |
|
1796 const QSplitter * const splitter = qobject_cast<const QSplitter * const>(interface.object()); |
|
1797 if (splitter == 0) |
|
1798 return CallNextEventHandler(next_ref, event); |
|
1799 |
|
1800 accessibleHierarchyManager()->registerChildren(interface); |
|
1801 |
|
1802 QList<QAElement> handles; |
|
1803 const int visibleSplitterCount = splitter->count() -1; // skip first handle, it's always invisible. |
|
1804 for (int i = 0; i < visibleSplitterCount; ++i) |
|
1805 handles.append(accessibleHierarchyManager()->lookup(splitter->handle(i + 1), 0)); |
|
1806 |
|
1807 return setAttributeValue(event, handles); |
|
1808 } |
|
1809 |
|
1810 // This handler gets the scroll bars for a scroll area |
|
1811 static OSStatus handleScrollBarAttribute(EventHandlerCallRef next_ref, EventRef event, QAInterface &scrollArea, Qt::Orientation orientation) |
|
1812 { |
|
1813 QAElement scrollBar = scrollAreaGetScrollBar(scrollArea, orientation); |
|
1814 if (scrollBar.isValid() == false) |
|
1815 return CallNextEventHandler(next_ref, event); |
|
1816 |
|
1817 AXUIElementRef elementRef = scrollBar.element(); |
|
1818 SetEventParameter(event, kEventParamAccessibleAttributeValue, typeCFTypeRef, sizeof(elementRef), &elementRef); |
|
1819 return noErr; |
|
1820 } |
|
1821 |
|
1822 // This handler gets the contents for a scroll area or tab widget. |
|
1823 static OSStatus handleContentsAttribute(EventHandlerCallRef next_ref, EventRef event, QAInterface &interface) |
|
1824 { |
|
1825 const QCFString mac_role = macRole(interface); |
|
1826 |
|
1827 QAElement contents; |
|
1828 |
|
1829 if (mac_role == kAXTabGroupRole) { |
|
1830 contents = tabWidgetGetContents(interface); |
|
1831 } else { |
|
1832 contents = scrollAreaGetContents(interface); |
|
1833 if (contents.isValid() == false) |
|
1834 return CallNextEventHandler(next_ref, event); |
|
1835 } |
|
1836 |
|
1837 return setAttributeValue(event, QList<QAElement>() << contents); |
|
1838 } |
|
1839 |
|
1840 static OSStatus handleRowsAttribute(EventHandlerCallRef, EventRef event, QAInterface &tableView) |
|
1841 { |
|
1842 QList<QAElement> rows = lookup(tableView.children()); |
|
1843 |
|
1844 // kill the first row which is the horizontal header. |
|
1845 rows.removeAt(0); |
|
1846 |
|
1847 return setAttributeValue(event, rows); |
|
1848 } |
|
1849 |
|
1850 static OSStatus handleVisibleRowsAttribute(EventHandlerCallRef, EventRef event, QAInterface &tableView) |
|
1851 { |
|
1852 QList<QAElement> visibleRows; |
|
1853 |
|
1854 QList<QAInterface> rows = tableView.children(); |
|
1855 // kill the first row which is the horizontal header. |
|
1856 rows.removeAt(0); |
|
1857 |
|
1858 foreach (const QAInterface &interface, rows) |
|
1859 if ((interface.state() & QAccessible::Invisible) == false) |
|
1860 visibleRows.append(accessibleHierarchyManager()->lookup(interface)); |
|
1861 |
|
1862 return setAttributeValue(event, visibleRows); |
|
1863 } |
|
1864 |
|
1865 static OSStatus handleSelectedRowsAttribute(EventHandlerCallRef, EventRef event, QAInterface &tableView) |
|
1866 { |
|
1867 QList<QAElement> selectedRows; |
|
1868 foreach (const QAInterface &interface, tableView.children()) |
|
1869 if ((interface.state() & QAccessible::Selected)) |
|
1870 selectedRows.append(accessibleHierarchyManager()->lookup(interface)); |
|
1871 |
|
1872 return setAttributeValue(event, selectedRows); |
|
1873 } |
|
1874 |
|
1875 static OSStatus getNamedAttribute(EventHandlerCallRef next_ref, EventRef event, QAInterface &interface) |
|
1876 { |
|
1877 CFStringRef var; |
|
1878 GetEventParameter(event, kEventParamAccessibleAttributeName, typeCFStringRef, 0, |
|
1879 sizeof(var), 0, &var); |
|
1880 |
|
1881 if (CFStringCompare(var, CFStringRef(QAXChildrenAttribute), 0) == kCFCompareEqualTo) { |
|
1882 return handleChildrenAttribute(next_ref, event, interface); |
|
1883 } else if(CFStringCompare(var, CFStringRef(QAXTopLevelUIElementAttribute), 0) == kCFCompareEqualTo) { |
|
1884 return handleTopLevelUIElementAttribute(next_ref, event, interface); |
|
1885 } else if(CFStringCompare(var, CFStringRef(QAXWindowAttribute), 0) == kCFCompareEqualTo) { |
|
1886 return handleWindowAttribute(next_ref, event, interface); |
|
1887 } else if(CFStringCompare(var, CFStringRef(QAXParentAttribute), 0) == kCFCompareEqualTo) { |
|
1888 return handleParentAttribute(next_ref, event, interface); |
|
1889 } else if (CFStringCompare(var, CFStringRef(QAXPositionAttribute), 0) == kCFCompareEqualTo) { |
|
1890 return handlePositionAttribute(next_ref, event, interface); |
|
1891 } else if (CFStringCompare(var, CFStringRef(QAXSizeAttribute), 0) == kCFCompareEqualTo) { |
|
1892 return handleSizeAttribute(next_ref, event, interface); |
|
1893 } else if (CFStringCompare(var, CFStringRef(QAXRoleAttribute), 0) == kCFCompareEqualTo) { |
|
1894 CFStringRef role = macRole(interface); |
|
1895 // ### |
|
1896 // QWidget * const widget = qobject_cast<QWidget *>(interface.object()); |
|
1897 // if (role == CFStringRef(QAXUnknownRole) && widget && widget->isWindow()) |
|
1898 // role = CFStringRef(QAXWindowRole); |
|
1899 |
|
1900 SetEventParameter(event, kEventParamAccessibleAttributeValue, typeCFStringRef, |
|
1901 sizeof(role), &role); |
|
1902 |
|
1903 } else if (CFStringCompare(var, CFStringRef(QAXEnabledAttribute), 0) == kCFCompareEqualTo) { |
|
1904 Boolean val = !((interface.state() & QAccessible::Unavailable)) |
|
1905 && !((interface.state() & QAccessible::Invisible)); |
|
1906 SetEventParameter(event, kEventParamAccessibleAttributeValue, typeBoolean, |
|
1907 sizeof(val), &val); |
|
1908 } else if (CFStringCompare(var, CFStringRef(QAXExpandedAttribute), 0) == kCFCompareEqualTo) { |
|
1909 Boolean val = (interface.state() & QAccessible::Expanded); |
|
1910 SetEventParameter(event, kEventParamAccessibleAttributeValue, typeBoolean, |
|
1911 sizeof(val), &val); |
|
1912 } else if (CFStringCompare(var, CFStringRef(QAXSelectedAttribute), 0) == kCFCompareEqualTo) { |
|
1913 Boolean val = (interface.state() & QAccessible::Selection); |
|
1914 SetEventParameter(event, kEventParamAccessibleAttributeValue, typeBoolean, |
|
1915 sizeof(val), &val); |
|
1916 } else if (CFStringCompare(var, CFStringRef(QAXFocusedAttribute), 0) == kCFCompareEqualTo) { |
|
1917 Boolean val = (interface.state() & QAccessible::Focus); |
|
1918 SetEventParameter(event, kEventParamAccessibleAttributeValue, typeBoolean, |
|
1919 sizeof(val), &val); |
|
1920 } else if (CFStringCompare(var, CFStringRef(QAXSelectedChildrenAttribute), 0) == kCFCompareEqualTo) { |
|
1921 const int cc = interface.childCount(); |
|
1922 QList<QAElement> selected; |
|
1923 for (int i = 1; i <= cc; ++i) { |
|
1924 const QAInterface child_iface = interface.navigate(QAccessible::Child, i); |
|
1925 if (child_iface.isValid() && child_iface.state() & QAccessible::Selected) |
|
1926 selected.append(accessibleHierarchyManager()->lookup(child_iface)); |
|
1927 } |
|
1928 |
|
1929 return setAttributeValue(event, selected); |
|
1930 |
|
1931 } else if (CFStringCompare(var, CFStringRef(QAXCloseButtonAttribute), 0) == kCFCompareEqualTo) { |
|
1932 if(interface.object() && interface.object()->isWidgetType()) { |
|
1933 Boolean val = true; //do we want to add a WState for this? |
|
1934 SetEventParameter(event, kEventParamAccessibleAttributeValue, typeBoolean, |
|
1935 sizeof(val), &val); |
|
1936 } |
|
1937 } else if (CFStringCompare(var, CFStringRef(QAXZoomButtonAttribute), 0) == kCFCompareEqualTo) { |
|
1938 if(interface.object() && interface.object()->isWidgetType()) { |
|
1939 QWidget *widget = (QWidget*)interface.object(); |
|
1940 Boolean val = (widget->windowFlags() & Qt::WindowMaximizeButtonHint); |
|
1941 SetEventParameter(event, kEventParamAccessibleAttributeValue, typeBoolean, |
|
1942 sizeof(val), &val); |
|
1943 } |
|
1944 } else if (CFStringCompare(var, CFStringRef(QAXMinimizeButtonAttribute), 0) == kCFCompareEqualTo) { |
|
1945 if(interface.object() && interface.object()->isWidgetType()) { |
|
1946 QWidget *widget = (QWidget*)interface.object(); |
|
1947 Boolean val = (widget->windowFlags() & Qt::WindowMinimizeButtonHint); |
|
1948 SetEventParameter(event, kEventParamAccessibleAttributeValue, typeBoolean, |
|
1949 sizeof(val), &val); |
|
1950 } |
|
1951 } else if (CFStringCompare(var, CFStringRef(QAXToolbarButtonAttribute), 0) == kCFCompareEqualTo) { |
|
1952 if(interface.object() && interface.object()->isWidgetType()) { |
|
1953 QWidget *widget = (QWidget*)interface.object(); |
|
1954 Boolean val = qobject_cast<QMainWindow *>(widget) != 0; |
|
1955 SetEventParameter(event, kEventParamAccessibleAttributeValue, typeBoolean, |
|
1956 sizeof(val), &val); |
|
1957 } |
|
1958 } else if (CFStringCompare(var, CFStringRef(QAXGrowAreaAttribute), 0) == kCFCompareEqualTo) { |
|
1959 if(interface.object() && interface.object()->isWidgetType()) { |
|
1960 Boolean val = true; //do we want to add a WState for this? |
|
1961 SetEventParameter(event, kEventParamAccessibleAttributeValue, typeBoolean, |
|
1962 sizeof(val), &val); |
|
1963 } |
|
1964 } else if (CFStringCompare(var, CFStringRef(QAXMinimizedAttribute), 0) == kCFCompareEqualTo) { |
|
1965 if (interface.object() && interface.object()->isWidgetType()) { |
|
1966 QWidget *widget = (QWidget*)interface.object(); |
|
1967 Boolean val = (widget->windowState() & Qt::WindowMinimized); |
|
1968 SetEventParameter(event, kEventParamAccessibleAttributeValue, typeBoolean, |
|
1969 sizeof(val), &val); |
|
1970 } |
|
1971 } else if (CFStringCompare(var, CFStringRef(QAXSubroleAttribute), 0) == kCFCompareEqualTo) { |
|
1972 return handleSubroleAttribute(next_ref, event, interface); |
|
1973 } else if (CFStringCompare(var, CFStringRef(QAXRoleDescriptionAttribute), 0) == kCFCompareEqualTo) { |
|
1974 #if !defined(QT_MAC_USE_COCOA) |
|
1975 if (HICopyAccessibilityRoleDescription) { |
|
1976 const CFStringRef roleDescription = HICopyAccessibilityRoleDescription(macRole(interface), 0); |
|
1977 SetEventParameter(event, kEventParamAccessibleAttributeValue, typeCFStringRef, |
|
1978 sizeof(roleDescription), &roleDescription); |
|
1979 } else |
|
1980 #endif |
|
1981 { |
|
1982 // Just use Qt::Description on 10.3 |
|
1983 handleStringAttribute(event, QAccessible::Description, interface); |
|
1984 } |
|
1985 } else if (CFStringCompare(var, CFStringRef(QAXTitleAttribute), 0) == kCFCompareEqualTo) { |
|
1986 const QAccessible::Role role = interface.role(); |
|
1987 const QAccessible::Text text = (QAccessible::Text)textForRoleAndAttribute(role, var); |
|
1988 handleStringAttribute(event, text, interface); |
|
1989 } else if (CFStringCompare(var, CFStringRef(QAXValueAttribute), 0) == kCFCompareEqualTo) { |
|
1990 const QAccessible::Role role = interface.role(); |
|
1991 const QAccessible::Text text = (QAccessible::Text)textForRoleAndAttribute(role, var); |
|
1992 if (role == QAccessible::CheckBox || role == QAccessible::RadioButton) { |
|
1993 int value = buttonValue(interface); |
|
1994 SetEventParameter(event, kEventParamAccessibleAttributeValue, typeUInt32, sizeof(value), &value); |
|
1995 } else { |
|
1996 handleStringAttribute(event, text, interface); |
|
1997 } |
|
1998 } else if (CFStringCompare(var, CFStringRef(QAXDescriptionAttribute), 0) == kCFCompareEqualTo) { |
|
1999 const QAccessible::Role role = interface.role(); |
|
2000 const QAccessible::Text text = (QAccessible::Text)textForRoleAndAttribute(role, var); |
|
2001 handleStringAttribute(event, text, interface); |
|
2002 } else if (CFStringCompare(var, CFStringRef(QAXLinkedUIElementsAttribute), 0) == kCFCompareEqualTo) { |
|
2003 return CallNextEventHandler(next_ref, event); |
|
2004 } else if (CFStringCompare(var, CFStringRef(QAXHelpAttribute), 0) == kCFCompareEqualTo) { |
|
2005 const QAccessible::Role role = interface.role(); |
|
2006 const QAccessible::Text text = (QAccessible::Text)textForRoleAndAttribute(role, var); |
|
2007 handleStringAttribute(event, text, interface); |
|
2008 } else if (CFStringCompare(var, kAXTitleUIElementAttribute, 0) == kCFCompareEqualTo) { |
|
2009 return CallNextEventHandler(next_ref, event); |
|
2010 } else if (CFStringCompare(var, CFStringRef(QAXTabsAttribute), 0) == kCFCompareEqualTo) { |
|
2011 return handleTabsAttribute(next_ref, event, interface); |
|
2012 } else if (CFStringCompare(var, CFStringRef(QAXMinValueAttribute), 0) == kCFCompareEqualTo) { |
|
2013 // tabs we first go to the tab bar which is child #2. |
|
2014 QAInterface tabBarInterface = interface.childAt(2); |
|
2015 return handleTabsAttribute(next_ref, event, tabBarInterface); |
|
2016 } else if (CFStringCompare(var, CFStringRef(QAXMinValueAttribute), 0) == kCFCompareEqualTo) { |
|
2017 if (interface.role() == QAccessible::RadioButton || interface.role() == QAccessible::CheckBox) { |
|
2018 uint value = 0; |
|
2019 SetEventParameter(event, kEventParamAccessibleAttributeValue, typeUInt32, sizeof(value), &value); |
|
2020 } else { |
|
2021 return CallNextEventHandler(next_ref, event); |
|
2022 } |
|
2023 } else if (CFStringCompare(var, CFStringRef(QAXMaxValueAttribute), 0) == kCFCompareEqualTo) { |
|
2024 if (interface.role() == QAccessible::RadioButton || interface.role() == QAccessible::CheckBox) { |
|
2025 uint value = 2; |
|
2026 SetEventParameter(event, kEventParamAccessibleAttributeValue, typeUInt32, sizeof(value), &value); |
|
2027 } else { |
|
2028 return CallNextEventHandler(next_ref, event); |
|
2029 } |
|
2030 } else if (CFStringCompare(var, CFStringRef(QAXOrientationAttribute), 0) == kCFCompareEqualTo) { |
|
2031 return handleOrientationAttribute(next_ref, event, interface); |
|
2032 } else if (CFStringCompare(var, CFStringRef(QAXPreviousContentsAttribute), 0) == kCFCompareEqualTo) { |
|
2033 return handleSplitterContentsAttribute(next_ref, event, interface, CFStringRef(QAXPreviousContentsAttribute)); |
|
2034 } else if (CFStringCompare(var, CFStringRef(QAXNextContentsAttribute), 0) == kCFCompareEqualTo) { |
|
2035 return handleSplitterContentsAttribute(next_ref, event, interface, CFStringRef(QAXNextContentsAttribute)); |
|
2036 } else if (CFStringCompare(var, CFStringRef(QAXSplittersAttribute), 0) == kCFCompareEqualTo) { |
|
2037 return handleSplittersAttribute(next_ref, event, interface); |
|
2038 } else if (CFStringCompare(var, CFStringRef(QAXHorizontalScrollBarAttribute), 0) == kCFCompareEqualTo) { |
|
2039 return handleScrollBarAttribute(next_ref, event, interface, Qt::Horizontal); |
|
2040 } else if (CFStringCompare(var, CFStringRef(QAXVerticalScrollBarAttribute), 0) == kCFCompareEqualTo) { |
|
2041 return handleScrollBarAttribute(next_ref, event, interface, Qt::Vertical); |
|
2042 } else if (CFStringCompare(var, CFStringRef(QAXContentsAttribute), 0) == kCFCompareEqualTo) { |
|
2043 return handleContentsAttribute(next_ref, event, interface); |
|
2044 } else if (CFStringCompare(var, CFStringRef(QAXRowsAttribute), 0) == kCFCompareEqualTo) { |
|
2045 return handleRowsAttribute(next_ref, event, interface); |
|
2046 } else if (CFStringCompare(var, CFStringRef(QAXVisibleRowsAttribute), 0) == kCFCompareEqualTo) { |
|
2047 return handleVisibleRowsAttribute(next_ref, event, interface); |
|
2048 } else if (CFStringCompare(var, CFStringRef(QAXSelectedRowsAttribute), 0) == kCFCompareEqualTo) { |
|
2049 return handleSelectedRowsAttribute(next_ref, event, interface); |
|
2050 } else { |
|
2051 return CallNextEventHandler(next_ref, event); |
|
2052 } |
|
2053 return noErr; |
|
2054 } |
|
2055 |
|
2056 static OSStatus isNamedAttributeSettable(EventRef event, const QAInterface &interface) |
|
2057 { |
|
2058 CFStringRef var; |
|
2059 GetEventParameter(event, kEventParamAccessibleAttributeName, typeCFStringRef, 0, |
|
2060 sizeof(var), 0, &var); |
|
2061 Boolean settable = false; |
|
2062 if (CFStringCompare(var, CFStringRef(QAXFocusedAttribute), 0) == kCFCompareEqualTo) { |
|
2063 settable = true; |
|
2064 } else { |
|
2065 for (int r = 0; text_bindings[r][0].qt != -1; r++) { |
|
2066 if(interface.role() == (QAccessible::Role)text_bindings[r][0].qt) { |
|
2067 for (int a = 1; text_bindings[r][a].qt != -1; a++) { |
|
2068 if (CFStringCompare(var, CFStringRef(text_bindings[r][a].mac), 0) == kCFCompareEqualTo) { |
|
2069 settable = text_bindings[r][a].settable; |
|
2070 break; |
|
2071 } |
|
2072 } |
|
2073 } |
|
2074 } |
|
2075 } |
|
2076 SetEventParameter(event, kEventParamAccessibleAttributeSettable, typeBoolean, |
|
2077 sizeof(settable), &settable); |
|
2078 return noErr; |
|
2079 } |
|
2080 |
|
2081 static OSStatus getChildAtPoint(EventHandlerCallRef next_ref, EventRef event, QAInterface &interface) |
|
2082 { |
|
2083 Q_UNUSED(next_ref); |
|
2084 if (interface.isValid() == false) |
|
2085 return eventNotHandledErr; |
|
2086 |
|
2087 // Add the children for this interface to the global QAccessibelHierachyManager. |
|
2088 accessibleHierarchyManager()->registerChildren(interface); |
|
2089 |
|
2090 Point where; |
|
2091 GetEventParameter(event, kEventParamMouseLocation, typeQDPoint, 0, sizeof(where), 0, &where); |
|
2092 const QAInterface childInterface = interface.childAt(where.h, where.v); |
|
2093 |
|
2094 if (childInterface.isValid() == false || childInterface == interface) |
|
2095 return eventNotHandledErr; |
|
2096 |
|
2097 const QAElement element = accessibleHierarchyManager()->lookup(childInterface); |
|
2098 if (element.isValid() == false) |
|
2099 return eventNotHandledErr; |
|
2100 |
|
2101 AXUIElementRef elementRef = element.element(); |
|
2102 CFRetain(elementRef); |
|
2103 SetEventParameter(event, kEventParamAccessibleChild, typeCFTypeRef, |
|
2104 sizeof(elementRef), &elementRef); |
|
2105 |
|
2106 return noErr; |
|
2107 } |
|
2108 |
|
2109 /* |
|
2110 Returns a list of actions the given interface supports. |
|
2111 Currently implemented by getting the interface role and deciding based on that. |
|
2112 */ |
|
2113 static QList<QAccessible::Action> supportedPredefinedActions(const QAInterface &interface) |
|
2114 { |
|
2115 QList<QAccessible::Action> actions; |
|
2116 switch (interface.role()) { |
|
2117 default: |
|
2118 // Most things can be pressed. |
|
2119 actions.append(QAccessible::Press); |
|
2120 break; |
|
2121 } |
|
2122 |
|
2123 return actions; |
|
2124 } |
|
2125 |
|
2126 /* |
|
2127 Translates a predefined QAccessible::Action to a Mac action constant. |
|
2128 Returns an empty string if the Qt Action has no mac equivalent. |
|
2129 */ |
|
2130 static QCFString translateAction(const QAccessible::Action action) |
|
2131 { |
|
2132 switch (action) { |
|
2133 case QAccessible::Press: |
|
2134 return CFStringRef(QAXPressAction); |
|
2135 break; |
|
2136 case QAccessible::Increase: |
|
2137 return CFStringRef(QAXIncrementAction); |
|
2138 break; |
|
2139 case QAccessible::Decrease: |
|
2140 return CFStringRef(QAXDecrementAction); |
|
2141 break; |
|
2142 case QAccessible::Accept: |
|
2143 return CFStringRef(QAXConfirmAction); |
|
2144 break; |
|
2145 case QAccessible::Select: |
|
2146 return CFStringRef(QAXPickAction); |
|
2147 break; |
|
2148 case QAccessible::Cancel: |
|
2149 return CFStringRef(QAXCancelAction); |
|
2150 break; |
|
2151 default: |
|
2152 return QCFString(); |
|
2153 break; |
|
2154 } |
|
2155 } |
|
2156 |
|
2157 /* |
|
2158 Translates between a Mac action constant and a QAccessible::Action. |
|
2159 Returns QAccessible::Default action if there is no Qt predefined equivalent. |
|
2160 */ |
|
2161 static QAccessible::Action translateAction(const CFStringRef actionName) |
|
2162 { |
|
2163 if(CFStringCompare(actionName, CFStringRef(QAXPressAction), 0) == kCFCompareEqualTo) { |
|
2164 return QAccessible::Press; |
|
2165 } else if(CFStringCompare(actionName, CFStringRef(QAXIncrementAction), 0) == kCFCompareEqualTo) { |
|
2166 return QAccessible::Increase; |
|
2167 } else if(CFStringCompare(actionName, CFStringRef(QAXDecrementAction), 0) == kCFCompareEqualTo) { |
|
2168 return QAccessible::Decrease; |
|
2169 } else if(CFStringCompare(actionName, CFStringRef(QAXConfirmAction), 0) == kCFCompareEqualTo) { |
|
2170 return QAccessible::Accept; |
|
2171 } else if(CFStringCompare(actionName, CFStringRef(QAXPickAction), 0) == kCFCompareEqualTo) { |
|
2172 return QAccessible::Select; |
|
2173 } else if(CFStringCompare(actionName, CFStringRef(QAXCancelAction), 0) == kCFCompareEqualTo) { |
|
2174 return QAccessible::Cancel; |
|
2175 } else { |
|
2176 return QAccessible::DefaultAction; |
|
2177 } |
|
2178 } |
|
2179 #endif // QT_MAC_USE_COCOA |
|
2180 |
|
2181 /* |
|
2182 Copies the translated names all supported actions for an interface into the kEventParamAccessibleActionNames |
|
2183 event parameter. |
|
2184 */ |
|
2185 #ifndef QT_MAC_USE_COCOA |
|
2186 static OSStatus getAllActionNames(EventHandlerCallRef next_ref, EventRef event, const QAInterface &interface) |
|
2187 { |
|
2188 Q_UNUSED(next_ref); |
|
2189 |
|
2190 CFMutableArrayRef actions = 0; |
|
2191 GetEventParameter(event, kEventParamAccessibleActionNames, typeCFMutableArrayRef, 0, |
|
2192 sizeof(actions), 0, &actions); |
|
2193 |
|
2194 // Add supported predefined actions. |
|
2195 const QList<QAccessible::Action> predefinedActions = supportedPredefinedActions(interface); |
|
2196 for (int i = 0; i < predefinedActions.count(); ++i) { |
|
2197 const QCFString action = translateAction(predefinedActions.at(i)); |
|
2198 if (action != QCFString()) |
|
2199 qt_mac_append_cf_uniq(actions, action); |
|
2200 } |
|
2201 |
|
2202 // Add user actions |
|
2203 const int actionCount = interface.userActionCount(); |
|
2204 for (int i = 0; i < actionCount; ++i) { |
|
2205 const QString actionName = interface.actionText(i, QAccessible::Name); |
|
2206 qt_mac_append_cf_uniq(actions, QCFString::toCFStringRef(actionName)); |
|
2207 } |
|
2208 |
|
2209 return noErr; |
|
2210 } |
|
2211 #endif |
|
2212 |
|
2213 /* |
|
2214 Handles the perforNamedAction event. |
|
2215 */ |
|
2216 #ifndef QT_MAC_USE_COCOA |
|
2217 static OSStatus performNamedAction(EventHandlerCallRef next_ref, EventRef event, const QAInterface& interface) |
|
2218 { |
|
2219 Q_UNUSED(next_ref); |
|
2220 |
|
2221 CFStringRef act; |
|
2222 GetEventParameter(event, kEventParamAccessibleActionName, typeCFStringRef, 0, |
|
2223 sizeof(act), 0, &act); |
|
2224 |
|
2225 const QAccessible::Action action = translateAction(act); |
|
2226 |
|
2227 // Perform built-in action |
|
2228 if (action != QAccessible::DefaultAction) { |
|
2229 interface.doAction(action, QVariantList()); |
|
2230 return noErr; |
|
2231 } |
|
2232 |
|
2233 // Search for user-defined actions and perform it if found. |
|
2234 const int actCount = interface.userActionCount(); |
|
2235 const QString qAct = QCFString::toQString(act); |
|
2236 for(int i = 0; i < actCount; i++) { |
|
2237 if(interface.actionText(i, QAccessible::Name) == qAct) { |
|
2238 interface.doAction(i, QVariantList()); |
|
2239 break; |
|
2240 } |
|
2241 } |
|
2242 return noErr; |
|
2243 } |
|
2244 |
|
2245 static OSStatus setNamedAttribute(EventHandlerCallRef next_ref, EventRef event, const QAInterface &interface) |
|
2246 { |
|
2247 Q_UNUSED(next_ref); |
|
2248 Q_UNUSED(event); |
|
2249 |
|
2250 CFStringRef var; |
|
2251 GetEventParameter(event, kEventParamAccessibleAttributeName, typeCFStringRef, 0, |
|
2252 sizeof(var), 0, &var); |
|
2253 if(CFStringCompare(var, CFStringRef(QAXFocusedAttribute), 0) == kCFCompareEqualTo) { |
|
2254 CFTypeRef val; |
|
2255 if(GetEventParameter(event, kEventParamAccessibleAttributeValue, typeCFTypeRef, 0, |
|
2256 sizeof(val), 0, &val) == noErr) { |
|
2257 if(CFGetTypeID(val) == CFBooleanGetTypeID() && |
|
2258 CFEqual(static_cast<CFBooleanRef>(val), kCFBooleanTrue)) { |
|
2259 interface.doAction(QAccessible::SetFocus); |
|
2260 } |
|
2261 } |
|
2262 } else { |
|
2263 bool found = false; |
|
2264 for(int r = 0; text_bindings[r][0].qt != -1; r++) { |
|
2265 if(interface.role() == (QAccessible::Role)text_bindings[r][0].qt) { |
|
2266 for(int a = 1; text_bindings[r][a].qt != -1; a++) { |
|
2267 if(CFStringCompare(var, CFStringRef(text_bindings[r][a].mac), 0) == kCFCompareEqualTo) { |
|
2268 if(!text_bindings[r][a].settable) { |
|
2269 } else { |
|
2270 CFTypeRef val; |
|
2271 if(GetEventParameter(event, kEventParamAccessibleAttributeValue, typeCFTypeRef, 0, |
|
2272 sizeof(val), 0, &val) == noErr) { |
|
2273 if(CFGetTypeID(val) == CFStringGetTypeID()) |
|
2274 interface.setText((QAccessible::Text)text_bindings[r][a].qt, |
|
2275 QCFString::toQString(static_cast<CFStringRef>(val))); |
|
2276 |
|
2277 } |
|
2278 } |
|
2279 found = true; |
|
2280 break; |
|
2281 } |
|
2282 } |
|
2283 break; |
|
2284 } |
|
2285 } |
|
2286 } |
|
2287 return noErr; |
|
2288 } |
|
2289 |
|
2290 /* |
|
2291 This is the main accessibility event handler. |
|
2292 */ |
|
2293 static OSStatus accessibilityEventHandler(EventHandlerCallRef next_ref, EventRef event, void *data) |
|
2294 { |
|
2295 Q_UNUSED(data) |
|
2296 |
|
2297 // Return if this event is not a AccessibleGetNamedAttribute event. |
|
2298 const UInt32 eclass = GetEventClass(event); |
|
2299 if (eclass != kEventClassAccessibility) |
|
2300 return eventNotHandledErr; |
|
2301 |
|
2302 // Get the AXUIElementRef and QAInterface pointer |
|
2303 AXUIElementRef element = 0; |
|
2304 GetEventParameter(event, kEventParamAccessibleObject, typeCFTypeRef, 0, sizeof(element), 0, &element); |
|
2305 QAInterface interface = accessibleHierarchyManager()->lookup(element); |
|
2306 if (interface.isValid() == false) |
|
2307 return eventNotHandledErr; |
|
2308 |
|
2309 const UInt32 ekind = GetEventKind(event); |
|
2310 OSStatus status = noErr; |
|
2311 switch (ekind) { |
|
2312 case kEventAccessibleGetAllAttributeNames: |
|
2313 status = getAllAttributeNames(event, interface, next_ref); |
|
2314 break; |
|
2315 case kEventAccessibleGetNamedAttribute: |
|
2316 status = getNamedAttribute(next_ref, event, interface); |
|
2317 break; |
|
2318 case kEventAccessibleIsNamedAttributeSettable: |
|
2319 status = isNamedAttributeSettable(event, interface); |
|
2320 break; |
|
2321 case kEventAccessibleGetChildAtPoint: |
|
2322 status = getChildAtPoint(next_ref, event, interface); |
|
2323 break; |
|
2324 case kEventAccessibleGetAllActionNames: |
|
2325 status = getAllActionNames(next_ref, event, interface); |
|
2326 break; |
|
2327 case kEventAccessibleGetFocusedChild: |
|
2328 status = CallNextEventHandler(next_ref, event); |
|
2329 break; |
|
2330 case kEventAccessibleSetNamedAttribute: |
|
2331 status = setNamedAttribute(next_ref, event, interface); |
|
2332 break; |
|
2333 case kEventAccessiblePerformNamedAction: |
|
2334 status = performNamedAction(next_ref, event, interface); |
|
2335 break; |
|
2336 default: |
|
2337 status = CallNextEventHandler(next_ref, event); |
|
2338 break; |
|
2339 }; |
|
2340 return status; |
|
2341 } |
|
2342 #endif |
|
2343 |
|
2344 void QAccessible::initialize() |
|
2345 { |
|
2346 #ifndef QT_MAC_USE_COCOA |
|
2347 registerQtAccessibilityHIObjectSubclass(); |
|
2348 installApplicationEventhandler(); |
|
2349 #endif |
|
2350 } |
|
2351 |
|
2352 // Sets thre root object for the application |
|
2353 void QAccessible::setRootObject(QObject *object) |
|
2354 { |
|
2355 // Call installed root object handler if we have one |
|
2356 if (rootObjectHandler) { |
|
2357 rootObjectHandler(object); |
|
2358 return; |
|
2359 } |
|
2360 |
|
2361 rootObject = object; |
|
2362 } |
|
2363 |
|
2364 void QAccessible::cleanup() |
|
2365 { |
|
2366 accessibleHierarchyManager()->reset(); |
|
2367 #ifndef QT_MAC_USE_COCOA |
|
2368 removeEventhandler(applicationEventHandlerUPP); |
|
2369 removeEventhandler(objectCreateEventHandlerUPP); |
|
2370 removeEventhandler(accessibilityEventHandlerUPP); |
|
2371 #endif |
|
2372 } |
|
2373 |
|
2374 void QAccessible::updateAccessibility(QObject *object, int child, Event reason) |
|
2375 { |
|
2376 // Call installed update handler if we have one. |
|
2377 if (updateHandler) { |
|
2378 updateHandler(object, child, reason); |
|
2379 return; |
|
2380 } |
|
2381 |
|
2382 #ifndef QT_MAC_USE_COCOA |
|
2383 // Return if the mac accessibility is not enabled. |
|
2384 if(!AXAPIEnabled()) |
|
2385 return; |
|
2386 |
|
2387 // Work around crash, disable accessiblity for focus frames. |
|
2388 if (qstrcmp(object->metaObject()->className(), "QFocusFrame") == 0) |
|
2389 return; |
|
2390 |
|
2391 // qDebug() << "updateAccessibility" << object << child << hex << reason; |
|
2392 |
|
2393 if (reason == ObjectShow) { |
|
2394 QAInterface interface = QAInterface(QAccessible::queryAccessibleInterface(object), child); |
|
2395 accessibleHierarchyManager()->registerInterface(interface); |
|
2396 } |
|
2397 |
|
2398 const QAElement element = accessibleHierarchyManager()->lookup(object, child); |
|
2399 if (element.isValid() == false) |
|
2400 return; |
|
2401 |
|
2402 |
|
2403 CFStringRef notification = 0; |
|
2404 if(object && object->isWidgetType() && reason == ObjectCreated) { |
|
2405 notification = CFStringRef(QAXWindowCreatedNotification); |
|
2406 } else if(reason == ValueChanged) { |
|
2407 notification = CFStringRef(QAXValueChangedNotification); |
|
2408 } else if(reason == MenuStart) { |
|
2409 notification = CFStringRef(QAXMenuOpenedNotification); |
|
2410 } else if(reason == MenuEnd) { |
|
2411 notification = CFStringRef(QAXMenuClosedNotification); |
|
2412 } else if(reason == LocationChanged) { |
|
2413 notification = CFStringRef(QAXWindowMovedNotification); |
|
2414 } else if(reason == ObjectShow || reason == ObjectHide ) { |
|
2415 // When a widget is deleted we get a ObjectHide before the destroyed(QObject *) |
|
2416 // signal is emitted (which makes sense). However, at this point we are in the |
|
2417 // middle of the QWidget destructor which means that we have to be careful when |
|
2418 // using the widget pointer. Since we can't control what the accessibilty interfaces |
|
2419 // does when navigate() is called below we ignore the hide update in this case. |
|
2420 // (the widget will be deleted soon anyway.) |
|
2421 extern QWidgetPrivate * qt_widget_private(QWidget *); |
|
2422 if (QWidget *widget = qobject_cast<QWidget*>(object)) { |
|
2423 if (qt_widget_private(widget)->data.in_destructor) |
|
2424 return; |
|
2425 |
|
2426 // Check widget parent as well, special case for preventing crash |
|
2427 // when the viewport() of an abstract scroll area is hidden when |
|
2428 // the QWidget destructor hides all its children. |
|
2429 QWidget *parentWidget = widget->parentWidget(); |
|
2430 if (parentWidget && qt_widget_private(parentWidget)->data.in_destructor) |
|
2431 return; |
|
2432 } |
|
2433 |
|
2434 // There is no equivalent Mac notification for ObjectShow/Hide, so we call HIObjectSetAccessibilityIgnored |
|
2435 // and isItIntersting which will mark the HIObject accociated with the element as ignored if the |
|
2436 // QAccessible::Invisible state bit is set. |
|
2437 QAInterface interface = accessibleHierarchyManager()->lookup(element); |
|
2438 if (interface.isValid()) { |
|
2439 HIObjectSetAccessibilityIgnored(element.object(), !isItInteresting(interface)); |
|
2440 } |
|
2441 |
|
2442 // If the interface manages its own children, also check if we should ignore those. |
|
2443 if (isItemView(interface) == false && managesChildren(interface)) { |
|
2444 for (int i = 1; i <= interface.childCount(); ++i) { |
|
2445 QAInterface childInterface = interface.navigate(QAccessible::Child, i); |
|
2446 if (childInterface.isValid() && childInterface.isHIView() == false) { |
|
2447 const QAElement element = accessibleHierarchyManager()->lookup(childInterface); |
|
2448 if (element.isValid()) { |
|
2449 HIObjectSetAccessibilityIgnored(element.object(), !isItInteresting(childInterface)); |
|
2450 } |
|
2451 } |
|
2452 } |
|
2453 } |
|
2454 |
|
2455 } else if(reason == Focus) { |
|
2456 if(object && object->isWidgetType()) { |
|
2457 QWidget *w = static_cast<QWidget*>(object); |
|
2458 if(w->isWindow()) |
|
2459 notification = CFStringRef(QAXFocusedWindowChangedNotification); |
|
2460 else |
|
2461 notification = CFStringRef(QAXFocusedUIElementChangedNotification); |
|
2462 } |
|
2463 } |
|
2464 |
|
2465 if (!notification) |
|
2466 return; |
|
2467 |
|
2468 AXNotificationHIObjectNotify(notification, element.object(), element.id()); |
|
2469 #endif |
|
2470 } |
|
2471 |
|
2472 QT_END_NAMESPACE |
|
2473 |
|
2474 #endif // QT_NO_ACCESSIBILITY |