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