summaryrefslogtreecommitdiffstats
path: root/src/widgets/accessible
diff options
context:
space:
mode:
Diffstat (limited to 'src/widgets/accessible')
-rw-r--r--src/widgets/accessible/accessible.pri25
-rw-r--r--src/widgets/accessible/qaccessible.cpp1094
-rw-r--r--src/widgets/accessible/qaccessible.h461
-rw-r--r--src/widgets/accessible/qaccessible2.cpp205
-rw-r--r--src/widgets/accessible/qaccessible2.h246
-rw-r--r--src/widgets/accessible/qaccessible_mac.mm2469
-rw-r--r--src/widgets/accessible/qaccessible_mac_carbon.cpp119
-rw-r--r--src/widgets/accessible/qaccessible_mac_cocoa.mm239
-rw-r--r--src/widgets/accessible/qaccessible_mac_p.h479
-rw-r--r--src/widgets/accessible/qaccessible_unix.cpp134
-rw-r--r--src/widgets/accessible/qaccessible_win.cpp1439
-rw-r--r--src/widgets/accessible/qaccessiblebridge.cpp158
-rw-r--r--src/widgets/accessible/qaccessiblebridge.h92
-rw-r--r--src/widgets/accessible/qaccessibleobject.cpp408
-rw-r--r--src/widgets/accessible/qaccessibleobject.h140
-rw-r--r--src/widgets/accessible/qaccessibleplugin.cpp107
-rw-r--r--src/widgets/accessible/qaccessibleplugin.h87
-rw-r--r--src/widgets/accessible/qaccessiblewidget.cpp1031
-rw-r--r--src/widgets/accessible/qaccessiblewidget.h141
19 files changed, 9074 insertions, 0 deletions
diff --git a/src/widgets/accessible/accessible.pri b/src/widgets/accessible/accessible.pri
new file mode 100644
index 0000000000..66a84bcce6
--- /dev/null
+++ b/src/widgets/accessible/accessible.pri
@@ -0,0 +1,25 @@
+# Qt accessibility module
+
+contains(QT_CONFIG, accessibility) {
+ HEADERS += accessible/qaccessible.h \
+ accessible/qaccessible2.h \
+ accessible/qaccessibleobject.h \
+ accessible/qaccessiblewidget.h \
+ accessible/qaccessibleplugin.h
+ SOURCES += accessible/qaccessible.cpp \
+ accessible/qaccessible2.cpp \
+ accessible/qaccessibleobject.cpp \
+ accessible/qaccessiblewidget.cpp \
+ accessible/qaccessibleplugin.cpp
+
+ mac:!qpa {
+ HEADERS += accessible/qaccessible_mac_p.h
+ OBJECTIVE_SOURCES += accessible/qaccessible_mac.mm \
+ accessible/qaccessible_mac_cocoa.mm
+ } else:win32 {
+ SOURCES += accessible/qaccessible_win.cpp
+ } else {
+ HEADERS += accessible/qaccessiblebridge.h
+ SOURCES += accessible/qaccessible_unix.cpp accessible/qaccessiblebridge.cpp
+ }
+}
diff --git a/src/widgets/accessible/qaccessible.cpp b/src/widgets/accessible/qaccessible.cpp
new file mode 100644
index 0000000000..abe68f8108
--- /dev/null
+++ b/src/widgets/accessible/qaccessible.cpp
@@ -0,0 +1,1094 @@
+/****************************************************************************
+**
+** Copyright (C) 2011 Nokia Corporation and/or its subsidiary(-ies).
+** All rights reserved.
+** Contact: Nokia Corporation (qt-info@nokia.com)
+**
+** This file is part of the QtGui module of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL$
+** No Commercial Usage
+** This file contains pre-release code and may not be distributed.
+** You may use this file in accordance with the terms and conditions
+** contained in the Technology Preview License Agreement accompanying
+** this package.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 2.1 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPL included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU Lesser General Public License version 2.1 requirements
+** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
+**
+** In addition, as a special exception, Nokia gives you certain additional
+** rights. These rights are described in the Nokia Qt LGPL Exception
+** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
+**
+** If you have questions regarding the use of this file, please contact
+** Nokia at qt-info@nokia.com.
+**
+**
+**
+**
+**
+**
+**
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#include "qaccessible.h"
+
+#ifndef QT_NO_ACCESSIBILITY
+
+#include "qaccessibleplugin.h"
+#include "qaccessiblewidget.h"
+#include "qapplication.h"
+#include "qhash.h"
+#include "qmetaobject.h"
+#include "qmutex.h"
+#include <private/qfactoryloader_p.h>
+
+#include "qwidget.h"
+
+QT_BEGIN_NAMESPACE
+
+/*!
+ \class QAccessible
+ \brief The QAccessible class provides enums and static functions
+ relating to accessibility.
+
+ \ingroup accessibility
+
+
+ Accessible applications can be used by people who are not able to
+ use applications by conventional means.
+
+ The functions in this class are used for communication between
+ accessible applications (also called AT Servers) and
+ accessibility tools (AT Clients), such as screen readers and
+ braille displays. Clients and servers communicate in the following way:
+
+ \list
+ \o \e{AT Servers} notify the clients about events through calls to the
+ updateAccessibility() function.
+
+ \o \e{AT Clients} request information about the objects in the server.
+ The QAccessibleInterface class is the core interface, and encapsulates
+ this information in a pure virtual API. Implementations of the interface
+ are provided by Qt through the queryAccessibleInterface() API.
+ \endlist
+
+ The communication between servers and clients is initialized by
+ the setRootObject() function. Function pointers can be installed
+ to replace or extend the default behavior of the static functions
+ in QAccessible.
+
+ Qt supports Microsoft Active Accessibility (MSAA), Mac OS X
+ Accessibility, and the Unix/X11 AT-SPI standard. Other backends
+ can be supported using QAccessibleBridge.
+
+ In addition to QAccessible's static functions, Qt offers one
+ generic interface, QAccessibleInterface, that can be used to wrap
+ all widgets and objects (e.g., QPushButton). This single
+ interface provides all the metadata necessary for the assistive
+ technologies. Qt provides implementations of this interface for
+ its built-in widgets as plugins.
+
+ When you develop custom widgets, you can create custom subclasses
+ of QAccessibleInterface and distribute them as plugins (using
+ QAccessiblePlugin) or compile them into the application.
+ Likewise, Qt's predefined accessibility support can be built as
+ plugin (the default) or directly into the Qt library. The main
+ advantage of using plugins is that the accessibility classes are
+ only loaded into memory if they are actually used; they don't
+ slow down the common case where no assistive technology is being
+ used.
+
+ Qt also includes two convenience classes, QAccessibleObject and
+ QAccessibleWidget, that inherit from QAccessibleInterface and
+ provide the lowest common denominator of metadata (e.g., widget
+ geometry, window title, basic help text). You can use them as
+ base classes when wrapping your custom QObject or QWidget
+ subclasses.
+
+ \sa QAccessibleInterface
+*/
+
+/*!
+ \enum QAccessible::Action
+
+ This enum describes the possible types of action that can occur.
+
+ \value DefaultAction
+ \value Press
+ \value SetFocus
+ \value Increase
+ \value Decrease
+ \value Accept
+ \value Cancel
+ \value Select
+ \value ClearSelection
+ \value RemoveSelection
+ \value ExtendSelection
+ \value AddToSelection
+
+ \value FirstStandardAction
+ \value LastStandardAction
+*/
+
+/*!
+ \enum QAccessible::Method
+
+ This enum describes the possible types of methods that can be
+ invoked on an accessible object.
+
+ \value ListSupportedMethods
+ \value SetCursorPosition
+ \value GetCursorPosition
+
+ \omitvalue ForegroundColor
+ \omitvalue BackgroundColor
+
+ \sa QAccessibleInterface::invokeMethod()
+*/
+
+/*!
+ \fn QSet<Method> QAccessibleInterface::supportedMethods()
+ \since 4.3
+
+ Returns a QSet of \l{QAccessible::}{Method}s that are supported by this
+ accessible interface.
+
+ \sa QAccessible::Method invokeMethod()
+*/
+
+/*!
+ \enum QAccessible::StateFlag
+
+ This enum type defines bit flags that can be combined to indicate
+ the state of an accessible object. The values are:
+
+ \value Animated The object's appearance changes frequently.
+ \value Busy The object cannot accept input at the moment.
+ \value Checked The object's check box is checked.
+ \value Collapsed The object is collapsed, e.g. a closed listview item, or an iconified window.
+ \value DefaultButton The object represents the default button in a dialog.
+ \value Expanded The object is expandable, and currently the children are visible.
+ \value ExtSelectable The object supports extended selection.
+ \value Focusable The object can receive focus. Only objects in the active window can receive focus.
+ \value Focused The object has keyboard focus.
+ \value HasPopup The object opens a popup.
+ \value HotTracked The object's appearance is sensitive to the mouse cursor position.
+ \value Invisible The object is not visible to the user.
+ \value Linked The object is linked to another object, e.g. a hyperlink.
+ \value Marqueed The object displays scrolling contents, e.g. a log view.
+ \value Mixed The state of the object is not determined, e.g. a tri-state check box that is neither checked nor unchecked.
+ \value Modal The object blocks input from other objects.
+ \value Movable The object can be moved.
+ \value MultiSelectable The object supports multiple selected items.
+ \value Normal The normal state.
+ \value Offscreen The object is clipped by the visible area. Objects that are off screen are also invisible.
+ \value Pressed The object is pressed.
+ \value Protected The object is password protected, e.g. a line edit for entering a Password.
+ \value ReadOnly The object can usually be edited, but is explicitly set to read-only.
+ \value Selectable The object is selectable.
+ \value Selected The object is selected.
+ \value SelfVoicing The object describes itself through speech or sound.
+ \value Sizeable The object can be resized, e.g. top-level windows.
+ \value Traversed The object is linked and has been visited.
+ \value Unavailable The object is unavailable to the user, e.g. a disabled widget.
+ \omitvalue Moveable
+ \omitvalue HasInvokeExtension
+
+ Implementations of QAccessibleInterface::state() return a combination
+ of these flags.
+*/
+
+/*!
+ \enum QAccessible::Event
+
+ This enum type defines accessible event types.
+
+ \value AcceleratorChanged
+ \value Alert A system alert (e.g., a message from a QMessageBox)
+ \value ContextHelpEnd Context help (QWhatsThis) for an object is finished.
+ \value ContextHelpStart Context help (QWhatsThis) for an object is initiated.
+ \value DefaultActionChanged The default QAccessible::Action for the accessible object changed
+ \value DescriptionChanged The objects QAccessible::Description changed.
+ \value DialogEnd A dialog (QDialog) is been hidden
+ \value DialogStart A dialog (QDialog) has been set visible.
+ \value DragDropEnd A Drag & Drop operation is about to finished.
+ \value DragDropStart A Drag & Drop operation is about to be initiated.
+ \value Focus An object has gained keyboard focus.
+ \value ForegroundChanged A window has been activated (i.e., a new window has gained focus on the desktop)
+ \value HelpChanged The QAccessible::Help text property of an object has changed
+ \value LocationChanged An objects location on the screen changed
+ \value MenuCommand A menu item is triggered.
+ \value MenuEnd A menu has been closed (Qt uses PopupMenuEnd for all menus)
+ \value MenuStart A menu has been opened on the menubar (Qt uses PopupMenuStart for all menus)
+ \value NameChanged The QAccessible::Name property of an object has changed
+ \value ObjectCreated A new object is created.
+ \value ObjectDestroyed An object is deleted.
+ \value ObjectHide An object is hidden (i.e., with QWidget::hide()). Any children the object that is hidden has do not send this event.
+ It is not send when an object is hidden as it is being obcured by others.
+ \value ObjectReorder A layout or item view has added, removed, or moved an object (Qt does not use this event).
+ \value ObjectShow An object is displayed (i.e., with QWidget::show()).
+ \value ParentChanged An objects parent object changed.
+ \value PopupMenuEnd A popup menu has closed.
+ \value PopupMenuStart A popupmenu has opened.
+ \value ScrollingEnd A scrollbar scroll operation has ended (the mouse has released the slider handle)
+ \value ScrollingStart A scrollbar scroll operation is about to start (i.e., the mouse has pressed on the slider handle)
+ \value Selection The selection has changed in a menu or item view.
+ \value SelectionAdd An item has been added to the selection in an item view.
+ \value SelectionRemove An item has been removed from an item view selection.
+ \value SelectionWithin Several changes to a selection has occurred in an item view.
+ \value SoundPlayed A sound has been played by an object
+ \value StateChanged The QAccessible::State of an object has changed.
+ \value ValueChanged The QAccessible::Value of an object has changed.
+*/
+
+/*!
+ \enum QAccessible::Role
+
+ This enum defines the role of an accessible object. The roles are:
+
+ \value AlertMessage An object that is used to alert the user.
+ \value Animation An object that displays an animation.
+ \value Application The application's main window.
+ \value Assistant An object that provids interactive help.
+ \value Border An object that represents a border.
+ \value ButtonDropDown A button that drops down a list of items.
+ \value ButtonDropGrid A button that drops down a grid.
+ \value ButtonMenu A button that drops down a menu.
+ \value Canvas An object that displays graphics that the user can interact with.
+ \value Caret An object that represents the system caret (text cursor).
+ \value Cell A cell in a table.
+ \value Chart An object that displays a graphical representation of data.
+ \value CheckBox An object that represents an option that can be checked or unchecked. Some options provide a "mixed" state, e.g. neither checked nor unchecked.
+ \value Client The client area in a window.
+ \value Clock A clock displaying time.
+ \value Column A column of cells, usually within a table.
+ \value ColumnHeader A header for a column of data.
+ \value ComboBox A list of choices that the user can select from.
+ \value Cursor An object that represents the mouse cursor.
+ \value Dial An object that represents a dial or knob.
+ \value Dialog A dialog box.
+ \value Document A document window, usually in an MDI environment.
+ \value EditableText Editable text
+ \value Equation An object that represents a mathematical equation.
+ \value Graphic A graphic or picture, e.g. an icon.
+ \value Grip A grip that the user can drag to change the size of widgets.
+ \value Grouping An object that represents a logical grouping of other objects.
+ \value HelpBalloon An object that displays help in a separate, short lived window.
+ \value HotkeyField A hotkey field that allows the user to enter a key sequence.
+ \value Indicator An indicator that represents a current value or item.
+ \value LayeredPane An object that can contain layered children, e.g. in a stack.
+ \value Link A link to something else.
+ \value List A list of items, from which the user can select one or more items.
+ \value ListItem An item in a list of items.
+ \value MenuBar A menu bar from which menus are opened by the user.
+ \value MenuItem An item in a menu or menu bar.
+ \value NoRole The object has no role. This usually indicates an invalid object.
+ \value PageTab A page tab that the user can select to switch to a different page in a dialog.
+ \value PageTabList A list of page tabs.
+ \value Pane A generic container.
+ \value PopupMenu A menu which lists options that the user can select to perform an action.
+ \value ProgressBar The object displays the progress of an operation in progress.
+ \value PropertyPage A property page where the user can change options and settings.
+ \value PushButton A button.
+ \value RadioButton An object that represents an option that is mutually exclusive with other options.
+ \value Row A row of cells, usually within a table.
+ \value RowHeader A header for a row of data.
+ \value ScrollBar A scroll bar, which allows the user to scroll the visible area.
+ \value Separator A separator that divides space into logical areas.
+ \value Slider A slider that allows the user to select a value within a given range.
+ \value Sound An object that represents a sound.
+ \value SpinBox A spin box widget that allows the user to enter a value within a given range.
+ \value Splitter A splitter distributing available space between its child widgets.
+ \value StaticText Static text, such as labels for other widgets.
+ \value StatusBar A status bar.
+ \value Table A table representing data in a grid of rows and columns.
+ \value TitleBar The title bar caption of a window.
+ \value ToolBar A tool bar, which groups widgets that the user accesses frequently.
+ \value ToolTip A tool tip which provides information about other objects.
+ \value Tree A list of items in a tree structure.
+ \value TreeItem An item in a tree structure.
+ \value UserRole The first value to be used for user defined roles.
+ \value Whitespace Blank space between other objects.
+ \value Window A top level window.
+*/
+
+/*!
+ \enum QAccessible::RelationFlag
+
+ This enum type defines bit flags that can be combined to indicate
+ the relationship between two accessible objects.
+
+ \value Unrelated The objects are unrelated.
+ \value Self The objects are the same.
+ \value Ancestor The first object is a parent of the second object.
+ \value Child The first object is a direct child of the second object.
+ \value Descendent The first object is an indirect child of the second object.
+ \value Sibling The objects are siblings.
+
+ \value Up The first object is above the second object.
+ \value Down The first object is below the second object.
+ \value Left The first object is left of the second object.
+ \value Right The first object is right of the second object.
+ \value Covers The first object covers the second object.
+ \value Covered The first object is covered by the second object.
+
+ \value FocusChild The first object is the second object's focus child.
+ \value Label The first object is the label of the second object.
+ \value Labelled The first object is labelled by the second object.
+ \value Controller The first object controls the second object.
+ \value Controlled The first object is controlled by the second object.
+
+ \omitvalue HierarchyMask
+ \omitvalue GeometryMask
+ \omitvalue LogicalMask
+
+ Implementations of relationTo() return a combination of these flags.
+ Some values are mutually exclusive.
+
+ Implementations of navigate() can accept only one distinct value.
+*/
+
+/*!
+ \enum QAccessible::Text
+
+ This enum specifies string information that an accessible object
+ returns.
+
+ \value Name The name of the object. This can be used both
+ as an identifier or a short description by
+ accessible clients.
+ \value Description A short text describing the object.
+ \value Value The value of the object.
+ \value Help A longer text giving information about how to use the object.
+ \value Accelerator The keyboard shortcut that executes the object's default action.
+ \value UserText The first value to be used for user defined text.
+*/
+
+/*!
+ \fn QAccessibleInterface::~QAccessibleInterface()
+
+ Destroys the object.
+*/
+
+/*!
+ \fn void QAccessible::initialize()
+ \internal
+*/
+
+/*!
+ \fn void QAccessible::cleanup()
+ \internal
+*/
+
+#ifndef QT_NO_LIBRARY
+Q_GLOBAL_STATIC_WITH_ARGS(QFactoryLoader, loader,
+ (QAccessibleFactoryInterface_iid, QLatin1String("/accessible")))
+#endif
+
+Q_GLOBAL_STATIC(QList<QAccessible::InterfaceFactory>, qAccessibleFactories)
+
+QAccessible::UpdateHandler QAccessible::updateHandler = 0;
+QAccessible::RootObjectHandler QAccessible::rootObjectHandler = 0;
+
+static bool accessibility_active = false;
+static bool cleanupAdded = false;
+static void qAccessibleCleanup()
+{
+ qAccessibleFactories()->clear();
+}
+
+/*!
+ \typedef QAccessible::InterfaceFactory
+
+ This is a typedef for a pointer to a function with the following
+ signature:
+
+ \snippet doc/src/snippets/code/src_gui_accessible_qaccessible.cpp 1
+
+ The function receives a QString and a QObject pointer, where the
+ QString is the key identifying the interface. The QObject is used
+ to pass on to the QAccessibleInterface so that it can hold a reference
+ to it.
+
+ If the key and the QObject does not have a corresponding
+ QAccessibleInterface, a null-pointer will be returned.
+
+ Installed factories are called by queryAccessibilityInterface() until
+ one provides an interface.
+*/
+
+/*!
+ \typedef QAccessible::UpdateHandler
+
+ \internal
+
+ A function pointer type. Use a function with this prototype to install
+ your own update function.
+
+ The function is called by updateAccessibility().
+*/
+
+/*!
+ \typedef QAccessible::RootObjectHandler
+
+ \internal
+
+ A function pointer type. Use a function with this prototype to install
+ your own root object handler.
+
+ The function is called by setRootObject().
+*/
+
+/*!
+ Installs the InterfaceFactory \a factory. The last factory added
+ is the first one used by queryAccessibleInterface().
+*/
+void QAccessible::installFactory(InterfaceFactory factory)
+{
+ if (!factory)
+ return;
+
+ if (!cleanupAdded) {
+ qAddPostRoutine(qAccessibleCleanup);
+ cleanupAdded = true;
+ }
+ if (qAccessibleFactories()->contains(factory))
+ return;
+ qAccessibleFactories()->append(factory);
+}
+
+/*!
+ Removes \a factory from the list of installed InterfaceFactories.
+*/
+void QAccessible::removeFactory(InterfaceFactory factory)
+{
+ qAccessibleFactories()->removeAll(factory);
+}
+
+/*!
+ \internal
+
+ Installs the given \a handler as the function to be used by
+ updateAccessibility(), and returns the previously installed
+ handler.
+*/
+QAccessible::UpdateHandler QAccessible::installUpdateHandler(UpdateHandler handler)
+{
+ UpdateHandler old = updateHandler;
+ updateHandler = handler;
+ return old;
+}
+
+/*!
+ Installs the given \a handler as the function to be used by setRootObject(),
+ and returns the previously installed handler.
+*/
+QAccessible::RootObjectHandler QAccessible::installRootObjectHandler(RootObjectHandler handler)
+{
+ RootObjectHandler old = rootObjectHandler;
+ rootObjectHandler = handler;
+ return old;
+}
+
+/*!
+ If a QAccessibleInterface implementation exists for the given \a object,
+ this function returns a pointer to the implementation; otherwise it
+ returns 0.
+
+ The function calls all installed factory functions (from most
+ recently installed to least recently installed) until one is found
+ that provides an interface for the class of \a object. If no
+ factory can provide an accessibility implementation for the class
+ the function loads installed accessibility plugins, and tests if
+ any of the plugins can provide the implementation.
+
+ If no implementation for the object's class is available, the
+ function tries to find an implementation for the object's parent
+ class, using the above strategy.
+
+ \warning The caller is responsible for deleting the returned
+ interface after use.
+*/
+QAccessibleInterface *QAccessible::queryAccessibleInterface(QObject *object)
+{
+ accessibility_active = true;
+ QAccessibleInterface *iface = 0;
+ if (!object)
+ return 0;
+
+ QEvent e(QEvent::AccessibilityPrepare);
+ QApplication::sendEvent(object, &e);
+
+ const QMetaObject *mo = object->metaObject();
+ while (mo) {
+ const QLatin1String cn(mo->className());
+ for (int i = qAccessibleFactories()->count(); i > 0; --i) {
+ InterfaceFactory factory = qAccessibleFactories()->at(i - 1);
+ iface = factory(cn, object);
+ if (iface)
+ return iface;
+ }
+#ifndef QT_NO_LIBRARY
+ QAccessibleFactoryInterface *factory = qobject_cast<QAccessibleFactoryInterface*>(loader()->instance(cn));
+ if (factory) {
+ iface = factory->create(cn, object);
+ if (iface)
+ return iface;
+ }
+#endif
+ mo = mo->superClass();
+ }
+
+ QWidget *widget = qobject_cast<QWidget*>(object);
+ if (widget)
+ return new QAccessibleWidget(widget);
+ else if (object == qApp)
+ return new QAccessibleApplication();
+
+ return 0;
+}
+
+/*!
+ Returns true if an accessibility implementation has been requested
+ during the runtime of the application; otherwise returns false.
+
+ Use this function to prevent potentially expensive notifications via
+ updateAccessibility().
+*/
+bool QAccessible::isActive()
+{
+ return accessibility_active;
+}
+
+/*!
+ \fn void QAccessible::setRootObject(QObject *object)
+
+ Sets the root accessible object of this application to \a object.
+ All other accessible objects in the application can be reached by the
+ client using object navigation.
+
+ You should never need to call this function. Qt sets the QApplication
+ object as the root object immediately before the event loop is entered
+ in QApplication::exec().
+
+ Use QAccessible::installRootObjectHandler() to redirect the function
+ call to a customized handler function.
+
+ \sa queryAccessibleInterface()
+*/
+
+/*!
+ \fn void QAccessible::updateAccessibility(QObject *object, int child, Event reason)
+
+ Notifies accessibility clients about a change in \a object's
+ accessibility information.
+
+ \a reason specifies the cause of the change, for example,
+ \c ValueChange when the position of a slider has been changed. \a
+ child is the (1-based) index of the child element that has changed.
+ When \a child is 0, the object itself has changed.
+
+ Call this function whenever the state of your accessible object or
+ one of its sub-elements has been changed either programmatically
+ (e.g. by calling QLabel::setText()) or by user interaction.
+
+ If there are no accessibility tools listening to this event, the
+ performance penalty for calling this function is small, but if determining
+ the parameters of the call is expensive you can test isActive() to
+ avoid unnecessary computations.
+*/
+
+
+/*!
+ \class QAccessibleInterface
+ \brief The QAccessibleInterface class defines an interface that exposes information
+ about accessible objects.
+
+ \ingroup accessibility
+
+ Accessibility tools (also called AT Clients), such as screen readers
+ or braille displays, require high-level information about
+ accessible objects in an application. Accessible objects provide
+ specialized input and output methods, making it possible for users
+ to use accessibility tools with enabled applications (AT Servers).
+
+ Every element that the user needs to interact with or react to is
+ an accessible object, and should provide this information. These
+ are mainly visual objects, such as widgets and widget elements, but
+ can also be content, such as sounds.
+
+ The AT client uses three basic concepts to acquire information
+ about any accessible object in an application:
+ \list
+ \i \e Properties The client can read information about
+ accessible objects. In some cases the client can also modify these
+ properties; such as text in a line edit.
+ \i \e Actions The client can invoke actions like pressing a button
+ or .
+ \i \e{Relationships and Navigation} The client can traverse from one
+ accessible object to another, using the relationships between objects.
+ \endlist
+
+ The QAccessibleInterface defines the API for these three concepts.
+
+ \section1 Relationships and Navigation
+
+ The functions childCount() and indexOfChild() return the number of
+ children of an accessible object and the index a child object has
+ in its parent. The childAt() function returns the index of a child
+ at a given position.
+
+ The relationTo() function provides information about how two
+ different objects relate to each other, and navigate() allows
+ traversing from one object to another object with a given
+ relationship.
+
+ \section1 Properties
+
+ The central property of an accessible objects is what role() it
+ has. Different objects can have the same role, e.g. both the "Add
+ line" element in a scroll bar and the \c OK button in a dialog have
+ the same role, "button". The role implies what kind of
+ interaction the user can perform with the user interface element.
+
+ An object's state() property is a combination of different state
+ flags and can describe both how the object's state differs from a
+ "normal" state, e.g. it might be unavailable, and also how it
+ behaves, e.g. it might be selectable.
+
+ The text() property provides textual information about the object.
+ An object usually has a name, but can provide extended information
+ such as a description, help text, or information about any
+ keyboard accelerators it provides. Some objects allow changing the
+ text() property through the setText() function, but this
+ information is in most cases read-only.
+
+ The rect() property provides information about the geometry of an
+ accessible object. This information is usually only available for
+ visual objects.
+
+ \section1 Actions and Selection
+
+ To enable the user to interact with an accessible object the
+ object must expose information about the actions that it can
+ perform. userActionCount() returns the number of actions supported by
+ an accessible object, and actionText() returns textual information
+ about those actions. doAction() invokes an action.
+
+ Objects that support selections can define actions to change the selection.
+
+ \section2 Objects and children
+
+ A QAccessibleInterface provides information about the accessible
+ object, and can also provide information for the children of that
+ object if those children don't provide a QAccessibleInterface
+ implementation themselves. This is practical if the object has
+ many similar children (e.g. items in a list view), or if the
+ children are an integral part of the object itself, for example, the
+ different sections in a scroll bar.
+
+ If an accessible object provides information about its children
+ through one QAccessibleInterface, the children are referenced
+ using indexes. The index is 1-based for the children, i.e. 0
+ refers to the object itself, 1 to the first child, 2 to the second
+ child, and so on.
+
+ All functions in QAccessibleInterface that take a child index
+ relate to the object itself if the index is 0, or to the child
+ specified. If a child provides its own interface implementation
+ (which can be retrieved through navigation) asking the parent for
+ information about that child will usually not succeed.
+
+ \sa QAccessible
+*/
+
+/*!
+ \fn bool QAccessibleInterface::isValid() const
+
+ Returns true if all the data necessary to use this interface
+ implementation is valid (e.g. all pointers are non-null);
+ otherwise returns false.
+
+ \sa object()
+*/
+
+/*!
+ \fn QObject *QAccessibleInterface::object() const
+
+ Returns a pointer to the QObject this interface implementation provides
+ information for.
+
+ \sa isValid()
+*/
+
+/*!
+ \fn int QAccessibleInterface::childCount() const
+
+ Returns the number of children that belong to this object. A child
+ can provide accessibility information on its own (e.g. a child
+ widget), or be a sub-element of this accessible object.
+
+ All objects provide this information.
+
+ \sa indexOfChild()
+*/
+
+/*!
+ \fn int QAccessibleInterface::indexOfChild(const QAccessibleInterface *child) const
+
+ Returns the 1-based index of the object \a child in this object's
+ children list, or -1 if \a child is not a child of this object. 0
+ is not a possible return value.
+
+ All objects provide this information about their children.
+
+ \sa childCount()
+*/
+
+/*!
+ \fn QAccessible::Relation QAccessibleInterface::relationTo(int child,
+const QAccessibleInterface *other, int otherChild) const
+
+ Returns the relationship between this object's \a child and the \a
+ other object's \a otherChild. If \a child is 0 the object's own relation
+ is returned.
+
+ The returned value indicates the relation of the called object to
+ the \a other object, e.g. if this object is a child of \a other
+ the return value will be \c Child.
+
+ The return value is a combination of the bit flags in the
+ QAccessible::Relation enumeration.
+
+ All objects provide this information.
+
+ \sa indexOfChild(), navigate()
+*/
+
+/*!
+ \fn int QAccessibleInterface::childAt(int x, int y) const
+
+ Returns the 1-based index of the child that contains the screen
+ coordinates (\a x, \a y). This function returns 0 if the point is
+ positioned on the object itself. If the tested point is outside
+ the boundaries of the object this function returns -1.
+
+ This function is only relyable for visible objects (invisible
+ object might not be laid out correctly).
+
+ All visual objects provide this information.
+
+ \sa rect()
+*/
+
+/*!
+ \fn int QAccessibleInterface::navigate(RelationFlag relation, int entry, QAccessibleInterface
+**target) const
+
+ Navigates from this object to an object that has a relationship
+ \a relation to this object, and returns the respective object in
+ \a target. It is the caller's responsibility to delete *\a target
+ after use.
+
+ If an object is found, \a target is set to point to the object, and
+ the index of the child of \a target is returned. The return value
+ is 0 if \a target itself is the requested object. \a target is set
+ to null if this object is the target object (i.e. the requested
+ object is a handled by this object).
+
+ If no object is found \a target is set to null, and the return
+ value is -1.
+
+ The \a entry parameter has two different meanings:
+ \list
+ \i \e{Hierarchical and Logical relationships} -- if multiple objects with
+ the requested relationship exist \a entry specifies which one to
+ return. \a entry is 1-based, e.g. use 1 to get the first (and
+ possibly only) object with the requested relationship.
+
+ The following code demonstrates how to use this function to
+ navigate to the first child of an object:
+
+ \snippet doc/src/snippets/code/src_gui_accessible_qaccessible.cpp 0
+
+ \i \e{Geometric relationships} -- the index of the child from
+ which to start navigating in the specified direction. \a entry
+ can be 0 to navigate to a sibling of this object, or non-null to
+ navigate within contained children that don't provide their own
+ accessible information.
+ \endlist
+
+ Note that the \c Descendent value for \a relation is not supported.
+
+ All objects support navigation.
+
+ \sa relationTo(), childCount()
+*/
+
+/*!
+ \fn QString QAccessibleInterface::text(Text t, int child) const
+
+ Returns the value of the text property \a t of the object, or of
+ the object's child if \a child is not 0.
+
+ The \l Name is a string used by clients to identify, find, or
+ announce an accessible object for the user. All objects must have
+ a name that is unique within their container. The name can be
+ used differently by clients, so the name should both give a
+ short description of the object and be unique.
+
+ An accessible object's \l Description provides textual information
+ about an object's visual appearance. The description is primarily
+ used to provide greater context for vision-impaired users, but is
+ also used for context searching or other applications. Not all
+ objects have a description. An "OK" button would not need a
+ description, but a tool button that shows a picture of a smiley
+ would.
+
+ The \l Value of an accessible object represents visual information
+ contained by the object, e.g. the text in a line edit. Usually,
+ the value can be modified by the user. Not all objects have a
+ value, e.g. static text labels don't, and some objects have a
+ state that already is the value, e.g. toggle buttons.
+
+ The \l Help text provides information about the function and
+ usage of an accessible object. Not all objects provide this
+ information.
+
+ The \l Accelerator is a keyboard shortcut that activates the
+ object's default action. A keyboard shortcut is the underlined
+ character in the text of a menu, menu item or widget, and is
+ either the character itself, or a combination of this character
+ and a modifier key like Alt, Ctrl or Shift. Command controls like
+ tool buttons also have shortcut keys and usually display them in
+ their tooltip.
+
+ All objects provide a string for \l Name.
+
+ \sa role(), state()
+*/
+
+/*!
+ \fn void QAccessibleInterface::setText(Text t, int child, const QString &text)
+
+ Sets the text property \a t of the object, or of the object's
+ child if \a child is not 0, to \a text.
+
+ Note that the text properties of most objects are read-only.
+
+ \sa text()
+*/
+
+/*!
+ \fn QRect QAccessibleInterface::rect(int child) const
+
+ Returns the geometry of the object, or of the object's child if \a child
+ is not 0. The geometry is in screen coordinates.
+
+ This function is only reliable for visible objects (invisible
+ objects might not be laid out correctly).
+
+ All visual objects provide this information.
+
+ \sa childAt()
+*/
+
+/*!
+ \fn QAccessible::Role QAccessibleInterface::role(int child) const
+
+ Returns the role of the object, or of the object's child if \a child
+ is not 0. The role of an object is usually static.
+
+ All accessible objects have a role.
+
+ \sa text(), state()
+*/
+
+/*!
+ \fn QAccessible::State QAccessibleInterface::state(int child) const
+
+ Returns the current state of the object, or of the object's child if
+ \a child is not 0. The returned value is a combination of the flags in
+ the QAccessible::StateFlag enumeration.
+
+ All accessible objects have a state.
+
+ \sa text(), role()
+*/
+
+/*!
+ \fn int QAccessibleInterface::userActionCount(int child) const
+
+ Returns the number of custom actions of the object, or of the
+ object's child if \a child is not 0.
+
+ The \c Action type enumerates predefined actions: these
+ are not included in the returned value.
+
+ \sa actionText(), doAction()
+*/
+
+/*!
+ \fn QString QAccessibleInterface::actionText(int action, Text t, int child) const
+
+ Returns the text property \a t of the action \a action supported by
+ the object, or of the object's child if \a child is not 0.
+
+ \sa text(), userActionCount()
+*/
+
+/*!
+ \fn bool QAccessibleInterface::doAction(int action, int child, const QVariantList &params)
+
+ Asks the object, or the object's \a child if \a child is not 0, to
+ execute \a action using the parameters, \a params. Returns true if
+ the action could be executed; otherwise returns false.
+
+ \a action can be a predefined or a custom action.
+
+ \sa userActionCount(), actionText()
+*/
+
+/*!
+ \fn QColor QAccessibleInterface::backgroundColor()
+ \internal
+*/
+
+/*!
+ \fn QAccessibleEditableTextInterface *QAccessibleInterface::editableTextInterface()
+ \internal
+*/
+
+/*!
+ \fn QColor QAccessibleInterface::foregroundColor()
+ \internal
+*/
+
+/*!
+ \fn QAccessibleTextInterface *QAccessibleInterface::textInterface()
+ \internal
+*/
+
+/*!
+ \fn QAccessibleValueInterface *QAccessibleInterface::valueInterface()
+ \internal
+*/
+
+/*!
+ \fn QAccessibleTableInterface *QAccessibleInterface::tableInterface()
+ \internal
+*/
+
+/*!
+ \fn QAccessibleActionInterface *QAccessibleInterface::actionInterface()
+ \internal
+*/
+
+/*!
+ \fn QAccessibleImageInterface *QAccessibleInterface::imageInterface()
+ \internal
+*/
+
+/*!
+ \class QAccessibleEvent
+ \brief The QAccessibleEvent class is used to query addition
+ accessibility information about complex widgets.
+
+ The event can be of type QEvent::AccessibilityDescription or
+ QEvent::AccessibilityHelp.
+
+ Some QAccessibleInterface implementations send QAccessibleEvents
+ to the widget they wrap to obtain the description or help text of
+ a widget or of its children. The widget can answer by calling
+ setValue() with the requested information.
+
+ The default QWidget::event() implementation simply sets the text
+ to be the widget's \l{QWidget::toolTip}{tooltip} (for \l
+ AccessibilityDescription event) or its
+ \l{QWidget::whatsThis}{"What's This?" text} (for \l
+ AccessibilityHelp event).
+
+ \ingroup accessibility
+ \ingroup events
+*/
+
+/*!
+ \fn QAccessibleEvent::QAccessibleEvent(Type type, int child)
+
+ Constructs an accessibility event of the given \a type, which
+ must be QEvent::AccessibilityDescription or
+ QEvent::AccessibilityHelp.
+
+ \a child is the (1-based) index of the child to which the request
+ applies. If \a child is 0, the request is for the widget itself.
+
+ \sa child()
+*/
+
+/*!
+ \fn int QAccessibleEvent::child() const
+
+ Returns the (1-based) index of the child to which the request
+ applies. If the child is 0, the request is for the widget itself.
+*/
+
+/*!
+ \fn QString QAccessibleEvent::value() const
+
+ Returns the text set using setValue().
+
+ \sa setValue()
+*/
+
+/*!
+ \fn void QAccessibleEvent::setValue(const QString &text)
+
+ Set the description or help text for the given child() to \a
+ text, thereby answering the request.
+
+ \sa value()
+*/
+
+/*!
+ \since 4.2
+
+ Invokes a \a method on \a child with the given parameters \a params
+ and returns the result of the operation as QVariant.
+
+ Note that the type of the returned QVariant depends on the action.
+
+ Returns an invalid QVariant if the object doesn't support the action.
+*/
+QVariant QAccessibleInterface::invokeMethod(Method method, int child, const QVariantList &params)
+{
+ if (!(state(0) & HasInvokeExtension))
+ return QVariant();
+
+ return static_cast<QAccessibleInterfaceEx *>(this)->invokeMethodEx(method, child, params);
+}
+
+QVariant QAccessibleInterfaceEx::virtual_hook(const QVariant &)
+{
+ return QVariant();
+}
+
+/*! \internal */
+QAccessible2Interface *QAccessibleInterface::cast_helper(QAccessible2::InterfaceType t)
+{
+ if (state(0) & HasInvokeExtension)
+ return static_cast<QAccessibleInterfaceEx *>(this)->interface_cast(t);
+ return 0;
+}
+
+QT_END_NAMESPACE
+
+#endif
diff --git a/src/widgets/accessible/qaccessible.h b/src/widgets/accessible/qaccessible.h
new file mode 100644
index 0000000000..33e76a7ad2
--- /dev/null
+++ b/src/widgets/accessible/qaccessible.h
@@ -0,0 +1,461 @@
+/****************************************************************************
+**
+** Copyright (C) 2011 Nokia Corporation and/or its subsidiary(-ies).
+** All rights reserved.
+** Contact: Nokia Corporation (qt-info@nokia.com)
+**
+** This file is part of the QtGui module of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL$
+** No Commercial Usage
+** This file contains pre-release code and may not be distributed.
+** You may use this file in accordance with the terms and conditions
+** contained in the Technology Preview License Agreement accompanying
+** this package.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 2.1 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPL included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU Lesser General Public License version 2.1 requirements
+** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
+**
+** In addition, as a special exception, Nokia gives you certain additional
+** rights. These rights are described in the Nokia Qt LGPL Exception
+** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
+**
+** If you have questions regarding the use of this file, please contact
+** Nokia at qt-info@nokia.com.
+**
+**
+**
+**
+**
+**
+**
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#ifndef QACCESSIBLE_H
+#define QACCESSIBLE_H
+
+#include <QtCore/qglobal.h>
+#include <QtCore/qobject.h>
+#include <QtCore/qrect.h>
+#include <QtCore/qset.h>
+#include <QtCore/qvector.h>
+#include <QtCore/qvariant.h>
+#include <QtGui/qcolor.h>
+#include <QtGui/qevent.h>
+
+QT_BEGIN_HEADER
+
+QT_BEGIN_NAMESPACE
+
+QT_MODULE(Gui)
+
+#ifndef QT_NO_ACCESSIBILITY
+
+class QAccessibleInterface;
+
+class Q_GUI_EXPORT QAccessible
+{
+public:
+ enum Event {
+ SoundPlayed = 0x0001,
+ Alert = 0x0002,
+ ForegroundChanged = 0x0003,
+ MenuStart = 0x0004,
+ MenuEnd = 0x0005,
+ PopupMenuStart = 0x0006,
+ PopupMenuEnd = 0x0007,
+ ContextHelpStart = 0x000C,
+ ContextHelpEnd = 0x000D,
+ DragDropStart = 0x000E,
+ DragDropEnd = 0x000F,
+ DialogStart = 0x0010,
+ DialogEnd = 0x0011,
+ ScrollingStart = 0x0012,
+ ScrollingEnd = 0x0013,
+
+ MenuCommand = 0x0018,
+
+ // Values from IAccessible2
+ ActionChanged = 0x0101,
+ ActiveDescendantChanged,
+ AttributeChanged,
+ DocumentContentChanged,
+ DocumentLoadComplete,
+ DocumentLoadStopped,
+ DocumentReload,
+ HyperlinkEndIndexChanged,
+ HyperlinkNumberOfAnchorsChanged,
+ HyperlinkSelectedLinkChanged,
+ HypertextLinkActivated,
+ HypertextLinkSelected,
+ HyperlinkStartIndexChanged,
+ HypertextChanged,
+ HypertextNLinksChanged,
+ ObjectAttributeChanged,
+ PageChanged,
+ SectionChanged,
+ TableCaptionChanged,
+ TableColumnDescriptionChanged,
+ TableColumnHeaderChanged,
+ TableModelChanged,
+ TableRowDescriptionChanged,
+ TableRowHeaderChanged,
+ TableSummaryChanged,
+ TextAttributeChanged,
+ TextCaretMoved,
+ TextChanged,
+ TextColumnChanged,
+ TextInserted,
+ TextRemoved,
+ TextUpdated,
+ TextSelectionChanged,
+ VisibleDataChanged,
+
+ ObjectCreated = 0x8000,
+ ObjectDestroyed = 0x8001,
+ ObjectShow = 0x8002,
+ ObjectHide = 0x8003,
+ ObjectReorder = 0x8004,
+ Focus = 0x8005,
+ Selection = 0x8006,
+ SelectionAdd = 0x8007,
+ SelectionRemove = 0x8008,
+ SelectionWithin = 0x8009,
+ StateChanged = 0x800A,
+ LocationChanged = 0x800B,
+ NameChanged = 0x800C,
+ DescriptionChanged = 0x800D,
+ ValueChanged = 0x800E,
+ ParentChanged = 0x800F,
+ HelpChanged = 0x80A0,
+ DefaultActionChanged = 0x80B0,
+ AcceleratorChanged = 0x80C0
+ };
+
+ enum StateFlag {
+ Normal = 0x00000000,
+ Unavailable = 0x00000001,
+ Selected = 0x00000002,
+ Focused = 0x00000004,
+ Pressed = 0x00000008,
+ Checked = 0x00000010,
+ Mixed = 0x00000020,
+ ReadOnly = 0x00000040,
+ HotTracked = 0x00000080,
+ DefaultButton = 0x00000100,
+ Expanded = 0x00000200,
+ Collapsed = 0x00000400,
+ Busy = 0x00000800,
+ // Floating = 0x00001000,
+ Marqueed = 0x00002000,
+ Animated = 0x00004000,
+ Invisible = 0x00008000,
+ Offscreen = 0x00010000,
+ Sizeable = 0x00020000,
+ Movable = 0x00040000,
+ SelfVoicing = 0x00080000,
+ Focusable = 0x00100000,
+ Selectable = 0x00200000,
+ Linked = 0x00400000,
+ Traversed = 0x00800000,
+ MultiSelectable = 0x01000000,
+ ExtSelectable = 0x02000000,
+ //AlertLow = 0x04000000,
+ //AlertMedium = 0x08000000,
+ //AlertHigh = 0x10000000, /* reused for HasInvokeExtension */
+ Protected = 0x20000000,
+ HasPopup = 0x40000000,
+ Modal = 0x80000000,
+
+ HasInvokeExtension = 0x10000000 // internal
+ };
+ Q_DECLARE_FLAGS(State, StateFlag)
+
+ enum Role {
+ NoRole = 0x00000000,
+ TitleBar = 0x00000001,
+ MenuBar = 0x00000002,
+ ScrollBar = 0x00000003,
+ Grip = 0x00000004,
+ Sound = 0x00000005,
+ Cursor = 0x00000006,
+ Caret = 0x00000007,
+ AlertMessage = 0x00000008,
+ Window = 0x00000009,
+ Client = 0x0000000A,
+ PopupMenu = 0x0000000B,
+ MenuItem = 0x0000000C,
+ ToolTip = 0x0000000D,
+ Application = 0x0000000E,
+ Document = 0x0000000F,
+ Pane = 0x00000010,
+ Chart = 0x00000011,
+ Dialog = 0x00000012,
+ Border = 0x00000013,
+ Grouping = 0x00000014,
+ Separator = 0x00000015,
+ ToolBar = 0x00000016,
+ StatusBar = 0x00000017,
+ Table = 0x00000018,
+ ColumnHeader = 0x00000019,
+ RowHeader = 0x0000001A,
+ Column = 0x0000001B,
+ Row = 0x0000001C,
+ Cell = 0x0000001D,
+ Link = 0x0000001E,
+ HelpBalloon = 0x0000001F,
+ Assistant = 0x00000020,
+ List = 0x00000021,
+ ListItem = 0x00000022,
+ Tree = 0x00000023,
+ TreeItem = 0x00000024,
+ PageTab = 0x00000025,
+ PropertyPage = 0x00000026,
+ Indicator = 0x00000027,
+ Graphic = 0x00000028,
+ StaticText = 0x00000029,
+ EditableText = 0x0000002A, // Editable, selectable, etc.
+ PushButton = 0x0000002B,
+ CheckBox = 0x0000002C,
+ RadioButton = 0x0000002D,
+ ComboBox = 0x0000002E,
+ // DropList = 0x0000002F,
+ ProgressBar = 0x00000030,
+ Dial = 0x00000031,
+ HotkeyField = 0x00000032,
+ Slider = 0x00000033,
+ SpinBox = 0x00000034,
+ Canvas = 0x00000035,
+ Animation = 0x00000036,
+ Equation = 0x00000037,
+ ButtonDropDown = 0x00000038,
+ ButtonMenu = 0x00000039,
+ ButtonDropGrid = 0x0000003A,
+ Whitespace = 0x0000003B,
+ PageTabList = 0x0000003C,
+ Clock = 0x0000003D,
+ Splitter = 0x0000003E,
+ // Additional Qt roles where enum value does not map directly to MSAA:
+ LayeredPane = 0x0000003F,
+ UserRole = 0x0000ffff
+ };
+
+ enum Text {
+ Name = 0,
+ Description,
+ Value,
+ Help,
+ Accelerator,
+ UserText = 0x0000ffff
+ };
+
+ enum RelationFlag {
+ Unrelated = 0x00000000,
+ Self = 0x00000001,
+ Ancestor = 0x00000002,
+ Child = 0x00000004,
+ Descendent = 0x00000008,
+ Sibling = 0x00000010,
+ HierarchyMask = 0x000000ff,
+
+ Up = 0x00000100,
+ Down = 0x00000200,
+ Left = 0x00000400,
+ Right = 0x00000800,
+ Covers = 0x00001000,
+ Covered = 0x00002000,
+ GeometryMask = 0x0000ff00,
+
+ FocusChild = 0x00010000,
+ Label = 0x00020000,
+ Labelled = 0x00040000,
+ Controller = 0x00080000,
+ Controlled = 0x00100000,
+ LogicalMask = 0x00ff0000
+ };
+ Q_DECLARE_FLAGS(Relation, RelationFlag)
+
+ enum Action {
+ DefaultAction = 0,
+ Press = -1,
+ FirstStandardAction = Press,
+ SetFocus = -2,
+ Increase = -3,
+ Decrease = -4,
+ Accept = -5,
+ Cancel = -6,
+ Select = -7,
+ ClearSelection = -8,
+ RemoveSelection = -9,
+ ExtendSelection = -10,
+ AddToSelection = -11,
+ LastStandardAction = AddToSelection
+ };
+
+ enum Method {
+ ListSupportedMethods = 0,
+ SetCursorPosition = 1,
+ GetCursorPosition = 2,
+ ForegroundColor = 3,
+ BackgroundColor = 4
+ };
+
+ typedef QAccessibleInterface*(*InterfaceFactory)(const QString &key, QObject*);
+ typedef void(*UpdateHandler)(QObject*, int who, Event reason);
+ typedef void(*RootObjectHandler)(QObject*);
+
+ static void installFactory(InterfaceFactory);
+ static void removeFactory(InterfaceFactory);
+ static UpdateHandler installUpdateHandler(UpdateHandler);
+ static RootObjectHandler installRootObjectHandler(RootObjectHandler);
+
+ static QAccessibleInterface *queryAccessibleInterface(QObject *);
+ static void updateAccessibility(QObject *, int who, Event reason);
+ static bool isActive();
+ static void setRootObject(QObject*);
+
+ static void initialize();
+ static void cleanup();
+
+private:
+ static UpdateHandler updateHandler;
+ static RootObjectHandler rootObjectHandler;
+};
+
+Q_DECLARE_OPERATORS_FOR_FLAGS(QAccessible::State)
+Q_DECLARE_OPERATORS_FOR_FLAGS(QAccessible::Relation)
+QT_END_NAMESPACE
+Q_DECLARE_METATYPE(QSet<QAccessible::Method>)
+QT_BEGIN_NAMESPACE
+
+namespace QAccessible2
+{
+ enum InterfaceType
+ {
+ TextInterface,
+ EditableTextInterface,
+ ValueInterface,
+ TableInterface,
+ ActionInterface,
+ ImageInterface
+ };
+}
+
+class QAccessible2Interface;
+class QAccessibleTextInterface;
+class QAccessibleEditableTextInterface;
+class QAccessibleValueInterface;
+class QAccessibleTableInterface;
+class QAccessibleActionInterface;
+class QAccessibleImageInterface;
+
+class Q_GUI_EXPORT QAccessibleInterface : public QAccessible
+{
+public:
+ virtual ~QAccessibleInterface() {}
+ // check for valid pointers
+ virtual bool isValid() const = 0;
+ virtual QObject *object() const = 0;
+
+ // hierarchy
+ virtual int childCount() const = 0;
+ virtual int indexOfChild(const QAccessibleInterface *) const = 0;
+
+ // relations
+ virtual Relation relationTo(int child, const QAccessibleInterface *other,
+ int otherChild) const = 0;
+ virtual int childAt(int x, int y) const = 0;
+
+ // navigation
+ virtual int navigate(RelationFlag relation, int index, QAccessibleInterface **iface) const = 0;
+
+ // properties and state
+ virtual QString text(Text t, int child) const = 0;
+ virtual void setText(Text t, int child, const QString &text) = 0;
+ virtual QRect rect(int child) const = 0;
+ virtual Role role(int child) const = 0;
+ virtual State state(int child) const = 0;
+
+ // action
+ virtual int userActionCount(int child) const = 0;
+ virtual QString actionText(int action, Text t, int child) const = 0;
+ virtual bool doAction(int action, int child, const QVariantList &params = QVariantList()) = 0;
+
+ QVariant invokeMethod(Method method, int child = 0,
+ const QVariantList &params = QVariantList());
+
+ inline QSet<Method> supportedMethods()
+ { return qvariant_cast<QSet<Method> >(invokeMethod(ListSupportedMethods)); }
+
+ inline QColor foregroundColor()
+ { return qvariant_cast<QColor>(invokeMethod(ForegroundColor)); }
+
+ inline QColor backgroundColor()
+ { return qvariant_cast<QColor>(invokeMethod(BackgroundColor)); }
+
+ inline QAccessibleTextInterface *textInterface()
+ { return reinterpret_cast<QAccessibleTextInterface *>(cast_helper(QAccessible2::TextInterface)); }
+
+ inline QAccessibleEditableTextInterface *editableTextInterface()
+ { return reinterpret_cast<QAccessibleEditableTextInterface *>(cast_helper(QAccessible2::EditableTextInterface)); }
+
+ inline QAccessibleValueInterface *valueInterface()
+ { return reinterpret_cast<QAccessibleValueInterface *>(cast_helper(QAccessible2::ValueInterface)); }
+
+ inline QAccessibleTableInterface *tableInterface()
+ { return reinterpret_cast<QAccessibleTableInterface *>(cast_helper(QAccessible2::TableInterface)); }
+
+ inline QAccessibleActionInterface *actionInterface()
+ { return reinterpret_cast<QAccessibleActionInterface *>(cast_helper(QAccessible2::ActionInterface)); }
+
+ inline QAccessibleImageInterface *imageInterface()
+ { return reinterpret_cast<QAccessibleImageInterface *>(cast_helper(QAccessible2::ImageInterface)); }
+
+private:
+ QAccessible2Interface *cast_helper(QAccessible2::InterfaceType);
+};
+
+class Q_GUI_EXPORT QAccessibleInterfaceEx: public QAccessibleInterface
+{
+public:
+ virtual QVariant invokeMethodEx(Method method, int child, const QVariantList &params) = 0;
+ virtual QVariant virtual_hook(const QVariant &data);
+ virtual QAccessible2Interface *interface_cast(QAccessible2::InterfaceType)
+ { return 0; }
+};
+
+
+class Q_GUI_EXPORT QAccessibleEvent : public QEvent
+{
+public:
+ inline QAccessibleEvent(Type type, int child);
+ inline int child() const { return c; }
+ inline QString value() const { return val; }
+ inline void setValue(const QString &aText) { val = aText; }
+
+private:
+ int c;
+ QString val;
+};
+
+inline QAccessibleEvent::QAccessibleEvent(Type atype, int achild)
+ : QEvent(atype), c(achild) {}
+
+#define QAccessibleInterface_iid "com.trolltech.Qt.QAccessibleInterface"
+Q_DECLARE_INTERFACE(QAccessibleInterface, QAccessibleInterface_iid)
+
+#endif // QT_NO_ACCESSIBILITY
+
+QT_END_NAMESPACE
+
+QT_END_HEADER
+
+#endif // QACCESSIBLE_H
diff --git a/src/widgets/accessible/qaccessible2.cpp b/src/widgets/accessible/qaccessible2.cpp
new file mode 100644
index 0000000000..36187f5315
--- /dev/null
+++ b/src/widgets/accessible/qaccessible2.cpp
@@ -0,0 +1,205 @@
+/****************************************************************************
+**
+** Copyright (C) 2011 Nokia Corporation and/or its subsidiary(-ies).
+** All rights reserved.
+** Contact: Nokia Corporation (qt-info@nokia.com)
+**
+** This file is part of the QtGui module of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL$
+** No Commercial Usage
+** This file contains pre-release code and may not be distributed.
+** You may use this file in accordance with the terms and conditions
+** contained in the Technology Preview License Agreement accompanying
+** this package.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 2.1 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPL included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU Lesser General Public License version 2.1 requirements
+** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
+**
+** In addition, as a special exception, Nokia gives you certain additional
+** rights. These rights are described in the Nokia Qt LGPL Exception
+** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
+**
+** If you have questions regarding the use of this file, please contact
+** Nokia at qt-info@nokia.com.
+**
+**
+**
+**
+**
+**
+**
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#include "qaccessible2.h"
+#include "qapplication.h"
+#include "qclipboard.h"
+
+#ifndef QT_NO_ACCESSIBILITY
+
+QT_BEGIN_NAMESPACE
+
+/*!
+ \namespace QAccessible2
+ \ingroup accessibility
+ \internal
+ \preliminary
+
+ \brief The QAccessible2 namespace defines constants relating to
+ IAccessible2-based interfaces
+
+ \link http://www.linux-foundation.org/en/Accessibility/IAccessible2 IAccessible2 Specification \endlink
+*/
+
+/*!
+ \class QAccessibleTextInterface
+
+ \ingroup accessibility
+ \internal
+ \preliminary
+
+ \brief The QAccessibleTextInterface class implements support for
+ the IAccessibleText interface.
+
+ \link http://www.linux-foundation.org/en/Accessibility/IAccessible2 IAccessible2 Specification \endlink
+*/
+
+/*!
+ \class QAccessibleEditableTextInterface
+ \ingroup accessibility
+ \internal
+ \preliminary
+
+ \brief The QAccessibleEditableTextInterface class implements support for
+ the IAccessibleEditableText interface.
+
+ \link http://www.linux-foundation.org/en/Accessibility/IAccessible2 IAccessible2 Specification \endlink
+*/
+
+/*!
+ \class QAccessibleSimpleEditableTextInterface
+ \ingroup accessibility
+ \internal
+ \preliminary
+
+ \brief The QAccessibleSimpleEditableTextInterface class is a convenience class for
+ text-based widgets.
+
+ \link http://www.linux-foundation.org/en/Accessibility/IAccessible2 IAccessible2 Specification \endlink
+*/
+
+/*!
+ \class QAccessibleValueInterface
+ \ingroup accessibility
+ \internal
+ \preliminary
+
+ \brief The QAccessibleValueInterface class implements support for
+ the IAccessibleValue interface.
+
+ \link http://www.linux-foundation.org/en/Accessibility/IAccessible2 IAccessible2 Specification \endlink
+*/
+
+/*!
+ \class QAccessibleActionInterface
+ \ingroup accessibility
+ \internal
+ \preliminary
+
+ \brief The QAccessibleActionInterface class implements support for
+ the IAccessibleAction interface.
+
+ \link http://www.linux-foundation.org/en/Accessibility/IAccessible2 IAccessible2 Specification \endlink
+*/
+
+/*!
+ \class QAccessibleImageInterface
+ \ingroup accessibility
+ \internal
+ \preliminary
+
+ \brief The QAccessibleImageInterface class implements support for
+ the IAccessibleImage interface.
+
+ \link http://www.linux-foundation.org/en/Accessibility/IAccessible2 IAccessible2 Specification \endlink
+*/
+
+QAccessibleSimpleEditableTextInterface::QAccessibleSimpleEditableTextInterface(
+ QAccessibleInterface *accessibleInterface)
+ : iface(accessibleInterface)
+{
+ Q_ASSERT(iface);
+}
+
+#ifndef QT_NO_CLIPBOARD
+static QString textForRange(QAccessibleInterface *iface, int startOffset, int endOffset)
+{
+ return iface->text(QAccessible::Value, 0).mid(startOffset, endOffset - startOffset);
+}
+#endif
+
+void QAccessibleSimpleEditableTextInterface::copyText(int startOffset, int endOffset)
+{
+#ifdef QT_NO_CLIPBOARD
+ Q_UNUSED(startOffset);
+ Q_UNUSED(endOffset);
+#else
+ QApplication::clipboard()->setText(textForRange(iface, startOffset, endOffset));
+#endif
+}
+
+void QAccessibleSimpleEditableTextInterface::deleteText(int startOffset, int endOffset)
+{
+ QString txt = iface->text(QAccessible::Value, 0);
+ txt.remove(startOffset, endOffset - startOffset);
+ iface->setText(QAccessible::Value, 0, txt);
+}
+
+void QAccessibleSimpleEditableTextInterface::insertText(int offset, const QString &text)
+{
+ QString txt = iface->text(QAccessible::Value, 0);
+ txt.insert(offset, text);
+ iface->setText(QAccessible::Value, 0, txt);
+}
+
+void QAccessibleSimpleEditableTextInterface::cutText(int startOffset, int endOffset)
+{
+#ifdef QT_NO_CLIPBOARD
+ Q_UNUSED(startOffset);
+ Q_UNUSED(endOffset);
+#else
+ QString sub = textForRange(iface, startOffset, endOffset);
+ deleteText(startOffset, endOffset);
+ QApplication::clipboard()->setText(sub);
+#endif
+}
+
+void QAccessibleSimpleEditableTextInterface::pasteText(int offset)
+{
+#ifdef QT_NO_CLIPBOARD
+ Q_UNUSED(offset);
+#else
+ QString txt = iface->text(QAccessible::Value, 0);
+ txt.insert(offset, QApplication::clipboard()->text());
+ iface->setText(QAccessible::Value, 0, txt);
+#endif
+}
+
+void QAccessibleSimpleEditableTextInterface::replaceText(int startOffset, int endOffset, const QString &text)
+{
+ QString txt = iface->text(QAccessible::Value, 0);
+ txt.replace(startOffset, endOffset - startOffset, text);
+ iface->setText(QAccessible::Value, 0, txt);
+}
+
+QT_END_NAMESPACE
+
+#endif // QT_NO_ACCESSIBILITY
diff --git a/src/widgets/accessible/qaccessible2.h b/src/widgets/accessible/qaccessible2.h
new file mode 100644
index 0000000000..2f660bda6e
--- /dev/null
+++ b/src/widgets/accessible/qaccessible2.h
@@ -0,0 +1,246 @@
+/****************************************************************************
+**
+** Copyright (C) 2011 Nokia Corporation and/or its subsidiary(-ies).
+** All rights reserved.
+** Contact: Nokia Corporation (qt-info@nokia.com)
+**
+** This file is part of the QtGui module of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL$
+** No Commercial Usage
+** This file contains pre-release code and may not be distributed.
+** You may use this file in accordance with the terms and conditions
+** contained in the Technology Preview License Agreement accompanying
+** this package.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 2.1 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPL included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU Lesser General Public License version 2.1 requirements
+** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
+**
+** In addition, as a special exception, Nokia gives you certain additional
+** rights. These rights are described in the Nokia Qt LGPL Exception
+** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
+**
+** If you have questions regarding the use of this file, please contact
+** Nokia at qt-info@nokia.com.
+**
+**
+**
+**
+**
+**
+**
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#ifndef QACCESSIBLE2_H
+#define QACCESSIBLE2_H
+
+#include <QtWidgets/qaccessible.h>
+
+QT_BEGIN_HEADER
+
+QT_BEGIN_NAMESPACE
+
+QT_MODULE(Gui)
+
+#ifndef QT_NO_ACCESSIBILITY
+
+namespace QAccessible2
+{
+ enum CoordinateType
+ {
+ RelativeToScreen = 0,
+ RelativeToParent = 1
+ };
+
+ enum BoundaryType {
+ CharBoundary,
+ WordBoundary,
+ SentenceBoundary,
+ ParagraphBoundary,
+ LineBoundary,
+ NoBoundary
+ };
+}
+
+class Q_GUI_EXPORT QAccessible2Interface
+{
+public:
+ virtual ~QAccessible2Interface() {}
+};
+
+// catch-all functions. If an accessible class doesn't implement interface T, return 0
+inline QAccessible2Interface *qAccessibleValueCastHelper() { return 0; }
+inline QAccessible2Interface *qAccessibleTextCastHelper() { return 0; }
+inline QAccessible2Interface *qAccessibleEditableTextCastHelper() { return 0; }
+inline QAccessible2Interface *qAccessibleTableCastHelper() { return 0; }
+inline QAccessible2Interface *qAccessibleActionCastHelper() { return 0; }
+inline QAccessible2Interface *qAccessibleImageCastHelper() { return 0; }
+
+#define Q_ACCESSIBLE_OBJECT \
+ public: \
+ QAccessible2Interface *interface_cast(QAccessible2::InterfaceType t) \
+ { \
+ switch (t) { \
+ case QAccessible2::TextInterface: \
+ return qAccessibleTextCastHelper(); \
+ case QAccessible2::EditableTextInterface: \
+ return qAccessibleEditableTextCastHelper(); \
+ case QAccessible2::ValueInterface: \
+ return qAccessibleValueCastHelper(); \
+ case QAccessible2::TableInterface: \
+ return qAccessibleTableCastHelper(); \
+ case QAccessible2::ActionInterface: \
+ return qAccessibleActionCastHelper(); \
+ case QAccessible2::ImageInterface: \
+ return qAccessibleImageCastHelper(); \
+ } \
+ return 0; \
+ } \
+ private:
+
+class Q_GUI_EXPORT QAccessibleTextInterface: public QAccessible2Interface
+{
+public:
+ inline QAccessible2Interface *qAccessibleTextCastHelper() { return this; }
+
+ virtual ~QAccessibleTextInterface() {}
+
+ virtual void addSelection(int startOffset, int endOffset) = 0;
+ virtual QString attributes(int offset, int *startOffset, int *endOffset) = 0;
+ virtual int cursorPosition() = 0;
+ virtual QRect characterRect(int offset, QAccessible2::CoordinateType coordType) = 0;
+ virtual int selectionCount() = 0;
+ virtual int offsetAtPoint(const QPoint &point, QAccessible2::CoordinateType coordType) = 0;
+ virtual void selection(int selectionIndex, int *startOffset, int *endOffset) = 0;
+ virtual QString text(int startOffset, int endOffset) = 0;
+ virtual QString textBeforeOffset (int offset, QAccessible2::BoundaryType boundaryType,
+ int *startOffset, int *endOffset) = 0;
+ virtual QString textAfterOffset(int offset, QAccessible2::BoundaryType boundaryType,
+ int *startOffset, int *endOffset) = 0;
+ virtual QString textAtOffset(int offset, QAccessible2::BoundaryType boundaryType,
+ int *startOffset, int *endOffset) = 0;
+ virtual void removeSelection(int selectionIndex) = 0;
+ virtual void setCursorPosition(int position) = 0;
+ virtual void setSelection(int selectionIndex, int startOffset, int endOffset) = 0;
+ virtual int characterCount() = 0;
+ virtual void scrollToSubstring(int startIndex, int endIndex) = 0;
+};
+
+class Q_GUI_EXPORT QAccessibleEditableTextInterface: public QAccessible2Interface
+{
+public:
+ inline QAccessible2Interface *qAccessibleEditableTextCastHelper() { return this; }
+
+ virtual ~QAccessibleEditableTextInterface() {}
+
+ virtual void copyText(int startOffset, int endOffset) = 0;
+ virtual void deleteText(int startOffset, int endOffset) = 0;
+ virtual void insertText(int offset, const QString &text) = 0;
+ virtual void cutText(int startOffset, int endOffset) = 0;
+ virtual void pasteText(int offset) = 0;
+ virtual void replaceText(int startOffset, int endOffset, const QString &text) = 0;
+ virtual void setAttributes(int startOffset, int endOffset, const QString &attributes) = 0;
+};
+
+class Q_GUI_EXPORT QAccessibleSimpleEditableTextInterface: public QAccessibleEditableTextInterface
+{
+public:
+ QAccessibleSimpleEditableTextInterface(QAccessibleInterface *accessibleInterface);
+
+ void copyText(int startOffset, int endOffset);
+ void deleteText(int startOffset, int endOffset);
+ void insertText(int offset, const QString &text);
+ void cutText(int startOffset, int endOffset);
+ void pasteText(int offset);
+ void replaceText(int startOffset, int endOffset, const QString &text);
+ inline void setAttributes(int, int, const QString &) {}
+
+private:
+ QAccessibleInterface *iface;
+};
+
+class Q_GUI_EXPORT QAccessibleValueInterface: public QAccessible2Interface
+{
+public:
+ inline QAccessible2Interface *qAccessibleValueCastHelper() { return this; }
+
+ virtual ~QAccessibleValueInterface() {}
+
+ virtual QVariant currentValue() = 0;
+ virtual void setCurrentValue(const QVariant &value) = 0;
+ virtual QVariant maximumValue() = 0;
+ virtual QVariant minimumValue() = 0;
+};
+
+class Q_GUI_EXPORT QAccessibleTableInterface: public QAccessible2Interface
+{
+public:
+ inline QAccessible2Interface *qAccessibleTableCastHelper() { return this; }
+
+ virtual QAccessibleInterface *accessibleAt(int row, int column) = 0;
+ virtual QAccessibleInterface *caption() = 0;
+ virtual int childIndex(int rowIndex, int columnIndex) = 0;
+ virtual QString columnDescription(int column) = 0;
+ virtual int columnSpan(int row, int column) = 0;
+ virtual QAccessibleInterface *columnHeader() = 0;
+ virtual int columnIndex(int childIndex) = 0;
+ virtual int columnCount() = 0;
+ virtual int rowCount() = 0;
+ virtual int selectedColumnCount() = 0;
+ virtual int selectedRowCount() = 0;
+ virtual QString rowDescription(int row) = 0;
+ virtual int rowSpan(int row, int column) = 0;
+ virtual QAccessibleInterface *rowHeader() = 0;
+ virtual int rowIndex(int childIndex) = 0;
+ virtual int selectedRows(int maxRows, QList<int> *rows) = 0;
+ virtual int selectedColumns(int maxColumns, QList<int> *columns) = 0;
+ virtual QAccessibleInterface *summary() = 0;
+ virtual bool isColumnSelected(int column) = 0;
+ virtual bool isRowSelected(int row) = 0;
+ virtual bool isSelected(int row, int column) = 0;
+ virtual void selectRow(int row) = 0;
+ virtual void selectColumn(int column) = 0;
+ virtual void unselectRow(int row) = 0;
+ virtual void unselectColumn(int column) = 0;
+ virtual void cellAtIndex(int index, int *row, int *column, int *rowSpan,
+ int *columnSpan, bool *isSelected) = 0;
+};
+
+class Q_GUI_EXPORT QAccessibleActionInterface : public QAccessible2Interface
+{
+public:
+ inline QAccessible2Interface *qAccessibleActionCastHelper() { return this; }
+
+ virtual int actionCount() = 0;
+ virtual void doAction(int actionIndex) = 0;
+ virtual QString description(int actionIndex) = 0;
+ virtual QString name(int actionIndex) = 0;
+ virtual QString localizedName(int actionIndex) = 0;
+ virtual QStringList keyBindings(int actionIndex) = 0;
+};
+
+class Q_GUI_EXPORT QAccessibleImageInterface : public QAccessible2Interface
+{
+public:
+ inline QAccessible2Interface *qAccessibleImageCastHelper() { return this; }
+
+ virtual QString imageDescription() = 0;
+ virtual QSize imageSize() = 0;
+ virtual QRect imagePosition(QAccessible2::CoordinateType coordType) = 0;
+};
+
+#endif // QT_NO_ACCESSIBILITY
+
+QT_END_NAMESPACE
+
+QT_END_HEADER
+
+#endif
diff --git a/src/widgets/accessible/qaccessible_mac.mm b/src/widgets/accessible/qaccessible_mac.mm
new file mode 100644
index 0000000000..d01c1c9733
--- /dev/null
+++ b/src/widgets/accessible/qaccessible_mac.mm
@@ -0,0 +1,2469 @@
+/****************************************************************************
+**
+** Copyright (C) 2011 Nokia Corporation and/or its subsidiary(-ies).
+** All rights reserved.
+** Contact: Nokia Corporation (qt-info@nokia.com)
+**
+** This file is part of the QtGui module of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL$
+** No Commercial Usage
+** This file contains pre-release code and may not be distributed.
+** You may use this file in accordance with the terms and conditions
+** contained in the Technology Preview License Agreement accompanying
+** this package.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 2.1 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPL included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU Lesser General Public License version 2.1 requirements
+** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
+**
+** In addition, as a special exception, Nokia gives you certain additional
+** rights. These rights are described in the Nokia Qt LGPL Exception
+** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
+**
+** If you have questions regarding the use of this file, please contact
+** Nokia at qt-info@nokia.com.
+**
+**
+**
+**
+**
+**
+**
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#include "qaccessible.h"
+
+#ifndef QT_NO_ACCESSIBILITY
+#include "qaccessible_mac_p.h"
+#include "qhash.h"
+#include "qset.h"
+#include "qpointer.h"
+#include "qapplication.h"
+#include "qmainwindow.h"
+#include "qtextdocument.h"
+#include "qdebug.h"
+#include "qabstractslider.h"
+#include "qsplitter.h"
+#include "qtabwidget.h"
+#include "qlistview.h"
+#include "qtableview.h"
+#include "qdockwidget.h"
+
+#include <private/qt_mac_p.h>
+#include <private/qwidget_p.h>
+#include <CoreFoundation/CoreFoundation.h>
+
+QT_BEGIN_NAMESPACE
+
+/*
+ Set up platform defines. There is a one-to-one correspondence between the
+ Carbon and Cocoa roles and attributes, but the prefix and type changes.
+*/
+#ifdef QT_MAC_USE_COCOA
+typedef NSString * const QAXRoleType;
+#define QAXApplicationRole NSAccessibilityApplicationRole
+#define QAXButtonRole NSAccessibilityButtonRole
+#define QAXCancelAction NSAccessibilityCancelAction
+#define QAXCheckBoxRole NSAccessibilityCheckBoxRole
+#define QAXChildrenAttribute NSAccessibilityChildrenAttribute
+#define QAXCloseButtonAttribute NSAccessibilityCloseButtonAttribute
+#define QAXCloseButtonAttribute NSAccessibilityCloseButtonAttribute
+#define QAXColumnRole NSAccessibilityColumnRole
+#define QAXConfirmAction NSAccessibilityConfirmAction
+#define QAXContentsAttribute NSAccessibilityContentsAttribute
+#define QAXDecrementAction NSAccessibilityDecrementAction
+#define QAXDecrementArrowSubrole NSAccessibilityDecrementArrowSubrole
+#define QAXDecrementPageSubrole NSAccessibilityDecrementPageSubrole
+#define QAXDescriptionAttribute NSAccessibilityDescriptionAttribute
+#define QAXEnabledAttribute NSAccessibilityEnabledAttribute
+#define QAXExpandedAttribute NSAccessibilityExpandedAttribute
+#define QAXFocusedAttribute NSAccessibilityFocusedAttribute
+#define QAXFocusedUIElementChangedNotification NSAccessibilityFocusedUIElementChangedNotification
+#define QAXFocusedWindowChangedNotification NSAccessibilityFocusedWindowChangedNotification
+#define QAXGroupRole NSAccessibilityGroupRole
+#define QAXGrowAreaAttribute NSAccessibilityGrowAreaAttribute
+#define QAXGrowAreaRole NSAccessibilityGrowAreaRole
+#define QAXHelpAttribute NSAccessibilityHelpAttribute
+#define QAXHorizontalOrientationValue NSAccessibilityHorizontalOrientationValue
+#define QAXHorizontalScrollBarAttribute NSAccessibilityHorizontalScrollBarAttribute
+#define QAXIncrementAction NSAccessibilityIncrementAction
+#define QAXIncrementArrowSubrole NSAccessibilityIncrementArrowSubrole
+#define QAXIncrementPageSubrole NSAccessibilityIncrementPageSubrole
+#define QAXIncrementorRole NSAccessibilityIncrementorRole
+#define QAXLinkedUIElementsAttribute NSAccessibilityLinkedUIElementsAttribute
+#define QAXListRole NSAccessibilityListRole
+#define QAXMainAttribute NSAccessibilityMainAttribute
+#define QAXMaxValueAttribute NSAccessibilityMaxValueAttribute
+#define QAXMenuBarRole NSAccessibilityMenuBarRole
+#define QAXMenuButtonRole NSAccessibilityMenuButtonRole
+#define QAXMenuClosedNotification NSAccessibilityMenuClosedNotification
+#define QAXMenuItemRole NSAccessibilityMenuItemRole
+#define QAXMenuOpenedNotification NSAccessibilityMenuOpenedNotification
+#define QAXMenuRole NSAccessibilityMenuRole
+#define QAXMinValueAttribute NSAccessibilityMinValueAttribute
+#define QAXMinimizeButtonAttribute NSAccessibilityMinimizeButtonAttribute
+#define QAXMinimizedAttribute NSAccessibilityMinimizedAttribute
+#define QAXNextContentsAttribute NSAccessibilityNextContentsAttribute
+#define QAXOrientationAttribute NSAccessibilityOrientationAttribute
+#define QAXParentAttribute NSAccessibilityParentAttribute
+#define QAXPickAction NSAccessibilityPickAction
+#define QAXPopUpButtonRole NSAccessibilityPopUpButtonRole
+#define QAXPositionAttribute NSAccessibilityPositionAttribute
+#define QAXPressAction NSAccessibilityPressAction
+#define QAXPreviousContentsAttribute NSAccessibilityPreviousContentsAttribute
+#define QAXProgressIndicatorRole NSAccessibilityProgressIndicatorRole
+#define QAXRadioButtonRole NSAccessibilityRadioButtonRole
+#define QAXRoleAttribute NSAccessibilityRoleAttribute
+#define QAXRoleDescriptionAttribute NSAccessibilityRoleDescriptionAttribute
+#define QAXRowRole NSAccessibilityRowRole
+#define QAXRowsAttribute NSAccessibilityRowsAttribute
+#define QAXScrollAreaRole NSAccessibilityScrollAreaRole
+#define QAXScrollBarRole NSAccessibilityScrollBarRole
+#define QAXSelectedAttribute NSAccessibilitySelectedAttribute
+#define QAXSelectedChildrenAttribute NSAccessibilitySelectedChildrenAttribute
+#define QAXSelectedRowsAttribute NSAccessibilitySelectedRowsAttribute
+#define QAXSizeAttribute NSAccessibilitySizeAttribute
+#define QAXSliderRole NSAccessibilitySliderRole
+#define QAXSplitGroupRole NSAccessibilitySplitGroupRole
+#define QAXSplitterRole NSAccessibilitySplitterRole
+#define QAXSplittersAttribute NSAccessibilitySplittersAttribute
+#define QAXStaticTextRole NSAccessibilityStaticTextRole
+#define QAXSubroleAttribute NSAccessibilitySubroleAttribute
+#define QAXSubroleAttribute NSAccessibilitySubroleAttribute
+#define QAXTabGroupRole NSAccessibilityTabGroupRole
+#define QAXTableRole NSAccessibilityTableRole
+#define QAXTabsAttribute NSAccessibilityTabsAttribute
+#define QAXTextFieldRole NSAccessibilityTextFieldRole
+#define QAXTitleAttribute NSAccessibilityTitleAttribute
+#define QAXTitleUIElementAttribute NSAccessibilityTitleUIElementAttribute
+#define QAXToolbarButtonAttribute NSAccessibilityToolbarButtonAttribute
+#define QAXToolbarRole NSAccessibilityToolbarRole
+#define QAXTopLevelUIElementAttribute NSAccessibilityTopLevelUIElementAttribute
+#define QAXUnknownRole NSAccessibilityUnknownRole
+#define QAXValueAttribute NSAccessibilityValueAttribute
+#define QAXValueChangedNotification NSAccessibilityValueChangedNotification
+#define QAXValueIndicatorRole NSAccessibilityValueIndicatorRole
+#define QAXVerticalOrientationValue NSAccessibilityVerticalOrientationValue
+#define QAXVerticalScrollBarAttribute NSAccessibilityVerticalScrollBarAttribute
+#define QAXVisibleRowsAttribute NSAccessibilityVisibleRowsAttribute
+#define QAXWindowAttribute NSAccessibilityWindowAttribute
+#define QAXWindowCreatedNotification NSAccessibilityWindowCreatedNotification
+#define QAXWindowMovedNotification NSAccessibilityWindowMovedNotification
+#define QAXWindowRole NSAccessibilityWindowRole
+#define QAXZoomButtonAttribute NSAccessibilityZoomButtonAttribute
+#else
+typedef CFStringRef const QAXRoleType;
+#define QAXApplicationRole kAXApplicationRole
+#define QAXButtonRole kAXButtonRole
+#define QAXCancelAction kAXCancelAction
+#define QAXCheckBoxRole kAXCheckBoxRole
+#define QAXChildrenAttribute kAXChildrenAttribute
+#define QAXCloseButtonAttribute kAXCloseButtonAttribute
+#define QAXColumnRole kAXColumnRole
+#define QAXConfirmAction kAXConfirmAction
+#define QAXContentsAttribute kAXContentsAttribute
+#define QAXDecrementAction kAXDecrementAction
+#define QAXDecrementArrowSubrole kAXDecrementArrowSubrole
+#define QAXDecrementPageSubrole kAXDecrementPageSubrole
+#define QAXDescriptionAttribute kAXDescriptionAttribute
+#define QAXEnabledAttribute kAXEnabledAttribute
+#define QAXExpandedAttribute kAXExpandedAttribute
+#define QAXFocusedAttribute kAXFocusedAttribute
+#define QAXFocusedUIElementChangedNotification kAXFocusedUIElementChangedNotification
+#define QAXFocusedWindowChangedNotification kAXFocusedWindowChangedNotification
+#define QAXGroupRole kAXGroupRole
+#define QAXGrowAreaAttribute kAXGrowAreaAttribute
+#define QAXGrowAreaRole kAXGrowAreaRole
+#define QAXHelpAttribute kAXHelpAttribute
+#define QAXHorizontalOrientationValue kAXHorizontalOrientationValue
+#define QAXHorizontalScrollBarAttribute kAXHorizontalScrollBarAttribute
+#define QAXIncrementAction kAXIncrementAction
+#define QAXIncrementArrowSubrole kAXIncrementArrowSubrole
+#define QAXIncrementPageSubrole kAXIncrementPageSubrole
+#define QAXIncrementorRole kAXIncrementorRole
+#define QAXLinkedUIElementsAttribute kAXLinkedUIElementsAttribute
+#define QAXListRole kAXListRole
+#define QAXMainAttribute kAXMainAttribute
+#define QAXMaxValueAttribute kAXMaxValueAttribute
+#define QAXMenuBarRole kAXMenuBarRole
+#define QAXMenuButtonRole kAXMenuButtonRole
+#define QAXMenuClosedNotification kAXMenuClosedNotification
+#define QAXMenuItemRole kAXMenuItemRole
+#define QAXMenuOpenedNotification kAXMenuOpenedNotification
+#define QAXMenuRole kAXMenuRole
+#define QAXMinValueAttribute kAXMinValueAttribute
+#define QAXMinimizeButtonAttribute kAXMinimizeButtonAttribute
+#define QAXMinimizedAttribute kAXMinimizedAttribute
+#define QAXNextContentsAttribute kAXNextContentsAttribute
+#define QAXOrientationAttribute kAXOrientationAttribute
+#define QAXParentAttribute kAXParentAttribute
+#define QAXPickAction kAXPickAction
+#define QAXPopUpButtonRole kAXPopUpButtonRole
+#define QAXPositionAttribute kAXPositionAttribute
+#define QAXPressAction kAXPressAction
+#define QAXPreviousContentsAttribute kAXPreviousContentsAttribute
+#define QAXProgressIndicatorRole kAXProgressIndicatorRole
+#define QAXRadioButtonRole kAXRadioButtonRole
+#define QAXRoleAttribute kAXRoleAttribute
+#define QAXRoleDescriptionAttribute kAXRoleDescriptionAttribute
+#define QAXRowRole kAXRowRole
+#define QAXRowsAttribute kAXRowsAttribute
+#define QAXScrollAreaRole kAXScrollAreaRole
+#define QAXScrollBarRole kAXScrollBarRole
+#define QAXSelectedAttribute kAXSelectedAttribute
+#define QAXSelectedChildrenAttribute kAXSelectedChildrenAttribute
+#define QAXSelectedRowsAttribute kAXSelectedRowsAttribute
+#define QAXSizeAttribute kAXSizeAttribute
+#define QAXSliderRole kAXSliderRole
+#define QAXSplitGroupRole kAXSplitGroupRole
+#define QAXSplitterRole kAXSplitterRole
+#define QAXSplittersAttribute kAXSplittersAttribute
+#define QAXStaticTextRole kAXStaticTextRole
+#define QAXSubroleAttribute kAXSubroleAttribute
+#define QAXTabGroupRole kAXTabGroupRole
+#define QAXTableRole kAXTableRole
+#define QAXTabsAttribute kAXTabsAttribute
+#define QAXTextFieldRole kAXTextFieldRole
+#define QAXTitleAttribute kAXTitleAttribute
+#define QAXTitleUIElementAttribute kAXTitleUIElementAttribute
+#define QAXToolbarButtonAttribute kAXToolbarButtonAttribute
+#define QAXToolbarRole kAXToolbarRole
+#define QAXTopLevelUIElementAttribute kAXTopLevelUIElementAttribute
+#define QAXUnknownRole kAXUnknownRole
+#define QAXValueAttribute kAXValueAttribute
+#define QAXValueChangedNotification kAXValueChangedNotification
+#define QAXValueIndicatorRole kAXValueIndicatorRole
+#define QAXVerticalOrientationValue kAXVerticalOrientationValue
+#define QAXVerticalScrollBarAttribute kAXVerticalScrollBarAttribute
+#define QAXVisibleRowsAttribute kAXVisibleRowsAttribute
+#define QAXWindowAttribute kAXWindowAttribute
+#define QAXWindowCreatedNotification kAXWindowCreatedNotification
+#define QAXWindowMovedNotification kAXWindowMovedNotification
+#define QAXWindowRole kAXWindowRole
+#define QAXZoomButtonAttribute kAXZoomButtonAttribute
+#endif
+
+
+/*****************************************************************************
+ Externals
+ *****************************************************************************/
+extern bool qt_mac_is_macsheet(const QWidget *w); //qwidget_mac.cpp
+extern bool qt_mac_is_macdrawer(const QWidget *w); //qwidget_mac.cpp
+
+/*****************************************************************************
+ QAccessible Bindings
+ *****************************************************************************/
+//hardcoded bindings between control info and (known) QWidgets
+struct QAccessibleTextBinding {
+ int qt;
+ QAXRoleType mac;
+ bool settable;
+} text_bindings[][10] = {
+ { { QAccessible::MenuItem, QAXMenuItemRole, false },
+ { -1, 0, false }
+ },
+ { { QAccessible::MenuBar, QAXMenuBarRole, false },
+ { -1, 0, false }
+ },
+ { { QAccessible::ScrollBar, QAXScrollBarRole, false },
+ { -1, 0, false }
+ },
+ { { QAccessible::Grip, QAXGrowAreaRole, false },
+ { -1, 0, false }
+ },
+ { { QAccessible::Window, QAXWindowRole, false },
+ { -1, 0, false }
+ },
+ { { QAccessible::Dialog, QAXWindowRole, false },
+ { -1, 0, false }
+ },
+ { { QAccessible::AlertMessage, QAXWindowRole, false },
+ { -1, 0, false }
+ },
+ { { QAccessible::ToolTip, QAXWindowRole, false },
+ { -1, 0, false }
+ },
+ { { QAccessible::HelpBalloon, QAXWindowRole, false },
+ { -1, 0, false }
+ },
+ { { QAccessible::PopupMenu, QAXMenuRole, false },
+ { -1, 0, false }
+ },
+ { { QAccessible::Application, QAXApplicationRole, false },
+ { -1, 0, false }
+ },
+ { { QAccessible::Pane, QAXGroupRole, false },
+ { -1, 0, false }
+ },
+ { { QAccessible::Grouping, QAXGroupRole, false },
+ { -1, 0, false }
+ },
+ { { QAccessible::Separator, QAXSplitterRole, false },
+ { -1, 0, false }
+ },
+ { { QAccessible::ToolBar, QAXToolbarRole, false },
+ { -1, 0, false }
+ },
+ { { QAccessible::PageTab, QAXRadioButtonRole, false },
+ { -1, 0, false }
+ },
+ { { QAccessible::ButtonMenu, QAXMenuButtonRole, false },
+ { -1, 0, false }
+ },
+ { { QAccessible::ButtonDropDown, QAXPopUpButtonRole, false },
+ { -1, 0, false }
+ },
+ { { QAccessible::SpinBox, QAXIncrementorRole, false },
+ { -1, 0, false }
+ },
+ { { QAccessible::Slider, QAXSliderRole, false },
+ { -1, 0, false }
+ },
+ { { QAccessible::ProgressBar, QAXProgressIndicatorRole, false },
+ { -1, 0, false }
+ },
+ { { QAccessible::ComboBox, QAXPopUpButtonRole, false },
+ { -1, 0, false }
+ },
+ { { QAccessible::RadioButton, QAXRadioButtonRole, false },
+ { -1, 0, false }
+ },
+ { { QAccessible::CheckBox, QAXCheckBoxRole, false },
+ { -1, 0, false }
+ },
+ { { QAccessible::StaticText, QAXStaticTextRole, false },
+ { QAccessible::Name, QAXValueAttribute, false },
+ { -1, 0, false }
+ },
+ { { QAccessible::Table, QAXTableRole, false },
+ { -1, 0, false }
+ },
+ { { QAccessible::StatusBar, QAXStaticTextRole, false },
+ { -1, 0, false }
+ },
+ { { QAccessible::Column, QAXColumnRole, false },
+ { -1, 0, false }
+ },
+ { { QAccessible::ColumnHeader, QAXColumnRole, false },
+ { -1, 0, false }
+ },
+ { { QAccessible::Row, QAXRowRole, false },
+ { -1, 0, false }
+ },
+ { { QAccessible::RowHeader, QAXRowRole, false },
+ { -1, 0, false }
+ },
+ { { QAccessible::Cell, QAXTextFieldRole, false },
+ { -1, 0, false }
+ },
+ { { QAccessible::PushButton, QAXButtonRole, false },
+ { -1, 0, false }
+ },
+ { { QAccessible::EditableText, QAXTextFieldRole, true },
+ { -1, 0, false }
+ },
+ { { QAccessible::Link, QAXTextFieldRole, false },
+ { -1, 0, false }
+ },
+ { { QAccessible::Indicator, QAXValueIndicatorRole, false },
+ { -1, 0, false }
+ },
+ { { QAccessible::Splitter, QAXSplitGroupRole, false },
+ { -1, 0, false }
+ },
+ { { QAccessible::List, QAXListRole, false },
+ { -1, 0, false }
+ },
+ { { QAccessible::ListItem, QAXStaticTextRole, false },
+ { -1, 0, false }
+ },
+ { { QAccessible::Cell, QAXStaticTextRole, false },
+ { -1, 0, false }
+ },
+ { { -1, 0, false } }
+};
+
+class QAInterface;
+static CFStringRef macRole(const QAInterface &interface);
+
+QDebug operator<<(QDebug debug, const QAInterface &interface)
+{
+ if (interface.isValid() == false)
+ debug << "invalid interface";
+ else
+ debug << interface.object() << "id" << interface.id() << "role" << hex << interface.role();
+ return debug;
+}
+
+// The root of the Qt accessible hiearchy.
+static QObject *rootObject = 0;
+
+
+bool QAInterface::operator==(const QAInterface &other) const
+{
+ if (isValid() == false || other.isValid() == false)
+ return (isValid() && other.isValid());
+
+ // walk up the parent chain, comparing child indexes, until we reach
+ // an interface that has a QObject.
+ QAInterface currentThis = *this;
+ QAInterface currentOther = other;
+
+ while (currentThis.object() == 0) {
+ if (currentOther.object() != 0)
+ return false;
+
+ // fail if the child indexes in the two hirearchies don't match.
+ if (currentThis.parent().indexOfChild(currentThis) !=
+ currentOther.parent().indexOfChild(currentOther))
+ return false;
+
+ currentThis = currentThis.parent();
+ currentOther = currentOther.parent();
+ }
+
+ return (currentThis.object() == currentOther.object() && currentThis.id() == currentOther.id());
+}
+
+bool QAInterface::operator!=(const QAInterface &other) const
+{
+ return !operator==(other);
+}
+
+uint qHash(const QAInterface &item)
+{
+ if (item.isValid())
+ return qHash(item.object()) + qHash(item.id());
+ else
+ return qHash(item.cachedObject()) + qHash(item.id());
+}
+
+QAInterface QAInterface::navigate(RelationFlag relation, int entry) const
+{
+ if (!checkValid())
+ return QAInterface();
+
+ // On a QAccessibleInterface that handles its own children we can short-circut
+ // the navigation if this QAInterface refers to one of the children:
+ if (child != 0) {
+ // The Ancestor interface will always be the same QAccessibleInterface with
+ // a child value of 0.
+ if (relation == QAccessible::Ancestor)
+ return QAInterface(*this, 0);
+
+ // The child hiearchy is only one level deep, so navigating to a child
+ // of a child is not possible.
+ if (relation == QAccessible::Child) {
+ return QAInterface();
+ }
+ }
+ QAccessibleInterface *child_iface = 0;
+
+ const int status = base.interface->navigate(relation, entry, &child_iface);
+
+ if (status == -1)
+ return QAInterface(); // not found;
+
+ // Check if target is a child of this interface.
+ if (!child_iface) {
+ return QAInterface(*this, status);
+ } else {
+ // Target is child_iface or a child of that (status decides).
+ return QAInterface(child_iface, status);
+ }
+}
+
+QAElement::QAElement()
+:elementRef(0)
+{}
+
+QAElement::QAElement(AXUIElementRef elementRef)
+:elementRef(elementRef)
+{
+ if (elementRef != 0) {
+ CFRetain(elementRef);
+ CFRetain(object());
+ }
+}
+
+QAElement::QAElement(const QAElement &element)
+:elementRef(element.elementRef)
+{
+ if (elementRef != 0) {
+ CFRetain(elementRef);
+ CFRetain(object());
+ }
+}
+
+QAElement::QAElement(HIObjectRef object, int child)
+{
+#ifndef QT_MAC_USE_COCOA
+ if (object == 0) {
+ elementRef = 0; // Create invalid QAElement.
+ } else {
+ elementRef = AXUIElementCreateWithHIObjectAndIdentifier(object, child);
+ CFRetain(object);
+ }
+#else
+ Q_UNUSED(object);
+ Q_UNUSED(child);
+#endif
+}
+
+QAElement::~QAElement()
+{
+ if (elementRef != 0) {
+ CFRelease(object());
+ CFRelease(elementRef);
+ }
+}
+
+void QAElement::operator=(const QAElement &other)
+{
+ if (*this == other)
+ return;
+
+ if (elementRef != 0) {
+ CFRelease(object());
+ CFRelease(elementRef);
+ }
+
+ elementRef = other.elementRef;
+
+ if (elementRef != 0) {
+ CFRetain(elementRef);
+ CFRetain(object());
+ }
+}
+
+bool QAElement::operator==(const QAElement &other) const
+{
+ if (elementRef == 0 || other.elementRef == 0)
+ return (elementRef == other.elementRef);
+
+ return CFEqual(elementRef, other.elementRef);
+}
+
+uint qHash(QAElement element)
+{
+ return qHash(element.object()) + qHash(element.id());
+}
+
+#ifndef QT_MAC_USE_COCOA
+static QInterfaceFactory *createFactory(const QAInterface &interface);
+#endif
+Q_GLOBAL_STATIC(QAccessibleHierarchyManager, accessibleHierarchyManager);
+
+/*
+ Reomves all accessibility info accosiated with the sender object.
+*/
+void QAccessibleHierarchyManager::objectDestroyed(QObject *object)
+{
+ HIObjectRef hiObject = qobjectHiobjectHash.value(object);
+ delete qobjectElementHash.value(object);
+ qobjectElementHash.remove(object);
+ hiobjectInterfaceHash.remove(hiObject);
+}
+
+/*
+ Removes all stored items.
+*/
+void QAccessibleHierarchyManager::reset()
+{
+ qDeleteAll(qobjectElementHash);
+ qobjectElementHash.clear();
+ hiobjectInterfaceHash.clear();
+ qobjectHiobjectHash.clear();
+}
+
+QAccessibleHierarchyManager *QAccessibleHierarchyManager::instance()
+{
+ return accessibleHierarchyManager();
+}
+
+#ifndef QT_MAC_USE_COCOA
+static bool isItemView(const QAInterface &interface)
+{
+ QObject *object = interface.object();
+ return (interface.role() == QAccessible::List || interface.role() == QAccessible::Table
+ || (object && qobject_cast<QAbstractItemView *>(interface.object()))
+ || (object && object->objectName() == QLatin1String("qt_scrollarea_viewport")
+ && qobject_cast<QAbstractItemView *>(object->parent())));
+}
+#endif
+
+static bool isTabWidget(const QAInterface &interface)
+{
+ if (QObject *object = interface.object())
+ return (object->inherits("QTabWidget") && interface.id() == 0);
+ return false;
+}
+
+static bool isStandaloneTabBar(const QAInterface &interface)
+{
+ QObject *object = interface.object();
+ if (interface.role() == QAccessible::PageTabList && object)
+ return (qobject_cast<QTabWidget *>(object->parent()) == 0);
+
+ return false;
+}
+
+static bool isEmbeddedTabBar(const QAInterface &interface)
+{
+ QObject *object = interface.object();
+ if (interface.role() == QAccessible::PageTabList && object)
+ return (qobject_cast<QTabWidget *>(object->parent()));
+
+ return false;
+}
+
+/*
+ Decides if a QAInterface is interesting from an accessibility users point of view.
+*/
+bool isItInteresting(const QAInterface &interface)
+{
+ // Mac accessibility does not have an attribute that corresponds to the Invisible/Offscreen
+ // state, so we disable the interface here.
+ const QAccessible::State state = interface.state();
+ if (state & QAccessible::Invisible ||
+ state & QAccessible::Offscreen )
+ return false;
+
+ const QAccessible::Role role = interface.role();
+
+ if (QObject * const object = interface.object()) {
+ const QString className = QLatin1String(object->metaObject()->className());
+
+ // VoiceOver focusing on tool tips can be confusing. The contents of the
+ // tool tip is avalible through the description attribute anyway, so
+ // we disable accessibility for tool tips.
+ if (className == QLatin1String("QTipLabel"))
+ return false;
+
+ // Hide TabBars that has a QTabWidget parent (the tab widget handles the accessibility)
+ if (isEmbeddedTabBar(interface))
+ return false;
+
+ // Hide docked dockwidgets. ### causes infinitie loop in the apple accessibility code.
+ /* if (QDockWidget *dockWidget = qobject_cast<QDockWidget *>(object)) {
+ if (dockWidget->isFloating() == false)
+ return false;
+ }
+ */
+ }
+
+ // Client is a generic role returned by plain QWidgets or other
+ // widgets that does not have separate QAccessible interface, such
+ // as the TabWidget. Return false unless macRole gives the interface
+ // a special role.
+ if (role == QAccessible::Client && macRole(interface) == CFStringRef(QAXUnknownRole))
+ return false;
+
+ // Some roles are not interesting:
+ if (role == QAccessible::Border || // QFrame
+ role == QAccessible::Application || // We use the system-provided application element.
+ role == QAccessible::MenuItem) // The system also provides the menu items.
+ return false;
+
+ // It is probably better to access the toolbar buttons directly than having
+ // to navigate through the toolbar.
+ if (role == QAccessible::ToolBar)
+ return false;
+
+ return true;
+}
+
+QAElement QAccessibleHierarchyManager::registerInterface(QObject *object, int child)
+{
+#ifndef QT_MAC_USE_COCOA
+ return registerInterface(QAInterface(QAccessible::queryAccessibleInterface(object), child));
+#else
+ Q_UNUSED(object);
+ Q_UNUSED(child);
+ return QAElement();
+#endif
+}
+
+/*
+ Creates a QAXUIelement that corresponds to the given QAInterface.
+*/
+QAElement QAccessibleHierarchyManager::registerInterface(const QAInterface &interface)
+{
+#ifndef QT_MAC_USE_COCOA
+ if (interface.isValid() == false)
+ return QAElement();
+ QAInterface objectInterface = interface.objectInterface();
+
+ QObject * qobject = objectInterface.object();
+ HIObjectRef hiobject = objectInterface.hiObject();
+ if (qobject == 0 || hiobject == 0)
+ return QAElement();
+
+ if (qobjectElementHash.contains(qobject) == false) {
+ registerInterface(qobject, hiobject, createFactory(interface));
+ HIObjectSetAccessibilityIgnored(hiobject, !isItInteresting(interface));
+ }
+
+ return QAElement(hiobject, interface.id());
+#else
+ Q_UNUSED(interface);
+ return QAElement();
+#endif
+}
+
+#ifndef QT_MAC_USE_COCOA
+#include "qaccessible_mac_carbon.cpp"
+#endif
+
+void QAccessibleHierarchyManager::registerInterface(QObject * qobject, HIObjectRef hiobject, QInterfaceFactory *interfaceFactory)
+{
+#ifndef QT_MAC_USE_COCOA
+ if (qobjectElementHash.contains(qobject) == false) {
+ qobjectElementHash.insert(qobject, interfaceFactory);
+ qobjectHiobjectHash.insert(qobject, hiobject);
+ connect(qobject, SIGNAL(destroyed(QObject *)), SLOT(objectDestroyed(QObject *)));
+ }
+
+ if (hiobjectInterfaceHash.contains(hiobject) == false) {
+ hiobjectInterfaceHash.insert(hiobject, interfaceFactory);
+ installAcessibilityEventHandler(hiobject);
+ }
+#else
+ Q_UNUSED(qobject);
+ Q_UNUSED(hiobject);
+ Q_UNUSED(interfaceFactory);
+#endif
+}
+
+void QAccessibleHierarchyManager::registerChildren(const QAInterface &interface)
+{
+ QObject * const object = interface.object();
+ if (object == 0)
+ return;
+
+ QInterfaceFactory *interfaceFactory = qobjectElementHash.value(object);
+
+ if (interfaceFactory == 0)
+ return;
+
+ interfaceFactory->registerChildren();
+}
+
+QAInterface QAccessibleHierarchyManager::lookup(const AXUIElementRef &element)
+{
+ if (element == 0)
+ return QAInterface();
+#ifndef QT_MAC_USE_COCOA
+ HIObjectRef hiObject = AXUIElementGetHIObject(element);
+
+ QInterfaceFactory *factory = hiobjectInterfaceHash.value(hiObject);
+ if (factory == 0) {
+ return QAInterface();
+ }
+
+ UInt64 id;
+ AXUIElementGetIdentifier(element, &id);
+ return factory->interface(id);
+#else
+ return QAInterface();
+#endif
+}
+
+QAInterface QAccessibleHierarchyManager::lookup(const QAElement &element)
+{
+ return lookup(element.element());
+}
+
+QAElement QAccessibleHierarchyManager::lookup(const QAInterface &interface)
+{
+ if (interface.isValid() == false)
+ return QAElement();
+
+ QInterfaceFactory *factory = qobjectElementHash.value(interface.objectInterface().object());
+ if (factory == 0)
+ return QAElement();
+
+ return factory->element(interface);
+}
+
+QAElement QAccessibleHierarchyManager::lookup(QObject * const object, int id)
+{
+ QInterfaceFactory *factory = qobjectElementHash.value(object);
+ if (factory == 0)
+ return QAElement();
+
+ return factory->element(id);
+}
+
+/*
+ Standard interface mapping, return the stored interface
+ or HIObjectRef, and there is an one-to-one mapping between
+ the identifier and child.
+*/
+class QStandardInterfaceFactory : public QInterfaceFactory
+{
+public:
+ QStandardInterfaceFactory(const QAInterface &interface)
+ : m_interface(interface), object(interface.hiObject())
+ {
+ CFRetain(object);
+ }
+
+ ~QStandardInterfaceFactory()
+ {
+ CFRelease(object);
+ }
+
+
+ QAInterface interface(UInt64 identifier)
+ {
+ const int child = identifier;
+ return QAInterface(m_interface, child);
+ }
+
+ QAElement element(int id)
+ {
+ return QAElement(object, id);
+ }
+
+ QAElement element(const QAInterface &interface)
+ {
+ if (interface.object() == 0)
+ return QAElement();
+ return QAElement(object, interface.id());
+ }
+
+ void registerChildren()
+ {
+ const int childCount = m_interface.childCount();
+ for (int i = 1; i <= childCount; ++i) {
+ accessibleHierarchyManager()->registerInterface(m_interface.navigate(QAccessible::Child, i));
+ }
+ }
+
+private:
+ QAInterface m_interface;
+ HIObjectRef object;
+};
+
+/*
+ Interface mapping where that creates one HIObject for each interface child.
+*/
+class QMultipleHIObjectFactory : public QInterfaceFactory
+{
+public:
+ QMultipleHIObjectFactory(const QAInterface &interface)
+ : m_interface(interface)
+ { }
+
+ ~QMultipleHIObjectFactory()
+ {
+ foreach (HIObjectRef object, objects) {
+ CFRelease(object);
+ }
+ }
+
+ QAInterface interface(UInt64 identifier)
+ {
+ const int child = identifier;
+ return QAInterface(m_interface, child);
+ }
+
+ QAElement element(int child)
+ {
+ if (child == 0)
+ return QAElement(m_interface.hiObject(), 0);
+
+ if (child > objects.count())
+ return QAElement();
+
+ return QAElement(objects.at(child - 1), child);
+ }
+
+ void registerChildren()
+ {
+#ifndef QT_MAC_USE_COCOA
+ const int childCount = m_interface.childCount();
+ for (int i = 1; i <= childCount; ++i) {
+ HIObjectRef hiobject;
+ HIObjectCreate(kObjectQtAccessibility, 0, &hiobject);
+ objects.append(hiobject);
+ accessibleHierarchyManager()->registerInterface(m_interface.object(), hiobject, this);
+ HIObjectSetAccessibilityIgnored(hiobject, !isItInteresting(m_interface.navigate(QAccessible::Child, i)));
+ }
+#endif
+ }
+
+private:
+ QAInterface m_interface;
+ QList<HIObjectRef> objects;
+};
+
+class QItemViewInterfaceFactory : public QInterfaceFactory
+{
+public:
+ QItemViewInterfaceFactory(const QAInterface &interface)
+ : m_interface(interface), object(interface.hiObject())
+ {
+ CFRetain(object);
+ columnCount = 0;
+ if (QTableView * tableView = qobject_cast<QTableView *>(interface.parent().object())) {
+ if (tableView->model())
+ columnCount = tableView->model()->columnCount();
+ if (tableView->verticalHeader())
+ ++columnCount;
+ }
+ }
+
+ ~QItemViewInterfaceFactory()
+ {
+ CFRelease(object);
+ }
+
+ QAInterface interface(UInt64 identifier)
+ {
+ if (identifier == 0)
+ return m_interface;
+
+ if (m_interface.role() == QAccessible::List)
+ return m_interface.childAt(identifier);
+
+ if (m_interface.role() == QAccessible::Table) {
+ const int index = identifier;
+ if (index == 0)
+ return m_interface; // return the item view interface.
+
+ const int rowIndex = (index - 1) / (columnCount + 1);
+ const int cellIndex = (index - 1) % (columnCount + 1);
+/*
+ qDebug() << "index" << index;
+ qDebug() << "rowIndex" << rowIndex;
+ qDebug() << "cellIndex" << cellIndex;
+*/
+ const QAInterface rowInterface = m_interface.childAt(rowIndex + 1);
+
+ if ((cellIndex) == 0) // Is it a row?
+ return rowInterface;
+ else {
+ return rowInterface.childAt(cellIndex);
+ }
+ }
+
+ return QAInterface();
+ }
+
+ QAElement element(int id)
+ {
+ if (id != 0) {
+ return QAElement();
+ }
+ return QAElement(object, 0);
+ }
+
+ QAElement element(const QAInterface &interface)
+ {
+ if (interface.object() && interface.object() == m_interface.object()) {
+ return QAElement(object, 0);
+ } else if (m_interface.role() == QAccessible::List) {
+ if (interface.parent().object() && interface.parent().object() == m_interface.object())
+ return QAElement(object, m_interface.indexOfChild(interface));
+ } else if (m_interface.role() == QAccessible::Table) {
+ QAInterface currentInterface = interface;
+ int index = 0;
+
+ while (currentInterface.isValid() && currentInterface.object() == 0) {
+ const QAInterface parentInterface = currentInterface.parent();
+/*
+ qDebug() << "current index" << index;
+ qDebug() << "current interface" << interface;
+
+ qDebug() << "parent interface" << parentInterface;
+ qDebug() << "grandparent interface" << parentInterface.parent();
+ qDebug() << "childCount" << interface.childCount();
+ qDebug() << "index of child" << parentInterface.indexOfChild(currentInterface);
+*/
+ index += ((parentInterface.indexOfChild(currentInterface) - 1) * (currentInterface.childCount() + 1)) + 1;
+ currentInterface = parentInterface;
+// qDebug() << "new current interface" << currentInterface;
+ }
+ if (currentInterface.object() == m_interface.object())
+ return QAElement(object, index);
+
+
+ }
+ return QAElement();
+ }
+
+ void registerChildren()
+ {
+ // Item view child interfraces don't have their own qobjects, so there is nothing to register here.
+ }
+
+private:
+ QAInterface m_interface;
+ HIObjectRef object;
+ int columnCount; // for table views;
+};
+
+#ifndef QT_MAC_USE_COCOA
+static bool managesChildren(const QAInterface &interface)
+{
+ return (interface.childCount() > 0 && interface.childAt(1).id() > 0);
+}
+
+static QInterfaceFactory *createFactory(const QAInterface &interface)
+{
+ if (isItemView(interface)) {
+ return new QItemViewInterfaceFactory(interface);
+ } if (managesChildren(interface)) {
+ return new QMultipleHIObjectFactory(interface);
+ }
+
+ return new QStandardInterfaceFactory(interface);
+}
+#endif
+
+QList<QAElement> lookup(const QList<QAInterface> &interfaces)
+{
+ QList<QAElement> elements;
+ foreach (const QAInterface &interface, interfaces)
+ if (interface.isValid()) {
+ const QAElement element = accessibleHierarchyManager()->lookup(interface);
+ if (element.isValid())
+ elements.append(element);
+ }
+ return elements;
+}
+
+// Debug output helpers:
+/*
+static QString nameForEventKind(UInt32 kind)
+{
+ switch(kind) {
+ case kEventAccessibleGetChildAtPoint: return QString("GetChildAtPoint"); break;
+ case kEventAccessibleGetAllAttributeNames: return QString("GetAllAttributeNames"); break;
+ case kEventAccessibleGetNamedAttribute: return QString("GetNamedAttribute"); break;
+ case kEventAccessibleSetNamedAttribute: return QString("SetNamedAttribute"); break;
+ case kEventAccessibleGetAllActionNames: return QString("GetAllActionNames"); break;
+ case kEventAccessibleGetFocusedChild: return QString("GetFocusedChild"); break;
+ default:
+ return QString("Unknown accessibility event type: %1").arg(kind);
+ break;
+ };
+}
+*/
+#ifndef QT_MAC_USE_COCOA
+static bool qt_mac_append_cf_uniq(CFMutableArrayRef array, CFTypeRef value)
+{
+ if (value == 0)
+ return false;
+
+ CFRange range;
+ range.location = 0;
+ range.length = CFArrayGetCount(array);
+ if(!CFArrayContainsValue(array, range, value)) {
+ CFArrayAppendValue(array, value);
+ return true;
+ }
+ return false;
+}
+
+static OSStatus setAttributeValue(EventRef event, const QList<QAElement> &elements)
+{
+ CFMutableArrayRef array = CFArrayCreateMutable(0, 0, &kCFTypeArrayCallBacks);
+ foreach (const QAElement &element, elements) {
+ if (element.isValid())
+ CFArrayAppendValue(array, element.element());
+ }
+
+ const OSStatus err = SetEventParameter(event, kEventParamAccessibleAttributeValue,
+ typeCFTypeRef, sizeof(array), &array);
+ CFRelease(array);
+ return err;
+}
+#endif //QT_MAC_USE_COCOA
+
+/*
+ Gets the AccessibleObject parameter from an event.
+*/
+static inline AXUIElementRef getAccessibleObjectParameter(EventRef event)
+{
+ AXUIElementRef element;
+ GetEventParameter(event, kEventParamAccessibleObject, typeCFTypeRef, 0,
+ sizeof(element), 0, &element);
+ return element;
+}
+
+/*
+ The application event handler makes sure that all top-level qt windows are registered
+ before any accessibility events are handeled.
+*/
+#ifndef QT_MAC_USE_COCOA
+static OSStatus applicationEventHandler(EventHandlerCallRef next_ref, EventRef event, void *)
+{
+ QAInterface rootInterface(QAccessible::queryAccessibleInterface(rootObject ? rootObject : qApp), 0);
+ accessibleHierarchyManager()->registerChildren(rootInterface);
+
+ return CallNextEventHandler(next_ref, event);
+}
+
+/*
+ Returns the value for element by combining the QAccessibility::Checked and
+ QAccessibility::Mixed flags into an int value that the Mac accessibilty
+ system understands. This works for check boxes, radio buttons, and the like.
+ The return values are:
+ 0: unchecked
+ 1: checked
+ 2: undecided
+*/
+static int buttonValue(QAInterface element)
+{
+ const QAccessible::State state = element.state();
+ if (state & QAccessible::Mixed)
+ return 2;
+ else if(state & QAccessible::Checked)
+ return 1;
+ else
+ return 0;
+}
+
+static QString getValue(const QAInterface &interface)
+{
+ const QAccessible::Role role = interface.role();
+ if (role == QAccessible::RadioButton || role == QAccessible::CheckBox)
+ return QString::number(buttonValue(interface));
+ else
+ return interface.text(QAccessible::Value);
+}
+#endif //QT_MAC_USE_COCOA
+
+/*
+ Translates a QAccessible::Role into a mac accessibility role.
+*/
+static CFStringRef macRole(const QAInterface &interface)
+{
+ const QAccessible::Role qtRole = interface.role();
+
+// qDebug() << "role for" << interface.object() << "interface role" << hex << qtRole;
+
+ // Qt accessibility: QAccessible::Splitter contains QAccessible::Grip.
+ // Mac accessibility: AXSplitGroup contains AXSplitter.
+ if (qtRole == QAccessible::Grip) {
+ const QAInterface parent = interface.parent();
+ if (parent.isValid() && parent.role() == QAccessible::Splitter)
+ return CFStringRef(QAXSplitterRole);
+ }
+
+ // Tab widgets and standalone tab bars get the kAXTabGroupRole. Accessibility
+ // for tab bars emebedded in a tab widget is handled by the tab widget.
+ if (isTabWidget(interface) || isStandaloneTabBar(interface))
+ return kAXTabGroupRole;
+
+ if (QObject *object = interface.object()) {
+ // ### The interface for an abstract scroll area returns the generic "Client"
+ // role, so we have to to an extra detect on the QObject here.
+ if (object->inherits("QAbstractScrollArea") && interface.id() == 0)
+ return CFStringRef(QAXScrollAreaRole);
+
+ if (object->inherits("QDockWidget"))
+ return CFStringRef(QAXUnknownRole);
+ }
+
+ int i = 0;
+ int testRole = text_bindings[i][0].qt;
+ while (testRole != -1) {
+ if (testRole == qtRole)
+ return CFStringRef(text_bindings[i][0].mac);
+ ++i;
+ testRole = text_bindings[i][0].qt;
+ }
+
+// qDebug() << "got unknown role!" << interface << interface.parent();
+
+ return CFStringRef(QAXUnknownRole);
+}
+
+/*
+ Translates a QAccessible::Role and an attribute name into a QAccessible::Text, taking into
+ account execptions listed in text_bindings.
+*/
+#ifndef QT_MAC_USE_COCOA
+static int textForRoleAndAttribute(QAccessible::Role role, CFStringRef attribute)
+{
+ // Search for exception, return it if found.
+ int testRole = text_bindings[0][0].qt;
+ int i = 0;
+ while (testRole != -1) {
+ if (testRole == role) {
+ int j = 1;
+ int qtRole = text_bindings[i][j].qt;
+ CFStringRef testAttribute = CFStringRef(text_bindings[i][j].mac);
+ while (qtRole != -1) {
+ if (CFStringCompare(attribute, testAttribute, 0) == kCFCompareEqualTo) {
+ return (QAccessible::Text)qtRole;
+ }
+ ++j;
+ testAttribute = CFStringRef(text_bindings[i][j].mac); /// ### custom compare
+ qtRole = text_bindings[i][j].qt; /// ### custom compare
+ }
+ break;
+ }
+ ++i;
+ testRole = text_bindings[i][0].qt;
+ }
+
+ // Return default mappping
+ if (CFStringCompare(attribute, CFStringRef(QAXTitleAttribute), 0) == kCFCompareEqualTo)
+ return QAccessible::Name;
+ else if (CFStringCompare(attribute, CFStringRef(QAXValueAttribute), 0) == kCFCompareEqualTo)
+ return QAccessible::Value;
+ else if (CFStringCompare(attribute, CFStringRef(QAXHelpAttribute), 0) == kCFCompareEqualTo)
+ return QAccessible::Help;
+ else if (CFStringCompare(attribute, CFStringRef(QAXDescriptionAttribute), 0) == kCFCompareEqualTo)
+ return QAccessible::Description;
+ else
+ return -1;
+}
+
+/*
+ Returns the subrole string constant for the interface if it has one,
+ else returns an empty string.
+*/
+static QCFString subrole(const QAInterface &interface)
+{
+ const QAInterface parent = interface.parent();
+ if (parent.isValid() == false)
+ return QCFString();
+
+ if (parent.role() == QAccessible::ScrollBar) {
+ QCFString subrole;
+ switch(interface.id()) {
+ case 1: subrole = CFStringRef(QAXDecrementArrowSubrole); break;
+ case 2: subrole = CFStringRef(QAXDecrementPageSubrole); break;
+ case 4: subrole = CFStringRef(QAXIncrementPageSubrole); break;
+ case 5: subrole = CFStringRef(QAXIncrementArrowSubrole); break;
+ default:
+ break;
+ }
+ return subrole;
+ }
+ return QCFString();
+}
+
+// Gets the scroll bar orientation by asking the QAbstractSlider object directly.
+static Qt::Orientation scrollBarOrientation(const QAInterface &scrollBar)
+{
+ QObject *const object = scrollBar.object();
+ if (QAbstractSlider * const sliderObject = qobject_cast<QAbstractSlider * const>(object))
+ return sliderObject->orientation();
+
+ return Qt::Vertical; // D'oh! The interface wasn't a scroll bar.
+}
+
+static QAInterface scrollAreaGetScrollBarInterface(const QAInterface &scrollArea, Qt::Orientation orientation)
+{
+ if (macRole(scrollArea) != CFStringRef(CFStringRef(QAXScrollAreaRole)))
+ return QAInterface();
+
+ // Child 1 is the contents widget, 2 and 3 are the scroll bar containers wich contains possible scroll bars.
+ for (int i = 2; i <= 3; ++i) {
+ QAInterface scrollBarContainer = scrollArea.childAt(i);
+ for (int i = 1; i <= scrollBarContainer.childCount(); ++i) {
+ QAInterface scrollBar = scrollBarContainer.childAt(i);
+ if (scrollBar.isValid() &&
+ scrollBar.role() == QAccessible::ScrollBar &&
+ scrollBarOrientation(scrollBar) == orientation)
+ return scrollBar;
+ }
+ }
+
+ return QAInterface();
+}
+
+static bool scrollAreaHasScrollBar(const QAInterface &scrollArea, Qt::Orientation orientation)
+{
+ return scrollAreaGetScrollBarInterface(scrollArea, orientation).isValid();
+}
+
+static QAElement scrollAreaGetScrollBar(const QAInterface &scrollArea, Qt::Orientation orientation)
+{
+ return accessibleHierarchyManager()->lookup(scrollAreaGetScrollBarInterface(scrollArea, orientation));
+}
+
+static QAElement scrollAreaGetContents(const QAInterface &scrollArea)
+{
+ // Child 1 is the contents widget,
+ return accessibleHierarchyManager()->lookup(scrollArea.navigate(QAccessible::Child, 1));
+}
+
+static QAElement tabWidgetGetContents(const QAInterface &interface)
+{
+ // A kAXTabGroup has a kAXContents attribute, which consists of the
+ // ui elements for the current tab page. Get the current tab page
+ // from the QStackedWidget, where the current visible page can
+ // be found at index 1.
+ QAInterface stackedWidget = interface.childAt(1);
+ accessibleHierarchyManager()->registerChildren(stackedWidget);
+ QAInterface tabPageInterface = stackedWidget.childAt(1);
+ return accessibleHierarchyManager()->lookup(tabPageInterface);
+}
+
+static QList<QAElement> tabBarGetTabs(const QAInterface &interface)
+{
+ // Get the tabs by searching for children with the "PageTab" role.
+ // This filters out the left/right navigation buttons.
+ accessibleHierarchyManager()->registerChildren(interface);
+ QList<QAElement> tabs;
+ const int numChildren = interface.childCount();
+ for (int i = 1; i < numChildren + 1; ++i) {
+ QAInterface child = interface.navigate(QAccessible::Child, i);
+ if (child.isValid() && child.role() == QAccessible::PageTab) {
+ tabs.append(accessibleHierarchyManager()->lookup(child));
+ }
+ }
+ return tabs;
+}
+
+static QList<QAElement> tabWidgetGetTabs(const QAInterface &interface)
+{
+ // Each QTabWidget has two children, a QStackedWidget and a QTabBar.
+ // Get the tabs from the QTabBar.
+ return tabBarGetTabs(interface.childAt(2));
+}
+
+static QList<QAElement> tabWidgetGetChildren(const QAInterface &interface)
+{
+ // The children for a kAXTabGroup should consist of the tabs and the
+ // contents of the current open tab page.
+ QList<QAElement> children = tabWidgetGetTabs(interface);
+ children += tabWidgetGetContents(interface);
+ return children;
+}
+#endif //QT_MAC_USE_COCOA
+
+/*
+ Returns the label (buddy) interface for interface, or 0 if it has none.
+*/
+/*
+static QAInterface findLabel(const QAInterface &interface)
+{
+ return interface.navigate(QAccessible::Label, 1);
+}
+*/
+/*
+ Returns a list of interfaces this interface labels, or an empty list if it doesn't label any.
+*/
+/*
+static QList<QAInterface> findLabelled(const QAInterface &interface)
+{
+ QList<QAInterface> interfaceList;
+
+ int count = 1;
+ const QAInterface labelled = interface.navigate(QAccessible::Labelled, count);
+ while (labelled.isValid()) {
+ interfaceList.append(labelled);
+ ++count;
+ }
+ return interfaceList;
+}
+*/
+/*
+ Tests if the given QAInterface has data for a mac attribute.
+*/
+#ifndef QT_MAC_USE_COCOA
+static bool supportsAttribute(CFStringRef attribute, const QAInterface &interface)
+{
+ const int text = textForRoleAndAttribute(interface.role(), attribute);
+
+ // Special case: Static texts don't have a title.
+ if (interface.role() == QAccessible::StaticText && attribute == CFStringRef(QAXTitleAttribute))
+ return false;
+
+ // Return true if we the attribute matched a QAccessible::Role and we get text for that role from the interface.
+ if (text != -1) {
+ if (text == QAccessible::Value) // Special case for Value, see getValue()
+ return !getValue(interface).isEmpty();
+ else
+ return !interface.text((QAccessible::Text)text).isEmpty();
+ }
+
+ if (CFStringCompare(attribute, CFStringRef(QAXChildrenAttribute), 0) == kCFCompareEqualTo) {
+ if (interface.childCount() > 0)
+ return true;
+ }
+
+ if (CFStringCompare(attribute, CFStringRef(QAXSubroleAttribute), 0) == kCFCompareEqualTo) {
+ return (subrole(interface) != QCFString());
+ }
+
+ return false;
+}
+
+static void appendIfSupported(CFMutableArrayRef array, CFStringRef attribute, const QAInterface &interface)
+{
+ if (supportsAttribute(attribute, interface))
+ qt_mac_append_cf_uniq(array, attribute);
+}
+
+/*
+ Returns the names of the attributes the give QAInterface supports.
+*/
+static OSStatus getAllAttributeNames(EventRef event, const QAInterface &interface, EventHandlerCallRef next_ref)
+{
+ // Call system event handler.
+ OSStatus err = CallNextEventHandler(next_ref, event);
+ if(err != noErr && err != eventNotHandledErr)
+ return err;
+ CFMutableArrayRef attrs = 0;
+ GetEventParameter(event, kEventParamAccessibleAttributeNames, typeCFMutableArrayRef, 0,
+ sizeof(attrs), 0, &attrs);
+
+ if (!attrs)
+ return eventNotHandledErr;
+
+ // Append attribute names that are always supported.
+ qt_mac_append_cf_uniq(attrs, CFStringRef(QAXPositionAttribute));
+ qt_mac_append_cf_uniq(attrs, CFStringRef(QAXSizeAttribute));
+ qt_mac_append_cf_uniq(attrs, CFStringRef(QAXRoleAttribute));
+ qt_mac_append_cf_uniq(attrs, CFStringRef(QAXEnabledAttribute));
+ qt_mac_append_cf_uniq(attrs, CFStringRef(QAXWindowAttribute));
+ qt_mac_append_cf_uniq(attrs, CFStringRef(QAXTopLevelUIElementAttribute));
+
+ // Append these names if the QInterafceItem returns any data for them.
+ appendIfSupported(attrs, CFStringRef(QAXTitleAttribute), interface);
+ appendIfSupported(attrs, CFStringRef(QAXValueAttribute), interface);
+ appendIfSupported(attrs, CFStringRef(QAXDescriptionAttribute), interface);
+ appendIfSupported(attrs, CFStringRef(QAXLinkedUIElementsAttribute), interface);
+ appendIfSupported(attrs, CFStringRef(QAXHelpAttribute), interface);
+ appendIfSupported(attrs, CFStringRef(QAXTitleUIElementAttribute), interface);
+ appendIfSupported(attrs, CFStringRef(QAXChildrenAttribute), interface);
+ appendIfSupported(attrs, CFStringRef(QAXSubroleAttribute), interface);
+
+ // Append attribute names based on the interaface role.
+ switch (interface.role()) {
+ case QAccessible::Window:
+ qt_mac_append_cf_uniq(attrs, CFStringRef(QAXMainAttribute));
+ qt_mac_append_cf_uniq(attrs, CFStringRef(QAXMinimizedAttribute));
+ qt_mac_append_cf_uniq(attrs, CFStringRef(QAXCloseButtonAttribute));
+ qt_mac_append_cf_uniq(attrs, CFStringRef(QAXZoomButtonAttribute));
+ qt_mac_append_cf_uniq(attrs, CFStringRef(QAXMinimizeButtonAttribute));
+ qt_mac_append_cf_uniq(attrs, CFStringRef(QAXToolbarButtonAttribute));
+ qt_mac_append_cf_uniq(attrs, CFStringRef(QAXGrowAreaAttribute));
+ break;
+ case QAccessible::RadioButton:
+ case QAccessible::CheckBox:
+ qt_mac_append_cf_uniq(attrs, CFStringRef(QAXMinValueAttribute));
+ qt_mac_append_cf_uniq(attrs, CFStringRef(QAXMaxValueAttribute));
+ break;
+ case QAccessible::ScrollBar:
+ qt_mac_append_cf_uniq(attrs, CFStringRef(QAXOrientationAttribute));
+ break;
+ case QAccessible::Splitter:
+ qt_mac_append_cf_uniq(attrs, CFStringRef(QAXSplittersAttribute));
+ break;
+ case QAccessible::Table:
+ qt_mac_append_cf_uniq(attrs, CFStringRef(QAXRowsAttribute));
+ qt_mac_append_cf_uniq(attrs, CFStringRef(QAXVisibleRowsAttribute));
+ qt_mac_append_cf_uniq(attrs, CFStringRef(QAXSelectedRowsAttribute));
+ break;
+ default:
+ break;
+ }
+
+ // Append attribute names based on the mac accessibility role.
+ const QCFString mac_role = macRole(interface);
+ if (mac_role == CFStringRef(QAXSplitterRole)) {
+ qt_mac_append_cf_uniq(attrs, CFStringRef(QAXPreviousContentsAttribute));
+ qt_mac_append_cf_uniq(attrs, CFStringRef(QAXNextContentsAttribute));
+ qt_mac_append_cf_uniq(attrs, CFStringRef(QAXOrientationAttribute));
+ } else if (mac_role == CFStringRef(QAXScrollAreaRole)) {
+ if (scrollAreaHasScrollBar(interface, Qt::Horizontal))
+ qt_mac_append_cf_uniq(attrs, CFStringRef(QAXHorizontalScrollBarAttribute));
+ if (scrollAreaHasScrollBar(interface, Qt::Vertical))
+ qt_mac_append_cf_uniq(attrs, CFStringRef(QAXVerticalScrollBarAttribute));
+ qt_mac_append_cf_uniq(attrs, CFStringRef(QAXContentsAttribute));
+ } else if (mac_role == CFStringRef(QAXTabGroupRole)) {
+ qt_mac_append_cf_uniq(attrs, CFStringRef(QAXTabsAttribute));
+ // Only tab widgets can have the contents attribute, there is no way of getting
+ // the contents from a QTabBar.
+ if (isTabWidget(interface))
+ qt_mac_append_cf_uniq(attrs, CFStringRef(QAXContentsAttribute));
+ }
+
+ return noErr;
+}
+
+static void handleStringAttribute(EventRef event, QAccessible::Text text, const QAInterface &interface)
+{
+ QString str = interface.text(text);
+ if (str.isEmpty())
+ return;
+
+ // Remove any html markup from the text string, or VoiceOver will read the html tags.
+ static QTextDocument document;
+ document.setHtml(str);
+ str = document.toPlainText();
+
+ CFStringRef cfstr = QCFString::toCFStringRef(str);
+ SetEventParameter(event, kEventParamAccessibleAttributeValue, typeCFStringRef, sizeof(cfstr), &cfstr);
+}
+
+/*
+ Handles the parent attribute for a interface.
+ There are basically three cases here:
+ 1. interface is a HIView and has only HIView children.
+ 2. interface is a HIView but has children that is not a HIView
+ 3. interface is not a HIView.
+*/
+static OSStatus handleChildrenAttribute(EventHandlerCallRef next_ref, EventRef event, QAInterface &interface)
+{
+ // Add the children for this interface to the global QAccessibelHierachyManager.
+ accessibleHierarchyManager()->registerChildren(interface);
+
+ if (isTabWidget(interface)) {
+ QList<QAElement> children = tabWidgetGetChildren(interface);
+ const int childCount = children.count();
+
+ CFMutableArrayRef array = 0;
+ array = CFArrayCreateMutable(0, 0, &kCFTypeArrayCallBacks);
+ for (int i = 0; i < childCount; ++i) {
+ qt_mac_append_cf_uniq(array, children.at(i).element());
+ }
+
+ OSStatus err;
+ err = SetEventParameter(event, kEventParamAccessibleAttributeValue, typeCFArrayRef, sizeof(array), &array);
+ if (err != noErr)
+ qWarning("Qt:Internal error (%s:%d)", __FILE__, __LINE__);
+
+ return noErr;
+ }
+
+ const QList<QAElement> children = lookup(interface.children());
+ const int childCount = children.count();
+
+ OSStatus err = eventNotHandledErr;
+ if (interface.isHIView())
+ err = CallNextEventHandler(next_ref, event);
+
+ CFMutableArrayRef array = 0;
+ int arraySize = 0;
+ if (err == noErr) {
+ CFTypeRef obj = 0;
+ err = GetEventParameter(event, kEventParamAccessibleAttributeValue, typeCFTypeRef, NULL , sizeof(obj), NULL, &obj);
+ if (err == noErr && obj != 0) {
+ array = (CFMutableArrayRef)obj;
+ arraySize = CFArrayGetCount(array);
+ }
+ }
+
+ if (array) {
+ CFArrayRemoveAllValues(array);
+ for (int i = 0; i < childCount; ++i) {
+ qt_mac_append_cf_uniq(array, children.at(i).element());
+ }
+ } else {
+ array = CFArrayCreateMutable(0, 0, &kCFTypeArrayCallBacks);
+ for (int i = 0; i < childCount; ++i) {
+ qt_mac_append_cf_uniq(array, children.at(i).element());
+ }
+
+ err = SetEventParameter(event, kEventParamAccessibleAttributeValue, typeCFArrayRef, sizeof(array), &array);
+ if (err != noErr)
+ qWarning("Qt:Internal error (%s:%d)", __FILE__, __LINE__);
+ }
+
+ return noErr;
+}
+
+/*
+
+*/
+static OSStatus handleParentAttribute(EventHandlerCallRef next_ref, EventRef event, const QAInterface &interface)
+{
+ OSStatus err = eventNotHandledErr;
+ if (interface.isHIView()) {
+ err = CallNextEventHandler(next_ref, event);
+ }
+ if (err == noErr)
+ return err;
+
+ const QAInterface parentInterface = interface.navigate(QAccessible::Ancestor, 1);
+ const QAElement parentElement = accessibleHierarchyManager()->lookup(parentInterface);
+
+ if (parentElement.isValid() == false)
+ return eventNotHandledErr;
+
+ AXUIElementRef elementRef = parentElement.element();
+ SetEventParameter(event, kEventParamAccessibleAttributeValue, typeCFTypeRef, sizeof(elementRef), &elementRef);
+ return noErr;
+}
+#endif
+
+struct IsWindowTest
+{
+ static inline bool test(const QAInterface &interface)
+ {
+ return (interface.role() == QAccessible::Window);
+ }
+};
+
+struct IsWindowAndNotDrawerOrSheetTest
+{
+ static inline bool test(const QAInterface &interface)
+ {
+ QWidget * const widget = qobject_cast<QWidget*>(interface.object());
+ return (interface.role() == QAccessible::Window &&
+ widget && widget->isWindow() &&
+ !qt_mac_is_macdrawer(widget) &&
+ !qt_mac_is_macsheet(widget));
+ }
+};
+
+/*
+ Navigates up the iterfaces ancestor hierachy until a QAccessibleInterface that
+ passes the Test is found. If we reach a interface that is a HIView we stop the
+ search and call AXUIElementCopyAttributeValue.
+*/
+template <typename TestType>
+OSStatus navigateAncestors(EventHandlerCallRef next_ref, EventRef event, const QAInterface &interface, CFStringRef attribute)
+{
+ if (interface.isHIView())
+ return CallNextEventHandler(next_ref, event);
+
+ QAInterface current = interface;
+ QAElement element;
+ while (current.isValid()) {
+ if (TestType::test(interface)) {
+ element = accessibleHierarchyManager()->lookup(current);
+ break;
+ }
+
+ // If we reach an InterfaceItem that is a HiView we can hand of the search to
+ // the system event handler. This is the common case.
+ if (current.isHIView()) {
+ CFTypeRef value = 0;
+ const QAElement currentElement = accessibleHierarchyManager()->lookup(current);
+ AXError err = AXUIElementCopyAttributeValue(currentElement.element(), attribute, &value);
+ AXUIElementRef newElement = (AXUIElementRef)value;
+
+ if (err == noErr)
+ element = QAElement(newElement);
+
+ if (newElement != 0)
+ CFRelease(newElement);
+ break;
+ }
+
+ QAInterface next = current.parent();
+ if (next.isValid() == false)
+ break;
+ if (next == current)
+ break;
+ current = next;
+ }
+
+ if (element.isValid() == false)
+ return eventNotHandledErr;
+
+
+ AXUIElementRef elementRef = element.element();
+ SetEventParameter(event, kEventParamAccessibleAttributeValue, typeCFTypeRef,
+ sizeof(elementRef), &elementRef);
+ return noErr;
+}
+
+/*
+ Returns the top-level window for an interface, which is the closest ancestor interface that
+ has the Window role, but is not a sheet or a drawer.
+*/
+#ifndef QT_MAC_USE_COCOA
+static OSStatus handleWindowAttribute(EventHandlerCallRef next_ref, EventRef event, const QAInterface &interface)
+{
+ return navigateAncestors<IsWindowAndNotDrawerOrSheetTest>(next_ref, event, interface, CFStringRef(QAXWindowAttribute));
+}
+
+/*
+ Returns the top-level window for an interface, which is the closest ancestor interface that
+ has the Window role. (Can also be a sheet or a drawer)
+*/
+static OSStatus handleTopLevelUIElementAttribute(EventHandlerCallRef next_ref, EventRef event, const QAInterface &interface)
+{
+ return navigateAncestors<IsWindowTest>(next_ref, event, interface, CFStringRef(QAXTopLevelUIElementAttribute));
+}
+
+/*
+ Returns the tab buttons for an interface.
+*/
+static OSStatus handleTabsAttribute(EventHandlerCallRef next_ref, EventRef event, QAInterface &interface)
+{
+ Q_UNUSED(next_ref);
+ if (isTabWidget(interface))
+ return setAttributeValue(event, tabWidgetGetTabs(interface));
+ else
+ return setAttributeValue(event, tabBarGetTabs(interface));
+}
+
+static OSStatus handlePositionAttribute(EventHandlerCallRef, EventRef event, const QAInterface &interface)
+{
+ QPoint qpoint(interface.rect().topLeft());
+ HIPoint point;
+ point.x = qpoint.x();
+ point.y = qpoint.y();
+ SetEventParameter(event, kEventParamAccessibleAttributeValue, typeHIPoint, sizeof(point), &point);
+ return noErr;
+}
+
+static OSStatus handleSizeAttribute(EventHandlerCallRef, EventRef event, const QAInterface &interface)
+{
+ QSize qSize(interface.rect().size());
+ HISize size;
+ size.width = qSize.width();
+ size.height = qSize.height();
+ SetEventParameter(event, kEventParamAccessibleAttributeValue, typeHISize, sizeof(size), &size);
+ return noErr;
+}
+
+static OSStatus handleSubroleAttribute(EventHandlerCallRef, EventRef event, const QAInterface &interface)
+{
+ const QCFString role = subrole(interface);
+ CFStringRef rolestr = (CFStringRef)role;
+ SetEventParameter(event, kEventParamAccessibleAttributeValue, typeCFTypeRef, sizeof(rolestr), &rolestr);
+ return noErr;
+}
+
+static OSStatus handleOrientationAttribute(EventHandlerCallRef next_ref, EventRef event, const QAInterface &interface)
+{
+ QObject *const object = interface.object();
+ Qt::Orientation orientation;
+ if (interface.role() == QAccessible::ScrollBar) {
+ orientation = scrollBarOrientation(interface);
+ } else if (QSplitterHandle * const splitter = qobject_cast<QSplitterHandle * const>(object)) {
+ // Qt reports the layout orientation, but we want the splitter handle orientation.
+ orientation = (splitter->orientation() == Qt::Horizontal) ? Qt::Vertical : Qt::Horizontal;
+ } else {
+ return CallNextEventHandler(next_ref, event);
+ }
+ const CFStringRef orientationString = (orientation == Qt::Vertical)
+ ? CFStringRef(QAXVerticalOrientationValue) : CFStringRef(QAXHorizontalOrientationValue);
+ SetEventParameter(event, kEventParamAccessibleAttributeValue, typeCFStringRef, sizeof(orientationString), &orientationString);
+ return noErr;
+}
+
+/*
+ Figures out the next or previous contents for a splitter.
+*/
+static OSStatus handleSplitterContentsAttribute(EventHandlerCallRef next_ref, EventRef event, const QAInterface &interface, QCFString nextOrPrev)
+{
+ if (interface.isValid() == false || interface.role() != QAccessible::Grip)
+ return eventNotHandledErr;
+
+ const QAInterface parent = interface.parent();
+ if (parent.isValid() == false)
+ return CallNextEventHandler(next_ref, event);
+
+ if (parent.role() != QAccessible::Splitter)
+ return CallNextEventHandler(next_ref, event);
+
+ const QSplitter * const splitter = qobject_cast<const QSplitter * const>(parent.object());
+ if (splitter == 0)
+ return CallNextEventHandler(next_ref, event);
+
+ QWidget * const splitterHandle = qobject_cast<QWidget * const>(interface.object());
+ const int splitterHandleIndex = splitter->indexOf(splitterHandle);
+ const int widgetIndex = (nextOrPrev == QCFString(CFStringRef(QAXPreviousContentsAttribute))) ? splitterHandleIndex - 1 : splitterHandleIndex;
+ const QAElement contentsElement = accessibleHierarchyManager()->lookup(splitter->widget(widgetIndex), 0);
+ return setAttributeValue(event, QList<QAElement>() << contentsElement);
+}
+
+/*
+ Creates a list of all splitter handles the splitter contains.
+*/
+static OSStatus handleSplittersAttribute(EventHandlerCallRef next_ref, EventRef event, QAInterface &interface)
+{
+ const QSplitter * const splitter = qobject_cast<const QSplitter * const>(interface.object());
+ if (splitter == 0)
+ return CallNextEventHandler(next_ref, event);
+
+ accessibleHierarchyManager()->registerChildren(interface);
+
+ QList<QAElement> handles;
+ const int visibleSplitterCount = splitter->count() -1; // skip first handle, it's always invisible.
+ for (int i = 0; i < visibleSplitterCount; ++i)
+ handles.append(accessibleHierarchyManager()->lookup(splitter->handle(i + 1), 0));
+
+ return setAttributeValue(event, handles);
+}
+
+// This handler gets the scroll bars for a scroll area
+static OSStatus handleScrollBarAttribute(EventHandlerCallRef next_ref, EventRef event, QAInterface &scrollArea, Qt::Orientation orientation)
+{
+ QAElement scrollBar = scrollAreaGetScrollBar(scrollArea, orientation);
+ if (scrollBar.isValid() == false)
+ return CallNextEventHandler(next_ref, event);
+
+ AXUIElementRef elementRef = scrollBar.element();
+ SetEventParameter(event, kEventParamAccessibleAttributeValue, typeCFTypeRef, sizeof(elementRef), &elementRef);
+ return noErr;
+}
+
+// This handler gets the contents for a scroll area or tab widget.
+static OSStatus handleContentsAttribute(EventHandlerCallRef next_ref, EventRef event, QAInterface &interface)
+{
+ const QCFString mac_role = macRole(interface);
+
+ QAElement contents;
+
+ if (mac_role == kAXTabGroupRole) {
+ contents = tabWidgetGetContents(interface);
+ } else {
+ contents = scrollAreaGetContents(interface);
+ if (contents.isValid() == false)
+ return CallNextEventHandler(next_ref, event);
+ }
+
+ return setAttributeValue(event, QList<QAElement>() << contents);
+}
+
+static OSStatus handleRowsAttribute(EventHandlerCallRef, EventRef event, QAInterface &tableView)
+{
+ QList<QAElement> rows = lookup(tableView.children());
+
+ // kill the first row which is the horizontal header.
+ rows.removeAt(0);
+
+ return setAttributeValue(event, rows);
+}
+
+static OSStatus handleVisibleRowsAttribute(EventHandlerCallRef, EventRef event, QAInterface &tableView)
+{
+ QList<QAElement> visibleRows;
+
+ QList<QAInterface> rows = tableView.children();
+ // kill the first row which is the horizontal header.
+ rows.removeAt(0);
+
+ foreach (const QAInterface &interface, rows)
+ if ((interface.state() & QAccessible::Invisible) == false)
+ visibleRows.append(accessibleHierarchyManager()->lookup(interface));
+
+ return setAttributeValue(event, visibleRows);
+}
+
+static OSStatus handleSelectedRowsAttribute(EventHandlerCallRef, EventRef event, QAInterface &tableView)
+{
+ QList<QAElement> selectedRows;
+ foreach (const QAInterface &interface, tableView.children())
+ if ((interface.state() & QAccessible::Selected))
+ selectedRows.append(accessibleHierarchyManager()->lookup(interface));
+
+ return setAttributeValue(event, selectedRows);
+}
+
+static OSStatus getNamedAttribute(EventHandlerCallRef next_ref, EventRef event, QAInterface &interface)
+{
+ CFStringRef var;
+ GetEventParameter(event, kEventParamAccessibleAttributeName, typeCFStringRef, 0,
+ sizeof(var), 0, &var);
+
+ if (CFStringCompare(var, CFStringRef(QAXChildrenAttribute), 0) == kCFCompareEqualTo) {
+ return handleChildrenAttribute(next_ref, event, interface);
+ } else if(CFStringCompare(var, CFStringRef(QAXTopLevelUIElementAttribute), 0) == kCFCompareEqualTo) {
+ return handleTopLevelUIElementAttribute(next_ref, event, interface);
+ } else if(CFStringCompare(var, CFStringRef(QAXWindowAttribute), 0) == kCFCompareEqualTo) {
+ return handleWindowAttribute(next_ref, event, interface);
+ } else if(CFStringCompare(var, CFStringRef(QAXParentAttribute), 0) == kCFCompareEqualTo) {
+ return handleParentAttribute(next_ref, event, interface);
+ } else if (CFStringCompare(var, CFStringRef(QAXPositionAttribute), 0) == kCFCompareEqualTo) {
+ return handlePositionAttribute(next_ref, event, interface);
+ } else if (CFStringCompare(var, CFStringRef(QAXSizeAttribute), 0) == kCFCompareEqualTo) {
+ return handleSizeAttribute(next_ref, event, interface);
+ } else if (CFStringCompare(var, CFStringRef(QAXRoleAttribute), 0) == kCFCompareEqualTo) {
+ CFStringRef role = macRole(interface);
+// ###
+// QWidget * const widget = qobject_cast<QWidget *>(interface.object());
+// if (role == CFStringRef(QAXUnknownRole) && widget && widget->isWindow())
+// role = CFStringRef(QAXWindowRole);
+
+ SetEventParameter(event, kEventParamAccessibleAttributeValue, typeCFStringRef,
+ sizeof(role), &role);
+
+ } else if (CFStringCompare(var, CFStringRef(QAXEnabledAttribute), 0) == kCFCompareEqualTo) {
+ Boolean val = !((interface.state() & QAccessible::Unavailable))
+ && !((interface.state() & QAccessible::Invisible));
+ SetEventParameter(event, kEventParamAccessibleAttributeValue, typeBoolean,
+ sizeof(val), &val);
+ } else if (CFStringCompare(var, CFStringRef(QAXExpandedAttribute), 0) == kCFCompareEqualTo) {
+ Boolean val = (interface.state() & QAccessible::Expanded);
+ SetEventParameter(event, kEventParamAccessibleAttributeValue, typeBoolean,
+ sizeof(val), &val);
+ } else if (CFStringCompare(var, CFStringRef(QAXSelectedAttribute), 0) == kCFCompareEqualTo) {
+ Boolean val = (interface.state() & QAccessible::Selection);
+ SetEventParameter(event, kEventParamAccessibleAttributeValue, typeBoolean,
+ sizeof(val), &val);
+ } else if (CFStringCompare(var, CFStringRef(QAXFocusedAttribute), 0) == kCFCompareEqualTo) {
+ Boolean val = (interface.state() & QAccessible::Focus);
+ SetEventParameter(event, kEventParamAccessibleAttributeValue, typeBoolean,
+ sizeof(val), &val);
+ } else if (CFStringCompare(var, CFStringRef(QAXSelectedChildrenAttribute), 0) == kCFCompareEqualTo) {
+ const int cc = interface.childCount();
+ QList<QAElement> selected;
+ for (int i = 1; i <= cc; ++i) {
+ const QAInterface child_iface = interface.navigate(QAccessible::Child, i);
+ if (child_iface.isValid() && child_iface.state() & QAccessible::Selected)
+ selected.append(accessibleHierarchyManager()->lookup(child_iface));
+ }
+
+ return setAttributeValue(event, selected);
+
+ } else if (CFStringCompare(var, CFStringRef(QAXCloseButtonAttribute), 0) == kCFCompareEqualTo) {
+ if(interface.object() && interface.object()->isWidgetType()) {
+ Boolean val = true; //do we want to add a WState for this?
+ SetEventParameter(event, kEventParamAccessibleAttributeValue, typeBoolean,
+ sizeof(val), &val);
+ }
+ } else if (CFStringCompare(var, CFStringRef(QAXZoomButtonAttribute), 0) == kCFCompareEqualTo) {
+ if(interface.object() && interface.object()->isWidgetType()) {
+ QWidget *widget = (QWidget*)interface.object();
+ Boolean val = (widget->windowFlags() & Qt::WindowMaximizeButtonHint);
+ SetEventParameter(event, kEventParamAccessibleAttributeValue, typeBoolean,
+ sizeof(val), &val);
+ }
+ } else if (CFStringCompare(var, CFStringRef(QAXMinimizeButtonAttribute), 0) == kCFCompareEqualTo) {
+ if(interface.object() && interface.object()->isWidgetType()) {
+ QWidget *widget = (QWidget*)interface.object();
+ Boolean val = (widget->windowFlags() & Qt::WindowMinimizeButtonHint);
+ SetEventParameter(event, kEventParamAccessibleAttributeValue, typeBoolean,
+ sizeof(val), &val);
+ }
+ } else if (CFStringCompare(var, CFStringRef(QAXToolbarButtonAttribute), 0) == kCFCompareEqualTo) {
+ if(interface.object() && interface.object()->isWidgetType()) {
+ QWidget *widget = (QWidget*)interface.object();
+ Boolean val = qobject_cast<QMainWindow *>(widget) != 0;
+ SetEventParameter(event, kEventParamAccessibleAttributeValue, typeBoolean,
+ sizeof(val), &val);
+ }
+ } else if (CFStringCompare(var, CFStringRef(QAXGrowAreaAttribute), 0) == kCFCompareEqualTo) {
+ if(interface.object() && interface.object()->isWidgetType()) {
+ Boolean val = true; //do we want to add a WState for this?
+ SetEventParameter(event, kEventParamAccessibleAttributeValue, typeBoolean,
+ sizeof(val), &val);
+ }
+ } else if (CFStringCompare(var, CFStringRef(QAXMinimizedAttribute), 0) == kCFCompareEqualTo) {
+ if (interface.object() && interface.object()->isWidgetType()) {
+ QWidget *widget = (QWidget*)interface.object();
+ Boolean val = (widget->windowState() & Qt::WindowMinimized);
+ SetEventParameter(event, kEventParamAccessibleAttributeValue, typeBoolean,
+ sizeof(val), &val);
+ }
+ } else if (CFStringCompare(var, CFStringRef(QAXSubroleAttribute), 0) == kCFCompareEqualTo) {
+ return handleSubroleAttribute(next_ref, event, interface);
+ } else if (CFStringCompare(var, CFStringRef(QAXRoleDescriptionAttribute), 0) == kCFCompareEqualTo) {
+#if !defined(QT_MAC_USE_COCOA)
+ if (HICopyAccessibilityRoleDescription) {
+ const CFStringRef roleDescription = HICopyAccessibilityRoleDescription(macRole(interface), 0);
+ SetEventParameter(event, kEventParamAccessibleAttributeValue, typeCFStringRef,
+ sizeof(roleDescription), &roleDescription);
+ } else
+#endif
+ {
+ // Just use Qt::Description on 10.3
+ handleStringAttribute(event, QAccessible::Description, interface);
+ }
+ } else if (CFStringCompare(var, CFStringRef(QAXTitleAttribute), 0) == kCFCompareEqualTo) {
+ const QAccessible::Role role = interface.role();
+ const QAccessible::Text text = (QAccessible::Text)textForRoleAndAttribute(role, var);
+ handleStringAttribute(event, text, interface);
+ } else if (CFStringCompare(var, CFStringRef(QAXValueAttribute), 0) == kCFCompareEqualTo) {
+ const QAccessible::Role role = interface.role();
+ const QAccessible::Text text = (QAccessible::Text)textForRoleAndAttribute(role, var);
+ if (role == QAccessible::CheckBox || role == QAccessible::RadioButton) {
+ int value = buttonValue(interface);
+ SetEventParameter(event, kEventParamAccessibleAttributeValue, typeUInt32, sizeof(value), &value);
+ } else {
+ handleStringAttribute(event, text, interface);
+ }
+ } else if (CFStringCompare(var, CFStringRef(QAXDescriptionAttribute), 0) == kCFCompareEqualTo) {
+ const QAccessible::Role role = interface.role();
+ const QAccessible::Text text = (QAccessible::Text)textForRoleAndAttribute(role, var);
+ handleStringAttribute(event, text, interface);
+ } else if (CFStringCompare(var, CFStringRef(QAXLinkedUIElementsAttribute), 0) == kCFCompareEqualTo) {
+ return CallNextEventHandler(next_ref, event);
+ } else if (CFStringCompare(var, CFStringRef(QAXHelpAttribute), 0) == kCFCompareEqualTo) {
+ const QAccessible::Role role = interface.role();
+ const QAccessible::Text text = (QAccessible::Text)textForRoleAndAttribute(role, var);
+ handleStringAttribute(event, text, interface);
+ } else if (CFStringCompare(var, kAXTitleUIElementAttribute, 0) == kCFCompareEqualTo) {
+ return CallNextEventHandler(next_ref, event);
+ } else if (CFStringCompare(var, CFStringRef(QAXTabsAttribute), 0) == kCFCompareEqualTo) {
+ return handleTabsAttribute(next_ref, event, interface);
+ } else if (CFStringCompare(var, CFStringRef(QAXMinValueAttribute), 0) == kCFCompareEqualTo) {
+ // tabs we first go to the tab bar which is child #2.
+ QAInterface tabBarInterface = interface.childAt(2);
+ return handleTabsAttribute(next_ref, event, tabBarInterface);
+ } else if (CFStringCompare(var, CFStringRef(QAXMinValueAttribute), 0) == kCFCompareEqualTo) {
+ if (interface.role() == QAccessible::RadioButton || interface.role() == QAccessible::CheckBox) {
+ uint value = 0;
+ SetEventParameter(event, kEventParamAccessibleAttributeValue, typeUInt32, sizeof(value), &value);
+ } else {
+ return CallNextEventHandler(next_ref, event);
+ }
+ } else if (CFStringCompare(var, CFStringRef(QAXMaxValueAttribute), 0) == kCFCompareEqualTo) {
+ if (interface.role() == QAccessible::RadioButton || interface.role() == QAccessible::CheckBox) {
+ uint value = 2;
+ SetEventParameter(event, kEventParamAccessibleAttributeValue, typeUInt32, sizeof(value), &value);
+ } else {
+ return CallNextEventHandler(next_ref, event);
+ }
+ } else if (CFStringCompare(var, CFStringRef(QAXOrientationAttribute), 0) == kCFCompareEqualTo) {
+ return handleOrientationAttribute(next_ref, event, interface);
+ } else if (CFStringCompare(var, CFStringRef(QAXPreviousContentsAttribute), 0) == kCFCompareEqualTo) {
+ return handleSplitterContentsAttribute(next_ref, event, interface, CFStringRef(QAXPreviousContentsAttribute));
+ } else if (CFStringCompare(var, CFStringRef(QAXNextContentsAttribute), 0) == kCFCompareEqualTo) {
+ return handleSplitterContentsAttribute(next_ref, event, interface, CFStringRef(QAXNextContentsAttribute));
+ } else if (CFStringCompare(var, CFStringRef(QAXSplittersAttribute), 0) == kCFCompareEqualTo) {
+ return handleSplittersAttribute(next_ref, event, interface);
+ } else if (CFStringCompare(var, CFStringRef(QAXHorizontalScrollBarAttribute), 0) == kCFCompareEqualTo) {
+ return handleScrollBarAttribute(next_ref, event, interface, Qt::Horizontal);
+ } else if (CFStringCompare(var, CFStringRef(QAXVerticalScrollBarAttribute), 0) == kCFCompareEqualTo) {
+ return handleScrollBarAttribute(next_ref, event, interface, Qt::Vertical);
+ } else if (CFStringCompare(var, CFStringRef(QAXContentsAttribute), 0) == kCFCompareEqualTo) {
+ return handleContentsAttribute(next_ref, event, interface);
+ } else if (CFStringCompare(var, CFStringRef(QAXRowsAttribute), 0) == kCFCompareEqualTo) {
+ return handleRowsAttribute(next_ref, event, interface);
+ } else if (CFStringCompare(var, CFStringRef(QAXVisibleRowsAttribute), 0) == kCFCompareEqualTo) {
+ return handleVisibleRowsAttribute(next_ref, event, interface);
+ } else if (CFStringCompare(var, CFStringRef(QAXSelectedRowsAttribute), 0) == kCFCompareEqualTo) {
+ return handleSelectedRowsAttribute(next_ref, event, interface);
+ } else {
+ return CallNextEventHandler(next_ref, event);
+ }
+ return noErr;
+}
+
+static OSStatus isNamedAttributeSettable(EventRef event, const QAInterface &interface)
+{
+ CFStringRef var;
+ GetEventParameter(event, kEventParamAccessibleAttributeName, typeCFStringRef, 0,
+ sizeof(var), 0, &var);
+ Boolean settable = false;
+ if (CFStringCompare(var, CFStringRef(QAXFocusedAttribute), 0) == kCFCompareEqualTo) {
+ settable = true;
+ } else {
+ for (int r = 0; text_bindings[r][0].qt != -1; r++) {
+ if(interface.role() == (QAccessible::Role)text_bindings[r][0].qt) {
+ for (int a = 1; text_bindings[r][a].qt != -1; a++) {
+ if (CFStringCompare(var, CFStringRef(text_bindings[r][a].mac), 0) == kCFCompareEqualTo) {
+ settable = text_bindings[r][a].settable;
+ break;
+ }
+ }
+ }
+ }
+ }
+ SetEventParameter(event, kEventParamAccessibleAttributeSettable, typeBoolean,
+ sizeof(settable), &settable);
+ return noErr;
+}
+
+static OSStatus getChildAtPoint(EventHandlerCallRef next_ref, EventRef event, QAInterface &interface)
+{
+ Q_UNUSED(next_ref);
+ if (interface.isValid() == false)
+ return eventNotHandledErr;
+
+ // Add the children for this interface to the global QAccessibelHierachyManager.
+ accessibleHierarchyManager()->registerChildren(interface);
+
+ Point where;
+ GetEventParameter(event, kEventParamMouseLocation, typeQDPoint, 0, sizeof(where), 0, &where);
+ const QAInterface childInterface = interface.childAt(where.h, where.v);
+
+ if (childInterface.isValid() == false || childInterface == interface)
+ return eventNotHandledErr;
+
+ const QAElement element = accessibleHierarchyManager()->lookup(childInterface);
+ if (element.isValid() == false)
+ return eventNotHandledErr;
+
+ AXUIElementRef elementRef = element.element();
+ CFRetain(elementRef);
+ SetEventParameter(event, kEventParamAccessibleChild, typeCFTypeRef,
+ sizeof(elementRef), &elementRef);
+
+ return noErr;
+}
+
+/*
+ Returns a list of actions the given interface supports.
+ Currently implemented by getting the interface role and deciding based on that.
+*/
+static QList<QAccessible::Action> supportedPredefinedActions(const QAInterface &interface)
+{
+ QList<QAccessible::Action> actions;
+ switch (interface.role()) {
+ default:
+ // Most things can be pressed.
+ actions.append(QAccessible::Press);
+ break;
+ }
+
+ return actions;
+}
+
+/*
+ Translates a predefined QAccessible::Action to a Mac action constant.
+ Returns an empty string if the Qt Action has no mac equivalent.
+*/
+static QCFString translateAction(const QAccessible::Action action)
+{
+ switch (action) {
+ case QAccessible::Press:
+ return CFStringRef(QAXPressAction);
+ break;
+ case QAccessible::Increase:
+ return CFStringRef(QAXIncrementAction);
+ break;
+ case QAccessible::Decrease:
+ return CFStringRef(QAXDecrementAction);
+ break;
+ case QAccessible::Accept:
+ return CFStringRef(QAXConfirmAction);
+ break;
+ case QAccessible::Select:
+ return CFStringRef(QAXPickAction);
+ break;
+ case QAccessible::Cancel:
+ return CFStringRef(QAXCancelAction);
+ break;
+ default:
+ return QCFString();
+ break;
+ }
+}
+
+/*
+ Translates between a Mac action constant and a QAccessible::Action.
+ Returns QAccessible::Default action if there is no Qt predefined equivalent.
+*/
+static QAccessible::Action translateAction(const CFStringRef actionName)
+{
+ if(CFStringCompare(actionName, CFStringRef(QAXPressAction), 0) == kCFCompareEqualTo) {
+ return QAccessible::Press;
+ } else if(CFStringCompare(actionName, CFStringRef(QAXIncrementAction), 0) == kCFCompareEqualTo) {
+ return QAccessible::Increase;
+ } else if(CFStringCompare(actionName, CFStringRef(QAXDecrementAction), 0) == kCFCompareEqualTo) {
+ return QAccessible::Decrease;
+ } else if(CFStringCompare(actionName, CFStringRef(QAXConfirmAction), 0) == kCFCompareEqualTo) {
+ return QAccessible::Accept;
+ } else if(CFStringCompare(actionName, CFStringRef(QAXPickAction), 0) == kCFCompareEqualTo) {
+ return QAccessible::Select;
+ } else if(CFStringCompare(actionName, CFStringRef(QAXCancelAction), 0) == kCFCompareEqualTo) {
+ return QAccessible::Cancel;
+ } else {
+ return QAccessible::DefaultAction;
+ }
+}
+#endif // QT_MAC_USE_COCOA
+
+/*
+ Copies the translated names all supported actions for an interface into the kEventParamAccessibleActionNames
+ event parameter.
+*/
+#ifndef QT_MAC_USE_COCOA
+static OSStatus getAllActionNames(EventHandlerCallRef next_ref, EventRef event, const QAInterface &interface)
+{
+ Q_UNUSED(next_ref);
+
+ CFMutableArrayRef actions = 0;
+ GetEventParameter(event, kEventParamAccessibleActionNames, typeCFMutableArrayRef, 0,
+ sizeof(actions), 0, &actions);
+
+ // Add supported predefined actions.
+ const QList<QAccessible::Action> predefinedActions = supportedPredefinedActions(interface);
+ for (int i = 0; i < predefinedActions.count(); ++i) {
+ const QCFString action = translateAction(predefinedActions.at(i));
+ if (action != QCFString())
+ qt_mac_append_cf_uniq(actions, action);
+ }
+
+ // Add user actions
+ const int actionCount = interface.userActionCount();
+ for (int i = 0; i < actionCount; ++i) {
+ const QString actionName = interface.actionText(i, QAccessible::Name);
+ qt_mac_append_cf_uniq(actions, QCFString::toCFStringRef(actionName));
+ }
+
+ return noErr;
+}
+#endif
+
+/*
+ Handles the perforNamedAction event.
+*/
+#ifndef QT_MAC_USE_COCOA
+static OSStatus performNamedAction(EventHandlerCallRef next_ref, EventRef event, const QAInterface& interface)
+{
+ Q_UNUSED(next_ref);
+
+ CFStringRef act;
+ GetEventParameter(event, kEventParamAccessibleActionName, typeCFStringRef, 0,
+ sizeof(act), 0, &act);
+
+ const QAccessible::Action action = translateAction(act);
+
+ // Perform built-in action
+ if (action != QAccessible::DefaultAction) {
+ interface.doAction(action, QVariantList());
+ return noErr;
+ }
+
+ // Search for user-defined actions and perform it if found.
+ const int actCount = interface.userActionCount();
+ const QString qAct = QCFString::toQString(act);
+ for(int i = 0; i < actCount; i++) {
+ if(interface.actionText(i, QAccessible::Name) == qAct) {
+ interface.doAction(i, QVariantList());
+ break;
+ }
+ }
+ return noErr;
+}
+
+static OSStatus setNamedAttribute(EventHandlerCallRef next_ref, EventRef event, const QAInterface &interface)
+{
+ Q_UNUSED(next_ref);
+ Q_UNUSED(event);
+
+ CFStringRef var;
+ GetEventParameter(event, kEventParamAccessibleAttributeName, typeCFStringRef, 0,
+ sizeof(var), 0, &var);
+ if(CFStringCompare(var, CFStringRef(QAXFocusedAttribute), 0) == kCFCompareEqualTo) {
+ CFTypeRef val;
+ if(GetEventParameter(event, kEventParamAccessibleAttributeValue, typeCFTypeRef, 0,
+ sizeof(val), 0, &val) == noErr) {
+ if(CFGetTypeID(val) == CFBooleanGetTypeID() &&
+ CFEqual(static_cast<CFBooleanRef>(val), kCFBooleanTrue)) {
+ interface.doAction(QAccessible::SetFocus);
+ }
+ }
+ } else {
+ bool found = false;
+ for(int r = 0; text_bindings[r][0].qt != -1; r++) {
+ if(interface.role() == (QAccessible::Role)text_bindings[r][0].qt) {
+ for(int a = 1; text_bindings[r][a].qt != -1; a++) {
+ if(CFStringCompare(var, CFStringRef(text_bindings[r][a].mac), 0) == kCFCompareEqualTo) {
+ if(!text_bindings[r][a].settable) {
+ } else {
+ CFTypeRef val;
+ if(GetEventParameter(event, kEventParamAccessibleAttributeValue, typeCFTypeRef, 0,
+ sizeof(val), 0, &val) == noErr) {
+ if(CFGetTypeID(val) == CFStringGetTypeID())
+ interface.setText((QAccessible::Text)text_bindings[r][a].qt,
+ QCFString::toQString(static_cast<CFStringRef>(val)));
+
+ }
+ }
+ found = true;
+ break;
+ }
+ }
+ break;
+ }
+ }
+ }
+ return noErr;
+}
+
+/*
+ This is the main accessibility event handler.
+*/
+static OSStatus accessibilityEventHandler(EventHandlerCallRef next_ref, EventRef event, void *data)
+{
+ Q_UNUSED(data)
+
+ // Return if this event is not a AccessibleGetNamedAttribute event.
+ const UInt32 eclass = GetEventClass(event);
+ if (eclass != kEventClassAccessibility)
+ return eventNotHandledErr;
+
+ // Get the AXUIElementRef and QAInterface pointer
+ AXUIElementRef element = 0;
+ GetEventParameter(event, kEventParamAccessibleObject, typeCFTypeRef, 0, sizeof(element), 0, &element);
+ QAInterface interface = accessibleHierarchyManager()->lookup(element);
+ if (interface.isValid() == false)
+ return eventNotHandledErr;
+
+ const UInt32 ekind = GetEventKind(event);
+ OSStatus status = noErr;
+ switch (ekind) {
+ case kEventAccessibleGetAllAttributeNames:
+ status = getAllAttributeNames(event, interface, next_ref);
+ break;
+ case kEventAccessibleGetNamedAttribute:
+ status = getNamedAttribute(next_ref, event, interface);
+ break;
+ case kEventAccessibleIsNamedAttributeSettable:
+ status = isNamedAttributeSettable(event, interface);
+ break;
+ case kEventAccessibleGetChildAtPoint:
+ status = getChildAtPoint(next_ref, event, interface);
+ break;
+ case kEventAccessibleGetAllActionNames:
+ status = getAllActionNames(next_ref, event, interface);
+ break;
+ case kEventAccessibleGetFocusedChild:
+ status = CallNextEventHandler(next_ref, event);
+ break;
+ case kEventAccessibleSetNamedAttribute:
+ status = setNamedAttribute(next_ref, event, interface);
+ break;
+ case kEventAccessiblePerformNamedAction:
+ status = performNamedAction(next_ref, event, interface);
+ break;
+ default:
+ status = CallNextEventHandler(next_ref, event);
+ break;
+ };
+ return status;
+}
+#endif
+
+void QAccessible::initialize()
+{
+#ifndef QT_MAC_USE_COCOA
+ registerQtAccessibilityHIObjectSubclass();
+ installApplicationEventhandler();
+#endif
+}
+
+// Sets thre root object for the application
+void QAccessible::setRootObject(QObject *object)
+{
+ // Call installed root object handler if we have one
+ if (rootObjectHandler) {
+ rootObjectHandler(object);
+ return;
+ }
+
+ rootObject = object;
+}
+
+void QAccessible::cleanup()
+{
+ accessibleHierarchyManager()->reset();
+#ifndef QT_MAC_USE_COCOA
+ removeEventhandler(applicationEventHandlerUPP);
+ removeEventhandler(objectCreateEventHandlerUPP);
+ removeEventhandler(accessibilityEventHandlerUPP);
+#endif
+}
+
+void QAccessible::updateAccessibility(QObject *object, int child, Event reason)
+{
+ // Call installed update handler if we have one.
+ if (updateHandler) {
+ updateHandler(object, child, reason);
+ return;
+ }
+
+#ifndef QT_MAC_USE_COCOA
+ // Return if the mac accessibility is not enabled.
+ if(!AXAPIEnabled())
+ return;
+
+ // Work around crash, disable accessiblity for focus frames.
+ if (qstrcmp(object->metaObject()->className(), "QFocusFrame") == 0)
+ return;
+
+// qDebug() << "updateAccessibility" << object << child << hex << reason;
+
+ if (reason == ObjectShow) {
+ QAInterface interface = QAInterface(QAccessible::queryAccessibleInterface(object), child);
+ accessibleHierarchyManager()->registerInterface(interface);
+ }
+
+ const QAElement element = accessibleHierarchyManager()->lookup(object, child);
+ if (element.isValid() == false)
+ return;
+
+
+ CFStringRef notification = 0;
+ if(object && object->isWidgetType() && reason == ObjectCreated) {
+ notification = CFStringRef(QAXWindowCreatedNotification);
+ } else if(reason == ValueChanged) {
+ notification = CFStringRef(QAXValueChangedNotification);
+ } else if(reason == MenuStart) {
+ notification = CFStringRef(QAXMenuOpenedNotification);
+ } else if(reason == MenuEnd) {
+ notification = CFStringRef(QAXMenuClosedNotification);
+ } else if(reason == LocationChanged) {
+ notification = CFStringRef(QAXWindowMovedNotification);
+ } else if(reason == ObjectShow || reason == ObjectHide ) {
+ // When a widget is deleted we get a ObjectHide before the destroyed(QObject *)
+ // signal is emitted (which makes sense). However, at this point we are in the
+ // middle of the QWidget destructor which means that we have to be careful when
+ // using the widget pointer. Since we can't control what the accessibilty interfaces
+ // does when navigate() is called below we ignore the hide update in this case.
+ // (the widget will be deleted soon anyway.)
+ extern QWidgetPrivate * qt_widget_private(QWidget *);
+ if (QWidget *widget = qobject_cast<QWidget*>(object)) {
+ if (qt_widget_private(widget)->data.in_destructor)
+ return;
+
+ // Check widget parent as well, special case for preventing crash
+ // when the viewport() of an abstract scroll area is hidden when
+ // the QWidget destructor hides all its children.
+ QWidget *parentWidget = widget->parentWidget();
+ if (parentWidget && qt_widget_private(parentWidget)->data.in_destructor)
+ return;
+ }
+
+ // There is no equivalent Mac notification for ObjectShow/Hide, so we call HIObjectSetAccessibilityIgnored
+ // and isItIntersting which will mark the HIObject accociated with the element as ignored if the
+ // QAccessible::Invisible state bit is set.
+ QAInterface interface = accessibleHierarchyManager()->lookup(element);
+ if (interface.isValid()) {
+ HIObjectSetAccessibilityIgnored(element.object(), !isItInteresting(interface));
+ }
+
+ // If the interface manages its own children, also check if we should ignore those.
+ if (isItemView(interface) == false && managesChildren(interface)) {
+ for (int i = 1; i <= interface.childCount(); ++i) {
+ QAInterface childInterface = interface.navigate(QAccessible::Child, i);
+ if (childInterface.isValid() && childInterface.isHIView() == false) {
+ const QAElement element = accessibleHierarchyManager()->lookup(childInterface);
+ if (element.isValid()) {
+ HIObjectSetAccessibilityIgnored(element.object(), !isItInteresting(childInterface));
+ }
+ }
+ }
+ }
+
+ } else if(reason == Focus) {
+ if(object && object->isWidgetType()) {
+ QWidget *w = static_cast<QWidget*>(object);
+ if(w->isWindow())
+ notification = CFStringRef(QAXFocusedWindowChangedNotification);
+ else
+ notification = CFStringRef(QAXFocusedUIElementChangedNotification);
+ }
+ }
+
+ if (!notification)
+ return;
+
+ AXNotificationHIObjectNotify(notification, element.object(), element.id());
+#endif
+}
+
+QT_END_NAMESPACE
+
+#endif // QT_NO_ACCESSIBILITY
diff --git a/src/widgets/accessible/qaccessible_mac_carbon.cpp b/src/widgets/accessible/qaccessible_mac_carbon.cpp
new file mode 100644
index 0000000000..2e8a7628e8
--- /dev/null
+++ b/src/widgets/accessible/qaccessible_mac_carbon.cpp
@@ -0,0 +1,119 @@
+/****************************************************************************
+**
+** Copyright (C) 2011 Nokia Corporation and/or its subsidiary(-ies).
+** All rights reserved.
+** Contact: Nokia Corporation (qt-info@nokia.com)
+**
+** This file is part of the QtGui module of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL$
+** No Commercial Usage
+** This file contains pre-release code and may not be distributed.
+** You may use this file in accordance with the terms and conditions
+** contained in the Technology Preview License Agreement accompanying
+** this package.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 2.1 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPL included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU Lesser General Public License version 2.1 requirements
+** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
+**
+** In addition, as a special exception, Nokia gives you certain additional
+** rights. These rights are described in the Nokia Qt LGPL Exception
+** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
+**
+** If you have questions regarding the use of this file, please contact
+** Nokia at qt-info@nokia.com.
+**
+**
+**
+**
+**
+**
+**
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+static OSStatus applicationEventHandler(EventHandlerCallRef next_ref, EventRef event, void *data);
+static EventHandlerUPP applicationEventHandlerUPP = 0;
+static EventTypeSpec application_events[] = {
+ { kEventClassAccessibility, kEventAccessibleGetChildAtPoint },
+ { kEventClassAccessibility, kEventAccessibleGetNamedAttribute }
+};
+
+static CFStringRef kObjectQtAccessibility = CFSTR("com.trolltech.qt.accessibility");
+static EventHandlerUPP objectCreateEventHandlerUPP = 0;
+static EventTypeSpec objectCreateEvents[] = {
+ { kEventClassHIObject, kEventHIObjectConstruct },
+ { kEventClassHIObject, kEventHIObjectInitialize },
+ { kEventClassHIObject, kEventHIObjectDestruct },
+ { kEventClassHIObject, kEventHIObjectPrintDebugInfo }
+};
+
+static OSStatus accessibilityEventHandler(EventHandlerCallRef next_ref, EventRef event, void *data);
+static EventHandlerUPP accessibilityEventHandlerUPP = 0;
+static EventTypeSpec accessibilityEvents[] = {
+ { kEventClassAccessibility, kEventAccessibleGetChildAtPoint },
+ { kEventClassAccessibility, kEventAccessibleGetFocusedChild },
+ { kEventClassAccessibility, kEventAccessibleGetAllAttributeNames },
+ { kEventClassAccessibility, kEventAccessibleGetNamedAttribute },
+ { kEventClassAccessibility, kEventAccessibleSetNamedAttribute },
+ { kEventClassAccessibility, kEventAccessibleIsNamedAttributeSettable },
+ { kEventClassAccessibility, kEventAccessibleGetAllActionNames },
+ { kEventClassAccessibility, kEventAccessiblePerformNamedAction },
+ { kEventClassAccessibility, kEventAccessibleGetNamedActionDescription }
+};
+
+static void installAcessibilityEventHandler(HIObjectRef hiObject)
+{
+ if (!accessibilityEventHandlerUPP)
+ accessibilityEventHandlerUPP = NewEventHandlerUPP(accessibilityEventHandler);
+
+ InstallHIObjectEventHandler(hiObject, accessibilityEventHandlerUPP,
+ GetEventTypeCount(accessibilityEvents),
+ accessibilityEvents, 0, 0);
+}
+
+static OSStatus objectCreateEventHandler(EventHandlerCallRef next_ref, EventRef event, void *data)
+{
+ Q_UNUSED(data)
+ Q_UNUSED(event)
+ Q_UNUSED(next_ref)
+ return noErr;
+}
+
+static void registerQtAccessibilityHIObjectSubclass()
+{
+ if (!objectCreateEventHandlerUPP)
+ objectCreateEventHandlerUPP = NewEventHandlerUPP(objectCreateEventHandler);
+ OSStatus err = HIObjectRegisterSubclass(kObjectQtAccessibility, 0, 0, objectCreateEventHandlerUPP,
+ GetEventTypeCount(objectCreateEvents), objectCreateEvents, 0, 0);
+ if (err && err != hiObjectClassExistsErr)
+ qWarning("qaccessible_mac internal error: Could not register accessibility HIObject subclass");
+}
+
+static void installApplicationEventhandler()
+{
+ if (!applicationEventHandlerUPP)
+ applicationEventHandlerUPP = NewEventHandlerUPP(applicationEventHandler);
+
+ OSStatus err = InstallApplicationEventHandler(applicationEventHandlerUPP,
+ GetEventTypeCount(application_events), application_events,
+ 0, 0);
+
+ if (err && err != eventHandlerAlreadyInstalledErr)
+ qWarning("qaccessible_mac internal error: Could not install application accessibility event handler");
+}
+
+static void removeEventhandler(EventHandlerUPP eventHandler)
+{
+ if (eventHandler) {
+ DisposeEventHandlerUPP(eventHandler);
+ eventHandler = 0;
+ }
+}
diff --git a/src/widgets/accessible/qaccessible_mac_cocoa.mm b/src/widgets/accessible/qaccessible_mac_cocoa.mm
new file mode 100644
index 0000000000..60b967ab39
--- /dev/null
+++ b/src/widgets/accessible/qaccessible_mac_cocoa.mm
@@ -0,0 +1,239 @@
+/****************************************************************************
+**
+** Copyright (C) 2011 Nokia Corporation and/or its subsidiary(-ies).
+** All rights reserved.
+** Contact: Nokia Corporation (qt-info@nokia.com)
+**
+** This file is part of the QtGui module of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL$
+** No Commercial Usage
+** This file contains pre-release code and may not be distributed.
+** You may use this file in accordance with the terms and conditions
+** contained in the Technology Preview License Agreement accompanying
+** this package.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 2.1 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPL included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU Lesser General Public License version 2.1 requirements
+** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
+**
+** In addition, as a special exception, Nokia gives you certain additional
+** rights. These rights are described in the Nokia Qt LGPL Exception
+** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
+**
+** If you have questions regarding the use of this file, please contact
+** Nokia at qt-info@nokia.com.
+**
+**
+**
+**
+**
+**
+**
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+
+#include "qaccessible.h"
+#include "qaccessible_mac_p.h"
+#include "qdebug.h"
+#include "qtabwidget.h"
+
+#include <private/qt_mac_p.h>
+#include <private/qcocoaview_mac_p.h>
+#include <private/qwidget_p.h>
+
+
+#ifndef QT_NO_ACCESSIBILITY
+
+#ifdef QT_MAC_USE_COCOA
+
+QT_BEGIN_NAMESPACE
+
+//#define MAC_ACCESSIBILTY_DEVELOPER_MODE
+
+#ifndef QT_NO_DEBUG_STREAM
+#ifdef MAC_ACCESSIBILTY_DEVELOPER_MODE
+#define MAC_ACCESSIBILTY_DEBUG QT_PREPEND_NAMESPACE(qDebug)
+#else
+#define MAC_ACCESSIBILTY_DEBUG if (0) QT_PREPEND_NAMESPACE(qDebug)
+#endif
+#else
+#define MAC_ACCESSIBILTY_DEBUG if (0) QT_PREPEND_NAMESPACE(QNoDebug)
+#endif
+
+typedef QMap<QAccessible::Role, NSString *> QMacAccessibiltyRoleMap;
+Q_GLOBAL_STATIC(QMacAccessibiltyRoleMap, qMacAccessibiltyRoleMap);
+
+static QAInterface interfaceForView(QT_MANGLE_NAMESPACE(QCocoaView) *view)
+{
+ return QAInterface(QAccessible::queryAccessibleInterface([view qt_qwidget]));
+}
+
+/*
+ Set up mappings from Qt accessibilty roles to Mac accessibilty roles.
+*/
+static void populateRoleMap()
+{
+ QMacAccessibiltyRoleMap &roleMap = *qMacAccessibiltyRoleMap();
+ roleMap[QAccessible::MenuItem] = NSAccessibilityMenuItemRole;
+ roleMap[QAccessible::MenuBar] = NSAccessibilityMenuBarRole;
+ roleMap[QAccessible::ScrollBar] = NSAccessibilityScrollBarRole;
+ roleMap[QAccessible::Grip] = NSAccessibilityGrowAreaRole;
+ roleMap[QAccessible::Window] = NSAccessibilityWindowRole;
+ roleMap[QAccessible::Dialog] = NSAccessibilityWindowRole;
+ roleMap[QAccessible::AlertMessage] = NSAccessibilityWindowRole;
+ roleMap[QAccessible::ToolTip] = NSAccessibilityWindowRole;
+ roleMap[QAccessible::HelpBalloon] = NSAccessibilityWindowRole;
+ roleMap[QAccessible::PopupMenu] = NSAccessibilityMenuRole;
+ roleMap[QAccessible::Application] = NSAccessibilityApplicationRole;
+ roleMap[QAccessible::Pane] = NSAccessibilityGroupRole;
+ roleMap[QAccessible::Grouping] = NSAccessibilityGroupRole;
+ roleMap[QAccessible::Separator] = NSAccessibilitySplitterRole;
+ roleMap[QAccessible::ToolBar] = NSAccessibilityToolbarRole;
+ roleMap[QAccessible::PageTab] = NSAccessibilityRadioButtonRole;
+ roleMap[QAccessible::ButtonMenu] = NSAccessibilityMenuButtonRole;
+ roleMap[QAccessible::ButtonDropDown] = NSAccessibilityPopUpButtonRole;
+ roleMap[QAccessible::SpinBox] = NSAccessibilityIncrementorRole;
+ roleMap[QAccessible::Slider] = NSAccessibilitySliderRole;
+ roleMap[QAccessible::ProgressBar] = NSAccessibilityProgressIndicatorRole;
+ roleMap[QAccessible::ComboBox] = NSAccessibilityPopUpButtonRole;
+ roleMap[QAccessible::RadioButton] = NSAccessibilityRadioButtonRole;
+ roleMap[QAccessible::CheckBox] = NSAccessibilityCheckBoxRole;
+ roleMap[QAccessible::StaticText] = NSAccessibilityStaticTextRole;
+ roleMap[QAccessible::Table] = NSAccessibilityTableRole;
+ roleMap[QAccessible::StatusBar] = NSAccessibilityStaticTextRole;
+ roleMap[QAccessible::Column] = NSAccessibilityColumnRole;
+ roleMap[QAccessible::ColumnHeader] = NSAccessibilityColumnRole;
+ roleMap[QAccessible::Row] = NSAccessibilityRowRole;
+ roleMap[QAccessible::RowHeader] = NSAccessibilityRowRole;
+ roleMap[QAccessible::Cell] = NSAccessibilityTextFieldRole;
+ roleMap[QAccessible::PushButton] = NSAccessibilityButtonRole;
+ roleMap[QAccessible::EditableText] = NSAccessibilityTextFieldRole;
+ roleMap[QAccessible::Link] = NSAccessibilityTextFieldRole;
+ roleMap[QAccessible::Indicator] = NSAccessibilityValueIndicatorRole;
+ roleMap[QAccessible::Splitter] = NSAccessibilitySplitGroupRole;
+ roleMap[QAccessible::List] = NSAccessibilityListRole;
+ roleMap[QAccessible::ListItem] = NSAccessibilityStaticTextRole;
+ roleMap[QAccessible::Cell] = NSAccessibilityStaticTextRole;
+}
+
+/*
+ Returns a Mac accessibility role for the given interface, or
+ NSAccessibilityUnknownRole if no role mapping is found.
+*/
+static NSString *macRoleForInterface(QAInterface interface)
+{
+ const QAccessible::Role qtRole = interface.role();
+ QMacAccessibiltyRoleMap &roleMap = *qMacAccessibiltyRoleMap();
+
+ if (roleMap.isEmpty())
+ populateRoleMap();
+
+ MAC_ACCESSIBILTY_DEBUG() << "role for" << interface.object() << "interface role" << hex << qtRole;
+
+ if (roleMap.contains(qtRole)) {
+ MAC_ACCESSIBILTY_DEBUG() << "return" << roleMap[qtRole];
+ return roleMap[qtRole];
+ }
+
+ MAC_ACCESSIBILTY_DEBUG() << "return NSAccessibilityUnknownRole";
+ return NSAccessibilityUnknownRole;
+}
+
+/*
+ Is the interface a QTabBar embedded in a QTabWidget?
+ (as opposed to a stand-alone tab bar)
+*/
+static bool isEmbeddedTabBar(const QAInterface &interface)
+{
+ QObject *object = interface.object();
+ if (interface.role() == QAccessible::PageTabList && object)
+ return (qobject_cast<QTabWidget *>(object->parent()));
+
+ return false;
+}
+
+static bool isInterfaceIgnored(QAInterface interface)
+{
+ // Mac accessibility does not have an attribute that corresponds to the
+ // Invisible/Offscreen state. Use the ignore facility to disable them.
+ const QAccessible::State state = interface.state();
+ if (state & QAccessible::Invisible ||
+ state & QAccessible::Offscreen )
+ return false;
+
+ // Hide QTabBars that has a QTabWidget parent (the QTabWidget handles the accessibility)
+ if (isEmbeddedTabBar(interface))
+ return false;
+
+ if (QObject * const object = interface.object()) {
+ const QString className = QLatin1String(object->metaObject()->className());
+
+ // Prevent VoiceOver from focusing on tool tips by ignoring those
+ // interfaces. Shifting VoiceOver focus to the tool tip is confusing
+ // and the contents of the tool tip is avalible through the description
+ // attribute anyway.
+ if (className == QLatin1String("QTipLabel"))
+ return false;
+ }
+
+ // Hide interfaces with an unknown role. When developing it's often useful to disable
+ // this check to see all interfaces in the hierarchy.
+#ifndef MAC_ACCESSIBILTY_DEVELOPER_MODE
+ return [macRoleForInterface(interface) isEqualToString: NSAccessibilityUnknownRole];
+#else
+ return NO;
+#endif
+}
+
+QT_END_NAMESPACE
+
+@implementation QT_MANGLE_NAMESPACE(QCocoaView) (Accessibility)
+
+- (BOOL)accessibilityIsIgnored
+{
+ QT_PREPEND_NAMESPACE(QAInterface) interface = QT_PREPEND_NAMESPACE(interfaceForView)(self);
+ return isInterfaceIgnored(interface);
+}
+
+- (NSArray *)accessibilityAttributeNames
+{
+ QT_PREPEND_NAMESPACE(QAInterface) interface = QT_PREPEND_NAMESPACE(interfaceForView)(self);
+
+ static NSArray *attributes = nil;
+ if (attributes == nil) {
+ attributes = [super accessibilityAttributeNames];
+
+ }
+ return attributes;
+}
+
+- (id)accessibilityAttributeValue:(NSString *)attribute
+{
+ MAC_ACCESSIBILTY_DEBUG() << "accessibilityAttributeValue" << self <<
+ QT_PREPEND_NAMESPACE(QCFString)::toQString(reinterpret_cast<CFStringRef>(attribute));
+
+ QT_PREPEND_NAMESPACE(QAInterface) interface = QT_PREPEND_NAMESPACE(interfaceForView)(self);
+
+ // Switch on the attribute name and call the appropriate handler function.
+ // Pass the call on to the NSView class for attributes we don't handle.
+ if ([attribute isEqualToString:@"AXRole"]) {
+ return macRoleForInterface(interface);
+ } else {
+ return [super accessibilityAttributeValue:attribute];
+ }
+}
+
+@end
+
+#endif // QT_MAC_USE_COCOA
+
+#endif // QT_NO_ACCESSIBILITY
+
diff --git a/src/widgets/accessible/qaccessible_mac_p.h b/src/widgets/accessible/qaccessible_mac_p.h
new file mode 100644
index 0000000000..9acb5d3aef
--- /dev/null
+++ b/src/widgets/accessible/qaccessible_mac_p.h
@@ -0,0 +1,479 @@
+/****************************************************************************
+**
+** Copyright (C) 2011 Nokia Corporation and/or its subsidiary(-ies).
+** All rights reserved.
+** Contact: Nokia Corporation (qt-info@nokia.com)
+**
+** This file is part of the QtGui module of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL$
+** No Commercial Usage
+** This file contains pre-release code and may not be distributed.
+** You may use this file in accordance with the terms and conditions
+** contained in the Technology Preview License Agreement accompanying
+** this package.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 2.1 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPL included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU Lesser General Public License version 2.1 requirements
+** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
+**
+** In addition, as a special exception, Nokia gives you certain additional
+** rights. These rights are described in the Nokia Qt LGPL Exception
+** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
+**
+** If you have questions regarding the use of this file, please contact
+** Nokia at qt-info@nokia.com.
+**
+**
+**
+**
+**
+**
+**
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#ifndef QACCESSIBLE_MAC_P_H
+#define QACCESSIBLE_MAC_P_H
+
+//
+// W A R N I N G
+// -------------
+//
+// This file is not part of the Qt API. It exists purely as an
+// implementation detail. This header file may change from version to
+// version without notice, or even be removed.
+//
+// We mean it.
+//
+//
+
+#include <qglobal.h>
+#include <private/qt_mac_p.h>
+#include <qaccessible.h>
+#include <qwidget.h>
+#include <qdebug.h>
+
+//#define Q_ACCESSIBLE_MAC_DEBUG
+
+QT_BEGIN_NAMESPACE
+
+/*
+ QAccessibleInterfaceWrapper wraps QAccessibleInterface and adds
+ a ref count. QAccessibleInterfaceWrapper is a "by-value" class.
+*/
+class Q_AUTOTEST_EXPORT QAccessibleInterfaceWrapper
+{
+public:
+ QAccessibleInterfaceWrapper()
+ : interface(0), childrenIsRegistered(new bool(false)), refCount(new int(1)) { }
+
+ QAccessibleInterfaceWrapper(QAccessibleInterface *interface)
+ :interface(interface), childrenIsRegistered(new bool(false)), refCount(new int(1)) { }
+
+ ~QAccessibleInterfaceWrapper()
+ {
+ if (--(*refCount) == 0) {
+ delete interface;
+ delete refCount;
+ delete childrenIsRegistered;
+ }
+ }
+
+ QAccessibleInterfaceWrapper(const QAccessibleInterfaceWrapper &other)
+ :interface(other.interface), childrenIsRegistered(other.childrenIsRegistered), refCount(other.refCount)
+ {
+ ++(*refCount);
+ }
+
+ void operator=(const QAccessibleInterfaceWrapper &other)
+ {
+ if (other.interface == interface)
+ return;
+
+ if (--(*refCount) == 0) {
+ delete interface;
+ delete refCount;
+ delete childrenIsRegistered;
+ }
+
+ interface = other.interface;
+ childrenIsRegistered = other.childrenIsRegistered;
+ refCount = other.refCount;
+ ++(*refCount);
+ }
+
+ QAccessibleInterface *interface;
+ bool *childrenIsRegistered;
+private:
+ int *refCount;
+};
+
+/*
+ QAInterface represents one accessiblity item. It hides the fact that
+ one QAccessibleInterface may represent more than one item, and it also
+ automates the memory management for QAccessibleInterfaces using the
+ QAccessibleInterfaceWrapper wrapper class.
+
+ It has the same API as QAccessibleInterface, minus the child parameter
+ in the functions.
+*/
+class Q_AUTOTEST_EXPORT QAInterface : public QAccessible
+{
+public:
+ QAInterface()
+ : base(QAccessibleInterfaceWrapper())
+ { }
+
+ QAInterface(QAccessibleInterface *interface, int child = 0)
+ {
+ if (interface == 0 || child > interface->childCount()) {
+ base = QAccessibleInterfaceWrapper();
+ } else {
+ base = QAccessibleInterfaceWrapper(interface);
+ m_cachedObject = interface->object();
+ this->child = child;
+ }
+ }
+
+ QAInterface(QAccessibleInterfaceWrapper wrapper, int child = 0)
+ :base(wrapper), m_cachedObject(wrapper.interface->object()), child(child)
+ { }
+
+ QAInterface(const QAInterface &other, int child)
+ {
+ if (other.isValid() == false || child > other.childCount()) {
+ base = QAccessibleInterfaceWrapper();
+ } else {
+ base = other.base;
+ m_cachedObject = other.m_cachedObject;
+ this->child = child;
+ }
+ }
+
+ bool operator==(const QAInterface &other) const;
+ bool operator!=(const QAInterface &other) const;
+
+ inline QString actionText (int action, Text text) const
+ { return base.interface->actionText(action, text, child); }
+
+ QAInterface childAt(int x, int y) const
+ {
+ if (!checkValid())
+ return QAInterface();
+
+ const int foundChild = base.interface->childAt(x, y);
+
+ if (foundChild == -1)
+ return QAInterface();
+
+ if (child == 0)
+ return navigate(QAccessible::Child, foundChild);
+
+ if (foundChild == child)
+ return *this;
+ return QAInterface();
+ }
+
+ int indexOfChild(const QAInterface &child) const
+ {
+ if (!checkValid())
+ return -1;
+
+ if (*this != child.parent())
+ return -1;
+
+ if (object() == child.object())
+ return child.id();
+
+ return base.interface->indexOfChild(child.base.interface);
+ }
+
+ inline int childCount() const
+ {
+ if (!checkValid())
+ return 0;
+
+ if (child != 0)
+ return 0;
+ return base.interface->childCount();
+ }
+
+ QList<QAInterface> children() const
+ {
+ if (!checkValid())
+ return QList<QAInterface>();
+
+ QList<QAInterface> children;
+ for (int i = 1; i <= childCount(); ++i) {
+ children.append(navigate(QAccessible::Child, i));
+ }
+ return children;
+ }
+
+ QAInterface childAt(int index) const
+ {
+ return navigate(QAccessible::Child, index);
+ }
+
+ inline void doAction(int action, const QVariantList &params = QVariantList()) const
+ {
+ if (!checkValid())
+ return;
+
+ base.interface->doAction(action, child, params);
+ }
+
+ QAInterface navigate(RelationFlag relation, int entry) const;
+
+ inline QObject * object() const
+ {
+ if (!checkValid())
+ return 0;
+
+ return base.interface->object();
+ }
+
+ QAInterface objectInterface() const
+ {
+ if (!checkValid())
+ return QAInterface();
+
+ QObject *obj = object();
+ QAInterface current = *this;
+ while (obj == 0)
+ {
+ QAInterface parent = current.parent();
+ if (parent.isValid() == false)
+ break;
+ obj = parent.object();
+ current = parent;
+ }
+ return current;
+ }
+
+ inline HIObjectRef hiObject() const
+ {
+ if (!checkValid())
+ return 0;
+ QWidget * const widget = qobject_cast<QWidget * const>(object());
+ if (widget)
+ return (HIObjectRef)widget->winId();
+ else
+ return 0;
+ }
+
+ inline QObject * cachedObject() const
+ {
+ if (!checkValid())
+ return 0;
+ return m_cachedObject;
+ }
+
+ inline QRect rect() const
+ {
+ if (!checkValid())
+ return QRect();
+ return base.interface->rect(child);
+ }
+
+ inline Role role() const
+ {
+ if (!checkValid())
+ return QAccessible::NoRole;
+ return base.interface->role(child);
+ }
+
+ inline void setText(Text t, const QString &text) const
+ {
+ if (!checkValid())
+ return;
+ base.interface->setText(t, child, text);
+ }
+
+ inline State state() const
+ {
+ if (!checkValid())
+ return 0;
+ return base.interface->state(child);
+ }
+
+ inline QString text (Text text) const
+ {
+ if (!checkValid())
+ return QString();
+ return base.interface->text(text, child);
+ }
+
+ inline QString value() const
+ { return text(QAccessible::Value); }
+
+ inline QString name() const
+ { return text(QAccessible::Name); }
+
+ inline int userActionCount() const
+ {
+ if (!checkValid())
+ return 0;
+ return base.interface->userActionCount(child);
+ }
+
+ inline QString className() const
+ {
+ if (!checkValid())
+ return QString();
+ return QLatin1String(base.interface->object()->metaObject()->className());
+ }
+
+ inline bool isHIView() const
+ { return (child == 0 && object() != 0); }
+
+ inline int id() const
+ { return child; }
+
+ inline bool isValid() const
+ {
+ return (base.interface != 0 && base.interface->isValid());
+ }
+
+ QAInterface parent() const
+ { return navigate(QAccessible::Ancestor, 1); }
+
+ QAccessibleInterfaceWrapper interfaceWrapper() const
+ { return base; }
+
+protected:
+ bool checkValid() const
+ {
+ const bool valid = isValid();
+#ifdef Q_ACCESSIBLE_MAC_DEBUG
+ if (!valid)
+ qFatal("QAccessible_mac: tried to use invalid interface.");
+#endif
+ return valid;
+ }
+
+ QAccessibleInterfaceWrapper base;
+ QObject *m_cachedObject;
+ int child;
+};
+
+Q_AUTOTEST_EXPORT QDebug operator<<(QDebug debug, const QAInterface &interface);
+
+/*
+ QAElement is a thin wrapper around an AXUIElementRef that automates
+ the ref-counting.
+*/
+class Q_AUTOTEST_EXPORT QAElement
+{
+public:
+ QAElement();
+ explicit QAElement(AXUIElementRef elementRef);
+ QAElement(const QAElement &element);
+ QAElement(HIObjectRef, int child);
+ ~QAElement();
+
+ inline HIObjectRef object() const
+ {
+#ifndef Q_WS_MAC64
+ return AXUIElementGetHIObject(elementRef);
+#else
+ return 0;
+#endif
+ }
+
+ inline int id() const
+ {
+ UInt64 theId;
+#ifndef QT_MAC_USE_COCOA
+ AXUIElementGetIdentifier(elementRef, &theId);
+#else
+ theId = 0;
+#endif
+ return theId;
+ }
+
+ inline AXUIElementRef element() const
+ {
+ return elementRef;
+ }
+
+ inline bool isValid() const
+ {
+ return (elementRef != 0);
+ }
+
+ void operator=(const QAElement &other);
+ bool operator==(const QAElement &other) const;
+private:
+ AXUIElementRef elementRef;
+};
+
+
+class QInterfaceFactory
+{
+public:
+ virtual QAInterface interface(UInt64 identifier) = 0;
+ virtual QAElement element(int id) = 0;
+ virtual QAElement element(const QAInterface &interface)
+ {
+ return element(interface.id());
+ }
+ virtual void registerChildren() = 0;
+ virtual ~QInterfaceFactory() {}
+};
+
+/*
+ QAccessibleHierarchyManager bridges the Mac and Qt accessibility hierarchies.
+ There is a one-to-one relationship between QAElements on the Mac side
+ and QAInterfaces on the Qt side, and this class provides lookup functions
+ that translates between these to items.
+
+ The identity of a QAInterface is determined by its QAccessibleInterface and
+ child identifier, and the identity of a QAElement is determined by its
+ HIObjectRef and identifier.
+
+ QAccessibleHierarchyManager receives QObject::destroyed() signals and deletes
+ the accessibility objects for destroyed objects.
+*/
+class Q_AUTOTEST_EXPORT QAccessibleHierarchyManager : public QObject
+{
+Q_OBJECT
+public:
+ ~QAccessibleHierarchyManager() { reset(); }
+ static QAccessibleHierarchyManager *instance();
+ void reset();
+
+ QAElement registerInterface(QObject *object, int child);
+ QAElement registerInterface(const QAInterface &interface);
+ void registerInterface(QObject *object, HIObjectRef hiobject, QInterfaceFactory *interfaceFactory);
+
+ void registerChildren(const QAInterface &interface);
+
+ QAInterface lookup(const AXUIElementRef &element);
+ QAInterface lookup(const QAElement &element);
+ QAElement lookup(const QAInterface &interface);
+ QAElement lookup(QObject * const object, int id);
+private slots:
+ void objectDestroyed(QObject *);
+private:
+ typedef QHash<QObject *, QInterfaceFactory *> QObjectElementHash;
+ typedef QHash<HIObjectRef, QInterfaceFactory *> HIObjectInterfaceHash;
+ typedef QHash<QObject *, HIObjectRef> QObjectHIObjectHash;
+
+ QObjectElementHash qobjectElementHash;
+ HIObjectInterfaceHash hiobjectInterfaceHash;
+ QObjectHIObjectHash qobjectHiobjectHash;
+};
+
+Q_AUTOTEST_EXPORT bool isItInteresting(const QAInterface &interface);
+
+QT_END_NAMESPACE
+
+#endif
diff --git a/src/widgets/accessible/qaccessible_unix.cpp b/src/widgets/accessible/qaccessible_unix.cpp
new file mode 100644
index 0000000000..f04d075543
--- /dev/null
+++ b/src/widgets/accessible/qaccessible_unix.cpp
@@ -0,0 +1,134 @@
+/****************************************************************************
+**
+** Copyright (C) 2011 Nokia Corporation and/or its subsidiary(-ies).
+** All rights reserved.
+** Contact: Nokia Corporation (qt-info@nokia.com)
+**
+** This file is part of the QtGui module of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL$
+** No Commercial Usage
+** This file contains pre-release code and may not be distributed.
+** You may use this file in accordance with the terms and conditions
+** contained in the Technology Preview License Agreement accompanying
+** this package.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 2.1 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPL included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU Lesser General Public License version 2.1 requirements
+** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
+**
+** In addition, as a special exception, Nokia gives you certain additional
+** rights. These rights are described in the Nokia Qt LGPL Exception
+** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
+**
+** If you have questions regarding the use of this file, please contact
+** Nokia at qt-info@nokia.com.
+**
+**
+**
+**
+**
+**
+**
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#include "qaccessible.h"
+#include "qaccessiblebridge.h"
+
+#ifndef QT_NO_ACCESSIBILITY
+
+#include "qcoreapplication.h"
+#include "qmutex.h"
+#include "qvector.h"
+#include "private/qfactoryloader_p.h"
+
+#include <stdlib.h>
+
+QT_BEGIN_NAMESPACE
+
+#ifndef QT_NO_LIBRARY
+Q_GLOBAL_STATIC_WITH_ARGS(QFactoryLoader, loader,
+ (QAccessibleBridgeFactoryInterface_iid, QLatin1String("/accessiblebridge")))
+#endif
+Q_GLOBAL_STATIC(QVector<QAccessibleBridge *>, bridges)
+static bool isInit = false;
+
+void QAccessible::initialize()
+{
+ if (isInit)
+ return;
+ isInit = true;
+
+ if (qgetenv("QT_ACCESSIBILITY") != "1")
+ return;
+#ifndef QT_NO_LIBRARY
+ const QStringList l = loader()->keys();
+ for (int i = 0; i < l.count(); ++i) {
+ if (QAccessibleBridgeFactoryInterface *factory =
+ qobject_cast<QAccessibleBridgeFactoryInterface*>(loader()->instance(l.at(i)))) {
+ QAccessibleBridge * bridge = factory->create(l.at(i));
+ if (bridge)
+ bridges()->append(bridge);
+ }
+ }
+#endif
+}
+
+void QAccessible::cleanup()
+{
+ qDeleteAll(*bridges());
+}
+
+void QAccessible::updateAccessibility(QObject *o, int who, Event reason)
+{
+ Q_ASSERT(o);
+
+ if (updateHandler) {
+ updateHandler(o, who, reason);
+ return;
+ }
+
+ initialize();
+ if (bridges()->isEmpty())
+ return;
+
+ QAccessibleInterface *iface = QAccessible::queryAccessibleInterface(o);
+ if (!iface)
+ return;
+
+ for (int i = 0; i < bridges()->count(); ++i)
+ bridges()->at(i)->notifyAccessibilityUpdate(reason, iface, who);
+ delete iface;
+}
+
+void QAccessible::setRootObject(QObject *o)
+{
+ if (rootObjectHandler) {
+ rootObjectHandler(o);
+ return;
+ }
+
+ initialize();
+ if (bridges()->isEmpty())
+ return;
+
+ if (!o)
+ return;
+
+ for (int i = 0; i < bridges()->count(); ++i) {
+ QAccessibleInterface *iface = QAccessible::queryAccessibleInterface(o);
+ bridges()->at(i)->setRootObject(iface);
+ }
+}
+
+QT_END_NAMESPACE
+
+#endif // QT_NO_ACCESSIBILITY
+
diff --git a/src/widgets/accessible/qaccessible_win.cpp b/src/widgets/accessible/qaccessible_win.cpp
new file mode 100644
index 0000000000..98db5293d2
--- /dev/null
+++ b/src/widgets/accessible/qaccessible_win.cpp
@@ -0,0 +1,1439 @@
+/****************************************************************************
+**
+** Copyright (C) 2011 Nokia Corporation and/or its subsidiary(-ies).
+** All rights reserved.
+** Contact: Nokia Corporation (qt-info@nokia.com)
+**
+** This file is part of the QtGui module of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL$
+** No Commercial Usage
+** This file contains pre-release code and may not be distributed.
+** You may use this file in accordance with the terms and conditions
+** contained in the Technology Preview License Agreement accompanying
+** this package.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 2.1 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPL included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU Lesser General Public License version 2.1 requirements
+** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
+**
+** In addition, as a special exception, Nokia gives you certain additional
+** rights. These rights are described in the Nokia Qt LGPL Exception
+** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
+**
+** If you have questions regarding the use of this file, please contact
+** Nokia at qt-info@nokia.com.
+**
+**
+**
+**
+**
+**
+**
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+#include "qaccessible.h"
+#ifndef QT_NO_ACCESSIBILITY
+
+#include "qapplication.h"
+#include <private/qsystemlibrary_p.h>
+#include "qmessagebox.h" // ### dependency
+#include "qt_windows.h"
+#include "qwidget.h"
+#include "qsettings.h"
+#include <QtCore/qmap.h>
+#include <QtCore/qpair.h>
+#include <QtGui/qgraphicsitem.h>
+#include <QtGui/qgraphicsscene.h>
+#include <QtGui/qgraphicsview.h>
+
+#include <winuser.h>
+#if !defined(WINABLEAPI)
+# if defined(Q_WS_WINCE)
+# include <bldver.h>
+# endif
+# include <winable.h>
+#endif
+
+#include <oleacc.h>
+#if !defined(Q_CC_BOR) && !defined (Q_CC_GNU)
+#include <comdef.h>
+#endif
+
+#ifdef Q_WS_WINCE
+#include "qguifunctions_wince.h"
+#endif
+
+QT_BEGIN_NAMESPACE
+
+//#define DEBUG_SHOW_ATCLIENT_COMMANDS
+#ifdef DEBUG_SHOW_ATCLIENT_COMMANDS
+QT_BEGIN_INCLUDE_NAMESPACE
+#include <qdebug.h>
+QT_END_INCLUDE_NAMESPACE
+
+static const char *roleString(QAccessible::Role role)
+{
+ static const char *roles[] = {
+ "NoRole" /* = 0x00000000 */,
+ "TitleBar" /* = 0x00000001 */,
+ "MenuBar" /* = 0x00000002 */,
+ "ScrollBar" /* = 0x00000003 */,
+ "Grip" /* = 0x00000004 */,
+ "Sound" /* = 0x00000005 */,
+ "Cursor" /* = 0x00000006 */,
+ "Caret" /* = 0x00000007 */,
+ "AlertMessage" /* = 0x00000008 */,
+ "Window" /* = 0x00000009 */,
+ "Client" /* = 0x0000000A */,
+ "PopupMenu" /* = 0x0000000B */,
+ "MenuItem" /* = 0x0000000C */,
+ "ToolTip" /* = 0x0000000D */,
+ "Application" /* = 0x0000000E */,
+ "Document" /* = 0x0000000F */,
+ "Pane" /* = 0x00000010 */,
+ "Chart" /* = 0x00000011 */,
+ "Dialog" /* = 0x00000012 */,
+ "Border" /* = 0x00000013 */,
+ "Grouping" /* = 0x00000014 */,
+ "Separator" /* = 0x00000015 */,
+ "ToolBar" /* = 0x00000016 */,
+ "StatusBar" /* = 0x00000017 */,
+ "Table" /* = 0x00000018 */,
+ "ColumnHeader" /* = 0x00000019 */,
+ "RowHeader" /* = 0x0000001A */,
+ "Column" /* = 0x0000001B */,
+ "Row" /* = 0x0000001C */,
+ "Cell" /* = 0x0000001D */,
+ "Link" /* = 0x0000001E */,
+ "HelpBalloon" /* = 0x0000001F */,
+ "Assistant" /* = 0x00000020 */,
+ "List" /* = 0x00000021 */,
+ "ListItem" /* = 0x00000022 */,
+ "Tree" /* = 0x00000023 */,
+ "TreeItem" /* = 0x00000024 */,
+ "PageTab" /* = 0x00000025 */,
+ "PropertyPage" /* = 0x00000026 */,
+ "Indicator" /* = 0x00000027 */,
+ "Graphic" /* = 0x00000028 */,
+ "StaticText" /* = 0x00000029 */,
+ "EditableText" /* = 0x0000002A */, // Editable, selectable, etc.
+ "PushButton" /* = 0x0000002B */,
+ "CheckBox" /* = 0x0000002C */,
+ "RadioButton" /* = 0x0000002D */,
+ "ComboBox" /* = 0x0000002E */,
+ "DropList" /* = 0x0000002F */, // commented out
+ "ProgressBar" /* = 0x00000030 */,
+ "Dial" /* = 0x00000031 */,
+ "HotkeyField" /* = 0x00000032 */,
+ "Slider" /* = 0x00000033 */,
+ "SpinBox" /* = 0x00000034 */,
+ "Canvas" /* = 0x00000035 */,
+ "Animation" /* = 0x00000036 */,
+ "Equation" /* = 0x00000037 */,
+ "ButtonDropDown" /* = 0x00000038 */,
+ "ButtonMenu" /* = 0x00000039 */,
+ "ButtonDropGrid" /* = 0x0000003A */,
+ "Whitespace" /* = 0x0000003B */,
+ "PageTabList" /* = 0x0000003C */,
+ "Clock" /* = 0x0000003D */,
+ "Splitter" /* = 0x0000003E */,
+ "LayeredPane" /* = 0x0000003F */,
+ "UserRole" /* = 0x0000ffff*/
+ };
+
+ if (role >=0x40)
+ role = QAccessible::UserRole;
+ return roles[int(role)];
+}
+
+static const char *eventString(QAccessible::Event ev)
+{
+ static const char *events[] = {
+ "null", // 0
+ "SoundPlayed" /*= 0x0001*/,
+ "Alert" /*= 0x0002*/,
+ "ForegroundChanged" /*= 0x0003*/,
+ "MenuStart" /*= 0x0004*/,
+ "MenuEnd" /*= 0x0005*/,
+ "PopupMenuStart" /*= 0x0006*/,
+ "PopupMenuEnd" /*= 0x0007*/,
+ "ContextHelpStart" /*= 0x000C*/, // 8
+ "ContextHelpEnd" /*= 0x000D*/,
+ "DragDropStart" /*= 0x000E*/,
+ "DragDropEnd" /*= 0x000F*/,
+ "DialogStart" /*= 0x0010*/,
+ "DialogEnd" /*= 0x0011*/,
+ "ScrollingStart" /*= 0x0012*/,
+ "ScrollingEnd" /*= 0x0013*/,
+ "MenuCommand" /*= 0x0018*/, // 16
+
+ // Values from IAccessible2
+ "ActionChanged" /*= 0x0101*/, // 17
+ "ActiveDescendantChanged",
+ "AttributeChanged",
+ "DocumentContentChanged",
+ "DocumentLoadComplete",
+ "DocumentLoadStopped",
+ "DocumentReload",
+ "HyperlinkEndIndexChanged",
+ "HyperlinkNumberOfAnchorsChanged",
+ "HyperlinkSelectedLinkChanged",
+ "HypertextLinkActivated",
+ "HypertextLinkSelected",
+ "HyperlinkStartIndexChanged",
+ "HypertextChanged",
+ "HypertextNLinksChanged",
+ "ObjectAttributeChanged",
+ "PageChanged",
+ "SectionChanged",
+ "TableCaptionChanged",
+ "TableColumnDescriptionChanged",
+ "TableColumnHeaderChanged",
+ "TableModelChanged",
+ "TableRowDescriptionChanged",
+ "TableRowHeaderChanged",
+ "TableSummaryChanged",
+ "TextAttributeChanged",
+ "TextCaretMoved",
+ // TextChanged, deprecated, use TextUpdated
+ //TextColumnChanged = TextCaretMoved + 2,
+ "TextInserted",
+ "TextRemoved",
+ "TextUpdated",
+ "TextSelectionChanged",
+ "VisibleDataChanged", /*= 0x0101+32*/
+ "ObjectCreated" /*= 0x8000*/, // 49
+ "ObjectDestroyed" /*= 0x8001*/,
+ "ObjectShow" /*= 0x8002*/,
+ "ObjectHide" /*= 0x8003*/,
+ "ObjectReorder" /*= 0x8004*/,
+ "Focus" /*= 0x8005*/,
+ "Selection" /*= 0x8006*/,
+ "SelectionAdd" /*= 0x8007*/,
+ "SelectionRemove" /*= 0x8008*/,
+ "SelectionWithin" /*= 0x8009*/,
+ "StateChanged" /*= 0x800A*/,
+ "LocationChanged" /*= 0x800B*/,
+ "NameChanged" /*= 0x800C*/,
+ "DescriptionChanged" /*= 0x800D*/,
+ "ValueChanged" /*= 0x800E*/,
+ "ParentChanged" /*= 0x800F*/,
+ "HelpChanged" /*= 0x80A0*/,
+ "DefaultActionChanged" /*= 0x80B0*/,
+ "AcceleratorChanged" /*= 0x80C0*/
+ };
+ int e = int(ev);
+ if (e <= 0x80c0) {
+ const int last = sizeof(events)/sizeof(char*) - 1;
+
+ if (e <= 0x07)
+ return events[e];
+ else if (e <= 0x13)
+ return events[e - 0x0c + 8];
+ else if (e == 0x18)
+ return events[16];
+ else if (e <= 0x0101 + 32)
+ return events[e - 0x101 + 17];
+ else if (e <= 0x800f)
+ return events[e - 0x8000 + 49];
+ else if (e == 0x80a0)
+ return events[last - 2];
+ else if (e == 0x80b0)
+ return events[last - 1];
+ else if (e == 0x80c0)
+ return events[last];
+ }
+ return "unknown";
+};
+
+void showDebug(const char* funcName, const QAccessibleInterface *iface)
+{
+ qDebug() << "Role:" << roleString(iface->role(0))
+ << "Name:" << iface->text(QAccessible::Name, 0)
+ << "State:" << QString::number(int(iface->state(0)), 16)
+ << QLatin1String(funcName);
+}
+#else
+# define showDebug(f, iface)
+#endif
+
+// This stuff is used for widgets/items with no window handle:
+typedef QMap<int, QPair<QObject*,int> > NotifyMap;
+Q_GLOBAL_STATIC(NotifyMap, qAccessibleRecentSentEvents)
+static int eventNum = 0;
+
+
+void QAccessible::initialize()
+{
+
+}
+void QAccessible::cleanup()
+{
+
+}
+
+void QAccessible::updateAccessibility(QObject *o, int who, Event reason)
+{
+ Q_ASSERT(o);
+
+ if (updateHandler) {
+ updateHandler(o, who, reason);
+ return;
+ }
+
+ QString soundName;
+ switch (reason) {
+ case PopupMenuStart:
+ soundName = QLatin1String("MenuPopup");
+ break;
+
+ case MenuCommand:
+ soundName = QLatin1String("MenuCommand");
+ break;
+
+ case Alert:
+ {
+#ifndef QT_NO_MESSAGEBOX
+ QMessageBox *mb = qobject_cast<QMessageBox*>(o);
+ if (mb) {
+ switch (mb->icon()) {
+ case QMessageBox::Warning:
+ soundName = QLatin1String("SystemExclamation");
+ break;
+ case QMessageBox::Critical:
+ soundName = QLatin1String("SystemHand");
+ break;
+ case QMessageBox::Information:
+ soundName = QLatin1String("SystemAsterisk");
+ break;
+ default:
+ break;
+ }
+ } else
+#endif // QT_NO_MESSAGEBOX
+ {
+ soundName = QLatin1String("SystemAsterisk");
+ }
+
+ }
+ break;
+ default:
+ break;
+ }
+
+ if (soundName.size()) {
+#ifndef QT_NO_SETTINGS
+ QSettings settings(QLatin1String("HKEY_CURRENT_USER\\AppEvents\\Schemes\\Apps\\.Default\\") + soundName,
+ QSettings::NativeFormat);
+ QString file = settings.value(QLatin1String(".Current/.")).toString();
+#else
+ QString file;
+#endif
+ if (!file.isEmpty()) {
+ PlaySound(reinterpret_cast<const wchar_t *>(soundName.utf16()), 0, SND_ALIAS | SND_ASYNC | SND_NODEFAULT | SND_NOWAIT);
+ }
+ }
+
+ if (!isActive())
+ return;
+
+ typedef void (WINAPI *PtrNotifyWinEvent)(DWORD, HWND, LONG, LONG);
+
+#if defined(Q_WS_WINCE) // ### TODO: check for NotifyWinEvent in CE 6.0
+ // There is no user32.lib nor NotifyWinEvent for CE
+ return;
+#else
+ static PtrNotifyWinEvent ptrNotifyWinEvent = 0;
+ static bool resolvedNWE = false;
+ if (!resolvedNWE) {
+ resolvedNWE = true;
+ ptrNotifyWinEvent = (PtrNotifyWinEvent)QSystemLibrary::resolve(QLatin1String("user32"), "NotifyWinEvent");
+ }
+ if (!ptrNotifyWinEvent)
+ return;
+
+ // An event has to be associated with a window,
+ // so find the first parent that is a widget.
+ QWidget *w = 0;
+ QObject *p = o;
+ do {
+ if (p->isWidgetType()) {
+ w = static_cast<QWidget*>(p);
+ if (w->internalWinId())
+ break;
+ }
+ if (QGraphicsObject *gfxObj = qobject_cast<QGraphicsObject*>(p)) {
+ QGraphicsItem *parentItem = gfxObj->parentItem();
+ if (parentItem) {
+ p = parentItem->toGraphicsObject();
+ } else {
+ QGraphicsView *view = 0;
+ if (QGraphicsScene *scene = gfxObj->scene()) {
+ QWidget *fw = QApplication::focusWidget();
+ const QList<QGraphicsView*> views = scene->views();
+ for (int i = 0 ; i < views.count() && view != fw; ++i) {
+ view = views.at(i);
+ }
+ }
+ p = view;
+ }
+ } else {
+ p = p->parent();
+ }
+
+ } while (p);
+
+ //qDebug() << "updateAccessibility(), hwnd:" << w << ", object:" << o << "," << eventString(reason);
+ if (!w) {
+ if (reason != QAccessible::ContextHelpStart &&
+ reason != QAccessible::ContextHelpEnd)
+ w = QApplication::focusWidget();
+ if (!w) {
+ w = QApplication::activeWindow();
+
+ if (!w)
+ return;
+
+// ### Fixme
+// if (!w) {
+// w = qApp->mainWidget();
+// if (!w)
+// return;
+// }
+ }
+ }
+
+ WId wid = w->internalWinId();
+ if (reason != MenuCommand) { // MenuCommand is faked
+ if (w != o) {
+ // See comment "SENDING EVENTS TO OBJECTS WITH NO WINDOW HANDLE"
+ eventNum %= 50; //[0..49]
+ int eventId = - eventNum - 1;
+
+ qAccessibleRecentSentEvents()->insert(eventId, qMakePair(o,who));
+ ptrNotifyWinEvent(reason, wid, OBJID_CLIENT, eventId );
+
+ ++eventNum;
+ } else {
+ ptrNotifyWinEvent(reason, wid, OBJID_CLIENT, who);
+ }
+ }
+#endif // Q_WS_WINCE
+}
+
+/* == SENDING EVENTS TO OBJECTS WITH NO WINDOW HANDLE ==
+
+ If the user requested to send the event to a widget with no window,
+ we need to send an event to an object with no hwnd.
+ The way we do that is to send it to the *first* ancestor widget
+ with a window.
+ Then we'll need a way of identifying the child:
+ We'll just keep a list of the most recent events that we have sent,
+ where each entry in the list is identified by a negative value
+ between [-50,-1]. This negative value we will pass on to
+ NotifyWinEvent() as the child id. When the negative value have
+ reached -50, it will wrap around to -1. This seems to be enough
+
+ Now, when the client receives that event, he will first call
+ AccessibleObjectFromEvent() where dwChildID is the special
+ negative value. AccessibleObjectFromEvent does two steps:
+ 1. It will first sent a WM_GETOBJECT to the server, asking
+ for the IAccessible interface for the HWND.
+ 2. With the IAccessible interface it got hold of it will call
+ acc_getChild where the child id argument is the special
+ negative identifier. In our reimplementation of get_accChild
+ we check for this if the child id is negative. If it is, then
+ we'll look up in our table for the entry that is associated
+ with that value.
+ The entry will then contain a pointer to the QObject /QWidget
+ that we can use to call queryAccessibleInterface() on.
+
+
+ The following figure shows how the interaction between server and
+ client is in the case when the server is sending an event.
+
+SERVER (Qt) | CLIENT |
+--------------------------------------------+---------------------------------------+
+ |
+acc->updateAccessibility(obj, childIndex) |
+ |
+recentEvents()->insert(- 1 - eventNum, |
+ qMakePair(obj, childIndex) |
+NotifyWinEvent(hwnd, childId) => |
+ | AccessibleObjectFromEvent(event, hwnd, OBJID_CLIENT, childId )
+ | will do:
+ <=== 1. send WM_GETOBJECT(hwnd, OBJID_CLIENT)
+widget ~= hwnd
+iface = queryAccessibleInteface(widget)
+(create IAccessible interface wrapper for
+ iface)
+ return iface ===> IAccessible* iface; (for hwnd)
+ |
+ <=== call iface->get_accChild(childId)
+get_accChild() { |
+ if (varChildID.lVal < 0) {
+ QPair ref = recentEvents().value(varChildID.lVal);
+ [...]
+ }
+*/
+
+
+void QAccessible::setRootObject(QObject *o)
+{
+ if (rootObjectHandler) {
+ rootObjectHandler(o);
+ }
+}
+
+class QWindowsEnumerate : public IEnumVARIANT
+{
+public:
+ QWindowsEnumerate(const QVector<int> &a)
+ : ref(0), current(0),array(a)
+ {
+ }
+
+ virtual ~QWindowsEnumerate() {}
+
+ HRESULT STDMETHODCALLTYPE QueryInterface(REFIID, LPVOID *);
+ ULONG STDMETHODCALLTYPE AddRef();
+ ULONG STDMETHODCALLTYPE Release();
+
+ HRESULT STDMETHODCALLTYPE Clone(IEnumVARIANT **ppEnum);
+ HRESULT STDMETHODCALLTYPE Next(unsigned long celt, VARIANT FAR* rgVar, unsigned long FAR* pCeltFetched);
+ HRESULT STDMETHODCALLTYPE Reset();
+ HRESULT STDMETHODCALLTYPE Skip(unsigned long celt);
+
+private:
+ ULONG ref;
+ ULONG current;
+ QVector<int> array;
+};
+
+HRESULT STDMETHODCALLTYPE QWindowsEnumerate::QueryInterface(REFIID id, LPVOID *iface)
+{
+ *iface = 0;
+ if (id == IID_IUnknown)
+ *iface = (IUnknown*)this;
+ else if (id == IID_IEnumVARIANT)
+ *iface = (IEnumVARIANT*)this;
+
+ if (*iface) {
+ AddRef();
+ return S_OK;
+ }
+
+ return E_NOINTERFACE;
+}
+
+ULONG STDMETHODCALLTYPE QWindowsEnumerate::AddRef()
+{
+ return ++ref;
+}
+
+ULONG STDMETHODCALLTYPE QWindowsEnumerate::Release()
+{
+ if (!--ref) {
+ delete this;
+ return 0;
+ }
+ return ref;
+}
+
+HRESULT STDMETHODCALLTYPE QWindowsEnumerate::Clone(IEnumVARIANT **ppEnum)
+{
+ QWindowsEnumerate *penum = 0;
+ *ppEnum = 0;
+
+ penum = new QWindowsEnumerate(array);
+ if (!penum)
+ return E_OUTOFMEMORY;
+ penum->current = current;
+ penum->array = array;
+ penum->AddRef();
+ *ppEnum = penum;
+
+ return S_OK;
+}
+
+HRESULT STDMETHODCALLTYPE QWindowsEnumerate::Next(unsigned long celt, VARIANT FAR* rgVar, unsigned long FAR* pCeltFetched)
+{
+ if (pCeltFetched)
+ *pCeltFetched = 0;
+
+ ULONG l;
+ for (l = 0; l < celt; l++) {
+ VariantInit(&rgVar[l]);
+ if ((current+1) > (ULONG)array.size()) {
+ *pCeltFetched = l;
+ return S_FALSE;
+ }
+
+ rgVar[l].vt = VT_I4;
+ rgVar[l].lVal = array[(int)current];
+ ++current;
+ }
+ *pCeltFetched = l;
+ return S_OK;
+}
+
+HRESULT STDMETHODCALLTYPE QWindowsEnumerate::Reset()
+{
+ current = 0;
+ return S_OK;
+}
+
+HRESULT STDMETHODCALLTYPE QWindowsEnumerate::Skip(unsigned long celt)
+{
+ current += celt;
+ if (current > (ULONG)array.size()) {
+ current = array.size();
+ return S_FALSE;
+ }
+ return S_OK;
+}
+
+/*
+*/
+class QWindowsAccessible : public IAccessible, IOleWindow, QAccessible
+{
+public:
+ QWindowsAccessible(QAccessibleInterface *a)
+ : ref(0), accessible(a)
+ {
+ }
+
+ virtual ~QWindowsAccessible()
+ {
+ delete accessible;
+ }
+
+ /* IUnknown */
+ HRESULT STDMETHODCALLTYPE QueryInterface(REFIID, LPVOID *);
+ ULONG STDMETHODCALLTYPE AddRef();
+ ULONG STDMETHODCALLTYPE Release();
+
+ /* IDispatch */
+ HRESULT STDMETHODCALLTYPE GetTypeInfoCount(unsigned int *);
+ HRESULT STDMETHODCALLTYPE GetTypeInfo(unsigned int, unsigned long, ITypeInfo **);
+ HRESULT STDMETHODCALLTYPE GetIDsOfNames(const _GUID &, wchar_t **, unsigned int, unsigned long, long *);
+ HRESULT STDMETHODCALLTYPE Invoke(long, const _GUID &, unsigned long, unsigned short, tagDISPPARAMS *, tagVARIANT *, tagEXCEPINFO *, unsigned int *);
+
+ /* IAccessible */
+ HRESULT STDMETHODCALLTYPE accHitTest(long xLeft, long yTop, VARIANT *pvarID);
+ HRESULT STDMETHODCALLTYPE accLocation(long *pxLeft, long *pyTop, long *pcxWidth, long *pcyHeight, VARIANT varID);
+ HRESULT STDMETHODCALLTYPE accNavigate(long navDir, VARIANT varStart, VARIANT *pvarEnd);
+ HRESULT STDMETHODCALLTYPE get_accChild(VARIANT varChildID, IDispatch** ppdispChild);
+ HRESULT STDMETHODCALLTYPE get_accChildCount(long* pcountChildren);
+ HRESULT STDMETHODCALLTYPE get_accParent(IDispatch** ppdispParent);
+
+ HRESULT STDMETHODCALLTYPE accDoDefaultAction(VARIANT varID);
+ HRESULT STDMETHODCALLTYPE get_accDefaultAction(VARIANT varID, BSTR* pszDefaultAction);
+ HRESULT STDMETHODCALLTYPE get_accDescription(VARIANT varID, BSTR* pszDescription);
+ HRESULT STDMETHODCALLTYPE get_accHelp(VARIANT varID, BSTR *pszHelp);
+ HRESULT STDMETHODCALLTYPE get_accHelpTopic(BSTR *pszHelpFile, VARIANT varChild, long *pidTopic);
+ HRESULT STDMETHODCALLTYPE get_accKeyboardShortcut(VARIANT varID, BSTR *pszKeyboardShortcut);
+ HRESULT STDMETHODCALLTYPE get_accName(VARIANT varID, BSTR* pszName);
+ HRESULT STDMETHODCALLTYPE put_accName(VARIANT varChild, BSTR szName);
+ HRESULT STDMETHODCALLTYPE get_accRole(VARIANT varID, VARIANT *pvarRole);
+ HRESULT STDMETHODCALLTYPE get_accState(VARIANT varID, VARIANT *pvarState);
+ HRESULT STDMETHODCALLTYPE get_accValue(VARIANT varID, BSTR* pszValue);
+ HRESULT STDMETHODCALLTYPE put_accValue(VARIANT varChild, BSTR szValue);
+
+ HRESULT STDMETHODCALLTYPE accSelect(long flagsSelect, VARIANT varID);
+ HRESULT STDMETHODCALLTYPE get_accFocus(VARIANT *pvarID);
+ HRESULT STDMETHODCALLTYPE get_accSelection(VARIANT *pvarChildren);
+
+ /* IOleWindow */
+ HRESULT STDMETHODCALLTYPE GetWindow(HWND *phwnd);
+ HRESULT STDMETHODCALLTYPE ContextSensitiveHelp(BOOL fEnterMode);
+
+private:
+ ULONG ref;
+ QAccessibleInterface *accessible;
+};
+
+static inline BSTR QStringToBSTR(const QString &str)
+{
+ BSTR bstrVal;
+
+ int wlen = str.length()+1;
+ bstrVal = SysAllocStringByteLen(0, wlen*2);
+ memcpy(bstrVal, str.unicode(), sizeof(QChar)*(wlen));
+ bstrVal[wlen] = 0;
+
+ return bstrVal;
+}
+
+/*
+*/
+IAccessible *qt_createWindowsAccessible(QAccessibleInterface *access)
+{
+ QWindowsAccessible *acc = new QWindowsAccessible(access);
+ IAccessible *iface;
+ acc->QueryInterface(IID_IAccessible, (void**)&iface);
+
+ return iface;
+}
+
+/*
+ IUnknown
+*/
+HRESULT STDMETHODCALLTYPE QWindowsAccessible::QueryInterface(REFIID id, LPVOID *iface)
+{
+ *iface = 0;
+ if (id == IID_IUnknown)
+ *iface = (IUnknown*)(IDispatch*)this;
+ else if (id == IID_IDispatch)
+ *iface = (IDispatch*)this;
+ else if (id == IID_IAccessible)
+ *iface = (IAccessible*)this;
+ else if (id == IID_IOleWindow)
+ *iface = (IOleWindow*)this;
+ else
+ return E_NOINTERFACE;
+
+ AddRef();
+ return S_OK;
+}
+
+ULONG STDMETHODCALLTYPE QWindowsAccessible::AddRef()
+{
+ return ++ref;
+}
+
+ULONG STDMETHODCALLTYPE QWindowsAccessible::Release()
+{
+ if (!--ref) {
+ delete this;
+ return 0;
+ }
+ return ref;
+}
+
+/*
+ IDispatch
+*/
+
+HRESULT STDMETHODCALLTYPE QWindowsAccessible::GetTypeInfoCount(unsigned int * pctinfo)
+{
+ // We don't use a type library
+ *pctinfo = 0;
+ return S_OK;
+}
+
+HRESULT STDMETHODCALLTYPE QWindowsAccessible::GetTypeInfo(unsigned int, unsigned long, ITypeInfo **pptinfo)
+{
+ // We don't use a type library
+ *pptinfo = 0;
+ return S_OK;
+}
+
+HRESULT STDMETHODCALLTYPE QWindowsAccessible::GetIDsOfNames(const _GUID &, wchar_t **rgszNames, unsigned int, unsigned long, long *rgdispid)
+{
+#if !defined(Q_CC_BOR) && !defined(Q_CC_GNU)
+ // PROPERTIES: Hierarchical
+ if (_bstr_t(rgszNames[0]) == _bstr_t(L"accParent"))
+ rgdispid[0] = DISPID_ACC_PARENT;
+ else if(_bstr_t(rgszNames[0]) == _bstr_t(L"accChildCount"))
+ rgdispid[0] = DISPID_ACC_CHILDCOUNT;
+ else if(_bstr_t(rgszNames[0]) == _bstr_t(L"accChild"))
+ rgdispid[0] = DISPID_ACC_CHILD;
+
+ // PROPERTIES: Descriptional
+ else if(_bstr_t(rgszNames[0]) == _bstr_t(L"accName("))
+ rgdispid[0] = DISPID_ACC_NAME;
+ else if(_bstr_t(rgszNames[0]) == _bstr_t(L"accValue"))
+ rgdispid[0] = DISPID_ACC_VALUE;
+ else if(_bstr_t(rgszNames[0]) == _bstr_t(L"accDescription"))
+ rgdispid[0] = DISPID_ACC_DESCRIPTION;
+ else if(_bstr_t(rgszNames[0]) == _bstr_t(L"accRole"))
+ rgdispid[0] = DISPID_ACC_ROLE;
+ else if(_bstr_t(rgszNames[0]) == _bstr_t(L"accState"))
+ rgdispid[0] = DISPID_ACC_STATE;
+ else if(_bstr_t(rgszNames[0]) == _bstr_t(L"accHelp"))
+ rgdispid[0] = DISPID_ACC_HELP;
+ else if(_bstr_t(rgszNames[0]) == _bstr_t(L"accHelpTopic"))
+ rgdispid[0] = DISPID_ACC_HELPTOPIC;
+ else if(_bstr_t(rgszNames[0]) == _bstr_t(L"accKeyboardShortcut"))
+ rgdispid[0] = DISPID_ACC_KEYBOARDSHORTCUT;
+ else if(_bstr_t(rgszNames[0]) == _bstr_t(L"accFocus"))
+ rgdispid[0] = DISPID_ACC_FOCUS;
+ else if(_bstr_t(rgszNames[0]) == _bstr_t(L"accSelection"))
+ rgdispid[0] = DISPID_ACC_SELECTION;
+ else if(_bstr_t(rgszNames[0]) == _bstr_t(L"accDefaultAction"))
+ rgdispid[0] = DISPID_ACC_DEFAULTACTION;
+
+ // METHODS
+ else if(_bstr_t(rgszNames[0]) == _bstr_t(L"accSelect"))
+ rgdispid[0] = DISPID_ACC_SELECT;
+ else if(_bstr_t(rgszNames[0]) == _bstr_t(L"accLocation"))
+ rgdispid[0] = DISPID_ACC_LOCATION;
+ else if(_bstr_t(rgszNames[0]) == _bstr_t(L"accNavigate"))
+ rgdispid[0] = DISPID_ACC_NAVIGATE;
+ else if(_bstr_t(rgszNames[0]) == _bstr_t(L"accHitTest"))
+ rgdispid[0] = DISPID_ACC_HITTEST;
+ else if(_bstr_t(rgszNames[0]) == _bstr_t(L"accDoDefaultAction"))
+ rgdispid[0] = DISPID_ACC_DODEFAULTACTION;
+ else
+ return DISP_E_UNKNOWNINTERFACE;
+
+ return S_OK;
+#else
+ Q_UNUSED(rgszNames);
+ Q_UNUSED(rgdispid);
+
+ return DISP_E_MEMBERNOTFOUND;
+#endif
+}
+
+HRESULT STDMETHODCALLTYPE QWindowsAccessible::Invoke(long dispIdMember, const _GUID &, unsigned long, unsigned short wFlags, tagDISPPARAMS *pDispParams, tagVARIANT *pVarResult, tagEXCEPINFO *, unsigned int *)
+{
+ HRESULT hr = DISP_E_MEMBERNOTFOUND;
+
+ switch(dispIdMember)
+ {
+ case DISPID_ACC_PARENT:
+ if (wFlags == DISPATCH_PROPERTYGET) {
+ if (!pVarResult)
+ return E_INVALIDARG;
+ hr = get_accParent(&pVarResult->pdispVal);
+ } else {
+ hr = DISP_E_MEMBERNOTFOUND;
+ }
+ break;
+
+ case DISPID_ACC_CHILDCOUNT:
+ if (wFlags == DISPATCH_PROPERTYGET) {
+ if (!pVarResult)
+ return E_INVALIDARG;
+ hr = get_accChildCount(&pVarResult->lVal);
+ } else {
+ hr = DISP_E_MEMBERNOTFOUND;
+ }
+ break;
+
+ case DISPID_ACC_CHILD:
+ if (wFlags == DISPATCH_PROPERTYGET)
+ hr = get_accChild(pDispParams->rgvarg[0], &pVarResult->pdispVal);
+ else
+ hr = DISP_E_MEMBERNOTFOUND;
+ break;
+
+ case DISPID_ACC_NAME:
+ if (wFlags == DISPATCH_PROPERTYGET)
+ hr = get_accName(pDispParams->rgvarg[0], &pVarResult->bstrVal);
+ else if (wFlags == DISPATCH_PROPERTYPUT)
+ hr = put_accName(pDispParams->rgvarg[0], pVarResult->bstrVal);
+ else
+ hr = DISP_E_MEMBERNOTFOUND;
+ break;
+
+ case DISPID_ACC_VALUE:
+ if (wFlags == DISPATCH_PROPERTYGET)
+ hr = get_accValue(pDispParams->rgvarg[0], &pVarResult->bstrVal);
+ else if (wFlags == DISPATCH_PROPERTYPUT)
+ hr = put_accValue(pDispParams->rgvarg[0], pVarResult->bstrVal);
+ else
+ hr = DISP_E_MEMBERNOTFOUND;
+ break;
+
+ case DISPID_ACC_DESCRIPTION:
+ if (wFlags == DISPATCH_PROPERTYGET)
+ hr = get_accDescription(pDispParams->rgvarg[0], &pVarResult->bstrVal);
+ else
+ hr = DISP_E_MEMBERNOTFOUND;
+ break;
+
+ case DISPID_ACC_ROLE:
+ if (wFlags == DISPATCH_PROPERTYGET)
+ hr = get_accRole(pDispParams->rgvarg[0], pVarResult);
+ else
+ hr = DISP_E_MEMBERNOTFOUND;
+ break;
+
+ case DISPID_ACC_STATE:
+ if (wFlags == DISPATCH_PROPERTYGET)
+ hr = get_accState(pDispParams->rgvarg[0], pVarResult);
+ else
+ hr = DISP_E_MEMBERNOTFOUND;
+ break;
+
+ case DISPID_ACC_HELP:
+ if (wFlags == DISPATCH_PROPERTYGET)
+ hr = get_accHelp(pDispParams->rgvarg[0], &pVarResult->bstrVal);
+ else
+ hr = DISP_E_MEMBERNOTFOUND;
+ break;
+
+ case DISPID_ACC_HELPTOPIC:
+ if (wFlags == DISPATCH_PROPERTYGET)
+ hr = get_accHelpTopic(&pDispParams->rgvarg[2].bstrVal, pDispParams->rgvarg[1], &pDispParams->rgvarg[0].lVal);
+ else
+ hr = DISP_E_MEMBERNOTFOUND;
+ break;
+
+ case DISPID_ACC_KEYBOARDSHORTCUT:
+ if (wFlags == DISPATCH_PROPERTYGET)
+ hr = get_accKeyboardShortcut(pDispParams->rgvarg[0], &pVarResult->bstrVal);
+ else
+ hr = DISP_E_MEMBERNOTFOUND;
+ break;
+
+ case DISPID_ACC_FOCUS:
+ if (wFlags == DISPATCH_PROPERTYGET)
+ hr = get_accFocus(pVarResult);
+ else
+ hr = DISP_E_MEMBERNOTFOUND;
+ break;
+
+ case DISPID_ACC_SELECTION:
+ if (wFlags == DISPATCH_PROPERTYGET)
+ hr = get_accSelection(pVarResult);
+ else
+ hr = DISP_E_MEMBERNOTFOUND;
+ break;
+
+ case DISPID_ACC_DEFAULTACTION:
+ if (wFlags == DISPATCH_PROPERTYGET)
+ hr = get_accDefaultAction(pDispParams->rgvarg[0], &pVarResult->bstrVal);
+ else
+ hr = DISP_E_MEMBERNOTFOUND;
+ break;
+
+ case DISPID_ACC_SELECT:
+ if (wFlags == DISPATCH_METHOD)
+ hr = accSelect(pDispParams->rgvarg[1].lVal, pDispParams->rgvarg[0]);
+ else
+ hr = DISP_E_MEMBERNOTFOUND;
+ break;
+
+ case DISPID_ACC_LOCATION:
+ if (wFlags == DISPATCH_METHOD)
+ hr = accLocation(&pDispParams->rgvarg[4].lVal, &pDispParams->rgvarg[3].lVal, &pDispParams->rgvarg[2].lVal, &pDispParams->rgvarg[1].lVal, pDispParams->rgvarg[0]);
+ else
+ hr = DISP_E_MEMBERNOTFOUND;
+ break;
+
+ case DISPID_ACC_NAVIGATE:
+ if (wFlags == DISPATCH_METHOD)
+ hr = accNavigate(pDispParams->rgvarg[1].lVal, pDispParams->rgvarg[0], pVarResult);
+ else
+ hr = DISP_E_MEMBERNOTFOUND;
+ break;
+
+ case DISPID_ACC_HITTEST:
+ if (wFlags == DISPATCH_METHOD)
+ hr = accHitTest(pDispParams->rgvarg[1].lVal, pDispParams->rgvarg[0].lVal, pVarResult);
+ else
+ hr = DISP_E_MEMBERNOTFOUND;
+ break;
+
+ case DISPID_ACC_DODEFAULTACTION:
+ if (wFlags == DISPATCH_METHOD)
+ hr = accDoDefaultAction(pDispParams->rgvarg[0]);
+ else
+ hr = DISP_E_MEMBERNOTFOUND;
+ break;
+
+ default:
+ hr = DISP_E_MEMBERNOTFOUND;
+ break;
+ }
+
+ if (!SUCCEEDED(hr)) {
+ return hr;
+ }
+ return hr;
+}
+
+/*
+ IAccessible
+*/
+HRESULT STDMETHODCALLTYPE QWindowsAccessible::accHitTest(long xLeft, long yTop, VARIANT *pvarID)
+{
+ showDebug(__FUNCTION__, accessible);
+ if (!accessible->isValid())
+ return E_FAIL;
+
+ int control = accessible->childAt(xLeft, yTop);
+ if (control == -1) {
+ (*pvarID).vt = VT_EMPTY;
+ return S_FALSE;
+ }
+ QAccessibleInterface *acc = 0;
+ if (control)
+ accessible->navigate(Child, control, &acc);
+ if (!acc) {
+ (*pvarID).vt = VT_I4;
+ (*pvarID).lVal = control;
+ return S_OK;
+ }
+
+ QWindowsAccessible* wacc = new QWindowsAccessible(acc);
+ IDispatch *iface = 0;
+ wacc->QueryInterface(IID_IDispatch, (void**)&iface);
+ if (iface) {
+ (*pvarID).vt = VT_DISPATCH;
+ (*pvarID).pdispVal = iface;
+ return S_OK;
+ } else {
+ delete wacc;
+ }
+
+ (*pvarID).vt = VT_EMPTY;
+ return S_FALSE;
+}
+
+HRESULT STDMETHODCALLTYPE QWindowsAccessible::accLocation(long *pxLeft, long *pyTop, long *pcxWidth, long *pcyHeight, VARIANT varID)
+{
+ showDebug(__FUNCTION__, accessible);
+ if (!accessible->isValid())
+ return E_FAIL;
+
+ QRect rect = accessible->rect(varID.lVal);
+ if (rect.isValid()) {
+ *pxLeft = rect.x();
+ *pyTop = rect.y();
+ *pcxWidth = rect.width();
+ *pcyHeight = rect.height();
+ } else {
+ *pxLeft = 0;
+ *pyTop = 0;
+ *pcxWidth = 0;
+ *pcyHeight = 0;
+ }
+ return S_OK;
+}
+
+HRESULT STDMETHODCALLTYPE QWindowsAccessible::accNavigate(long navDir, VARIANT varStart, VARIANT *pvarEnd)
+{
+ showDebug(__FUNCTION__, accessible);
+ if (!accessible->isValid())
+ return E_FAIL;
+
+ QAccessibleInterface *acc = 0;
+ int control = -1;
+ switch(navDir) {
+ case NAVDIR_FIRSTCHILD:
+ control = accessible->navigate(Child, 1, &acc);
+ break;
+ case NAVDIR_LASTCHILD:
+ control = accessible->navigate(Child, accessible->childCount(), &acc);
+ break;
+ case NAVDIR_NEXT:
+ case NAVDIR_PREVIOUS:
+ if (!varStart.lVal){
+ QAccessibleInterface *parent = 0;
+ accessible->navigate(Ancestor, 1, &parent);
+ if (parent) {
+ int index = parent->indexOfChild(accessible);
+ index += (navDir == NAVDIR_NEXT) ? 1 : -1;
+ if (index > 0 && index <= parent->childCount())
+ control = parent->navigate(Child, index, &acc);
+ delete parent;
+ }
+ } else {
+ int index = varStart.lVal;
+ index += (navDir == NAVDIR_NEXT) ? 1 : -1;
+ if (index > 0 && index <= accessible->childCount())
+ control = accessible->navigate(Child, index, &acc);
+ }
+ break;
+ case NAVDIR_UP:
+ control = accessible->navigate(Up, varStart.lVal, &acc);
+ break;
+ case NAVDIR_DOWN:
+ control = accessible->navigate(Down, varStart.lVal, &acc);
+ break;
+ case NAVDIR_LEFT:
+ control = accessible->navigate(Left, varStart.lVal, &acc);
+ break;
+ case NAVDIR_RIGHT:
+ control = accessible->navigate(Right, varStart.lVal, &acc);
+ break;
+ default:
+ break;
+ }
+ if (control == -1) {
+ (*pvarEnd).vt = VT_EMPTY;
+ return S_FALSE;
+ }
+ if (!acc) {
+ (*pvarEnd).vt = VT_I4;
+ (*pvarEnd).lVal = control;
+ return S_OK;
+ }
+
+ QWindowsAccessible* wacc = new QWindowsAccessible(acc);
+
+ IDispatch *iface = 0;
+ wacc->QueryInterface(IID_IDispatch, (void**)&iface);
+ if (iface) {
+ (*pvarEnd).vt = VT_DISPATCH;
+ (*pvarEnd).pdispVal = iface;
+ return S_OK;
+ } else {
+ delete wacc;
+ }
+
+ (*pvarEnd).vt = VT_EMPTY;
+ return S_FALSE;
+}
+
+HRESULT STDMETHODCALLTYPE QWindowsAccessible::get_accChild(VARIANT varChildID, IDispatch** ppdispChild)
+{
+ showDebug(__FUNCTION__, accessible);
+ if (!accessible->isValid())
+ return E_FAIL;
+
+ if (varChildID.vt == VT_EMPTY)
+ return E_INVALIDARG;
+
+
+ int childIndex = varChildID.lVal;
+ QAccessibleInterface *acc = 0;
+
+ if (childIndex < 0) {
+ const int entry = childIndex;
+ QPair<QObject*, int> ref = qAccessibleRecentSentEvents()->value(entry);
+ if (ref.first) {
+ acc = queryAccessibleInterface(ref.first);
+ if (acc && ref.second) {
+ if (ref.second) {
+ QAccessibleInterface *res;
+ int index = acc->navigate(Child, ref.second, &res);
+ delete acc;
+ if (index == -1)
+ return E_INVALIDARG;
+ acc = res;
+ }
+ }
+ }
+ } else {
+ RelationFlag rel = childIndex ? Child : Self;
+ accessible->navigate(rel, childIndex, &acc);
+ }
+
+ if (acc) {
+ QWindowsAccessible* wacc = new QWindowsAccessible(acc);
+ wacc->QueryInterface(IID_IDispatch, (void**)ppdispChild);
+ return S_OK;
+ }
+
+ *ppdispChild = 0;
+ return S_FALSE;
+}
+
+HRESULT STDMETHODCALLTYPE QWindowsAccessible::get_accChildCount(long* pcountChildren)
+{
+ showDebug(__FUNCTION__, accessible);
+ if (!accessible->isValid())
+ return E_FAIL;
+
+ *pcountChildren = accessible->childCount();
+ return S_OK;
+}
+
+HRESULT STDMETHODCALLTYPE QWindowsAccessible::get_accParent(IDispatch** ppdispParent)
+{
+ showDebug(__FUNCTION__, accessible);
+ if (!accessible->isValid())
+ return E_FAIL;
+
+ QAccessibleInterface *acc = 0;
+ accessible->navigate(Ancestor, 1, &acc);
+ if (acc) {
+ QWindowsAccessible* wacc = new QWindowsAccessible(acc);
+ wacc->QueryInterface(IID_IDispatch, (void**)ppdispParent);
+
+ if (*ppdispParent)
+ return S_OK;
+ }
+
+ *ppdispParent = 0;
+ return S_FALSE;
+}
+
+/*
+ Properties and methods
+*/
+HRESULT STDMETHODCALLTYPE QWindowsAccessible::accDoDefaultAction(VARIANT varID)
+{
+ showDebug(__FUNCTION__, accessible);
+ if (!accessible->isValid())
+ return E_FAIL;
+
+ return accessible->doAction(DefaultAction, varID.lVal, QVariantList()) ? S_OK : S_FALSE;
+}
+
+HRESULT STDMETHODCALLTYPE QWindowsAccessible::get_accDefaultAction(VARIANT varID, BSTR* pszDefaultAction)
+{
+ showDebug(__FUNCTION__, accessible);
+ if (!accessible->isValid())
+ return E_FAIL;
+
+ QString def = accessible->actionText(DefaultAction, Name, varID.lVal);
+ if (def.isEmpty()) {
+ *pszDefaultAction = 0;
+ return S_FALSE;
+ }
+
+ *pszDefaultAction = QStringToBSTR(def);
+ return S_OK;
+}
+
+HRESULT STDMETHODCALLTYPE QWindowsAccessible::get_accDescription(VARIANT varID, BSTR* pszDescription)
+{
+ showDebug(__FUNCTION__, accessible);
+ if (!accessible->isValid())
+ return E_FAIL;
+
+ QString descr = accessible->text(Description, varID.lVal);
+ if (descr.size()) {
+ *pszDescription = QStringToBSTR(descr);
+ return S_OK;
+ }
+
+ *pszDescription = 0;
+ return S_FALSE;
+}
+
+HRESULT STDMETHODCALLTYPE QWindowsAccessible::get_accHelp(VARIANT varID, BSTR *pszHelp)
+{
+ showDebug(__FUNCTION__, accessible);
+ if (!accessible->isValid())
+ return E_FAIL;
+
+ QString help = accessible->text(Help, varID.lVal);
+ if (help.size()) {
+ *pszHelp = QStringToBSTR(help);
+ return S_OK;
+ }
+
+ *pszHelp = 0;
+ return S_FALSE;
+}
+
+HRESULT STDMETHODCALLTYPE QWindowsAccessible::get_accHelpTopic(BSTR *, VARIANT, long *)
+{
+ return DISP_E_MEMBERNOTFOUND;
+}
+
+HRESULT STDMETHODCALLTYPE QWindowsAccessible::get_accKeyboardShortcut(VARIANT varID, BSTR *pszKeyboardShortcut)
+{
+ showDebug(__FUNCTION__, accessible);
+ if (!accessible->isValid())
+ return E_FAIL;
+
+ QString sc = accessible->text(Accelerator, varID.lVal);
+ if (sc.size()) {
+ *pszKeyboardShortcut = QStringToBSTR(sc);
+ return S_OK;
+ }
+
+ *pszKeyboardShortcut = 0;
+ return S_FALSE;
+}
+
+HRESULT STDMETHODCALLTYPE QWindowsAccessible::get_accName(VARIANT varID, BSTR* pszName)
+{
+ showDebug(__FUNCTION__, accessible);
+ if (!accessible->isValid())
+ return E_FAIL;
+
+ QString n = accessible->text(Name, varID.lVal);
+ if (n.size()) {
+ *pszName = QStringToBSTR(n);
+ return S_OK;
+ }
+
+ *pszName = 0;
+ return S_FALSE;
+}
+
+HRESULT STDMETHODCALLTYPE QWindowsAccessible::put_accName(VARIANT, BSTR)
+{
+ showDebug(__FUNCTION__, accessible);
+ return DISP_E_MEMBERNOTFOUND;
+}
+
+HRESULT STDMETHODCALLTYPE QWindowsAccessible::get_accRole(VARIANT varID, VARIANT *pvarRole)
+{
+ showDebug(__FUNCTION__, accessible);
+ if (!accessible->isValid())
+ return E_FAIL;
+
+ Role role = accessible->role(varID.lVal);
+ if (role != NoRole) {
+ if (role == LayeredPane)
+ role = QAccessible::Pane;
+ (*pvarRole).vt = VT_I4;
+ (*pvarRole).lVal = role;
+ } else {
+ (*pvarRole).vt = VT_EMPTY;
+ }
+ return S_OK;
+}
+
+HRESULT STDMETHODCALLTYPE QWindowsAccessible::get_accState(VARIANT varID, VARIANT *pvarState)
+{
+ showDebug(__FUNCTION__, accessible);
+ if (!accessible->isValid())
+ return E_FAIL;
+
+ (*pvarState).vt = VT_I4;
+ (*pvarState).lVal = accessible->state(varID.lVal);
+ return S_OK;
+}
+
+HRESULT STDMETHODCALLTYPE QWindowsAccessible::get_accValue(VARIANT varID, BSTR* pszValue)
+{
+ showDebug(__FUNCTION__, accessible);
+ if (!accessible->isValid())
+ return E_FAIL;
+
+ QString value = accessible->text(Value, varID.lVal);
+ if (!value.isNull()) {
+ *pszValue = QStringToBSTR(value);
+ return S_OK;
+ }
+
+ *pszValue = 0;
+ return S_FALSE;
+}
+
+HRESULT STDMETHODCALLTYPE QWindowsAccessible::put_accValue(VARIANT, BSTR)
+{
+ showDebug(__FUNCTION__, accessible);
+ return DISP_E_MEMBERNOTFOUND;
+}
+
+HRESULT STDMETHODCALLTYPE QWindowsAccessible::accSelect(long flagsSelect, VARIANT varID)
+{
+ showDebug(__FUNCTION__, accessible);
+ if (!accessible->isValid())
+ return E_FAIL;
+
+ bool res = false;
+
+ if (flagsSelect & SELFLAG_TAKEFOCUS)
+ res = accessible->doAction(SetFocus, varID.lVal, QVariantList());
+ if (flagsSelect & SELFLAG_TAKESELECTION) {
+ accessible->doAction(ClearSelection, 0, QVariantList());
+ res = accessible->doAction(AddToSelection, varID.lVal, QVariantList());
+ }
+ if (flagsSelect & SELFLAG_EXTENDSELECTION)
+ res = accessible->doAction(ExtendSelection, varID.lVal, QVariantList());
+ if (flagsSelect & SELFLAG_ADDSELECTION)
+ res = accessible->doAction(AddToSelection, varID.lVal, QVariantList());
+ if (flagsSelect & SELFLAG_REMOVESELECTION)
+ res = accessible->doAction(RemoveSelection, varID.lVal, QVariantList());
+
+ return res ? S_OK : S_FALSE;
+}
+
+HRESULT STDMETHODCALLTYPE QWindowsAccessible::get_accFocus(VARIANT *pvarID)
+{
+ showDebug(__FUNCTION__, accessible);
+ if (!accessible->isValid())
+ return E_FAIL;
+
+ QAccessibleInterface *acc = 0;
+ int control = accessible->navigate(FocusChild, 1, &acc);
+ if (control == -1) {
+ (*pvarID).vt = VT_EMPTY;
+ return S_FALSE;
+ }
+ if (!acc || control == 0) {
+ (*pvarID).vt = VT_I4;
+ (*pvarID).lVal = control ? control : CHILDID_SELF;
+ return S_OK;
+ }
+
+ QWindowsAccessible* wacc = new QWindowsAccessible(acc);
+ IDispatch *iface = 0;
+ wacc->QueryInterface(IID_IDispatch, (void**)&iface);
+ if (iface) {
+ (*pvarID).vt = VT_DISPATCH;
+ (*pvarID).pdispVal = iface;
+ return S_OK;
+ } else {
+ delete wacc;
+ }
+
+ (*pvarID).vt = VT_EMPTY;
+ return S_FALSE;
+}
+
+HRESULT STDMETHODCALLTYPE QWindowsAccessible::get_accSelection(VARIANT *pvarChildren)
+{
+ showDebug(__FUNCTION__, accessible);
+ if (!accessible->isValid())
+ return E_FAIL;
+
+ int cc = accessible->childCount();
+ QVector<int> sel(cc);
+ int selIndex = 0;
+ for (int i = 1; i <= cc; ++i) {
+ QAccessibleInterface *child = 0;
+ int i2 = accessible->navigate(Child, i, &child);
+ bool isSelected = false;
+ if (child) {
+ isSelected = child->state(0) & Selected;
+ delete child;
+ child = 0;
+ } else {
+ isSelected = accessible->state(i2) & Selected;
+ }
+ if (isSelected)
+ sel[selIndex++] = i;
+ }
+ sel.resize(selIndex);
+ if (sel.isEmpty()) {
+ (*pvarChildren).vt = VT_EMPTY;
+ return S_FALSE;
+ }
+ if (sel.size() == 1) {
+ (*pvarChildren).vt = VT_I4;
+ (*pvarChildren).lVal = sel[0];
+ return S_OK;
+ }
+ IEnumVARIANT *iface = new QWindowsEnumerate(sel);
+ IUnknown *uiface;
+ iface->QueryInterface(IID_IUnknown, (void**)&uiface);
+ (*pvarChildren).vt = VT_UNKNOWN;
+ (*pvarChildren).punkVal = uiface;
+
+ return S_OK;
+}
+
+HRESULT STDMETHODCALLTYPE QWindowsAccessible::GetWindow(HWND *phwnd)
+{
+ *phwnd = 0;
+ if (!accessible->isValid())
+ return E_UNEXPECTED;
+
+ QObject *o = accessible->object();
+ if (!o || !o->isWidgetType())
+ return E_FAIL;
+
+ *phwnd = static_cast<QWidget*>(o)->effectiveWinId();
+ return S_OK;
+}
+
+HRESULT STDMETHODCALLTYPE QWindowsAccessible::ContextSensitiveHelp(BOOL)
+{
+ return S_OK;
+}
+
+QT_END_NAMESPACE
+
+#endif // QT_NO_ACCESSIBILITY
diff --git a/src/widgets/accessible/qaccessiblebridge.cpp b/src/widgets/accessible/qaccessiblebridge.cpp
new file mode 100644
index 0000000000..e151bb6752
--- /dev/null
+++ b/src/widgets/accessible/qaccessiblebridge.cpp
@@ -0,0 +1,158 @@
+/****************************************************************************
+**
+** Copyright (C) 2011 Nokia Corporation and/or its subsidiary(-ies).
+** All rights reserved.
+** Contact: Nokia Corporation (qt-info@nokia.com)
+**
+** This file is part of the QtGui module of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL$
+** No Commercial Usage
+** This file contains pre-release code and may not be distributed.
+** You may use this file in accordance with the terms and conditions
+** contained in the Technology Preview License Agreement accompanying
+** this package.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 2.1 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPL included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU Lesser General Public License version 2.1 requirements
+** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
+**
+** In addition, as a special exception, Nokia gives you certain additional
+** rights. These rights are described in the Nokia Qt LGPL Exception
+** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
+**
+** If you have questions regarding the use of this file, please contact
+** Nokia at qt-info@nokia.com.
+**
+**
+**
+**
+**
+**
+**
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#include "qaccessiblebridge.h"
+
+#ifndef QT_NO_ACCESSIBILITY
+
+QT_BEGIN_NAMESPACE
+
+/*!
+ \class QAccessibleBridge
+ \brief The QAccessibleBridge class is the base class for
+ accessibility back-ends.
+
+ \ingroup accessibility
+
+ Qt supports Microsoft Active Accessibility (MSAA), Mac OS X
+ Accessibility, and the Unix/X11 AT-SPI standard. By subclassing
+ QAccessibleBridge, you can support other backends than the
+ predefined ones.
+
+ Currently, custom bridges are only supported on Unix. We might
+ add support for them on other platforms as well if there is
+ enough demand.
+
+ \sa QAccessible, QAccessibleBridgePlugin
+*/
+
+/*!
+ \fn QAccessibleBridge::~QAccessibleBridge()
+
+ Destroys the accessibility bridge object.
+*/
+
+/*!
+ \fn void QAccessibleBridge::setRootObject(QAccessibleInterface *object)
+
+ This function is called by Qt at application startup to set the
+ root accessible object of the application to \a object. All other
+ accessible objects in the application can be reached by the
+ client using object navigation.
+*/
+
+/*!
+ \fn void QAccessibleBridge::notifyAccessibilityUpdate(int reason, QAccessibleInterface *interface, int child)
+
+ This function is called by Qt to notify the bridge about a change
+ in the accessibility information for object wrapped by the given
+ \a interface.
+
+ \a reason specifies the cause of the change. It can take values
+ of type QAccessible::Event.
+
+ \a child is the (1-based) index of the child element that has
+ changed. When \a child is 0, the object itself has changed.
+
+ \sa QAccessible::updateAccessibility()
+*/
+
+/*!
+ \class QAccessibleBridgePlugin
+ \brief The QAccessibleBridgePlugin class provides an abstract
+ base for accessibility bridge plugins.
+
+ \ingroup plugins
+ \ingroup accessibility
+
+ Writing an accessibility bridge plugin is achieved by subclassing
+ this base class, reimplementing the pure virtual functions keys()
+ and create(), and exporting the class with the
+ Q_EXPORT_PLUGIN2() macro.
+
+ \sa QAccessibleBridge, QAccessiblePlugin, {How to Create Qt Plugins}
+*/
+
+/*!
+ Constructs an accessibility bridge plugin with the given \a
+ parent. This is invoked automatically by the Q_EXPORT_PLUGIN2()
+ macro.
+*/
+QAccessibleBridgePlugin::QAccessibleBridgePlugin(QObject *parent)
+ : QObject(parent)
+{
+
+}
+
+/*!
+ Destroys the accessibility bridge plugin.
+
+ You never have to call this explicitly. Qt destroys a plugin
+ automatically when it is no longer used.
+*/
+QAccessibleBridgePlugin::~QAccessibleBridgePlugin()
+{
+
+}
+
+/*!
+ \fn QStringList QAccessibleBridgePlugin::keys() const
+
+ Returns the list of keys this plugins supports.
+
+ These keys must be the names of the bridges that this
+ plugin provides.
+
+ \sa create()
+*/
+
+/*!
+ \fn QAccessibleBridge *QAccessibleBridgePlugin::create(const QString &key)
+
+ Creates and returns the QAccessibleBridge object corresponding to
+ the given \a key. Keys are case sensitive.
+
+ \sa keys()
+*/
+
+QT_END_NAMESPACE
+
+#endif // QT_NO_ACCESSIBILITY
diff --git a/src/widgets/accessible/qaccessiblebridge.h b/src/widgets/accessible/qaccessiblebridge.h
new file mode 100644
index 0000000000..d5e35df33f
--- /dev/null
+++ b/src/widgets/accessible/qaccessiblebridge.h
@@ -0,0 +1,92 @@
+/****************************************************************************
+**
+** Copyright (C) 2011 Nokia Corporation and/or its subsidiary(-ies).
+** All rights reserved.
+** Contact: Nokia Corporation (qt-info@nokia.com)
+**
+** This file is part of the QtGui module of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL$
+** No Commercial Usage
+** This file contains pre-release code and may not be distributed.
+** You may use this file in accordance with the terms and conditions
+** contained in the Technology Preview License Agreement accompanying
+** this package.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 2.1 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPL included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU Lesser General Public License version 2.1 requirements
+** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
+**
+** In addition, as a special exception, Nokia gives you certain additional
+** rights. These rights are described in the Nokia Qt LGPL Exception
+** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
+**
+** If you have questions regarding the use of this file, please contact
+** Nokia at qt-info@nokia.com.
+**
+**
+**
+**
+**
+**
+**
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#ifndef QACCESSIBLEBRIDGE_H
+#define QACCESSIBLEBRIDGE_H
+
+#include <QtCore/qplugin.h>
+#include <QtCore/qfactoryinterface.h>
+
+QT_BEGIN_HEADER
+
+QT_BEGIN_NAMESPACE
+
+QT_MODULE(Gui)
+
+#ifndef QT_NO_ACCESSIBILITY
+
+class QAccessibleInterface;
+
+class QAccessibleBridge
+{
+public:
+ virtual ~QAccessibleBridge() {}
+ virtual void setRootObject(QAccessibleInterface *) = 0;
+ virtual void notifyAccessibilityUpdate(int, QAccessibleInterface*, int) = 0;
+};
+
+struct Q_GUI_EXPORT QAccessibleBridgeFactoryInterface : public QFactoryInterface
+{
+ virtual QAccessibleBridge *create(const QString& name) = 0;
+};
+
+#define QAccessibleBridgeFactoryInterface_iid "com.trolltech.Qt.QAccessibleBridgeFactoryInterface"
+Q_DECLARE_INTERFACE(QAccessibleBridgeFactoryInterface, QAccessibleBridgeFactoryInterface_iid)
+
+class Q_GUI_EXPORT QAccessibleBridgePlugin : public QObject, public QAccessibleBridgeFactoryInterface
+{
+ Q_OBJECT
+ Q_INTERFACES(QAccessibleBridgeFactoryInterface:QFactoryInterface)
+public:
+ explicit QAccessibleBridgePlugin(QObject *parent = 0);
+ ~QAccessibleBridgePlugin();
+
+ virtual QStringList keys() const = 0;
+ virtual QAccessibleBridge *create(const QString &key) = 0;
+};
+
+#endif // QT_NO_ACCESSIBILITY
+
+QT_END_NAMESPACE
+
+QT_END_HEADER
+
+#endif // QACCESSIBLEBRIDGE_H
diff --git a/src/widgets/accessible/qaccessibleobject.cpp b/src/widgets/accessible/qaccessibleobject.cpp
new file mode 100644
index 0000000000..0cb2c08a3e
--- /dev/null
+++ b/src/widgets/accessible/qaccessibleobject.cpp
@@ -0,0 +1,408 @@
+/****************************************************************************
+**
+** Copyright (C) 2011 Nokia Corporation and/or its subsidiary(-ies).
+** All rights reserved.
+** Contact: Nokia Corporation (qt-info@nokia.com)
+**
+** This file is part of the QtGui module of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL$
+** No Commercial Usage
+** This file contains pre-release code and may not be distributed.
+** You may use this file in accordance with the terms and conditions
+** contained in the Technology Preview License Agreement accompanying
+** this package.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 2.1 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPL included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU Lesser General Public License version 2.1 requirements
+** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
+**
+** In addition, as a special exception, Nokia gives you certain additional
+** rights. These rights are described in the Nokia Qt LGPL Exception
+** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
+**
+** If you have questions regarding the use of this file, please contact
+** Nokia at qt-info@nokia.com.
+**
+**
+**
+**
+**
+**
+**
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#include "qaccessibleobject.h"
+
+#ifndef QT_NO_ACCESSIBILITY
+
+#include "qapplication.h"
+#include "qwidget.h"
+#include "qpointer.h"
+#include "qmetaobject.h"
+#include "qvarlengtharray.h"
+
+QT_BEGIN_NAMESPACE
+
+class QAccessibleObjectPrivate
+{
+public:
+ QPointer<QObject> object;
+
+ QList<QByteArray> actionList() const;
+};
+
+QList<QByteArray> QAccessibleObjectPrivate::actionList() const
+{
+ QList<QByteArray> actionList;
+
+ if (!object)
+ return actionList;
+
+ const QMetaObject *mo = object->metaObject();
+ Q_ASSERT(mo);
+
+ QByteArray defaultAction = QMetaObject::normalizedSignature(
+ mo->classInfo(mo->indexOfClassInfo("DefaultSlot")).value());
+
+ for (int i = 0; i < mo->methodCount(); ++i) {
+ const QMetaMethod member = mo->method(i);
+ if (member.methodType() != QMetaMethod::Slot && member.access() != QMetaMethod::Public)
+ continue;
+
+ if (!qstrcmp(member.tag(), "QACCESSIBLE_SLOT")) {
+ if (member.signature() == defaultAction)
+ actionList.prepend(defaultAction);
+ else
+ actionList << member.signature();
+ }
+ }
+
+ return actionList;
+}
+
+/*!
+ \class QAccessibleObject
+ \brief The QAccessibleObject class implements parts of the
+ QAccessibleInterface for QObjects.
+
+ \ingroup accessibility
+
+ This class is mainly provided for convenience. All subclasses of
+ the QAccessibleInterface that provide implementations of non-widget objects
+ should use this class as their base class.
+
+ \sa QAccessible, QAccessibleWidget
+*/
+
+/*!
+ Creates a QAccessibleObject for \a object.
+*/
+QAccessibleObject::QAccessibleObject(QObject *object)
+{
+ d = new QAccessibleObjectPrivate;
+ d->object = object;
+}
+
+/*!
+ Destroys the QAccessibleObject.
+
+ This only happens when a call to release() decrements the internal
+ reference counter to zero.
+*/
+QAccessibleObject::~QAccessibleObject()
+{
+ delete d;
+}
+
+/*!
+ \reimp
+*/
+QObject *QAccessibleObject::object() const
+{
+#ifndef QT_NO_DEBUG
+ if (!d->object)
+ qWarning("QAccessibleInterface is invalid. Crash pending...");
+#endif
+ return d->object;
+}
+
+/*!
+ \reimp
+*/
+bool QAccessibleObject::isValid() const
+{
+ return !d->object.isNull();
+}
+
+/*! \reimp */
+QRect QAccessibleObject::rect(int) const
+{
+ return QRect();
+}
+
+/*! \reimp */
+void QAccessibleObject::setText(Text, int, const QString &)
+{
+}
+
+/*! \reimp */
+int QAccessibleObject::userActionCount(int) const
+{
+ return 0;
+}
+
+/*! \reimp */
+bool QAccessibleObject::doAction(int, int, const QVariantList &)
+{
+ return false;
+}
+
+static const char * const action_text[][5] =
+{
+ // Name, Description, Value, Help, Accelerator
+ { "Press", "", "", "", "Space" },
+ { "SetFocus", "Passes focus to this widget", "", "", "" },
+ { "Increase", "", "", "", "" },
+ { "Decrease", "", "", "", "" },
+ { "Accept", "", "", "", "" },
+ { "Cancel", "", "", "", "" },
+ { "Select", "", "", "", "" },
+ { "ClearSelection", "", "", "", "" },
+ { "RemoveSelection", "", "", "", "" },
+ { "ExtendSelection", "", "", "", "" },
+ { "AddToSelection", "", "", "", "" }
+};
+
+/*! \reimp */
+QString QAccessibleObject::actionText(int action, Text t, int child) const
+{
+ if (child || action > FirstStandardAction || action < LastStandardAction || t > Accelerator)
+ return QString();
+
+ return QString::fromLatin1(action_text[-(action - FirstStandardAction)][t]);
+}
+
+
+/*!
+ \class QAccessibleApplication
+ \brief The QAccessibleApplication class implements the QAccessibleInterface for QApplication.
+
+ \internal
+
+ \ingroup accessibility
+*/
+
+/*!
+ Creates a QAccessibleApplication for the QApplication object referenced by qApp.
+*/
+QAccessibleApplication::QAccessibleApplication()
+: QAccessibleObject(qApp)
+{
+}
+
+// all toplevel widgets except popups and the desktop
+static QWidgetList topLevelWidgets()
+{
+ QWidgetList list;
+ const QWidgetList tlw(QApplication::topLevelWidgets());
+ for (int i = 0; i < tlw.count(); ++i) {
+ QWidget *w = tlw.at(i);
+ if (!(w->windowType() == Qt::Popup) && !(w->windowType() == Qt::Desktop))
+ list.append(w);
+ }
+
+ return list;
+}
+
+/*! \reimp */
+int QAccessibleApplication::childCount() const
+{
+ return topLevelWidgets().count();
+}
+
+/*! \reimp */
+int QAccessibleApplication::indexOfChild(const QAccessibleInterface *child) const
+{
+ if (!child->object()->isWidgetType())
+ return -1;
+
+ const QWidgetList tlw(topLevelWidgets());
+ int index = tlw.indexOf(static_cast<QWidget*>(child->object()));
+ if (index != -1)
+ ++index;
+ return index;
+}
+
+/*! \reimp */
+int QAccessibleApplication::childAt(int x, int y) const
+{
+ const QWidgetList tlw(topLevelWidgets());
+ for (int i = 0; i < tlw.count(); ++i) {
+ QWidget *w = tlw.at(i);
+ if (w->frameGeometry().contains(x,y))
+ return i+1;
+ }
+ return -1;
+}
+
+/*! \reimp */
+QAccessible::Relation QAccessibleApplication::relationTo(int child, const
+ QAccessibleInterface *other, int otherChild) const
+{
+ QObject *o = other ? other->object() : 0;
+ if (!o)
+ return Unrelated;
+
+ if(o == object()) {
+ if (child && !otherChild)
+ return Child;
+ if (!child && otherChild)
+ return Ancestor;
+ if (!child && !otherChild)
+ return Self;
+ }
+
+ QWidgetList tlw(topLevelWidgets());
+ if (tlw.contains(qobject_cast<QWidget*>(o)))
+ return Ancestor;
+
+ for (int i = 0; i < tlw.count(); ++i) {
+ QWidget *w = tlw.at(i);
+ QObjectList cl = w->findChildren<QObject *>(QString());
+ if (cl.contains(o))
+ return Ancestor;
+ }
+
+ return Unrelated;
+}
+
+/*! \reimp */
+int QAccessibleApplication::navigate(RelationFlag relation, int entry,
+ QAccessibleInterface **target) const
+{
+ if (!target)
+ return -1;
+
+ *target = 0;
+ QObject *targetObject = 0;
+
+ switch (relation) {
+ case Self:
+ targetObject = object();
+ break;
+ case Child:
+ if (entry > 0 && entry <= childCount()) {
+ const QWidgetList tlw(topLevelWidgets());
+ if (tlw.count() >= entry)
+ targetObject = tlw.at(entry-1);
+ } else {
+ return -1;
+ }
+ break;
+ case FocusChild:
+ targetObject = QApplication::activeWindow();
+ break;
+ default:
+ break;
+ }
+ *target = QAccessible::queryAccessibleInterface(targetObject);
+ return *target ? 0 : -1;
+}
+
+/*! \reimp */
+QString QAccessibleApplication::text(Text t, int) const
+{
+ switch (t) {
+ case Name:
+ return QApplication::applicationName();
+ case Description:
+ return QApplication::applicationFilePath();
+ default:
+ break;
+ }
+ return QString();
+}
+
+/*! \reimp */
+QAccessible::Role QAccessibleApplication::role(int) const
+{
+ return Application;
+}
+
+/*! \reimp */
+QAccessible::State QAccessibleApplication::state(int) const
+{
+ return QApplication::activeWindow() ? Focused : Normal;
+}
+
+/*! \reimp */
+int QAccessibleApplication::userActionCount(int) const
+{
+ return 1;
+}
+
+/*! \reimp */
+bool QAccessibleApplication::doAction(int action, int child, const QVariantList &param)
+{
+ if (action == 0 || action == 1) {
+ QWidget *w = 0;
+ w = QApplication::activeWindow();
+ if (!w)
+ w = topLevelWidgets().at(0);
+ if (!w)
+ return false;
+ w->activateWindow();
+ return true;
+ }
+ return QAccessibleObject::doAction(action, child, param);
+}
+
+/*! \reimp */
+QString QAccessibleApplication::actionText(int action, Text text, int child) const
+{
+ QString str;
+ if ((action == 0 || action == 1) && !child) switch (text) {
+ case Name:
+ return QApplication::tr("Activate");
+ case Description:
+ return QApplication::tr("Activates the program's main window");
+ default:
+ break;
+ }
+ return QAccessibleObject::actionText(action, text, child);
+}
+
+// ### Qt 5: remove me - binary compatibility hack
+QAccessibleObjectEx::QAccessibleObjectEx(QObject *object)
+{
+ d = new QAccessibleObjectPrivate;
+ d->object = object;
+}
+bool QAccessibleObjectEx::isValid() const
+{ return reinterpret_cast<const QAccessibleObject *>(this)->QAccessibleObject::isValid(); }
+QObject *QAccessibleObjectEx::object() const
+{ return reinterpret_cast<const QAccessibleObject *>(this)->QAccessibleObject::object(); }
+QRect QAccessibleObjectEx::rect(int child) const
+{ return reinterpret_cast<const QAccessibleObject *>(this)->QAccessibleObject::rect(child); }
+void QAccessibleObjectEx::setText(Text t, int child, const QString &text)
+{ reinterpret_cast<QAccessibleObject *>(this)->QAccessibleObject::setText(t, child, text); }
+int QAccessibleObjectEx::userActionCount(int child) const
+{ return reinterpret_cast<const QAccessibleObject *>(this)->QAccessibleObject::userActionCount(child); }
+bool QAccessibleObjectEx::doAction(int action, int child, const QVariantList &params)
+{ return reinterpret_cast<QAccessibleObject *>(this)->QAccessibleObject::doAction(action, child, params); }
+QString QAccessibleObjectEx::actionText(int action, Text t, int child) const
+{ return reinterpret_cast<const QAccessibleObject *>(this)->QAccessibleObject::actionText(action, t, child); }
+QAccessibleObjectEx::~QAccessibleObjectEx()
+{ delete d; }
+
+QT_END_NAMESPACE
+
+#endif //QT_NO_ACCESSIBILITY
diff --git a/src/widgets/accessible/qaccessibleobject.h b/src/widgets/accessible/qaccessibleobject.h
new file mode 100644
index 0000000000..cc17fdc7c6
--- /dev/null
+++ b/src/widgets/accessible/qaccessibleobject.h
@@ -0,0 +1,140 @@
+/****************************************************************************
+**
+** Copyright (C) 2011 Nokia Corporation and/or its subsidiary(-ies).
+** All rights reserved.
+** Contact: Nokia Corporation (qt-info@nokia.com)
+**
+** This file is part of the QtGui module of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL$
+** No Commercial Usage
+** This file contains pre-release code and may not be distributed.
+** You may use this file in accordance with the terms and conditions
+** contained in the Technology Preview License Agreement accompanying
+** this package.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 2.1 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPL included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU Lesser General Public License version 2.1 requirements
+** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
+**
+** In addition, as a special exception, Nokia gives you certain additional
+** rights. These rights are described in the Nokia Qt LGPL Exception
+** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
+**
+** If you have questions regarding the use of this file, please contact
+** Nokia at qt-info@nokia.com.
+**
+**
+**
+**
+**
+**
+**
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#ifndef QACCESSIBLEOBJECT_H
+#define QACCESSIBLEOBJECT_H
+
+#include <QtWidgets/qaccessible.h>
+
+QT_BEGIN_HEADER
+
+QT_BEGIN_NAMESPACE
+
+QT_MODULE(Gui)
+
+#ifndef QT_NO_ACCESSIBILITY
+
+class QAccessibleObjectPrivate;
+class QObject;
+
+class Q_GUI_EXPORT QAccessibleObject : public QAccessibleInterface
+{
+public:
+ explicit QAccessibleObject(QObject *object);
+
+ bool isValid() const;
+ QObject *object() const;
+
+ // properties
+ QRect rect(int child) const;
+ void setText(Text t, int child, const QString &text);
+
+ // actions
+ int userActionCount(int child) const;
+ bool doAction(int action, int child, const QVariantList &params);
+ QString actionText(int action, Text t, int child) const;
+
+protected:
+ virtual ~QAccessibleObject();
+
+private:
+ friend class QAccessibleObjectEx;
+ QAccessibleObjectPrivate *d;
+ Q_DISABLE_COPY(QAccessibleObject)
+};
+
+class Q_GUI_EXPORT QAccessibleObjectEx : public QAccessibleInterfaceEx
+{
+public:
+ explicit QAccessibleObjectEx(QObject *object);
+
+ bool isValid() const;
+ QObject *object() const;
+
+ // properties
+ QRect rect(int child) const;
+ void setText(Text t, int child, const QString &text);
+
+ // actions
+ int userActionCount(int child) const;
+ bool doAction(int action, int child, const QVariantList &params);
+ QString actionText(int action, Text t, int child) const;
+
+protected:
+ virtual ~QAccessibleObjectEx();
+
+private:
+ QAccessibleObjectPrivate *d;
+ Q_DISABLE_COPY(QAccessibleObjectEx)
+};
+
+class Q_GUI_EXPORT QAccessibleApplication : public QAccessibleObject
+{
+public:
+ QAccessibleApplication();
+
+ // relations
+ int childCount() const;
+ int indexOfChild(const QAccessibleInterface*) const;
+ Relation relationTo(int, const QAccessibleInterface *, int) const;
+
+ // navigation
+ int childAt(int x, int y) const;
+ int navigate(RelationFlag, int, QAccessibleInterface **) const;
+
+ // properties and state
+ QString text(Text t, int child) const;
+ Role role(int child) const;
+ State state(int child) const;
+
+ // actions
+ int userActionCount(int child) const;
+ bool doAction(int action, int child, const QVariantList &params);
+ QString actionText(int action, Text t, int child) const;
+};
+
+#endif // QT_NO_ACCESSIBILITY
+
+QT_END_NAMESPACE
+
+QT_END_HEADER
+
+#endif // QACCESSIBLEOBJECT_H
diff --git a/src/widgets/accessible/qaccessibleplugin.cpp b/src/widgets/accessible/qaccessibleplugin.cpp
new file mode 100644
index 0000000000..f52d4b1807
--- /dev/null
+++ b/src/widgets/accessible/qaccessibleplugin.cpp
@@ -0,0 +1,107 @@
+/****************************************************************************
+**
+** Copyright (C) 2011 Nokia Corporation and/or its subsidiary(-ies).
+** All rights reserved.
+** Contact: Nokia Corporation (qt-info@nokia.com)
+**
+** This file is part of the QtGui module of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL$
+** No Commercial Usage
+** This file contains pre-release code and may not be distributed.
+** You may use this file in accordance with the terms and conditions
+** contained in the Technology Preview License Agreement accompanying
+** this package.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 2.1 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPL included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU Lesser General Public License version 2.1 requirements
+** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
+**
+** In addition, as a special exception, Nokia gives you certain additional
+** rights. These rights are described in the Nokia Qt LGPL Exception
+** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
+**
+** If you have questions regarding the use of this file, please contact
+** Nokia at qt-info@nokia.com.
+**
+**
+**
+**
+**
+**
+**
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#include "qaccessibleplugin.h"
+
+#ifndef QT_NO_ACCESSIBILITY
+
+#include "qaccessible.h"
+
+QT_BEGIN_NAMESPACE
+
+/*!
+ \class QAccessiblePlugin
+ \brief The QAccessiblePlugin class provides an abstract base for
+ accessibility plugins.
+
+ \ingroup plugins
+ \ingroup accessibility
+
+ Writing an accessibility plugin is achieved by subclassing this
+ base class, reimplementing the pure virtual functions keys() and
+ create(), and exporting the class with the Q_EXPORT_PLUGIN2()
+ macro.
+
+ \sa QAccessibleBridgePlugin, {How to Create Qt Plugins}
+*/
+
+/*!
+ Constructs an accessibility plugin with the given \a parent. This
+ is invoked automatically by the Q_EXPORT_PLUGIN2() macro.
+*/
+QAccessiblePlugin::QAccessiblePlugin(QObject *parent)
+ : QObject(parent)
+{
+}
+
+/*!
+ Destroys the accessibility plugin.
+
+ You never have to call this explicitly. Qt destroys a plugin
+ automatically when it is no longer used.
+*/
+QAccessiblePlugin::~QAccessiblePlugin()
+{
+}
+
+/*!
+ \fn QStringList QAccessiblePlugin::keys() const
+
+ Returns the list of keys this plugin supports.
+
+ These keys must be the class names that this plugin provides
+ an accessibility implementation for.
+
+ \sa create()
+*/
+
+/*!
+ \fn QAccessibleInterface *QAccessiblePlugin::create(const QString &key, QObject *object)
+
+ Creates and returns a QAccessibleInterface implementation for the
+ class \a key and the object \a object. Keys are case sensitive.
+
+ \sa keys()
+*/
+
+QT_END_NAMESPACE
+
+#endif // QT_NO_ACCESSIBILITY
diff --git a/src/widgets/accessible/qaccessibleplugin.h b/src/widgets/accessible/qaccessibleplugin.h
new file mode 100644
index 0000000000..b073ca103a
--- /dev/null
+++ b/src/widgets/accessible/qaccessibleplugin.h
@@ -0,0 +1,87 @@
+/****************************************************************************
+**
+** Copyright (C) 2011 Nokia Corporation and/or its subsidiary(-ies).
+** All rights reserved.
+** Contact: Nokia Corporation (qt-info@nokia.com)
+**
+** This file is part of the QtGui module of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL$
+** No Commercial Usage
+** This file contains pre-release code and may not be distributed.
+** You may use this file in accordance with the terms and conditions
+** contained in the Technology Preview License Agreement accompanying
+** this package.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 2.1 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPL included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU Lesser General Public License version 2.1 requirements
+** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
+**
+** In addition, as a special exception, Nokia gives you certain additional
+** rights. These rights are described in the Nokia Qt LGPL Exception
+** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
+**
+** If you have questions regarding the use of this file, please contact
+** Nokia at qt-info@nokia.com.
+**
+**
+**
+**
+**
+**
+**
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#ifndef QACCESSIBLEPLUGIN_H
+#define QACCESSIBLEPLUGIN_H
+
+#include <QtWidgets/qaccessible.h>
+#include <QtCore/qfactoryinterface.h>
+
+QT_BEGIN_HEADER
+
+QT_BEGIN_NAMESPACE
+
+QT_MODULE(Gui)
+
+#ifndef QT_NO_ACCESSIBILITY
+
+class QStringList;
+class QAccessibleInterface;
+
+struct Q_GUI_EXPORT QAccessibleFactoryInterface : public QAccessible, public QFactoryInterface
+{
+ virtual QAccessibleInterface* create(const QString &key, QObject *object) = 0;
+};
+
+#define QAccessibleFactoryInterface_iid "com.trolltech.Qt.QAccessibleFactoryInterface"
+Q_DECLARE_INTERFACE(QAccessibleFactoryInterface, QAccessibleFactoryInterface_iid)
+
+class QAccessiblePluginPrivate;
+
+class Q_GUI_EXPORT QAccessiblePlugin : public QObject, public QAccessibleFactoryInterface
+{
+ Q_OBJECT
+ Q_INTERFACES(QAccessibleFactoryInterface:QFactoryInterface)
+public:
+ explicit QAccessiblePlugin(QObject *parent = 0);
+ ~QAccessiblePlugin();
+
+ virtual QStringList keys() const = 0;
+ virtual QAccessibleInterface *create(const QString &key, QObject *object) = 0;
+};
+
+#endif // QT_NO_ACCESSIBILITY
+
+QT_END_NAMESPACE
+
+QT_END_HEADER
+
+#endif // QACCESSIBLEPLUGIN_H
diff --git a/src/widgets/accessible/qaccessiblewidget.cpp b/src/widgets/accessible/qaccessiblewidget.cpp
new file mode 100644
index 0000000000..d2d2984533
--- /dev/null
+++ b/src/widgets/accessible/qaccessiblewidget.cpp
@@ -0,0 +1,1031 @@
+/****************************************************************************
+**
+** Copyright (C) 2011 Nokia Corporation and/or its subsidiary(-ies).
+** All rights reserved.
+** Contact: Nokia Corporation (qt-info@nokia.com)
+**
+** This file is part of the QtGui module of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL$
+** No Commercial Usage
+** This file contains pre-release code and may not be distributed.
+** You may use this file in accordance with the terms and conditions
+** contained in the Technology Preview License Agreement accompanying
+** this package.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 2.1 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPL included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU Lesser General Public License version 2.1 requirements
+** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
+**
+** In addition, as a special exception, Nokia gives you certain additional
+** rights. These rights are described in the Nokia Qt LGPL Exception
+** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
+**
+** If you have questions regarding the use of this file, please contact
+** Nokia at qt-info@nokia.com.
+**
+**
+**
+**
+**
+**
+**
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#include "qaccessiblewidget.h"
+
+#ifndef QT_NO_ACCESSIBILITY
+
+#include "qaction.h"
+#include "qapplication.h"
+#include "qgroupbox.h"
+#include "qlabel.h"
+#include "qtooltip.h"
+#include "qwhatsthis.h"
+#include "qwidget.h"
+#include "qdebug.h"
+#include <qmath.h>
+#include <QRubberBand>
+#include <QFocusFrame>
+#include <QMenu>
+
+QT_BEGIN_NAMESPACE
+
+static QList<QWidget*> childWidgets(const QWidget *widget)
+{
+ QList<QObject*> list = widget->children();
+ QList<QWidget*> widgets;
+ for (int i = 0; i < list.size(); ++i) {
+ QWidget *w = qobject_cast<QWidget *>(list.at(i));
+ if (w && !w->isWindow()
+ && !qobject_cast<QFocusFrame*>(w)
+#if !defined(QT_NO_MENU)
+ && !qobject_cast<QMenu*>(w)
+#endif
+ && w->objectName() != QLatin1String("qt_rubberband"))
+ widgets.append(w);
+ }
+ return widgets;
+}
+
+static QString buddyString(const QWidget *widget)
+{
+ if (!widget)
+ return QString();
+ QWidget *parent = widget->parentWidget();
+ if (!parent)
+ return QString();
+#ifndef QT_NO_SHORTCUT
+ QObjectList ol = parent->children();
+ for (int i = 0; i < ol.size(); ++i) {
+ QLabel *label = qobject_cast<QLabel*>(ol.at(i));
+ if (label && label->buddy() == widget)
+ return label->text();
+ }
+#endif
+
+#ifndef QT_NO_GROUPBOX
+ QGroupBox *groupbox = qobject_cast<QGroupBox*>(parent);
+ if (groupbox)
+ return groupbox->title();
+#endif
+
+ return QString();
+}
+
+QString Q_GUI_EXPORT qt_accStripAmp(const QString &text)
+{
+ return QString(text).remove(QLatin1Char('&'));
+}
+
+QString Q_GUI_EXPORT qt_accHotKey(const QString &text)
+{
+#ifndef QT_NO_SHORTCUT
+ if (text.isEmpty())
+ return text;
+
+ int fa = 0;
+ QChar ac;
+ while ((fa = text.indexOf(QLatin1Char('&'), fa)) != -1) {
+ ++fa;
+ if (fa < text.length()) {
+ // ignore "&&"
+ if (text.at(fa) == QLatin1Char('&')) {
+ ++fa;
+ continue;
+ } else {
+ ac = text.at(fa);
+ break;
+ }
+ }
+ }
+ if (ac.isNull())
+ return QString();
+ return (QString)QKeySequence(Qt::ALT) + ac.toUpper();
+#else
+ Q_UNUSED(text);
+ return QString();
+#endif
+}
+
+class QAccessibleWidgetPrivate : public QAccessible
+{
+public:
+ QAccessibleWidgetPrivate()
+ :role(Client)
+ {}
+
+ Role role;
+ QString name;
+ QString description;
+ QString value;
+ QString help;
+ QString accelerator;
+ QStringList primarySignals;
+ const QAccessibleInterface *asking;
+};
+
+/*!
+ \class QAccessibleWidget
+ \brief The QAccessibleWidget class implements the QAccessibleInterface for QWidgets.
+
+ \ingroup accessibility
+
+ This class is convenient to use as a base class for custom
+ implementations of QAccessibleInterfaces that provide information
+ about widget objects.
+
+ The class provides functions to retrieve the parentObject() (the
+ widget's parent widget), and the associated widget(). Controlling
+ signals can be added with addControllingSignal(), and setters are
+ provided for various aspects of the interface implementation, for
+ example setValue(), setDescription(), setAccelerator(), and
+ setHelp().
+
+ \sa QAccessible, QAccessibleObject
+*/
+
+/*!
+ Creates a QAccessibleWidget object for widget \a w.
+ \a role and \a name are optional parameters that set the object's
+ role and name properties.
+*/
+QAccessibleWidget::QAccessibleWidget(QWidget *w, Role role, const QString &name)
+: QAccessibleObject(w)
+{
+ Q_ASSERT(widget());
+ d = new QAccessibleWidgetPrivate();
+ d->role = role;
+ d->name = name;
+ d->asking = 0;
+}
+
+/*!
+ Destroys this object.
+*/
+QAccessibleWidget::~QAccessibleWidget()
+{
+ delete d;
+}
+
+/*!
+ Returns the associated widget.
+*/
+QWidget *QAccessibleWidget::widget() const
+{
+ return qobject_cast<QWidget*>(object());
+}
+
+/*!
+ Returns the associated widget's parent object, which is either the
+ parent widget, or qApp for top-level widgets.
+*/
+QObject *QAccessibleWidget::parentObject() const
+{
+ QObject *parent = object()->parent();
+ if (!parent)
+ parent = qApp;
+ return parent;
+}
+
+/*! \reimp */
+int QAccessibleWidget::childAt(int x, int y) const
+{
+ QWidget *w = widget();
+ if (!w->isVisible())
+ return -1;
+ QPoint gp = w->mapToGlobal(QPoint(0, 0));
+ if (!QRect(gp.x(), gp.y(), w->width(), w->height()).contains(x, y))
+ return -1;
+
+ QWidgetList list = childWidgets(w);
+ int ccount = childCount();
+
+ // a complex child
+ if (list.size() < ccount) {
+ for (int i = 1; i <= ccount; ++i) {
+ if (rect(i).contains(x, y))
+ return i;
+ }
+ return 0;
+ }
+
+ QPoint rp = w->mapFromGlobal(QPoint(x, y));
+ for (int i = 0; i<list.size(); ++i) {
+ QWidget *child = list.at(i);
+ if (!child->isWindow() && !child->isHidden() && child->geometry().contains(rp)) {
+ return i + 1;
+ }
+ }
+ return 0;
+}
+
+/*! \reimp */
+QRect QAccessibleWidget::rect(int child) const
+{
+ if (child) {
+ qWarning("QAccessibleWidget::rect: This implementation does not support subelements! "
+ "(ID %d unknown for %s)", child, widget()->metaObject()->className());
+ }
+
+ QWidget *w = widget();
+ if (!w->isVisible())
+ return QRect();
+ QPoint wpos = w->mapToGlobal(QPoint(0, 0));
+
+ return QRect(wpos.x(), wpos.y(), w->width(), w->height());
+}
+
+QT_BEGIN_INCLUDE_NAMESPACE
+#include <private/qobject_p.h>
+QT_END_INCLUDE_NAMESPACE
+
+class QACConnectionObject : public QObject
+{
+ Q_DECLARE_PRIVATE(QObject)
+public:
+ inline bool isSender(const QObject *receiver, const char *signal) const
+ { return d_func()->isSender(receiver, signal); }
+ inline QObjectList receiverList(const char *signal) const
+ { return d_func()->receiverList(signal); }
+ inline QObjectList senderList() const
+ { return d_func()->senderList(); }
+};
+
+/*!
+ Registers \a signal as a controlling signal.
+
+ An object is a Controller to any other object connected to a
+ controlling signal.
+*/
+void QAccessibleWidget::addControllingSignal(const QString &signal)
+{
+ QByteArray s = QMetaObject::normalizedSignature(signal.toAscii());
+ if (object()->metaObject()->indexOfSignal(s) < 0)
+ qWarning("Signal %s unknown in %s", s.constData(), object()->metaObject()->className());
+ d->primarySignals << QLatin1String(s);
+}
+
+/*!
+ Sets the value of this interface implementation to \a value.
+
+ The default implementation of text() returns the set value for
+ the Value text.
+
+ Note that the object wrapped by this interface is not modified.
+*/
+void QAccessibleWidget::setValue(const QString &value)
+{
+ d->value = value;
+}
+
+/*!
+ Sets the description of this interface implementation to \a desc.
+
+ The default implementation of text() returns the set value for
+ the Description text.
+
+ Note that the object wrapped by this interface is not modified.
+*/
+void QAccessibleWidget::setDescription(const QString &desc)
+{
+ d->description = desc;
+}
+
+/*!
+ Sets the help of this interface implementation to \a help.
+
+ The default implementation of text() returns the set value for
+ the Help text.
+
+ Note that the object wrapped by this interface is not modified.
+*/
+void QAccessibleWidget::setHelp(const QString &help)
+{
+ d->help = help;
+}
+
+/*!
+ Sets the accelerator of this interface implementation to \a accel.
+
+ The default implementation of text() returns the set value for
+ the Accelerator text.
+
+ Note that the object wrapped by this interface is not modified.
+*/
+void QAccessibleWidget::setAccelerator(const QString &accel)
+{
+ d->accelerator = accel;
+}
+
+static inline bool isAncestor(const QObject *obj, const QObject *child)
+{
+ while (child) {
+ if (child == obj)
+ return true;
+ child = child->parent();
+ }
+ return false;
+}
+
+
+/*! \reimp */
+QAccessible::Relation QAccessibleWidget::relationTo(int child,
+ const QAccessibleInterface *other, int otherChild) const
+{
+ Relation relation = Unrelated;
+ if (d->asking == this) // recursive call
+ return relation;
+
+ QObject *o = other ? other->object() : 0;
+ if (!o)
+ return relation;
+
+ QWidget *focus = widget()->focusWidget();
+ if (object() == focus && isAncestor(o, focus))
+ relation |= FocusChild;
+
+ QACConnectionObject *connectionObject = (QACConnectionObject*)object();
+ for (int sig = 0; sig < d->primarySignals.count(); ++sig) {
+ if (connectionObject->isSender(o, d->primarySignals.at(sig).toAscii())) {
+ relation |= Controller;
+ break;
+ }
+ }
+ // test for passive relationships.
+ // d->asking protects from endless recursion.
+ d->asking = this;
+ int inverse = other->relationTo(otherChild, this, child);
+ d->asking = 0;
+
+ if (inverse & Controller)
+ relation |= Controlled;
+ if (inverse & Label)
+ relation |= Labelled;
+
+ if(o == object()) {
+ if (child && !otherChild)
+ return relation | Child;
+ if (!child && otherChild)
+ return relation | Ancestor;
+ if (!child && !otherChild)
+ return relation | Self;
+ }
+
+ QObject *parent = object()->parent();
+ if (o == parent)
+ return relation | Child;
+
+ if (o->parent() == parent) {
+ relation |= Sibling;
+ QAccessibleInterface *sibIface = QAccessible::queryAccessibleInterface(o);
+ Q_ASSERT(sibIface);
+ QRect wg = rect(0);
+ QRect sg = sibIface->rect(0);
+ if (wg.intersects(sg)) {
+ QAccessibleInterface *pIface = 0;
+ sibIface->navigate(Ancestor, 1, &pIface);
+ if (pIface && !((sibIface->state(0) | state(0)) & Invisible)) {
+ int wi = pIface->indexOfChild(this);
+ int si = pIface->indexOfChild(sibIface);
+
+ if (wi > si)
+ relation |= QAccessible::Covers;
+ else
+ relation |= QAccessible::Covered;
+ }
+ delete pIface;
+ } else {
+ QPoint wc = wg.center();
+ QPoint sc = sg.center();
+ if (wc.x() < sc.x())
+ relation |= QAccessible::Left;
+ else if(wc.x() > sc.x())
+ relation |= QAccessible::Right;
+ if (wc.y() < sc.y())
+ relation |= QAccessible::Up;
+ else if (wc.y() > sc.y())
+ relation |= QAccessible::Down;
+ }
+ delete sibIface;
+
+ return relation;
+ }
+
+ if (isAncestor(o, object()))
+ return relation | Descendent;
+ if (isAncestor(object(), o))
+ return relation | Ancestor;
+
+ return relation;
+}
+
+/*! \reimp */
+int QAccessibleWidget::navigate(RelationFlag relation, int entry,
+ QAccessibleInterface **target) const
+{
+ if (!target)
+ return -1;
+
+ *target = 0;
+ QObject *targetObject = 0;
+
+ QWidgetList childList = childWidgets(widget());
+ bool complexWidget = childList.size() < childCount();
+
+ switch (relation) {
+ // Hierarchical
+ case Self:
+ targetObject = object();
+ break;
+ case Child:
+ if (complexWidget) {
+ if (entry > 0 && entry <= childCount())
+ return entry;
+ return -1;
+ }else {
+ if (entry > 0 && childList.size() >= entry)
+ targetObject = childList.at(entry - 1);
+ }
+ break;
+ case Ancestor:
+ {
+ if (entry <= 0)
+ return -1;
+ targetObject = widget()->parentWidget();
+ int i;
+ for (i = entry; i > 1 && targetObject; --i)
+ targetObject = targetObject->parent();
+ if (!targetObject && i == 1)
+ targetObject = qApp;
+ }
+ break;
+ case Sibling:
+ {
+ QAccessibleInterface *iface = QAccessible::queryAccessibleInterface(parentObject());
+ if (!iface)
+ return -1;
+
+ iface->navigate(Child, entry, target);
+ delete iface;
+ if (*target)
+ return 0;
+ }
+ break;
+
+ // Geometrical
+ case QAccessible::Left:
+ if (complexWidget && entry) {
+ if (entry < 2 || widget()->height() > widget()->width() + 20) // looks vertical
+ return -1;
+ return entry - 1;
+ }
+ // fall through
+ case QAccessible::Right:
+ if (complexWidget && entry) {
+ if (entry >= childCount() || widget()->height() > widget()->width() + 20) // looks vertical
+ return -1;
+ return entry + 1;
+ }
+ // fall through
+ case QAccessible::Up:
+ if (complexWidget && entry) {
+ if (entry < 2 || widget()->width() > widget()->height() + 20) // looks horizontal
+ return - 1;
+ return entry - 1;
+ }
+ // fall through
+ case QAccessible::Down:
+ if (complexWidget && entry) {
+ if (entry >= childCount() || widget()->width() > widget()->height() + 20) // looks horizontal
+ return - 1;
+ return entry + 1;
+ } else {
+ QAccessibleInterface *pIface = QAccessible::queryAccessibleInterface(parentObject());
+ if (!pIface)
+ return -1;
+
+ QRect startg = rect(0);
+ QPoint startc = startg.center();
+ QAccessibleInterface *candidate = 0;
+ int mindist = 100000;
+ int sibCount = pIface->childCount();
+ for (int i = 0; i < sibCount; ++i) {
+ QAccessibleInterface *sibling = 0;
+ pIface->navigate(Child, i+1, &sibling);
+ Q_ASSERT(sibling);
+ if ((relationTo(0, sibling, 0) & Self) || (sibling->state(0) & QAccessible::Invisible)) {
+ //ignore ourself and invisible siblings
+ delete sibling;
+ continue;
+ }
+
+ QRect sibg = sibling->rect(0);
+ QPoint sibc = sibg.center();
+ QPoint sibp;
+ QPoint startp;
+ QPoint distp;
+ switch (relation) {
+ case QAccessible::Left:
+ startp = QPoint(startg.left(), startg.top() + startg.height() / 2);
+ sibp = QPoint(sibg.right(), sibg.top() + sibg.height() / 2);
+ if (QPoint(sibc - startc).x() >= 0) {
+ delete sibling;
+ continue;
+ }
+ distp = sibp - startp;
+ break;
+ case QAccessible::Right:
+ startp = QPoint(startg.right(), startg.top() + startg.height() / 2);
+ sibp = QPoint(sibg.left(), sibg.top() + sibg.height() / 2);
+ if (QPoint(sibc - startc).x() <= 0) {
+ delete sibling;
+ continue;
+ }
+ distp = sibp - startp;
+ break;
+ case QAccessible::Up:
+ startp = QPoint(startg.left() + startg.width() / 2, startg.top());
+ sibp = QPoint(sibg.left() + sibg.width() / 2, sibg.bottom());
+ if (QPoint(sibc - startc).y() >= 0) {
+ delete sibling;
+ continue;
+ }
+ distp = sibp - startp;
+ break;
+ case QAccessible::Down:
+ startp = QPoint(startg.left() + startg.width() / 2, startg.bottom());
+ sibp = QPoint(sibg.left() + sibg.width() / 2, sibg.top());
+ if (QPoint(sibc - startc).y() <= 0) {
+ delete sibling;
+ continue;
+ }
+ distp = sibp - startp;
+ break;
+ default:
+ break;
+ }
+
+ int dist = (int)qSqrt((qreal)distp.x() * distp.x() + distp.y() * distp.y());
+ if (dist < mindist) {
+ delete candidate;
+ candidate = sibling;
+ mindist = dist;
+ } else {
+ delete sibling;
+ }
+ }
+ delete pIface;
+ *target = candidate;
+ if (*target)
+ return 0;
+ }
+ break;
+ case Covers:
+ if (entry > 0) {
+ QAccessibleInterface *pIface = QAccessible::queryAccessibleInterface(parentObject());
+ if (!pIface)
+ return -1;
+
+ QRect r = rect(0);
+ int sibCount = pIface->childCount();
+ QAccessibleInterface *sibling = 0;
+ for (int i = pIface->indexOfChild(this) + 1; i <= sibCount && entry; ++i) {
+ pIface->navigate(Child, i, &sibling);
+ if (!sibling || (sibling->state(0) & Invisible)) {
+ delete sibling;
+ sibling = 0;
+ continue;
+ }
+ if (sibling->rect(0).intersects(r))
+ --entry;
+ if (!entry)
+ break;
+ delete sibling;
+ sibling = 0;
+ }
+ delete pIface;
+ *target = sibling;
+ if (*target)
+ return 0;
+ }
+ break;
+ case Covered:
+ if (entry > 0) {
+ QAccessibleInterface *pIface = QAccessible::queryAccessibleInterface(parentObject());
+ if (!pIface)
+ return -1;
+
+ QRect r = rect(0);
+ int index = pIface->indexOfChild(this);
+ QAccessibleInterface *sibling = 0;
+ for (int i = 1; i < index && entry; ++i) {
+ pIface->navigate(Child, i, &sibling);
+ Q_ASSERT(sibling);
+ if (!sibling || (sibling->state(0) & Invisible)) {
+ delete sibling;
+ sibling = 0;
+ continue;
+ }
+ if (sibling->rect(0).intersects(r))
+ --entry;
+ if (!entry)
+ break;
+ delete sibling;
+ sibling = 0;
+ }
+ delete pIface;
+ *target = sibling;
+ if (*target)
+ return 0;
+ }
+ break;
+
+ // Logical
+ case FocusChild:
+ {
+ if (widget()->hasFocus()) {
+ targetObject = object();
+ break;
+ }
+
+ QWidget *fw = widget()->focusWidget();
+ if (!fw)
+ return -1;
+
+ if (isAncestor(widget(), fw) || fw == widget())
+ targetObject = fw;
+ /* ###
+ QWidget *parent = fw;
+ while (parent && !targetObject) {
+ parent = parent->parentWidget();
+ if (parent == widget())
+ targetObject = fw;
+ }
+ */
+ }
+ break;
+ case Label:
+ if (entry > 0) {
+ QAccessibleInterface *pIface = QAccessible::queryAccessibleInterface(parentObject());
+ if (!pIface)
+ return -1;
+
+ // first check for all siblings that are labels to us
+ // ideally we would go through all objects and check, but that
+ // will be too expensive
+ int sibCount = pIface->childCount();
+ QAccessibleInterface *candidate = 0;
+ for (int i = 0; i < sibCount && entry; ++i) {
+ pIface->navigate(Child, i+1, &candidate);
+ Q_ASSERT(candidate);
+ if (candidate->relationTo(0, this, 0) & Label)
+ --entry;
+ if (!entry)
+ break;
+ delete candidate;
+ candidate = 0;
+ }
+ if (!candidate) {
+ if (pIface->relationTo(0, this, 0) & Label)
+ --entry;
+ if (!entry)
+ candidate = pIface;
+ }
+ if (pIface != candidate)
+ delete pIface;
+
+ *target = candidate;
+ if (*target)
+ return 0;
+ }
+ break;
+ case Labelled: // only implemented in subclasses
+ break;
+ case Controller:
+ if (entry > 0) {
+ // check all senders we are connected to,
+ // and figure out which one are controllers to us
+ QACConnectionObject *connectionObject = (QACConnectionObject*)object();
+ QObjectList allSenders = connectionObject->senderList();
+ QObjectList senders;
+ for (int s = 0; s < allSenders.size(); ++s) {
+ QObject *sender = allSenders.at(s);
+ QAccessibleInterface *candidate = QAccessible::queryAccessibleInterface(sender);
+ if (!candidate)
+ continue;
+ if (candidate->relationTo(0, this, 0)&Controller)
+ senders << sender;
+ delete candidate;
+ }
+ if (entry <= senders.size())
+ targetObject = senders.at(entry-1);
+ }
+ break;
+ case Controlled:
+ if (entry > 0) {
+ QObjectList allReceivers;
+ QACConnectionObject *connectionObject = (QACConnectionObject*)object();
+ for (int sig = 0; sig < d->primarySignals.count(); ++sig) {
+ QObjectList receivers = connectionObject->receiverList(d->primarySignals.at(sig).toAscii());
+ allReceivers += receivers;
+ }
+ if (entry <= allReceivers.size())
+ targetObject = allReceivers.at(entry-1);
+ }
+ break;
+ default:
+ break;
+ }
+
+ *target = QAccessible::queryAccessibleInterface(targetObject);
+ return *target ? 0 : -1;
+}
+
+/*! \reimp */
+int QAccessibleWidget::childCount() const
+{
+ QWidgetList cl = childWidgets(widget());
+ return cl.size();
+}
+
+/*! \reimp */
+int QAccessibleWidget::indexOfChild(const QAccessibleInterface *child) const
+{
+ QWidgetList cl = childWidgets(widget());
+ int index = cl.indexOf(qobject_cast<QWidget *>(child->object()));
+ if (index != -1)
+ ++index;
+ return index;
+}
+
+// from qwidget.cpp
+extern QString qt_setWindowTitle_helperHelper(const QString &, const QWidget*);
+
+/*! \reimp */
+QString QAccessibleWidget::text(Text t, int child) const
+{
+ QString str;
+
+ switch (t) {
+ case Name:
+ if (!d->name.isEmpty()) {
+ str = d->name;
+ } else if (!widget()->accessibleName().isEmpty()) {
+ str = widget()->accessibleName();
+ } else if (!child && widget()->isWindow()) {
+ if (widget()->isMinimized())
+ str = qt_setWindowTitle_helperHelper(widget()->windowIconText(), widget());
+ else
+ str = qt_setWindowTitle_helperHelper(widget()->windowTitle(), widget());
+ } else {
+ str = qt_accStripAmp(buddyString(widget()));
+ }
+ break;
+ case Description:
+ if (!d->description.isEmpty())
+ str = d->description;
+ else if (!widget()->accessibleDescription().isEmpty())
+ str = widget()->accessibleDescription();
+#ifndef QT_NO_TOOLTIP
+ else
+ str = widget()->toolTip();
+#endif
+ break;
+ case Help:
+ if (!d->help.isEmpty())
+ str = d->help;
+#ifndef QT_NO_WHATSTHIS
+ else
+ str = widget()->whatsThis();
+#endif
+ break;
+ case Accelerator:
+ if (!d->accelerator.isEmpty())
+ str = d->accelerator;
+ else
+ str = qt_accHotKey(buddyString(widget()));
+ break;
+ case Value:
+ str = d->value;
+ break;
+ default:
+ break;
+ }
+ return str;
+}
+
+#ifndef QT_NO_ACTION
+
+/*! \reimp */
+int QAccessibleWidget::userActionCount(int child) const
+{
+ if (child)
+ return 0;
+ return widget()->actions().count();
+}
+
+/*! \reimp */
+QString QAccessibleWidget::actionText(int action, Text t, int child) const
+{
+ if (action == DefaultAction)
+ action = SetFocus;
+
+ if (action > 0 && !child) {
+ QAction *act = widget()->actions().value(action - 1);
+ if (act) {
+ switch (t) {
+ case Name:
+ return act->text();
+ case Description:
+ return act->toolTip();
+#ifndef QT_NO_SHORTCUT
+ case Accelerator:
+ return act->shortcut().toString();
+#endif
+ default:
+ break;
+ }
+ }
+ }
+
+ return QAccessibleObject::actionText(action, t, child);
+}
+
+/*! \reimp */
+bool QAccessibleWidget::doAction(int action, int child, const QVariantList &params)
+{
+ if (action == SetFocus || action == DefaultAction) {
+ if (child || !widget()->isEnabled())
+ return false;
+ if (widget()->focusPolicy() != Qt::NoFocus)
+ widget()->setFocus();
+ else if (widget()->isWindow())
+ widget()->activateWindow();
+ else
+ return false;
+ return true;
+ } else if (action > 0) {
+ if (QAction *act = widget()->actions().value(action - 1)) {
+ act->trigger();
+ return true;
+ }
+ }
+ return QAccessibleObject::doAction(action, child, params);
+}
+
+#endif // QT_NO_ACTION
+
+/*! \reimp */
+QAccessible::Role QAccessibleWidget::role(int child) const
+{
+ if (!child)
+ return d->role;
+
+ QWidgetList childList = childWidgets(widget());
+ if (childList.count() > 0 && child <= childList.count()) {
+ QWidget *targetWidget = childList.at(child - 1);
+ QAccessibleInterface *iface = QAccessible::queryAccessibleInterface(targetWidget);
+ if (iface) {
+ QAccessible::Role role = iface->role(0);
+ delete iface;
+ return role;
+ }
+ }
+
+ return NoRole;
+}
+
+/*! \reimp */
+QAccessible::State QAccessibleWidget::state(int child) const
+{
+ if (child)
+ return Normal;
+
+ QAccessible::State state = Normal;
+
+ QWidget *w = widget();
+ if (w->testAttribute(Qt::WA_WState_Visible) == false)
+ state |= Invisible;
+ if (w->focusPolicy() != Qt::NoFocus && w->isActiveWindow())
+ state |= Focusable;
+ if (w->hasFocus())
+ state |= Focused;
+ if (!w->isEnabled())
+ state |= Unavailable;
+ if (w->isWindow()) {
+ if (w->windowFlags() & Qt::WindowSystemMenuHint)
+ state |= Movable;
+ if (w->minimumSize() != w->maximumSize())
+ state |= Sizeable;
+ }
+
+ return state;
+}
+
+// ### Qt 5: remove me - binary compatibility hack
+QAccessibleWidgetEx::QAccessibleWidgetEx(QWidget *o, Role role, const QString& name)
+ : QAccessibleObjectEx(o)
+{
+ Q_ASSERT(widget());
+ d = new QAccessibleWidgetPrivate();
+ d->role = role;
+ d->name = name;
+ d->asking = 0;
+}
+
+int QAccessibleWidgetEx::childCount() const
+{ return reinterpret_cast<const QAccessibleWidget *>(this)->QAccessibleWidget::childCount(); }
+int QAccessibleWidgetEx::indexOfChild(const QAccessibleInterface *child) const
+{ return reinterpret_cast<const QAccessibleWidget *>(this)->QAccessibleWidget::indexOfChild(child); }
+QAccessible::Relation QAccessibleWidgetEx::relationTo(int child, const QAccessibleInterface *other, int otherChild) const
+{ return reinterpret_cast<const QAccessibleWidget *>(this)->QAccessibleWidget::relationTo(child, other, otherChild); }
+
+int QAccessibleWidgetEx::childAt(int x, int y) const
+{ return reinterpret_cast<const QAccessibleWidget *>(this)->QAccessibleWidget::childAt(x, y); }
+QRect QAccessibleWidgetEx::rect(int child) const
+{ return reinterpret_cast<const QAccessibleWidget *>(this)->QAccessibleWidget::rect(child); }
+int QAccessibleWidgetEx::navigate(RelationFlag rel, int entry, QAccessibleInterface **target) const
+{ return reinterpret_cast<const QAccessibleWidget *>(this)->QAccessibleWidget::navigate(rel, entry, target); }
+
+QString QAccessibleWidgetEx::text(Text t, int child) const
+{ return reinterpret_cast<const QAccessibleWidget *>(this)->QAccessibleWidget::text(t, child); }
+QAccessible::Role QAccessibleWidgetEx::role(int child) const
+{ return reinterpret_cast<const QAccessibleWidget *>(this)->QAccessibleWidget::role(child); }
+QAccessible::State QAccessibleWidgetEx::state(int child) const
+{ return (reinterpret_cast<const QAccessibleWidget *>(this)->QAccessibleWidget::state(child))
+ | HasInvokeExtension; }
+
+QString QAccessibleWidgetEx::actionText(int action, Text t, int child) const
+{ return reinterpret_cast<const QAccessibleWidget *>(this)->QAccessibleWidget::actionText(action, t, child); }
+bool QAccessibleWidgetEx::doAction(int action, int child, const QVariantList &params)
+{ return reinterpret_cast<QAccessibleWidget *>(this)->QAccessibleWidget::doAction(action, child, params); }
+
+QAccessibleWidgetEx::~QAccessibleWidgetEx()
+{ delete d; }
+QWidget *QAccessibleWidgetEx::widget() const
+{ return reinterpret_cast<const QAccessibleWidget *>(this)->QAccessibleWidget::widget(); }
+QObject *QAccessibleWidgetEx::parentObject() const
+{ return reinterpret_cast<const QAccessibleWidget *>(this)->QAccessibleWidget::parentObject(); }
+
+void QAccessibleWidgetEx::addControllingSignal(const QString &signal)
+{ reinterpret_cast<QAccessibleWidget *>(this)->QAccessibleWidget::addControllingSignal(signal); }
+void QAccessibleWidgetEx::setValue(const QString &value)
+{ reinterpret_cast<QAccessibleWidget *>(this)->QAccessibleWidget::setValue(value); }
+void QAccessibleWidgetEx::setDescription(const QString &desc)
+{ reinterpret_cast<QAccessibleWidget *>(this)->QAccessibleWidget::setDescription(desc); }
+void QAccessibleWidgetEx::setHelp(const QString &help)
+{ reinterpret_cast<QAccessibleWidget *>(this)->QAccessibleWidget::setHelp(help); }
+void QAccessibleWidgetEx::setAccelerator(const QString &accel)
+{ reinterpret_cast<QAccessibleWidget *>(this)->QAccessibleWidget::setAccelerator(accel); }
+
+QVariant QAccessibleWidgetEx::invokeMethodEx(Method method, int child, const QVariantList & /*params*/)
+{
+ if (child)
+ return QVariant();
+
+ switch (method) {
+ case ListSupportedMethods: {
+ QSet<QAccessible::Method> set;
+ set << ListSupportedMethods << ForegroundColor << BackgroundColor;
+ return QVariant::fromValue(set);
+ }
+ case ForegroundColor:
+ return widget()->palette().color(widget()->foregroundRole());
+ case BackgroundColor:
+ return widget()->palette().color(widget()->backgroundRole());
+ default:
+ return QVariant();
+ }
+}
+
+QT_END_NAMESPACE
+
+#endif //QT_NO_ACCESSIBILITY
diff --git a/src/widgets/accessible/qaccessiblewidget.h b/src/widgets/accessible/qaccessiblewidget.h
new file mode 100644
index 0000000000..4b53e319b1
--- /dev/null
+++ b/src/widgets/accessible/qaccessiblewidget.h
@@ -0,0 +1,141 @@
+/****************************************************************************
+**
+** Copyright (C) 2011 Nokia Corporation and/or its subsidiary(-ies).
+** All rights reserved.
+** Contact: Nokia Corporation (qt-info@nokia.com)
+**
+** This file is part of the QtGui module of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL$
+** No Commercial Usage
+** This file contains pre-release code and may not be distributed.
+** You may use this file in accordance with the terms and conditions
+** contained in the Technology Preview License Agreement accompanying
+** this package.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 2.1 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPL included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU Lesser General Public License version 2.1 requirements
+** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
+**
+** In addition, as a special exception, Nokia gives you certain additional
+** rights. These rights are described in the Nokia Qt LGPL Exception
+** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
+**
+** If you have questions regarding the use of this file, please contact
+** Nokia at qt-info@nokia.com.
+**
+**
+**
+**
+**
+**
+**
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#ifndef QACCESSIBLEWIDGET_H
+#define QACCESSIBLEWIDGET_H
+
+#include <QtWidgets/qaccessibleobject.h>
+
+QT_BEGIN_HEADER
+
+QT_BEGIN_NAMESPACE
+
+QT_MODULE(Gui)
+
+#ifndef QT_NO_ACCESSIBILITY
+
+class QAccessibleWidgetPrivate;
+
+class Q_GUI_EXPORT QAccessibleWidget : public QAccessibleObject
+{
+public:
+ explicit QAccessibleWidget(QWidget *o, Role r = Client, const QString& name = QString());
+
+ int childCount() const;
+ int indexOfChild(const QAccessibleInterface *child) const;
+ Relation relationTo(int child, const QAccessibleInterface *other, int otherChild) const;
+
+ int childAt(int x, int y) const;
+ QRect rect(int child) const;
+ int navigate(RelationFlag rel, int entry, QAccessibleInterface **target) const;
+
+ QString text(Text t, int child) const;
+ Role role(int child) const;
+ State state(int child) const;
+
+#ifndef QT_NO_ACTION
+ int userActionCount(int child) const;
+ QString actionText(int action, Text t, int child) const;
+ bool doAction(int action, int child, const QVariantList &params);
+#endif
+
+protected:
+ ~QAccessibleWidget();
+ QWidget *widget() const;
+ QObject *parentObject() const;
+
+ void addControllingSignal(const QString &signal);
+ void setValue(const QString &value);
+ void setDescription(const QString &desc);
+ void setHelp(const QString &help);
+ void setAccelerator(const QString &accel);
+
+private:
+ friend class QAccessibleWidgetEx;
+ QAccessibleWidgetPrivate *d;
+ Q_DISABLE_COPY(QAccessibleWidget)
+};
+
+class Q_GUI_EXPORT QAccessibleWidgetEx : public QAccessibleObjectEx
+{
+public:
+ explicit QAccessibleWidgetEx(QWidget *o, Role r = Client, const QString& name = QString());
+
+ int childCount() const;
+ int indexOfChild(const QAccessibleInterface *child) const;
+ Relation relationTo(int child, const QAccessibleInterface *other, int otherChild) const;
+
+ int childAt(int x, int y) const;
+ QRect rect(int child) const;
+ int navigate(RelationFlag rel, int entry, QAccessibleInterface **target) const;
+
+ QString text(Text t, int child) const;
+ Role role(int child) const;
+ State state(int child) const;
+
+ QString actionText(int action, Text t, int child) const;
+ bool doAction(int action, int child, const QVariantList &params);
+
+ QVariant invokeMethodEx(Method method, int child, const QVariantList &params);
+
+protected:
+ ~QAccessibleWidgetEx();
+ QWidget *widget() const;
+ QObject *parentObject() const;
+
+ void addControllingSignal(const QString &signal);
+ void setValue(const QString &value);
+ void setDescription(const QString &desc);
+ void setHelp(const QString &help);
+ void setAccelerator(const QString &accel);
+
+private:
+ QAccessibleWidgetPrivate *d;
+ Q_DISABLE_COPY(QAccessibleWidgetEx)
+};
+
+#endif // QT_NO_ACCESSIBILITY
+
+QT_END_NAMESPACE
+
+QT_END_HEADER
+
+#endif // QACCESSIBLEWIDGET_H