1 | /****************************************************************************
|
---|
2 | **
|
---|
3 | ** Copyright (C) 2009 Nokia Corporation and/or its subsidiary(-ies).
|
---|
4 | ** Contact: Qt Software Information ([email protected])
|
---|
5 | **
|
---|
6 | ** This file is part of the QtGui module of the Qt Toolkit.
|
---|
7 | **
|
---|
8 | ** $QT_BEGIN_LICENSE:LGPL$
|
---|
9 | ** Commercial Usage
|
---|
10 | ** Licensees holding valid Qt Commercial licenses may use this file in
|
---|
11 | ** accordance with the Qt Commercial License Agreement provided with the
|
---|
12 | ** Software or, alternatively, in accordance with the terms contained in
|
---|
13 | ** a written agreement between you and Nokia.
|
---|
14 | **
|
---|
15 | ** GNU Lesser General Public License Usage
|
---|
16 | ** Alternatively, this file may be used under the terms of the GNU Lesser
|
---|
17 | ** General Public License version 2.1 as published by the Free Software
|
---|
18 | ** Foundation and appearing in the file LICENSE.LGPL included in the
|
---|
19 | ** packaging of this file. Please review the following information to
|
---|
20 | ** ensure the GNU Lesser General Public License version 2.1 requirements
|
---|
21 | ** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
|
---|
22 | **
|
---|
23 | ** In addition, as a special exception, Nokia gives you certain
|
---|
24 | ** additional rights. These rights are described in the Nokia Qt LGPL
|
---|
25 | ** Exception version 1.0, included in the file LGPL_EXCEPTION.txt in this
|
---|
26 | ** package.
|
---|
27 | **
|
---|
28 | ** GNU General Public License Usage
|
---|
29 | ** Alternatively, this file may be used under the terms of the GNU
|
---|
30 | ** General Public License version 3.0 as published by the Free Software
|
---|
31 | ** Foundation and appearing in the file LICENSE.GPL included in the
|
---|
32 | ** packaging of this file. Please review the following information to
|
---|
33 | ** ensure the GNU General Public License version 3.0 requirements will be
|
---|
34 | ** met: http://www.gnu.org/copyleft/gpl.html.
|
---|
35 | **
|
---|
36 | ** If you are unsure which license is appropriate for your use, please
|
---|
37 | ** contact the sales department at [email protected].
|
---|
38 | ** $QT_END_LICENSE$
|
---|
39 | **
|
---|
40 | ****************************************************************************/
|
---|
41 |
|
---|
42 | #include "qaccessible.h"
|
---|
43 |
|
---|
44 | #ifndef QT_NO_ACCESSIBILITY
|
---|
45 | #include "qaccessible_mac_p.h"
|
---|
46 | #include "qhash.h"
|
---|
47 | #include "qset.h"
|
---|
48 | #include "qpointer.h"
|
---|
49 | #include "qapplication.h"
|
---|
50 | #include "qmainwindow.h"
|
---|
51 | #include "qtextdocument.h"
|
---|
52 | #include "qdebug.h"
|
---|
53 | #include "qabstractslider.h"
|
---|
54 | #include "qsplitter.h"
|
---|
55 | #include "qtabwidget.h"
|
---|
56 | #include "qlistview.h"
|
---|
57 | #include "qtableview.h"
|
---|
58 | #include "qdockwidget.h"
|
---|
59 |
|
---|
60 | #include <private/qt_mac_p.h>
|
---|
61 | #include <private/qwidget_p.h>
|
---|
62 | #include <CoreFoundation/CoreFoundation.h>
|
---|
63 |
|
---|
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 | #if (MAC_OS_X_VERSION_MAX_ALLOWED >= MAC_OS_X_VERSION_10_4)
|
---|
1236 | else if (CFStringCompare(attribute, CFStringRef(QAXDescriptionAttribute), 0) == kCFCompareEqualTo)
|
---|
1237 | return QAccessible::Description;
|
---|
1238 | #endif
|
---|
1239 | else
|
---|
1240 | return -1;
|
---|
1241 | }
|
---|
1242 |
|
---|
1243 | /*
|
---|
1244 | Returns the subrole string constant for the interface if it has one,
|
---|
1245 | else returns an empty string.
|
---|
1246 | */
|
---|
1247 | static QCFString subrole(const QAInterface &interface)
|
---|
1248 | {
|
---|
1249 | const QAInterface parent = interface.parent();
|
---|
1250 | if (parent.isValid() == false)
|
---|
1251 | return QCFString();
|
---|
1252 |
|
---|
1253 | if (parent.role() == QAccessible::ScrollBar) {
|
---|
1254 | QCFString subrole;
|
---|
1255 | switch(interface.id()) {
|
---|
1256 | case 1: subrole = CFStringRef(QAXDecrementArrowSubrole); break;
|
---|
1257 | case 2: subrole = CFStringRef(QAXDecrementPageSubrole); break;
|
---|
1258 | case 4: subrole = CFStringRef(QAXIncrementPageSubrole); break;
|
---|
1259 | case 5: subrole = CFStringRef(QAXIncrementArrowSubrole); break;
|
---|
1260 | default:
|
---|
1261 | break;
|
---|
1262 | }
|
---|
1263 | return subrole;
|
---|
1264 | }
|
---|
1265 | return QCFString();
|
---|
1266 | }
|
---|
1267 |
|
---|
1268 | // Gets the scroll bar orientation by asking the QAbstractSlider object directly.
|
---|
1269 | static Qt::Orientation scrollBarOrientation(const QAInterface &scrollBar)
|
---|
1270 | {
|
---|
1271 | QObject *const object = scrollBar.object();
|
---|
1272 | if (QAbstractSlider * const sliderObject = qobject_cast<QAbstractSlider * const>(object))
|
---|
1273 | return sliderObject->orientation();
|
---|
1274 |
|
---|
1275 | return Qt::Vertical; // D'oh! The interface wasn't a scroll bar.
|
---|
1276 | }
|
---|
1277 |
|
---|
1278 | static QAInterface scrollAreaGetScrollBarInterface(const QAInterface &scrollArea, Qt::Orientation orientation)
|
---|
1279 | {
|
---|
1280 | if (macRole(scrollArea) != CFStringRef(CFStringRef(QAXScrollAreaRole)))
|
---|
1281 | return QAInterface();
|
---|
1282 |
|
---|
1283 | // Child 1 is the contents widget, 2 and 3 are the scroll bar containers wich contains possible scroll bars.
|
---|
1284 | for (int i = 2; i <= 3; ++i) {
|
---|
1285 | QAInterface scrollBarContainer = scrollArea.childAt(i);
|
---|
1286 | for (int i = 1; i <= scrollBarContainer.childCount(); ++i) {
|
---|
1287 | QAInterface scrollBar = scrollBarContainer.childAt(i);
|
---|
1288 | if (scrollBar.isValid() &&
|
---|
1289 | scrollBar.role() == QAccessible::ScrollBar &&
|
---|
1290 | scrollBarOrientation(scrollBar) == orientation)
|
---|
1291 | return scrollBar;
|
---|
1292 | }
|
---|
1293 | }
|
---|
1294 |
|
---|
1295 | return QAInterface();
|
---|
1296 | }
|
---|
1297 |
|
---|
1298 | static bool scrollAreaHasScrollBar(const QAInterface &scrollArea, Qt::Orientation orientation)
|
---|
1299 | {
|
---|
1300 | return scrollAreaGetScrollBarInterface(scrollArea, orientation).isValid();
|
---|
1301 | }
|
---|
1302 |
|
---|
1303 | static QAElement scrollAreaGetScrollBar(const QAInterface &scrollArea, Qt::Orientation orientation)
|
---|
1304 | {
|
---|
1305 | return accessibleHierarchyManager()->lookup(scrollAreaGetScrollBarInterface(scrollArea, orientation));
|
---|
1306 | }
|
---|
1307 |
|
---|
1308 | static QAElement scrollAreaGetContents(const QAInterface &scrollArea)
|
---|
1309 | {
|
---|
1310 | // Child 1 is the contents widget,
|
---|
1311 | return accessibleHierarchyManager()->lookup(scrollArea.navigate(QAccessible::Child, 1));
|
---|
1312 | }
|
---|
1313 |
|
---|
1314 | static QAElement tabWidgetGetContents(const QAInterface &interface)
|
---|
1315 | {
|
---|
1316 | // A kAXTabGroup has a kAXContents attribute, which consists of the
|
---|
1317 | // ui elements for the current tab page. Get the current tab page
|
---|
1318 | // from the QStackedWidget, where the current visible page can
|
---|
1319 | // be found at index 1.
|
---|
1320 | QAInterface stackedWidget = interface.childAt(1);
|
---|
1321 | accessibleHierarchyManager()->registerChildren(stackedWidget);
|
---|
1322 | QAInterface tabPageInterface = stackedWidget.childAt(1);
|
---|
1323 | return accessibleHierarchyManager()->lookup(tabPageInterface);
|
---|
1324 | }
|
---|
1325 |
|
---|
1326 | static QList<QAElement> tabBarGetTabs(const QAInterface &interface)
|
---|
1327 | {
|
---|
1328 | // Get the tabs by searching for children with the "PageTab" role.
|
---|
1329 | // This filters out the left/right navigation buttons.
|
---|
1330 | accessibleHierarchyManager()->registerChildren(interface);
|
---|
1331 | QList<QAElement> tabs;
|
---|
1332 | const int numChildren = interface.childCount();
|
---|
1333 | for (int i = 1; i < numChildren + 1; ++i) {
|
---|
1334 | QAInterface child = interface.navigate(QAccessible::Child, i);
|
---|
1335 | if (child.isValid() && child.role() == QAccessible::PageTab) {
|
---|
1336 | tabs.append(accessibleHierarchyManager()->lookup(child));
|
---|
1337 | }
|
---|
1338 | }
|
---|
1339 | return tabs;
|
---|
1340 | }
|
---|
1341 |
|
---|
1342 | static QList<QAElement> tabWidgetGetTabs(const QAInterface &interface)
|
---|
1343 | {
|
---|
1344 | // Each QTabWidget has two children, a QStackedWidget and a QTabBar.
|
---|
1345 | // Get the tabs from the QTabBar.
|
---|
1346 | return tabBarGetTabs(interface.childAt(2));
|
---|
1347 | }
|
---|
1348 |
|
---|
1349 | static QList<QAElement> tabWidgetGetChildren(const QAInterface &interface)
|
---|
1350 | {
|
---|
1351 | // The children for a kAXTabGroup should consist of the tabs and the
|
---|
1352 | // contents of the current open tab page.
|
---|
1353 | QList<QAElement> children = tabWidgetGetTabs(interface);
|
---|
1354 | children += tabWidgetGetContents(interface);
|
---|
1355 | return children;
|
---|
1356 | }
|
---|
1357 | #endif //QT_MAC_USE_COCOA
|
---|
1358 |
|
---|
1359 | /*
|
---|
1360 | Returns the label (buddy) interface for interface, or 0 if it has none.
|
---|
1361 | */
|
---|
1362 | /*
|
---|
1363 | static QAInterface findLabel(const QAInterface &interface)
|
---|
1364 | {
|
---|
1365 | return interface.navigate(QAccessible::Label, 1);
|
---|
1366 | }
|
---|
1367 | */
|
---|
1368 | /*
|
---|
1369 | Returns a list of interfaces this interface labels, or an empty list if it doesn't label any.
|
---|
1370 | */
|
---|
1371 | /*
|
---|
1372 | static QList<QAInterface> findLabelled(const QAInterface &interface)
|
---|
1373 | {
|
---|
1374 | QList<QAInterface> interfaceList;
|
---|
1375 |
|
---|
1376 | int count = 1;
|
---|
1377 | const QAInterface labelled = interface.navigate(QAccessible::Labelled, count);
|
---|
1378 | while (labelled.isValid()) {
|
---|
1379 | interfaceList.append(labelled);
|
---|
1380 | ++count;
|
---|
1381 | }
|
---|
1382 | return interfaceList;
|
---|
1383 | }
|
---|
1384 | */
|
---|
1385 | /*
|
---|
1386 | Tests if the given QAInterface has data for a mac attribute.
|
---|
1387 | */
|
---|
1388 | #ifndef QT_MAC_USE_COCOA
|
---|
1389 | static bool supportsAttribute(CFStringRef attribute, const QAInterface &interface)
|
---|
1390 | {
|
---|
1391 | const int text = textForRoleAndAttribute(interface.role(), attribute);
|
---|
1392 |
|
---|
1393 | // Special case: Static texts don't have a title.
|
---|
1394 | if (interface.role() == QAccessible::StaticText && attribute == CFStringRef(QAXTitleAttribute))
|
---|
1395 | return false;
|
---|
1396 |
|
---|
1397 | // Return true if we the attribute matched a QAccessible::Role and we get text for that role from the interface.
|
---|
1398 | if (text != -1) {
|
---|
1399 | if (text == QAccessible::Value) // Special case for Value, see getValue()
|
---|
1400 | return !getValue(interface).isEmpty();
|
---|
1401 | else
|
---|
1402 | return !interface.text((QAccessible::Text)text).isEmpty();
|
---|
1403 | }
|
---|
1404 |
|
---|
1405 | if (CFStringCompare(attribute, CFStringRef(QAXChildrenAttribute), 0) == kCFCompareEqualTo) {
|
---|
1406 | if (interface.childCount() > 0)
|
---|
1407 | return true;
|
---|
1408 | }
|
---|
1409 |
|
---|
1410 | if (CFStringCompare(attribute, CFStringRef(QAXSubroleAttribute), 0) == kCFCompareEqualTo) {
|
---|
1411 | return (subrole(interface) != QCFString());
|
---|
1412 | }
|
---|
1413 |
|
---|
1414 | return false;
|
---|
1415 | }
|
---|
1416 |
|
---|
1417 | static void appendIfSupported(CFMutableArrayRef array, CFStringRef attribute, const QAInterface &interface)
|
---|
1418 | {
|
---|
1419 | if (supportsAttribute(attribute, interface))
|
---|
1420 | qt_mac_append_cf_uniq(array, attribute);
|
---|
1421 | }
|
---|
1422 |
|
---|
1423 | /*
|
---|
1424 | Returns the names of the attributes the give QAInterface supports.
|
---|
1425 | */
|
---|
1426 | static OSStatus getAllAttributeNames(EventRef event, const QAInterface &interface, EventHandlerCallRef next_ref)
|
---|
1427 | {
|
---|
1428 | // Call system event handler.
|
---|
1429 | OSStatus err = CallNextEventHandler(next_ref, event);
|
---|
1430 | if(err != noErr && err != eventNotHandledErr)
|
---|
1431 | return err;
|
---|
1432 | CFMutableArrayRef attrs = 0;
|
---|
1433 | GetEventParameter(event, kEventParamAccessibleAttributeNames, typeCFMutableArrayRef, 0,
|
---|
1434 | sizeof(attrs), 0, &attrs);
|
---|
1435 |
|
---|
1436 | if (!attrs)
|
---|
1437 | return eventNotHandledErr;
|
---|
1438 |
|
---|
1439 | // Append attribute names that are always supported.
|
---|
1440 | qt_mac_append_cf_uniq(attrs, CFStringRef(QAXPositionAttribute));
|
---|
1441 | qt_mac_append_cf_uniq(attrs, CFStringRef(QAXSizeAttribute));
|
---|
1442 | qt_mac_append_cf_uniq(attrs, CFStringRef(QAXRoleAttribute));
|
---|
1443 | qt_mac_append_cf_uniq(attrs, CFStringRef(QAXEnabledAttribute));
|
---|
1444 | qt_mac_append_cf_uniq(attrs, CFStringRef(QAXWindowAttribute));
|
---|
1445 | #if (MAC_OS_X_VERSION_MAX_ALLOWED >= MAC_OS_X_VERSION_10_4)
|
---|
1446 | qt_mac_append_cf_uniq(attrs, CFStringRef(QAXTopLevelUIElementAttribute));
|
---|
1447 | #endif
|
---|
1448 |
|
---|
1449 | // Append these names if the QInterafceItem returns any data for them.
|
---|
1450 | appendIfSupported(attrs, CFStringRef(QAXTitleAttribute), interface);
|
---|
1451 | appendIfSupported(attrs, CFStringRef(QAXValueAttribute), interface);
|
---|
1452 | #if (MAC_OS_X_VERSION_MAX_ALLOWED >= MAC_OS_X_VERSION_10_4)
|
---|
1453 | appendIfSupported(attrs, CFStringRef(QAXDescriptionAttribute), interface);
|
---|
1454 | appendIfSupported(attrs, CFStringRef(QAXLinkedUIElementsAttribute), interface);
|
---|
1455 | #endif
|
---|
1456 | appendIfSupported(attrs, CFStringRef(QAXHelpAttribute), interface);
|
---|
1457 | appendIfSupported(attrs, CFStringRef(QAXTitleUIElementAttribute), interface);
|
---|
1458 | appendIfSupported(attrs, CFStringRef(QAXChildrenAttribute), interface);
|
---|
1459 | appendIfSupported(attrs, CFStringRef(QAXSubroleAttribute), interface);
|
---|
1460 |
|
---|
1461 | // Append attribute names based on the interaface role.
|
---|
1462 | switch (interface.role()) {
|
---|
1463 | case QAccessible::Window:
|
---|
1464 | qt_mac_append_cf_uniq(attrs, CFStringRef(QAXMainAttribute));
|
---|
1465 | qt_mac_append_cf_uniq(attrs, CFStringRef(QAXMinimizedAttribute));
|
---|
1466 | qt_mac_append_cf_uniq(attrs, CFStringRef(QAXCloseButtonAttribute));
|
---|
1467 | qt_mac_append_cf_uniq(attrs, CFStringRef(QAXZoomButtonAttribute));
|
---|
1468 | qt_mac_append_cf_uniq(attrs, CFStringRef(QAXMinimizeButtonAttribute));
|
---|
1469 | qt_mac_append_cf_uniq(attrs, CFStringRef(QAXToolbarButtonAttribute));
|
---|
1470 | qt_mac_append_cf_uniq(attrs, CFStringRef(QAXGrowAreaAttribute));
|
---|
1471 | break;
|
---|
1472 | case QAccessible::RadioButton:
|
---|
1473 | case QAccessible::CheckBox:
|
---|
1474 | qt_mac_append_cf_uniq(attrs, CFStringRef(QAXMinValueAttribute));
|
---|
1475 | qt_mac_append_cf_uniq(attrs, CFStringRef(QAXMaxValueAttribute));
|
---|
1476 | break;
|
---|
1477 | case QAccessible::ScrollBar:
|
---|
1478 | qt_mac_append_cf_uniq(attrs, CFStringRef(QAXOrientationAttribute));
|
---|
1479 | break;
|
---|
1480 | case QAccessible::Splitter:
|
---|
1481 | qt_mac_append_cf_uniq(attrs, CFStringRef(QAXSplittersAttribute));
|
---|
1482 | break;
|
---|
1483 | case QAccessible::Table:
|
---|
1484 | qt_mac_append_cf_uniq(attrs, CFStringRef(QAXRowsAttribute));
|
---|
1485 | qt_mac_append_cf_uniq(attrs, CFStringRef(QAXVisibleRowsAttribute));
|
---|
1486 | qt_mac_append_cf_uniq(attrs, CFStringRef(QAXSelectedRowsAttribute));
|
---|
1487 | break;
|
---|
1488 | default:
|
---|
1489 | break;
|
---|
1490 | }
|
---|
1491 |
|
---|
1492 | // Append attribute names based on the mac accessibility role.
|
---|
1493 | const QCFString mac_role = macRole(interface);
|
---|
1494 | if (mac_role == CFStringRef(QAXSplitterRole)) {
|
---|
1495 | qt_mac_append_cf_uniq(attrs, CFStringRef(QAXPreviousContentsAttribute));
|
---|
1496 | qt_mac_append_cf_uniq(attrs, CFStringRef(QAXNextContentsAttribute));
|
---|
1497 | qt_mac_append_cf_uniq(attrs, CFStringRef(QAXOrientationAttribute));
|
---|
1498 | } else if (mac_role == CFStringRef(QAXScrollAreaRole)) {
|
---|
1499 | if (scrollAreaHasScrollBar(interface, Qt::Horizontal))
|
---|
1500 | qt_mac_append_cf_uniq(attrs, CFStringRef(QAXHorizontalScrollBarAttribute));
|
---|
1501 | if (scrollAreaHasScrollBar(interface, Qt::Vertical))
|
---|
1502 | qt_mac_append_cf_uniq(attrs, CFStringRef(QAXVerticalScrollBarAttribute));
|
---|
1503 | qt_mac_append_cf_uniq(attrs, CFStringRef(QAXContentsAttribute));
|
---|
1504 | } else if (mac_role == CFStringRef(QAXTabGroupRole)) {
|
---|
1505 | qt_mac_append_cf_uniq(attrs, CFStringRef(QAXTabsAttribute));
|
---|
1506 | // Only tab widgets can have the contents attribute, there is no way of getting
|
---|
1507 | // the contents from a QTabBar.
|
---|
1508 | if (isTabWidget(interface))
|
---|
1509 | qt_mac_append_cf_uniq(attrs, CFStringRef(QAXContentsAttribute));
|
---|
1510 | }
|
---|
1511 |
|
---|
1512 | return noErr;
|
---|
1513 | }
|
---|
1514 |
|
---|
1515 | static void handleStringAttribute(EventRef event, QAccessible::Text text, const QAInterface &interface)
|
---|
1516 | {
|
---|
1517 | QString str = interface.text(text);
|
---|
1518 | if (str.isEmpty())
|
---|
1519 | return;
|
---|
1520 |
|
---|
1521 | // Remove any html markup from the text string, or VoiceOver will read the html tags.
|
---|
1522 | static QTextDocument document;
|
---|
1523 | document.setHtml(str);
|
---|
1524 | str = document.toPlainText();
|
---|
1525 |
|
---|
1526 | CFStringRef cfstr = QCFString::toCFStringRef(str);
|
---|
1527 | SetEventParameter(event, kEventParamAccessibleAttributeValue, typeCFStringRef, sizeof(cfstr), &cfstr);
|
---|
1528 | }
|
---|
1529 |
|
---|
1530 | /*
|
---|
1531 | Handles the parent attribute for a interface.
|
---|
1532 | There are basically three cases here:
|
---|
1533 | 1. interface is a HIView and has only HIView children.
|
---|
1534 | 2. interface is a HIView but has children that is not a HIView
|
---|
1535 | 3. interface is not a HIView.
|
---|
1536 | */
|
---|
1537 | static OSStatus handleChildrenAttribute(EventHandlerCallRef next_ref, EventRef event, QAInterface &interface)
|
---|
1538 | {
|
---|
1539 | // Add the children for this interface to the global QAccessibelHierachyManager.
|
---|
1540 | accessibleHierarchyManager()->registerChildren(interface);
|
---|
1541 |
|
---|
1542 | if (isTabWidget(interface)) {
|
---|
1543 | QList<QAElement> children = tabWidgetGetChildren(interface);
|
---|
1544 | const int childCount = children.count();
|
---|
1545 |
|
---|
1546 | CFMutableArrayRef array = 0;
|
---|
1547 | array = CFArrayCreateMutable(0, 0, &kCFTypeArrayCallBacks);
|
---|
1548 | for (int i = 0; i < childCount; ++i) {
|
---|
1549 | qt_mac_append_cf_uniq(array, children.at(i).element());
|
---|
1550 | }
|
---|
1551 |
|
---|
1552 | OSStatus err;
|
---|
1553 | err = SetEventParameter(event, kEventParamAccessibleAttributeValue, typeCFArrayRef, sizeof(array), &array);
|
---|
1554 | if (err != noErr)
|
---|
1555 | qWarning("Qt:Internal error (%s:%d)", __FILE__, __LINE__);
|
---|
1556 |
|
---|
1557 | return noErr;
|
---|
1558 | }
|
---|
1559 |
|
---|
1560 | const QList<QAElement> children = lookup(interface.children());
|
---|
1561 | const int childCount = children.count();
|
---|
1562 |
|
---|
1563 | OSStatus err = eventNotHandledErr;
|
---|
1564 | if (interface.isHIView())
|
---|
1565 | err = CallNextEventHandler(next_ref, event);
|
---|
1566 |
|
---|
1567 | CFMutableArrayRef array = 0;
|
---|
1568 | int arraySize = 0;
|
---|
1569 | if (err == noErr) {
|
---|
1570 | CFTypeRef obj = 0;
|
---|
1571 | err = GetEventParameter(event, kEventParamAccessibleAttributeValue, typeCFTypeRef, NULL , sizeof(obj), NULL, &obj);
|
---|
1572 | if (err == noErr && obj != 0) {
|
---|
1573 | array = (CFMutableArrayRef)obj;
|
---|
1574 | arraySize = CFArrayGetCount(array);
|
---|
1575 | }
|
---|
1576 | }
|
---|
1577 |
|
---|
1578 | if (array) {
|
---|
1579 | CFArrayRemoveAllValues(array);
|
---|
1580 | for (int i = 0; i < childCount; ++i) {
|
---|
1581 | qt_mac_append_cf_uniq(array, children.at(i).element());
|
---|
1582 | }
|
---|
1583 | } else {
|
---|
1584 | array = CFArrayCreateMutable(0, 0, &kCFTypeArrayCallBacks);
|
---|
1585 | for (int i = 0; i < childCount; ++i) {
|
---|
1586 | qt_mac_append_cf_uniq(array, children.at(i).element());
|
---|
1587 | }
|
---|
1588 |
|
---|
1589 | err = SetEventParameter(event, kEventParamAccessibleAttributeValue, typeCFArrayRef, sizeof(array), &array);
|
---|
1590 | if (err != noErr)
|
---|
1591 | qWarning("Qt:Internal error (%s:%d)", __FILE__, __LINE__);
|
---|
1592 | }
|
---|
1593 |
|
---|
1594 | return noErr;
|
---|
1595 | }
|
---|
1596 |
|
---|
1597 | /*
|
---|
1598 |
|
---|
1599 | */
|
---|
1600 | static OSStatus handleParentAttribute(EventHandlerCallRef next_ref, EventRef event, const QAInterface &interface)
|
---|
1601 | {
|
---|
1602 | OSStatus err = eventNotHandledErr;
|
---|
1603 | if (interface.isHIView()) {
|
---|
1604 | err = CallNextEventHandler(next_ref, event);
|
---|
1605 | }
|
---|
1606 | if (err == noErr)
|
---|
1607 | return err;
|
---|
1608 |
|
---|
1609 | const QAInterface parentInterface = interface.navigate(QAccessible::Ancestor, 1);
|
---|
1610 | const QAElement parentElement = accessibleHierarchyManager()->lookup(parentInterface);
|
---|
1611 |
|
---|
1612 | if (parentElement.isValid() == false)
|
---|
1613 | return eventNotHandledErr;
|
---|
1614 |
|
---|
1615 | AXUIElementRef elementRef = parentElement.element();
|
---|
1616 | SetEventParameter(event, kEventParamAccessibleAttributeValue, typeCFTypeRef, sizeof(elementRef), &elementRef);
|
---|
1617 | return noErr;
|
---|
1618 | }
|
---|
1619 | #endif
|
---|
1620 |
|
---|
1621 | struct IsWindowTest
|
---|
1622 | {
|
---|
1623 | static inline bool test(const QAInterface &interface)
|
---|
1624 | {
|
---|
1625 | return (interface.role() == QAccessible::Window);
|
---|
1626 | }
|
---|
1627 | };
|
---|
1628 |
|
---|
1629 | struct IsWindowAndNotDrawerOrSheetTest
|
---|
1630 | {
|
---|
1631 | static inline bool test(const QAInterface &interface)
|
---|
1632 | {
|
---|
1633 | QWidget * const widget = qobject_cast<QWidget*>(interface.object());
|
---|
1634 | return (interface.role() == QAccessible::Window &&
|
---|
1635 | widget && widget->isWindow() &&
|
---|
1636 | !qt_mac_is_macdrawer(widget) &&
|
---|
1637 | !qt_mac_is_macsheet(widget));
|
---|
1638 | }
|
---|
1639 | };
|
---|
1640 |
|
---|
1641 | /*
|
---|
1642 | Navigates up the iterfaces ancestor hierachy until a QAccessibleInterface that
|
---|
1643 | passes the Test is found. If we reach a interface that is a HIView we stop the
|
---|
1644 | search and call AXUIElementCopyAttributeValue.
|
---|
1645 | */
|
---|
1646 | template <typename TestType>
|
---|
1647 | OSStatus navigateAncestors(EventHandlerCallRef next_ref, EventRef event, const QAInterface &interface, CFStringRef attribute)
|
---|
1648 | {
|
---|
1649 | if (interface.isHIView())
|
---|
1650 | return CallNextEventHandler(next_ref, event);
|
---|
1651 |
|
---|
1652 | QAInterface current = interface;
|
---|
1653 | QAElement element;
|
---|
1654 | while (current.isValid()) {
|
---|
1655 | if (TestType::test(interface)) {
|
---|
1656 | element = accessibleHierarchyManager()->lookup(current);
|
---|
1657 | break;
|
---|
1658 | }
|
---|
1659 |
|
---|
1660 | // If we reach an InterfaceItem that is a HiView we can hand of the search to
|
---|
1661 | // the system event handler. This is the common case.
|
---|
1662 | if (current.isHIView()) {
|
---|
1663 | CFTypeRef value = 0;
|
---|
1664 | const QAElement currentElement = accessibleHierarchyManager()->lookup(current);
|
---|
1665 | AXError err = AXUIElementCopyAttributeValue(currentElement.element(), attribute, &value);
|
---|
1666 | AXUIElementRef newElement = (AXUIElementRef)value;
|
---|
1667 |
|
---|
1668 | if (err == noErr)
|
---|
1669 | element = QAElement(newElement);
|
---|
1670 |
|
---|
1671 | if (newElement != 0)
|
---|
1672 | CFRelease(newElement);
|
---|
1673 | break;
|
---|
1674 | }
|
---|
1675 |
|
---|
1676 | QAInterface next = current.parent();
|
---|
1677 | if (next.isValid() == false)
|
---|
1678 | break;
|
---|
1679 | if (next == current)
|
---|
1680 | break;
|
---|
1681 | current = next;
|
---|
1682 | }
|
---|
1683 |
|
---|
1684 | if (element.isValid() == false)
|
---|
1685 | return eventNotHandledErr;
|
---|
1686 |
|
---|
1687 |
|
---|
1688 | AXUIElementRef elementRef = element.element();
|
---|
1689 | SetEventParameter(event, kEventParamAccessibleAttributeValue, typeCFTypeRef,
|
---|
1690 | sizeof(elementRef), &elementRef);
|
---|
1691 | return noErr;
|
---|
1692 | }
|
---|
1693 |
|
---|
1694 | /*
|
---|
1695 | Returns the top-level window for an interface, which is the closest ancestor interface that
|
---|
1696 | has the Window role, but is not a sheet or a drawer.
|
---|
1697 | */
|
---|
1698 | #ifndef QT_MAC_USE_COCOA
|
---|
1699 | static OSStatus handleWindowAttribute(EventHandlerCallRef next_ref, EventRef event, const QAInterface &interface)
|
---|
1700 | {
|
---|
1701 | return navigateAncestors<IsWindowAndNotDrawerOrSheetTest>(next_ref, event, interface, CFStringRef(QAXWindowAttribute));
|
---|
1702 | }
|
---|
1703 |
|
---|
1704 | /*
|
---|
1705 | Returns the top-level window for an interface, which is the closest ancestor interface that
|
---|
1706 | has the Window role. (Can also be a sheet or a drawer)
|
---|
1707 | */
|
---|
1708 | #if (MAC_OS_X_VERSION_MAX_ALLOWED >= MAC_OS_X_VERSION_10_4)
|
---|
1709 | static OSStatus handleTopLevelUIElementAttribute(EventHandlerCallRef next_ref, EventRef event, const QAInterface &interface)
|
---|
1710 | {
|
---|
1711 | return navigateAncestors<IsWindowTest>(next_ref, event, interface, CFStringRef(QAXTopLevelUIElementAttribute));
|
---|
1712 | }
|
---|
1713 | #endif
|
---|
1714 |
|
---|
1715 | /*
|
---|
1716 | Returns the tab buttons for an interface.
|
---|
1717 | */
|
---|
1718 | static OSStatus handleTabsAttribute(EventHandlerCallRef next_ref, EventRef event, QAInterface &interface)
|
---|
1719 | {
|
---|
1720 | Q_UNUSED(next_ref);
|
---|
1721 | if (isTabWidget(interface))
|
---|
1722 | return setAttributeValue(event, tabWidgetGetTabs(interface));
|
---|
1723 | else
|
---|
1724 | return setAttributeValue(event, tabBarGetTabs(interface));
|
---|
1725 | }
|
---|
1726 |
|
---|
1727 | static OSStatus handlePositionAttribute(EventHandlerCallRef, EventRef event, const QAInterface &interface)
|
---|
1728 | {
|
---|
1729 | QPoint qpoint(interface.rect().topLeft());
|
---|
1730 | HIPoint point;
|
---|
1731 | point.x = qpoint.x();
|
---|
1732 | point.y = qpoint.y();
|
---|
1733 | SetEventParameter(event, kEventParamAccessibleAttributeValue, typeHIPoint, sizeof(point), &point);
|
---|
1734 | return noErr;
|
---|
1735 | }
|
---|
1736 |
|
---|
1737 | static OSStatus handleSizeAttribute(EventHandlerCallRef, EventRef event, const QAInterface &interface)
|
---|
1738 | {
|
---|
1739 | QSize qSize(interface.rect().size());
|
---|
1740 | HISize size;
|
---|
1741 | size.width = qSize.width();
|
---|
1742 | size.height = qSize.height();
|
---|
1743 | SetEventParameter(event, kEventParamAccessibleAttributeValue, typeHISize, sizeof(size), &size);
|
---|
1744 | return noErr;
|
---|
1745 | }
|
---|
1746 |
|
---|
1747 | static OSStatus handleSubroleAttribute(EventHandlerCallRef, EventRef event, const QAInterface &interface)
|
---|
1748 | {
|
---|
1749 | const QCFString role = subrole(interface);
|
---|
1750 | CFStringRef rolestr = (CFStringRef)role;
|
---|
1751 | SetEventParameter(event, kEventParamAccessibleAttributeValue, typeCFTypeRef, sizeof(rolestr), &rolestr);
|
---|
1752 | return noErr;
|
---|
1753 | }
|
---|
1754 |
|
---|
1755 | static OSStatus handleOrientationAttribute(EventHandlerCallRef next_ref, EventRef event, const QAInterface &interface)
|
---|
1756 | {
|
---|
1757 | QObject *const object = interface.object();
|
---|
1758 | Qt::Orientation orientation;
|
---|
1759 | if (interface.role() == QAccessible::ScrollBar) {
|
---|
1760 | orientation = scrollBarOrientation(interface);
|
---|
1761 | } else if (QSplitterHandle * const splitter = qobject_cast<QSplitterHandle * const>(object)) {
|
---|
1762 | // Qt reports the layout orientation, but we want the splitter handle orientation.
|
---|
1763 | orientation = (splitter->orientation() == Qt::Horizontal) ? Qt::Vertical : Qt::Horizontal;
|
---|
1764 | } else {
|
---|
1765 | return CallNextEventHandler(next_ref, event);
|
---|
1766 | }
|
---|
1767 | const CFStringRef orientationString = (orientation == Qt::Vertical)
|
---|
1768 | ? CFStringRef(QAXVerticalOrientationValue) : CFStringRef(QAXHorizontalOrientationValue);
|
---|
1769 | SetEventParameter(event, kEventParamAccessibleAttributeValue, typeCFStringRef, sizeof(orientationString), &orientationString);
|
---|
1770 | return noErr;
|
---|
1771 | }
|
---|
1772 |
|
---|
1773 | /*
|
---|
1774 | Figures out the next or previous contents for a splitter.
|
---|
1775 | */
|
---|
1776 | static OSStatus handleSplitterContentsAttribute(EventHandlerCallRef next_ref, EventRef event, const QAInterface &interface, QCFString nextOrPrev)
|
---|
1777 | {
|
---|
1778 | if (interface.isValid() == false || interface.role() != QAccessible::Grip)
|
---|
1779 | return eventNotHandledErr;
|
---|
1780 |
|
---|
1781 | const QAInterface parent = interface.parent();
|
---|
1782 | if (parent.isValid() == false)
|
---|
1783 | return CallNextEventHandler(next_ref, event);
|
---|
1784 |
|
---|
1785 | if (parent.role() != QAccessible::Splitter)
|
---|
1786 | return CallNextEventHandler(next_ref, event);
|
---|
1787 |
|
---|
1788 | const QSplitter * const splitter = qobject_cast<const QSplitter * const>(parent.object());
|
---|
1789 | if (splitter == 0)
|
---|
1790 | return CallNextEventHandler(next_ref, event);
|
---|
1791 |
|
---|
1792 | QWidget * const splitterHandle = qobject_cast<QWidget * const>(interface.object());
|
---|
1793 | const int splitterHandleIndex = splitter->indexOf(splitterHandle);
|
---|
1794 | const int widgetIndex = (nextOrPrev == QCFString(CFStringRef(QAXPreviousContentsAttribute))) ? splitterHandleIndex - 1 : splitterHandleIndex;
|
---|
1795 | const QAElement contentsElement = accessibleHierarchyManager()->lookup(splitter->widget(widgetIndex), 0);
|
---|
1796 | return setAttributeValue(event, QList<QAElement>() << contentsElement);
|
---|
1797 | }
|
---|
1798 |
|
---|
1799 | /*
|
---|
1800 | Creates a list of all splitter handles the splitter contains.
|
---|
1801 | */
|
---|
1802 | static OSStatus handleSplittersAttribute(EventHandlerCallRef next_ref, EventRef event, QAInterface &interface)
|
---|
1803 | {
|
---|
1804 | const QSplitter * const splitter = qobject_cast<const QSplitter * const>(interface.object());
|
---|
1805 | if (splitter == 0)
|
---|
1806 | return CallNextEventHandler(next_ref, event);
|
---|
1807 |
|
---|
1808 | accessibleHierarchyManager()->registerChildren(interface);
|
---|
1809 |
|
---|
1810 | QList<QAElement> handles;
|
---|
1811 | const int visibleSplitterCount = splitter->count() -1; // skip first handle, it's always invisible.
|
---|
1812 | for (int i = 0; i < visibleSplitterCount; ++i)
|
---|
1813 | handles.append(accessibleHierarchyManager()->lookup(splitter->handle(i + 1), 0));
|
---|
1814 |
|
---|
1815 | return setAttributeValue(event, handles);
|
---|
1816 | }
|
---|
1817 |
|
---|
1818 | // This handler gets the scroll bars for a scroll area
|
---|
1819 | static OSStatus handleScrollBarAttribute(EventHandlerCallRef next_ref, EventRef event, QAInterface &scrollArea, Qt::Orientation orientation)
|
---|
1820 | {
|
---|
1821 | QAElement scrollBar = scrollAreaGetScrollBar(scrollArea, orientation);
|
---|
1822 | if (scrollBar.isValid() == false)
|
---|
1823 | return CallNextEventHandler(next_ref, event);
|
---|
1824 |
|
---|
1825 | AXUIElementRef elementRef = scrollBar.element();
|
---|
1826 | SetEventParameter(event, kEventParamAccessibleAttributeValue, typeCFTypeRef, sizeof(elementRef), &elementRef);
|
---|
1827 | return noErr;
|
---|
1828 | }
|
---|
1829 |
|
---|
1830 | // This handler gets the contents for a scroll area or tab widget.
|
---|
1831 | static OSStatus handleContentsAttribute(EventHandlerCallRef next_ref, EventRef event, QAInterface &interface)
|
---|
1832 | {
|
---|
1833 | const QCFString mac_role = macRole(interface);
|
---|
1834 |
|
---|
1835 | QAElement contents;
|
---|
1836 |
|
---|
1837 | if (mac_role == kAXTabGroupRole) {
|
---|
1838 | contents = tabWidgetGetContents(interface);
|
---|
1839 | } else {
|
---|
1840 | contents = scrollAreaGetContents(interface);
|
---|
1841 | if (contents.isValid() == false)
|
---|
1842 | return CallNextEventHandler(next_ref, event);
|
---|
1843 | }
|
---|
1844 |
|
---|
1845 | return setAttributeValue(event, QList<QAElement>() << contents);
|
---|
1846 | }
|
---|
1847 |
|
---|
1848 | static OSStatus handleRowsAttribute(EventHandlerCallRef, EventRef event, QAInterface &tableView)
|
---|
1849 | {
|
---|
1850 | QList<QAElement> rows = lookup(tableView.children());
|
---|
1851 |
|
---|
1852 | // kill the first row which is the horizontal header.
|
---|
1853 | rows.removeAt(0);
|
---|
1854 |
|
---|
1855 | return setAttributeValue(event, rows);
|
---|
1856 | }
|
---|
1857 |
|
---|
1858 | static OSStatus handleVisibleRowsAttribute(EventHandlerCallRef, EventRef event, QAInterface &tableView)
|
---|
1859 | {
|
---|
1860 | QList<QAElement> visibleRows;
|
---|
1861 |
|
---|
1862 | QList<QAInterface> rows = tableView.children();
|
---|
1863 | // kill the first row which is the horizontal header.
|
---|
1864 | rows.removeAt(0);
|
---|
1865 |
|
---|
1866 | foreach (const QAInterface &interface, rows)
|
---|
1867 | if ((interface.state() & QAccessible::Invisible) == false)
|
---|
1868 | visibleRows.append(accessibleHierarchyManager()->lookup(interface));
|
---|
1869 |
|
---|
1870 | return setAttributeValue(event, visibleRows);
|
---|
1871 | }
|
---|
1872 |
|
---|
1873 | static OSStatus handleSelectedRowsAttribute(EventHandlerCallRef, EventRef event, QAInterface &tableView)
|
---|
1874 | {
|
---|
1875 | QList<QAElement> selectedRows;
|
---|
1876 | foreach (const QAInterface &interface, tableView.children())
|
---|
1877 | if ((interface.state() & QAccessible::Selected))
|
---|
1878 | selectedRows.append(accessibleHierarchyManager()->lookup(interface));
|
---|
1879 |
|
---|
1880 | return setAttributeValue(event, selectedRows);
|
---|
1881 | }
|
---|
1882 |
|
---|
1883 | static OSStatus getNamedAttribute(EventHandlerCallRef next_ref, EventRef event, QAInterface &interface)
|
---|
1884 | {
|
---|
1885 | CFStringRef var;
|
---|
1886 | GetEventParameter(event, kEventParamAccessibleAttributeName, typeCFStringRef, 0,
|
---|
1887 | sizeof(var), 0, &var);
|
---|
1888 |
|
---|
1889 | if (CFStringCompare(var, CFStringRef(QAXChildrenAttribute), 0) == kCFCompareEqualTo) {
|
---|
1890 | return handleChildrenAttribute(next_ref, event, interface);
|
---|
1891 | #if (MAC_OS_X_VERSION_MAX_ALLOWED >= MAC_OS_X_VERSION_10_4)
|
---|
1892 | } else if(CFStringCompare(var, CFStringRef(QAXTopLevelUIElementAttribute), 0) == kCFCompareEqualTo) {
|
---|
1893 | return handleTopLevelUIElementAttribute(next_ref, event, interface);
|
---|
1894 | #endif
|
---|
1895 | } else if(CFStringCompare(var, CFStringRef(QAXWindowAttribute), 0) == kCFCompareEqualTo) {
|
---|
1896 | return handleWindowAttribute(next_ref, event, interface);
|
---|
1897 | } else if(CFStringCompare(var, CFStringRef(QAXParentAttribute), 0) == kCFCompareEqualTo) {
|
---|
1898 | return handleParentAttribute(next_ref, event, interface);
|
---|
1899 | } else if (CFStringCompare(var, CFStringRef(QAXPositionAttribute), 0) == kCFCompareEqualTo) {
|
---|
1900 | return handlePositionAttribute(next_ref, event, interface);
|
---|
1901 | } else if (CFStringCompare(var, CFStringRef(QAXSizeAttribute), 0) == kCFCompareEqualTo) {
|
---|
1902 | return handleSizeAttribute(next_ref, event, interface);
|
---|
1903 | } else if (CFStringCompare(var, CFStringRef(QAXRoleAttribute), 0) == kCFCompareEqualTo) {
|
---|
1904 | CFStringRef role = macRole(interface);
|
---|
1905 | // ###
|
---|
1906 | // QWidget * const widget = qobject_cast<QWidget *>(interface.object());
|
---|
1907 | // if (role == CFStringRef(QAXUnknownRole) && widget && widget->isWindow())
|
---|
1908 | // role = CFStringRef(QAXWindowRole);
|
---|
1909 |
|
---|
1910 | SetEventParameter(event, kEventParamAccessibleAttributeValue, typeCFStringRef,
|
---|
1911 | sizeof(role), &role);
|
---|
1912 |
|
---|
1913 | } else if (CFStringCompare(var, CFStringRef(QAXEnabledAttribute), 0) == kCFCompareEqualTo) {
|
---|
1914 | Boolean val = !((interface.state() & QAccessible::Unavailable))
|
---|
1915 | && !((interface.state() & QAccessible::Invisible));
|
---|
1916 | SetEventParameter(event, kEventParamAccessibleAttributeValue, typeBoolean,
|
---|
1917 | sizeof(val), &val);
|
---|
1918 | } else if (CFStringCompare(var, CFStringRef(QAXExpandedAttribute), 0) == kCFCompareEqualTo) {
|
---|
1919 | Boolean val = (interface.state() & QAccessible::Expanded);
|
---|
1920 | SetEventParameter(event, kEventParamAccessibleAttributeValue, typeBoolean,
|
---|
1921 | sizeof(val), &val);
|
---|
1922 | } else if (CFStringCompare(var, CFStringRef(QAXSelectedAttribute), 0) == kCFCompareEqualTo) {
|
---|
1923 | Boolean val = (interface.state() & QAccessible::Selection);
|
---|
1924 | SetEventParameter(event, kEventParamAccessibleAttributeValue, typeBoolean,
|
---|
1925 | sizeof(val), &val);
|
---|
1926 | } else if (CFStringCompare(var, CFStringRef(QAXFocusedAttribute), 0) == kCFCompareEqualTo) {
|
---|
1927 | Boolean val = (interface.state() & QAccessible::Focus);
|
---|
1928 | SetEventParameter(event, kEventParamAccessibleAttributeValue, typeBoolean,
|
---|
1929 | sizeof(val), &val);
|
---|
1930 | } else if (CFStringCompare(var, CFStringRef(QAXSelectedChildrenAttribute), 0) == kCFCompareEqualTo) {
|
---|
1931 | const int cc = interface.childCount();
|
---|
1932 | QList<QAElement> selected;
|
---|
1933 | for (int i = 1; i <= cc; ++i) {
|
---|
1934 | const QAInterface child_iface = interface.navigate(QAccessible::Child, i);
|
---|
1935 | if (child_iface.isValid() && child_iface.state() & QAccessible::Selected)
|
---|
1936 | selected.append(accessibleHierarchyManager()->lookup(child_iface));
|
---|
1937 | }
|
---|
1938 |
|
---|
1939 | return setAttributeValue(event, selected);
|
---|
1940 |
|
---|
1941 | } else if (CFStringCompare(var, CFStringRef(QAXCloseButtonAttribute), 0) == kCFCompareEqualTo) {
|
---|
1942 | if(interface.object() && interface.object()->isWidgetType()) {
|
---|
1943 | Boolean val = true; //do we want to add a WState for this?
|
---|
1944 | SetEventParameter(event, kEventParamAccessibleAttributeValue, typeBoolean,
|
---|
1945 | sizeof(val), &val);
|
---|
1946 | }
|
---|
1947 | } else if (CFStringCompare(var, CFStringRef(QAXZoomButtonAttribute), 0) == kCFCompareEqualTo) {
|
---|
1948 | if(interface.object() && interface.object()->isWidgetType()) {
|
---|
1949 | QWidget *widget = (QWidget*)interface.object();
|
---|
1950 | Boolean val = (widget->windowFlags() & Qt::WindowMaximizeButtonHint);
|
---|
1951 | SetEventParameter(event, kEventParamAccessibleAttributeValue, typeBoolean,
|
---|
1952 | sizeof(val), &val);
|
---|
1953 | }
|
---|
1954 | } else if (CFStringCompare(var, CFStringRef(QAXMinimizeButtonAttribute), 0) == kCFCompareEqualTo) {
|
---|
1955 | if(interface.object() && interface.object()->isWidgetType()) {
|
---|
1956 | QWidget *widget = (QWidget*)interface.object();
|
---|
1957 | Boolean val = (widget->windowFlags() & Qt::WindowMinimizeButtonHint);
|
---|
1958 | SetEventParameter(event, kEventParamAccessibleAttributeValue, typeBoolean,
|
---|
1959 | sizeof(val), &val);
|
---|
1960 | }
|
---|
1961 | } else if (CFStringCompare(var, CFStringRef(QAXToolbarButtonAttribute), 0) == kCFCompareEqualTo) {
|
---|
1962 | if(interface.object() && interface.object()->isWidgetType()) {
|
---|
1963 | QWidget *widget = (QWidget*)interface.object();
|
---|
1964 | Boolean val = qobject_cast<QMainWindow *>(widget) != 0;
|
---|
1965 | SetEventParameter(event, kEventParamAccessibleAttributeValue, typeBoolean,
|
---|
1966 | sizeof(val), &val);
|
---|
1967 | }
|
---|
1968 | } else if (CFStringCompare(var, CFStringRef(QAXGrowAreaAttribute), 0) == kCFCompareEqualTo) {
|
---|
1969 | if(interface.object() && interface.object()->isWidgetType()) {
|
---|
1970 | Boolean val = true; //do we want to add a WState for this?
|
---|
1971 | SetEventParameter(event, kEventParamAccessibleAttributeValue, typeBoolean,
|
---|
1972 | sizeof(val), &val);
|
---|
1973 | }
|
---|
1974 | } else if (CFStringCompare(var, CFStringRef(QAXMinimizedAttribute), 0) == kCFCompareEqualTo) {
|
---|
1975 | if (interface.object() && interface.object()->isWidgetType()) {
|
---|
1976 | QWidget *widget = (QWidget*)interface.object();
|
---|
1977 | Boolean val = (widget->windowState() & Qt::WindowMinimized);
|
---|
1978 | SetEventParameter(event, kEventParamAccessibleAttributeValue, typeBoolean,
|
---|
1979 | sizeof(val), &val);
|
---|
1980 | }
|
---|
1981 | } else if (CFStringCompare(var, CFStringRef(QAXSubroleAttribute), 0) == kCFCompareEqualTo) {
|
---|
1982 | return handleSubroleAttribute(next_ref, event, interface);
|
---|
1983 | } else if (CFStringCompare(var, CFStringRef(QAXRoleDescriptionAttribute), 0) == kCFCompareEqualTo) {
|
---|
1984 | #if (MAC_OS_X_VERSION_MAX_ALLOWED >= MAC_OS_X_VERSION_10_4) && !defined(QT_MAC_USE_COCOA)
|
---|
1985 | if (HICopyAccessibilityRoleDescription) {
|
---|
1986 | const CFStringRef roleDescription = HICopyAccessibilityRoleDescription(macRole(interface), 0);
|
---|
1987 | SetEventParameter(event, kEventParamAccessibleAttributeValue, typeCFStringRef,
|
---|
1988 | sizeof(roleDescription), &roleDescription);
|
---|
1989 | } else
|
---|
1990 | #endif
|
---|
1991 | {
|
---|
1992 | // Just use Qt::Description on 10.3
|
---|
1993 | handleStringAttribute(event, QAccessible::Description, interface);
|
---|
1994 | }
|
---|
1995 | } else if (CFStringCompare(var, CFStringRef(QAXTitleAttribute), 0) == kCFCompareEqualTo) {
|
---|
1996 | const QAccessible::Role role = interface.role();
|
---|
1997 | const QAccessible::Text text = (QAccessible::Text)textForRoleAndAttribute(role, var);
|
---|
1998 | handleStringAttribute(event, text, interface);
|
---|
1999 | } else if (CFStringCompare(var, CFStringRef(QAXValueAttribute), 0) == kCFCompareEqualTo) {
|
---|
2000 | const QAccessible::Role role = interface.role();
|
---|
2001 | const QAccessible::Text text = (QAccessible::Text)textForRoleAndAttribute(role, var);
|
---|
2002 | if (role == QAccessible::CheckBox || role == QAccessible::RadioButton) {
|
---|
2003 | int value = buttonValue(interface);
|
---|
2004 | SetEventParameter(event, kEventParamAccessibleAttributeValue, typeUInt32, sizeof(value), &value);
|
---|
2005 | } else {
|
---|
2006 | handleStringAttribute(event, text, interface);
|
---|
2007 | }
|
---|
2008 | #if (MAC_OS_X_VERSION_MAX_ALLOWED >= MAC_OS_X_VERSION_10_4)
|
---|
2009 | } else if (CFStringCompare(var, CFStringRef(QAXDescriptionAttribute), 0) == kCFCompareEqualTo) {
|
---|
2010 | const QAccessible::Role role = interface.role();
|
---|
2011 | const QAccessible::Text text = (QAccessible::Text)textForRoleAndAttribute(role, var);
|
---|
2012 | handleStringAttribute(event, text, interface);
|
---|
2013 | } else if (CFStringCompare(var, CFStringRef(QAXLinkedUIElementsAttribute), 0) == kCFCompareEqualTo) {
|
---|
2014 | return CallNextEventHandler(next_ref, event);
|
---|
2015 | #endif
|
---|
2016 | } else if (CFStringCompare(var, CFStringRef(QAXHelpAttribute), 0) == kCFCompareEqualTo) {
|
---|
2017 | const QAccessible::Role role = interface.role();
|
---|
2018 | const QAccessible::Text text = (QAccessible::Text)textForRoleAndAttribute(role, var);
|
---|
2019 | handleStringAttribute(event, text, interface);
|
---|
2020 | } else if (CFStringCompare(var, kAXTitleUIElementAttribute, 0) == kCFCompareEqualTo) {
|
---|
2021 | return CallNextEventHandler(next_ref, event);
|
---|
2022 | } else if (CFStringCompare(var, CFStringRef(QAXTabsAttribute), 0) == kCFCompareEqualTo) {
|
---|
2023 | return handleTabsAttribute(next_ref, event, interface);
|
---|
2024 | } else if (CFStringCompare(var, CFStringRef(QAXMinValueAttribute), 0) == kCFCompareEqualTo) {
|
---|
2025 | // tabs we first go to the tab bar which is child #2.
|
---|
2026 | QAInterface tabBarInterface = interface.childAt(2);
|
---|
2027 | return handleTabsAttribute(next_ref, event, tabBarInterface);
|
---|
2028 | } else if (CFStringCompare(var, CFStringRef(QAXMinValueAttribute), 0) == kCFCompareEqualTo) {
|
---|
2029 | if (interface.role() == QAccessible::RadioButton || interface.role() == QAccessible::CheckBox) {
|
---|
2030 | uint value = 0;
|
---|
2031 | SetEventParameter(event, kEventParamAccessibleAttributeValue, typeUInt32, sizeof(value), &value);
|
---|
2032 | } else {
|
---|
2033 | return CallNextEventHandler(next_ref, event);
|
---|
2034 | }
|
---|
2035 | } else if (CFStringCompare(var, CFStringRef(QAXMaxValueAttribute), 0) == kCFCompareEqualTo) {
|
---|
2036 | if (interface.role() == QAccessible::RadioButton || interface.role() == QAccessible::CheckBox) {
|
---|
2037 | uint value = 2;
|
---|
2038 | SetEventParameter(event, kEventParamAccessibleAttributeValue, typeUInt32, sizeof(value), &value);
|
---|
2039 | } else {
|
---|
2040 | return CallNextEventHandler(next_ref, event);
|
---|
2041 | }
|
---|
2042 | } else if (CFStringCompare(var, CFStringRef(QAXOrientationAttribute), 0) == kCFCompareEqualTo) {
|
---|
2043 | return handleOrientationAttribute(next_ref, event, interface);
|
---|
2044 | } else if (CFStringCompare(var, CFStringRef(QAXPreviousContentsAttribute), 0) == kCFCompareEqualTo) {
|
---|
2045 | return handleSplitterContentsAttribute(next_ref, event, interface, CFStringRef(QAXPreviousContentsAttribute));
|
---|
2046 | } else if (CFStringCompare(var, CFStringRef(QAXNextContentsAttribute), 0) == kCFCompareEqualTo) {
|
---|
2047 | return handleSplitterContentsAttribute(next_ref, event, interface, CFStringRef(QAXNextContentsAttribute));
|
---|
2048 | } else if (CFStringCompare(var, CFStringRef(QAXSplittersAttribute), 0) == kCFCompareEqualTo) {
|
---|
2049 | return handleSplittersAttribute(next_ref, event, interface);
|
---|
2050 | } else if (CFStringCompare(var, CFStringRef(QAXHorizontalScrollBarAttribute), 0) == kCFCompareEqualTo) {
|
---|
2051 | return handleScrollBarAttribute(next_ref, event, interface, Qt::Horizontal);
|
---|
2052 | } else if (CFStringCompare(var, CFStringRef(QAXVerticalScrollBarAttribute), 0) == kCFCompareEqualTo) {
|
---|
2053 | return handleScrollBarAttribute(next_ref, event, interface, Qt::Vertical);
|
---|
2054 | } else if (CFStringCompare(var, CFStringRef(QAXContentsAttribute), 0) == kCFCompareEqualTo) {
|
---|
2055 | return handleContentsAttribute(next_ref, event, interface);
|
---|
2056 | } else if (CFStringCompare(var, CFStringRef(QAXRowsAttribute), 0) == kCFCompareEqualTo) {
|
---|
2057 | return handleRowsAttribute(next_ref, event, interface);
|
---|
2058 | } else if (CFStringCompare(var, CFStringRef(QAXVisibleRowsAttribute), 0) == kCFCompareEqualTo) {
|
---|
2059 | return handleVisibleRowsAttribute(next_ref, event, interface);
|
---|
2060 | } else if (CFStringCompare(var, CFStringRef(QAXSelectedRowsAttribute), 0) == kCFCompareEqualTo) {
|
---|
2061 | return handleSelectedRowsAttribute(next_ref, event, interface);
|
---|
2062 | } else {
|
---|
2063 | return CallNextEventHandler(next_ref, event);
|
---|
2064 | }
|
---|
2065 | return noErr;
|
---|
2066 | }
|
---|
2067 |
|
---|
2068 | static OSStatus isNamedAttributeSettable(EventRef event, const QAInterface &interface)
|
---|
2069 | {
|
---|
2070 | CFStringRef var;
|
---|
2071 | GetEventParameter(event, kEventParamAccessibleAttributeName, typeCFStringRef, 0,
|
---|
2072 | sizeof(var), 0, &var);
|
---|
2073 | Boolean settable = false;
|
---|
2074 | if (CFStringCompare(var, CFStringRef(QAXFocusedAttribute), 0) == kCFCompareEqualTo) {
|
---|
2075 | settable = true;
|
---|
2076 | } else {
|
---|
2077 | for (int r = 0; text_bindings[r][0].qt != -1; r++) {
|
---|
2078 | if(interface.role() == (QAccessible::Role)text_bindings[r][0].qt) {
|
---|
2079 | for (int a = 1; text_bindings[r][a].qt != -1; a++) {
|
---|
2080 | if (CFStringCompare(var, CFStringRef(text_bindings[r][a].mac), 0) == kCFCompareEqualTo) {
|
---|
2081 | settable = text_bindings[r][a].settable;
|
---|
2082 | break;
|
---|
2083 | }
|
---|
2084 | }
|
---|
2085 | }
|
---|
2086 | }
|
---|
2087 | }
|
---|
2088 | SetEventParameter(event, kEventParamAccessibleAttributeSettable, typeBoolean,
|
---|
2089 | sizeof(settable), &settable);
|
---|
2090 | return noErr;
|
---|
2091 | }
|
---|
2092 |
|
---|
2093 | static OSStatus getChildAtPoint(EventHandlerCallRef next_ref, EventRef event, QAInterface &interface)
|
---|
2094 | {
|
---|
2095 | Q_UNUSED(next_ref);
|
---|
2096 | if (interface.isValid() == false)
|
---|
2097 | return eventNotHandledErr;
|
---|
2098 |
|
---|
2099 | // Add the children for this interface to the global QAccessibelHierachyManager.
|
---|
2100 | accessibleHierarchyManager()->registerChildren(interface);
|
---|
2101 |
|
---|
2102 | Point where;
|
---|
2103 | GetEventParameter(event, kEventParamMouseLocation, typeQDPoint, 0, sizeof(where), 0, &where);
|
---|
2104 | const QAInterface childInterface = interface.childAt(where.h, where.v);
|
---|
2105 |
|
---|
2106 | if (childInterface.isValid() == false || childInterface == interface)
|
---|
2107 | return eventNotHandledErr;
|
---|
2108 |
|
---|
2109 | const QAElement element = accessibleHierarchyManager()->lookup(childInterface);
|
---|
2110 | if (element.isValid() == false)
|
---|
2111 | return eventNotHandledErr;
|
---|
2112 |
|
---|
2113 | AXUIElementRef elementRef = element.element();
|
---|
2114 | CFRetain(elementRef);
|
---|
2115 | SetEventParameter(event, kEventParamAccessibleChild, typeCFTypeRef,
|
---|
2116 | sizeof(elementRef), &elementRef);
|
---|
2117 |
|
---|
2118 | return noErr;
|
---|
2119 | }
|
---|
2120 |
|
---|
2121 | /*
|
---|
2122 | Returns a list of actions the given interface supports.
|
---|
2123 | Currently implemented by getting the interface role and deciding based on that.
|
---|
2124 | */
|
---|
2125 | static QList<QAccessible::Action> supportedPredefinedActions(const QAInterface &interface)
|
---|
2126 | {
|
---|
2127 | QList<QAccessible::Action> actions;
|
---|
2128 | switch (interface.role()) {
|
---|
2129 | default:
|
---|
2130 | // Most things can be pressed.
|
---|
2131 | actions.append(QAccessible::Press);
|
---|
2132 | break;
|
---|
2133 | }
|
---|
2134 |
|
---|
2135 | return actions;
|
---|
2136 | }
|
---|
2137 |
|
---|
2138 | /*
|
---|
2139 | Translates a predefined QAccessible::Action to a Mac action constant.
|
---|
2140 | Returns an empty string if the Qt Action has no mac equivalent.
|
---|
2141 | */
|
---|
2142 | static QCFString translateAction(const QAccessible::Action action)
|
---|
2143 | {
|
---|
2144 | switch (action) {
|
---|
2145 | case QAccessible::Press:
|
---|
2146 | return CFStringRef(QAXPressAction);
|
---|
2147 | break;
|
---|
2148 | case QAccessible::Increase:
|
---|
2149 | return CFStringRef(QAXIncrementAction);
|
---|
2150 | break;
|
---|
2151 | case QAccessible::Decrease:
|
---|
2152 | return CFStringRef(QAXDecrementAction);
|
---|
2153 | break;
|
---|
2154 | case QAccessible::Accept:
|
---|
2155 | return CFStringRef(QAXConfirmAction);
|
---|
2156 | break;
|
---|
2157 | case QAccessible::Select:
|
---|
2158 | return CFStringRef(QAXPickAction);
|
---|
2159 | break;
|
---|
2160 | case QAccessible::Cancel:
|
---|
2161 | return CFStringRef(QAXCancelAction);
|
---|
2162 | break;
|
---|
2163 | default:
|
---|
2164 | return QCFString();
|
---|
2165 | break;
|
---|
2166 | }
|
---|
2167 | }
|
---|
2168 |
|
---|
2169 | /*
|
---|
2170 | Translates between a Mac action constant and a QAccessible::Action.
|
---|
2171 | Returns QAccessible::Default action if there is no Qt predefined equivalent.
|
---|
2172 | */
|
---|
2173 | static QAccessible::Action translateAction(const CFStringRef actionName)
|
---|
2174 | {
|
---|
2175 | if(CFStringCompare(actionName, CFStringRef(QAXPressAction), 0) == kCFCompareEqualTo) {
|
---|
2176 | return QAccessible::Press;
|
---|
2177 | } else if(CFStringCompare(actionName, CFStringRef(QAXIncrementAction), 0) == kCFCompareEqualTo) {
|
---|
2178 | return QAccessible::Increase;
|
---|
2179 | } else if(CFStringCompare(actionName, CFStringRef(QAXDecrementAction), 0) == kCFCompareEqualTo) {
|
---|
2180 | return QAccessible::Decrease;
|
---|
2181 | } else if(CFStringCompare(actionName, CFStringRef(QAXConfirmAction), 0) == kCFCompareEqualTo) {
|
---|
2182 | return QAccessible::Accept;
|
---|
2183 | } else if(CFStringCompare(actionName, CFStringRef(QAXPickAction), 0) == kCFCompareEqualTo) {
|
---|
2184 | return QAccessible::Select;
|
---|
2185 | } else if(CFStringCompare(actionName, CFStringRef(QAXCancelAction), 0) == kCFCompareEqualTo) {
|
---|
2186 | return QAccessible::Cancel;
|
---|
2187 | } else {
|
---|
2188 | return QAccessible::DefaultAction;
|
---|
2189 | }
|
---|
2190 | }
|
---|
2191 | #endif // QT_MAC_USE_COCOA
|
---|
2192 |
|
---|
2193 | /*
|
---|
2194 | Copies the translated names all supported actions for an interface into the kEventParamAccessibleActionNames
|
---|
2195 | event parameter.
|
---|
2196 | */
|
---|
2197 | #ifndef QT_MAC_USE_COCOA
|
---|
2198 | static OSStatus getAllActionNames(EventHandlerCallRef next_ref, EventRef event, const QAInterface &interface)
|
---|
2199 | {
|
---|
2200 | Q_UNUSED(next_ref);
|
---|
2201 |
|
---|
2202 | CFMutableArrayRef actions = 0;
|
---|
2203 | GetEventParameter(event, kEventParamAccessibleActionNames, typeCFMutableArrayRef, 0,
|
---|
2204 | sizeof(actions), 0, &actions);
|
---|
2205 |
|
---|
2206 | // Add supported predefined actions.
|
---|
2207 | const QList<QAccessible::Action> predefinedActions = supportedPredefinedActions(interface);
|
---|
2208 | for (int i = 0; i < predefinedActions.count(); ++i) {
|
---|
2209 | const QCFString action = translateAction(predefinedActions.at(i));
|
---|
2210 | if (action != QCFString())
|
---|
2211 | qt_mac_append_cf_uniq(actions, action);
|
---|
2212 | }
|
---|
2213 |
|
---|
2214 | // Add user actions
|
---|
2215 | const int actionCount = interface.userActionCount();
|
---|
2216 | for (int i = 0; i < actionCount; ++i) {
|
---|
2217 | const QString actionName = interface.actionText(i, QAccessible::Name);
|
---|
2218 | qt_mac_append_cf_uniq(actions, QCFString::toCFStringRef(actionName));
|
---|
2219 | }
|
---|
2220 |
|
---|
2221 | return noErr;
|
---|
2222 | }
|
---|
2223 | #endif
|
---|
2224 |
|
---|
2225 | /*
|
---|
2226 | Handles the perforNamedAction event.
|
---|
2227 | */
|
---|
2228 | #ifndef QT_MAC_USE_COCOA
|
---|
2229 | static OSStatus performNamedAction(EventHandlerCallRef next_ref, EventRef event, const QAInterface& interface)
|
---|
2230 | {
|
---|
2231 | Q_UNUSED(next_ref);
|
---|
2232 |
|
---|
2233 | CFStringRef act;
|
---|
2234 | GetEventParameter(event, kEventParamAccessibleActionName, typeCFStringRef, 0,
|
---|
2235 | sizeof(act), 0, &act);
|
---|
2236 |
|
---|
2237 | const QAccessible::Action action = translateAction(act);
|
---|
2238 |
|
---|
2239 | // Perform built-in action
|
---|
2240 | if (action != QAccessible::DefaultAction) {
|
---|
2241 | interface.doAction(action, QVariantList());
|
---|
2242 | return noErr;
|
---|
2243 | }
|
---|
2244 |
|
---|
2245 | // Search for user-defined actions and perform it if found.
|
---|
2246 | const int actCount = interface.userActionCount();
|
---|
2247 | const QString qAct = QCFString::toQString(act);
|
---|
2248 | for(int i = 0; i < actCount; i++) {
|
---|
2249 | if(interface.actionText(i, QAccessible::Name) == qAct) {
|
---|
2250 | interface.doAction(i, QVariantList());
|
---|
2251 | break;
|
---|
2252 | }
|
---|
2253 | }
|
---|
2254 | return noErr;
|
---|
2255 | }
|
---|
2256 |
|
---|
2257 | static OSStatus setNamedAttribute(EventHandlerCallRef next_ref, EventRef event, const QAInterface &interface)
|
---|
2258 | {
|
---|
2259 | Q_UNUSED(next_ref);
|
---|
2260 | Q_UNUSED(event);
|
---|
2261 |
|
---|
2262 | CFStringRef var;
|
---|
2263 | GetEventParameter(event, kEventParamAccessibleAttributeName, typeCFStringRef, 0,
|
---|
2264 | sizeof(var), 0, &var);
|
---|
2265 | if(CFStringCompare(var, CFStringRef(QAXFocusedAttribute), 0) == kCFCompareEqualTo) {
|
---|
2266 | CFTypeRef val;
|
---|
2267 | if(GetEventParameter(event, kEventParamAccessibleAttributeValue, typeCFTypeRef, 0,
|
---|
2268 | sizeof(val), 0, &val) == noErr) {
|
---|
2269 | if(CFGetTypeID(val) == CFBooleanGetTypeID() &&
|
---|
2270 | CFEqual(static_cast<CFBooleanRef>(val), kCFBooleanTrue)) {
|
---|
2271 | interface.doAction(QAccessible::SetFocus);
|
---|
2272 | }
|
---|
2273 | }
|
---|
2274 | } else {
|
---|
2275 | bool found = false;
|
---|
2276 | for(int r = 0; text_bindings[r][0].qt != -1; r++) {
|
---|
2277 | if(interface.role() == (QAccessible::Role)text_bindings[r][0].qt) {
|
---|
2278 | for(int a = 1; text_bindings[r][a].qt != -1; a++) {
|
---|
2279 | if(CFStringCompare(var, CFStringRef(text_bindings[r][a].mac), 0) == kCFCompareEqualTo) {
|
---|
2280 | if(!text_bindings[r][a].settable) {
|
---|
2281 | } else {
|
---|
2282 | CFTypeRef val;
|
---|
2283 | if(GetEventParameter(event, kEventParamAccessibleAttributeValue, typeCFTypeRef, 0,
|
---|
2284 | sizeof(val), 0, &val) == noErr) {
|
---|
2285 | if(CFGetTypeID(val) == CFStringGetTypeID())
|
---|
2286 | interface.setText((QAccessible::Text)text_bindings[r][a].qt,
|
---|
2287 | QCFString::toQString(static_cast<CFStringRef>(val)));
|
---|
2288 |
|
---|
2289 | }
|
---|
2290 | }
|
---|
2291 | found = true;
|
---|
2292 | break;
|
---|
2293 | }
|
---|
2294 | }
|
---|
2295 | break;
|
---|
2296 | }
|
---|
2297 | }
|
---|
2298 | }
|
---|
2299 | return noErr;
|
---|
2300 | }
|
---|
2301 |
|
---|
2302 | /*
|
---|
2303 | This is the main accessibility event handler.
|
---|
2304 | */
|
---|
2305 | static OSStatus accessibilityEventHandler(EventHandlerCallRef next_ref, EventRef event, void *data)
|
---|
2306 | {
|
---|
2307 | Q_UNUSED(data)
|
---|
2308 |
|
---|
2309 | // Return if this event is not a AccessibleGetNamedAttribute event.
|
---|
2310 | const UInt32 eclass = GetEventClass(event);
|
---|
2311 | if (eclass != kEventClassAccessibility)
|
---|
2312 | return eventNotHandledErr;
|
---|
2313 |
|
---|
2314 | // Get the AXUIElementRef and QAInterface pointer
|
---|
2315 | AXUIElementRef element = 0;
|
---|
2316 | GetEventParameter(event, kEventParamAccessibleObject, typeCFTypeRef, 0, sizeof(element), 0, &element);
|
---|
2317 | QAInterface interface = accessibleHierarchyManager()->lookup(element);
|
---|
2318 | if (interface.isValid() == false)
|
---|
2319 | return eventNotHandledErr;
|
---|
2320 |
|
---|
2321 | const UInt32 ekind = GetEventKind(event);
|
---|
2322 | OSStatus status = noErr;
|
---|
2323 | switch (ekind) {
|
---|
2324 | case kEventAccessibleGetAllAttributeNames:
|
---|
2325 | status = getAllAttributeNames(event, interface, next_ref);
|
---|
2326 | break;
|
---|
2327 | case kEventAccessibleGetNamedAttribute:
|
---|
2328 | status = getNamedAttribute(next_ref, event, interface);
|
---|
2329 | break;
|
---|
2330 | case kEventAccessibleIsNamedAttributeSettable:
|
---|
2331 | status = isNamedAttributeSettable(event, interface);
|
---|
2332 | break;
|
---|
2333 | case kEventAccessibleGetChildAtPoint:
|
---|
2334 | status = getChildAtPoint(next_ref, event, interface);
|
---|
2335 | break;
|
---|
2336 | case kEventAccessibleGetAllActionNames:
|
---|
2337 | status = getAllActionNames(next_ref, event, interface);
|
---|
2338 | break;
|
---|
2339 | case kEventAccessibleGetFocusedChild:
|
---|
2340 | status = CallNextEventHandler(next_ref, event);
|
---|
2341 | break;
|
---|
2342 | case kEventAccessibleSetNamedAttribute:
|
---|
2343 | status = setNamedAttribute(next_ref, event, interface);
|
---|
2344 | break;
|
---|
2345 | case kEventAccessiblePerformNamedAction:
|
---|
2346 | status = performNamedAction(next_ref, event, interface);
|
---|
2347 | break;
|
---|
2348 | default:
|
---|
2349 | status = CallNextEventHandler(next_ref, event);
|
---|
2350 | break;
|
---|
2351 | };
|
---|
2352 | return status;
|
---|
2353 | }
|
---|
2354 | #endif
|
---|
2355 |
|
---|
2356 | void QAccessible::initialize()
|
---|
2357 | {
|
---|
2358 | #ifndef QT_MAC_USE_COCOA
|
---|
2359 | registerQtAccessibilityHIObjectSubclass();
|
---|
2360 | installApplicationEventhandler();
|
---|
2361 | #endif
|
---|
2362 | }
|
---|
2363 |
|
---|
2364 | // Sets thre root object for the application
|
---|
2365 | void QAccessible::setRootObject(QObject *object)
|
---|
2366 | {
|
---|
2367 | // Call installed root object handler if we have one
|
---|
2368 | if (rootObjectHandler) {
|
---|
2369 | rootObjectHandler(object);
|
---|
2370 | return;
|
---|
2371 | }
|
---|
2372 |
|
---|
2373 | rootObject = object;
|
---|
2374 | }
|
---|
2375 |
|
---|
2376 | void QAccessible::cleanup()
|
---|
2377 | {
|
---|
2378 | accessibleHierarchyManager()->reset();
|
---|
2379 | #ifndef QT_MAC_USE_COCOA
|
---|
2380 | removeEventhandler(applicationEventHandlerUPP);
|
---|
2381 | removeEventhandler(objectCreateEventHandlerUPP);
|
---|
2382 | removeEventhandler(accessibilityEventHandlerUPP);
|
---|
2383 | #endif
|
---|
2384 | }
|
---|
2385 |
|
---|
2386 | void QAccessible::updateAccessibility(QObject *object, int child, Event reason)
|
---|
2387 | {
|
---|
2388 | // Call installed update handler if we have one.
|
---|
2389 | if (updateHandler) {
|
---|
2390 | updateHandler(object, child, reason);
|
---|
2391 | return;
|
---|
2392 | }
|
---|
2393 |
|
---|
2394 | #ifndef QT_MAC_USE_COCOA
|
---|
2395 | // Return if the mac accessibility is not enabled.
|
---|
2396 | if(!AXAPIEnabled())
|
---|
2397 | return;
|
---|
2398 |
|
---|
2399 | // Work around crash, disable accessiblity for focus frames.
|
---|
2400 | if (qstrcmp(object->metaObject()->className(), "QFocusFrame") == 0)
|
---|
2401 | return;
|
---|
2402 |
|
---|
2403 | // qDebug() << "updateAccessibility" << object << child << hex << reason;
|
---|
2404 |
|
---|
2405 | if (reason == ObjectShow) {
|
---|
2406 | QAInterface interface = QAInterface(QAccessible::queryAccessibleInterface(object), child);
|
---|
2407 | accessibleHierarchyManager()->registerInterface(interface);
|
---|
2408 | }
|
---|
2409 |
|
---|
2410 | const QAElement element = accessibleHierarchyManager()->lookup(object, child);
|
---|
2411 | if (element.isValid() == false)
|
---|
2412 | return;
|
---|
2413 |
|
---|
2414 |
|
---|
2415 | CFStringRef notification = 0;
|
---|
2416 | if(object && object->isWidgetType() && reason == ObjectCreated) {
|
---|
2417 | notification = CFStringRef(QAXWindowCreatedNotification);
|
---|
2418 | } else if(reason == ValueChanged) {
|
---|
2419 | notification = CFStringRef(QAXValueChangedNotification);
|
---|
2420 | } else if(reason == MenuStart) {
|
---|
2421 | notification = CFStringRef(QAXMenuOpenedNotification);
|
---|
2422 | } else if(reason == MenuEnd) {
|
---|
2423 | notification = CFStringRef(QAXMenuClosedNotification);
|
---|
2424 | } else if(reason == LocationChanged) {
|
---|
2425 | notification = CFStringRef(QAXWindowMovedNotification);
|
---|
2426 | } else if(reason == ObjectShow || reason == ObjectHide ) {
|
---|
2427 | // When a widget is deleted we get a ObjectHide before the destroyed(QObject *)
|
---|
2428 | // signal is emitted (which makes sense). However, at this point we are in the
|
---|
2429 | // middle of the QWidget destructor which means that we have to be careful when
|
---|
2430 | // using the widget pointer. Since we can't control what the accessibilty interfaces
|
---|
2431 | // does when navigate() is called below we ignore the hide update in this case.
|
---|
2432 | // (the widget will be deleted soon anyway.)
|
---|
2433 | extern QWidgetPrivate * qt_widget_private(QWidget *);
|
---|
2434 | if (QWidget *widget = qobject_cast<QWidget*>(object)) {
|
---|
2435 | if (qt_widget_private(widget)->data.in_destructor)
|
---|
2436 | return;
|
---|
2437 |
|
---|
2438 | // Check widget parent as well, special case for preventing crash
|
---|
2439 | // when the viewport() of an abstract scroll area is hidden when
|
---|
2440 | // the QWidget destructor hides all its children.
|
---|
2441 | QWidget *parentWidget = widget->parentWidget();
|
---|
2442 | if (parentWidget && qt_widget_private(parentWidget)->data.in_destructor)
|
---|
2443 | return;
|
---|
2444 | }
|
---|
2445 |
|
---|
2446 | // There is no equivalent Mac notification for ObjectShow/Hide, so we call HIObjectSetAccessibilityIgnored
|
---|
2447 | // and isItIntersting which will mark the HIObject accociated with the element as ignored if the
|
---|
2448 | // QAccessible::Invisible state bit is set.
|
---|
2449 | QAInterface interface = accessibleHierarchyManager()->lookup(element);
|
---|
2450 | if (interface.isValid()) {
|
---|
2451 | HIObjectSetAccessibilityIgnored(element.object(), !isItInteresting(interface));
|
---|
2452 | }
|
---|
2453 |
|
---|
2454 | // If the interface manages its own children, also check if we should ignore those.
|
---|
2455 | if (isItemView(interface) == false && managesChildren(interface)) {
|
---|
2456 | for (int i = 1; i <= interface.childCount(); ++i) {
|
---|
2457 | QAInterface childInterface = interface.navigate(QAccessible::Child, i);
|
---|
2458 | if (childInterface.isValid() && childInterface.isHIView() == false) {
|
---|
2459 | const QAElement element = accessibleHierarchyManager()->lookup(childInterface);
|
---|
2460 | if (element.isValid()) {
|
---|
2461 | HIObjectSetAccessibilityIgnored(element.object(), !isItInteresting(childInterface));
|
---|
2462 | }
|
---|
2463 | }
|
---|
2464 | }
|
---|
2465 | }
|
---|
2466 |
|
---|
2467 | } else if(reason == Focus) {
|
---|
2468 | if(object && object->isWidgetType()) {
|
---|
2469 | QWidget *w = static_cast<QWidget*>(object);
|
---|
2470 | if(w->isWindow())
|
---|
2471 | notification = CFStringRef(QAXFocusedWindowChangedNotification);
|
---|
2472 | else
|
---|
2473 | notification = CFStringRef(QAXFocusedUIElementChangedNotification);
|
---|
2474 | }
|
---|
2475 | }
|
---|
2476 |
|
---|
2477 | if (!notification)
|
---|
2478 | return;
|
---|
2479 |
|
---|
2480 | AXNotificationHIObjectNotify(notification, element.object(), element.id());
|
---|
2481 | #endif
|
---|
2482 | }
|
---|
2483 |
|
---|
2484 | QT_END_NAMESPACE
|
---|
2485 |
|
---|
2486 | #endif // QT_NO_ACCESSIBILITY
|
---|