diff options
author | Lars Knoll <lars.knoll@nokia.com> | 2009-03-23 09:18:55 (GMT) |
---|---|---|
committer | Simon Hausmann <simon.hausmann@nokia.com> | 2009-03-23 09:18:55 (GMT) |
commit | e5fcad302d86d316390c6b0f62759a067313e8a9 (patch) | |
tree | c2afbf6f1066b6ce261f14341cf6d310e5595bc1 /src/gui/accessible | |
download | Qt-e5fcad302d86d316390c6b0f62759a067313e8a9.zip Qt-e5fcad302d86d316390c6b0f62759a067313e8a9.tar.gz Qt-e5fcad302d86d316390c6b0f62759a067313e8a9.tar.bz2 |
Long live Qt 4.5!
Diffstat (limited to 'src/gui/accessible')
-rw-r--r-- | src/gui/accessible/accessible.pri | 24 | ||||
-rw-r--r-- | src/gui/accessible/qaccessible.cpp | 1079 | ||||
-rw-r--r-- | src/gui/accessible/qaccessible.h | 417 | ||||
-rw-r--r-- | src/gui/accessible/qaccessible2.cpp | 181 | ||||
-rw-r--r-- | src/gui/accessible/qaccessible2.h | 217 | ||||
-rw-r--r-- | src/gui/accessible/qaccessible_mac.mm | 2608 | ||||
-rw-r--r-- | src/gui/accessible/qaccessible_mac_carbon.cpp | 119 | ||||
-rw-r--r-- | src/gui/accessible/qaccessible_mac_cocoa.mm | 0 | ||||
-rw-r--r-- | src/gui/accessible/qaccessible_mac_p.h | 479 | ||||
-rw-r--r-- | src/gui/accessible/qaccessible_unix.cpp | 134 | ||||
-rw-r--r-- | src/gui/accessible/qaccessible_win.cpp | 1219 | ||||
-rw-r--r-- | src/gui/accessible/qaccessiblebridge.cpp | 158 | ||||
-rw-r--r-- | src/gui/accessible/qaccessiblebridge.h | 92 | ||||
-rw-r--r-- | src/gui/accessible/qaccessibleobject.cpp | 410 | ||||
-rw-r--r-- | src/gui/accessible/qaccessibleobject.h | 140 | ||||
-rw-r--r-- | src/gui/accessible/qaccessibleplugin.cpp | 107 | ||||
-rw-r--r-- | src/gui/accessible/qaccessibleplugin.h | 87 | ||||
-rw-r--r-- | src/gui/accessible/qaccessiblewidget.cpp | 1041 | ||||
-rw-r--r-- | src/gui/accessible/qaccessiblewidget.h | 141 |
19 files changed, 8653 insertions, 0 deletions
diff --git a/src/gui/accessible/accessible.pri b/src/gui/accessible/accessible.pri new file mode 100644 index 0000000..76b6687 --- /dev/null +++ b/src/gui/accessible/accessible.pri @@ -0,0 +1,24 @@ +# 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:!embedded { + HEADERS += accessible/qaccessible_mac_p.h + OBJECTIVE_SOURCES += accessible/qaccessible_mac.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/gui/accessible/qaccessible.cpp b/src/gui/accessible/qaccessible.cpp new file mode 100644 index 0000000..b0878ab --- /dev/null +++ b/src/gui/accessible/qaccessible.cpp @@ -0,0 +1,1079 @@ +/**************************************************************************** +** +** Copyright (C) 2009 Nokia Corporation and/or its subsidiary(-ies). +** Contact: Qt Software Information (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 either Technology Preview License Agreement or the +** Beta Release License Agreement. +** +** 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.0, included in the file LGPL_EXCEPTION.txt in this +** package. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU +** General Public License version 3.0 as published by the Free Software +** Foundation and appearing in the file LICENSE.GPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU General Public License version 3.0 requirements will be +** met: http://www.gnu.org/copyleft/gpl.html. +** +** If you are unsure which license is appropriate for your use, please +** contact the sales department at qt-sales@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 + \mainclass + + 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 +*/ + +#if !defined(QT_NO_LIBRARY) && (!defined(QT_NO_SETTINGS) || !defined(Q_OS_WIN)) +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 + + A function pointer type. Use a function with this prototype to install + interface factories with installFactory(). + + The function receives a QObject pointer. If the QObject + provides a QAccessibleInterface, it sets the second parameter to + point to the corresponding QAccessibleInterface, and returns true; + otherwise returns false. + + 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; + } +#if !defined(QT_NO_LIBRARY) && (!defined(QT_NO_SETTINGS) || !defined(Q_OS_WIN)) + 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 ¶ms) + + 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 +*/ + +/*! + \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 ¶ms) +{ + 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/gui/accessible/qaccessible.h b/src/gui/accessible/qaccessible.h new file mode 100644 index 0000000..91f18b3 --- /dev/null +++ b/src/gui/accessible/qaccessible.h @@ -0,0 +1,417 @@ +/**************************************************************************** +** +** Copyright (C) 2009 Nokia Corporation and/or its subsidiary(-ies). +** Contact: Qt Software Information (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 either Technology Preview License Agreement or the +** Beta Release License Agreement. +** +** 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.0, included in the file LGPL_EXCEPTION.txt in this +** package. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU +** General Public License version 3.0 as published by the Free Software +** Foundation and appearing in the file LICENSE.GPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU General Public License version 3.0 requirements will be +** met: http://www.gnu.org/copyleft/gpl.html. +** +** If you are unsure which license is appropriate for your use, please +** contact the sales department at qt-sales@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, + + 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, +#ifdef QT3_SUPPORT + Moveable = Movable, +#endif + 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, + 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 + }; +} + +class QAccessible2Interface; +class QAccessibleTextInterface; +class QAccessibleEditableTextInterface; +class QAccessibleValueInterface; +class QAccessibleTableInterface; + +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 ¶ms = QVariantList()) = 0; + + QVariant invokeMethod(Method method, int child = 0, + const QVariantList ¶ms = 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)); } + +private: + QAccessible2Interface *cast_helper(QAccessible2::InterfaceType); +}; + +class Q_GUI_EXPORT QAccessibleInterfaceEx: public QAccessibleInterface +{ +public: + virtual QVariant invokeMethodEx(Method method, int child, const QVariantList ¶ms) = 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/gui/accessible/qaccessible2.cpp b/src/gui/accessible/qaccessible2.cpp new file mode 100644 index 0000000..465ea4e --- /dev/null +++ b/src/gui/accessible/qaccessible2.cpp @@ -0,0 +1,181 @@ +/**************************************************************************** +** +** Copyright (C) 2009 Nokia Corporation and/or its subsidiary(-ies). +** Contact: Qt Software Information (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 either Technology Preview License Agreement or the +** Beta Release License Agreement. +** +** 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.0, included in the file LGPL_EXCEPTION.txt in this +** package. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU +** General Public License version 3.0 as published by the Free Software +** Foundation and appearing in the file LICENSE.GPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU General Public License version 3.0 requirements will be +** met: http://www.gnu.org/copyleft/gpl.html. +** +** If you are unsure which license is appropriate for your use, please +** contact the sales department at qt-sales@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 +*/ + +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/gui/accessible/qaccessible2.h b/src/gui/accessible/qaccessible2.h new file mode 100644 index 0000000..1e7b5f0 --- /dev/null +++ b/src/gui/accessible/qaccessible2.h @@ -0,0 +1,217 @@ +/**************************************************************************** +** +** Copyright (C) 2009 Nokia Corporation and/or its subsidiary(-ies). +** Contact: Qt Software Information (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 either Technology Preview License Agreement or the +** Beta Release License Agreement. +** +** 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.0, included in the file LGPL_EXCEPTION.txt in this +** package. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU +** General Public License version 3.0 as published by the Free Software +** Foundation and appearing in the file LICENSE.GPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU General Public License version 3.0 requirements will be +** met: http://www.gnu.org/copyleft/gpl.html. +** +** If you are unsure which license is appropriate for your use, please +** contact the sales department at qt-sales@nokia.com. +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#ifndef QACCESSIBLE2_H +#define QACCESSIBLE2_H + +#include <QtGui/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; } + +#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(); \ + } \ + 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; +}; + +#endif // QT_NO_ACCESSIBILITY + +QT_END_NAMESPACE + +QT_END_HEADER + +#endif diff --git a/src/gui/accessible/qaccessible_mac.mm b/src/gui/accessible/qaccessible_mac.mm new file mode 100644 index 0000000..b6412c2 --- /dev/null +++ b/src/gui/accessible/qaccessible_mac.mm @@ -0,0 +1,2608 @@ +/**************************************************************************** +** +** Copyright (C) 2009 Nokia Corporation and/or its subsidiary(-ies). +** Contact: Qt Software Information (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 either Technology Preview License Agreement or the +** Beta Release License Agreement. +** +** 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.0, included in the file LGPL_EXCEPTION.txt in this +** package. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU +** General Public License version 3.0 as published by the Free Software +** Foundation and appearing in the file LICENSE.GPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU General Public License version 3.0 requirements will be +** met: http://www.gnu.org/copyleft/gpl.html. +** +** If you are unsure which license is appropriate for your use, please +** contact the sales department at qt-sales@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 QAXCancelAction NSAccessibilityCancelAction +#define QAXCheckBoxRole NSAccessibilityCheckBoxRole +#define QAXChildrenAttribute NSAccessibilityChildrenAttribute +#define QAXChildrenAttribute NSAccessibilityChildrenAttribute +#define QAXChildrenAttribute NSAccessibilityChildrenAttribute +#define QAXCloseButtonAttribute NSAccessibilityCloseButtonAttribute +#define QAXCloseButtonAttribute NSAccessibilityCloseButtonAttribute +#define QAXColumnRole NSAccessibilityColumnRole +#define QAXConfirmAction NSAccessibilityConfirmAction +#define QAXConfirmAction NSAccessibilityConfirmAction +#define QAXContentsAttribute NSAccessibilityContentsAttribute +#define QAXContentsAttribute NSAccessibilityContentsAttribute +#define QAXDecrementAction NSAccessibilityDecrementAction +#define QAXDecrementAction NSAccessibilityDecrementAction +#define QAXDecrementArrowSubrole NSAccessibilityDecrementArrowSubrole +#define QAXDecrementPageSubrole NSAccessibilityDecrementPageSubrole +#define QAXDescriptionAttribute NSAccessibilityDescriptionAttribute +#define QAXDescriptionAttribute NSAccessibilityDescriptionAttribute +#define QAXDescriptionAttribute NSAccessibilityDescriptionAttribute +#define QAXDescriptionAttribute NSAccessibilityDescriptionAttribute +#define QAXEnabledAttribute NSAccessibilityEnabledAttribute +#define QAXEnabledAttribute NSAccessibilityEnabledAttribute +#define QAXExpandedAttribute NSAccessibilityExpandedAttribute +#define QAXFocusedAttribute NSAccessibilityFocusedAttribute +#define QAXFocusedAttribute NSAccessibilityFocusedAttribute +#define QAXFocusedAttribute NSAccessibilityFocusedAttribute +#define QAXFocusedUIElementChangedNotification NSAccessibilityFocusedUIElementChangedNotification +#define QAXFocusedWindowChangedNotification NSAccessibilityFocusedWindowChangedNotification +#define QAXGroupRole NSAccessibilityGroupRole +#define QAXGrowAreaAttribute NSAccessibilityGrowAreaAttribute +#define QAXGrowAreaAttribute NSAccessibilityGrowAreaAttribute +#define QAXGrowAreaRole NSAccessibilityGrowAreaRole +#define QAXHelpAttribute NSAccessibilityHelpAttribute +#define QAXHelpAttribute NSAccessibilityHelpAttribute +#define QAXHelpAttribute NSAccessibilityHelpAttribute +#define QAXHorizontalOrientationValue NSAccessibilityHorizontalOrientationValue +#define QAXHorizontalScrollBarAttribute NSAccessibilityHorizontalScrollBarAttribute +#define QAXHorizontalScrollBarAttribute NSAccessibilityHorizontalScrollBarAttribute +#define QAXIncrementAction NSAccessibilityIncrementAction +#define QAXIncrementAction NSAccessibilityIncrementAction +#define QAXIncrementArrowSubrole NSAccessibilityIncrementArrowSubrole +#define QAXIncrementPageSubrole NSAccessibilityIncrementPageSubrole +#define QAXIncrementorRole NSAccessibilityIncrementorRole +#define QAXLinkedUIElementsAttribute NSAccessibilityLinkedUIElementsAttribute +#define QAXLinkedUIElementsAttribute NSAccessibilityLinkedUIElementsAttribute +#define QAXListRole NSAccessibilityListRole +#define QAXMainAttribute NSAccessibilityMainAttribute +#define QAXMaxValueAttribute NSAccessibilityMaxValueAttribute +#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 QAXMinValueAttribute NSAccessibilityMinValueAttribute +#define QAXMinimizeButtonAttribute NSAccessibilityMinimizeButtonAttribute +#define QAXMinimizeButtonAttribute NSAccessibilityMinimizeButtonAttribute +#define QAXMinimizedAttribute NSAccessibilityMinimizedAttribute +#define QAXMinimizedAttribute NSAccessibilityMinimizedAttribute +#define QAXNextContentsAttribute NSAccessibilityNextContentsAttribute +#define QAXNextContentsAttribute NSAccessibilityNextContentsAttribute +#define QAXOrientationAttribute NSAccessibilityOrientationAttribute +#define QAXOrientationAttribute NSAccessibilityOrientationAttribute +#define QAXOrientationAttribute NSAccessibilityOrientationAttribute +#define QAXParentAttribute NSAccessibilityParentAttribute +#define QAXPickAction NSAccessibilityPickAction +#define QAXPickAction NSAccessibilityPickAction +#define QAXPopUpButtonRole NSAccessibilityPopUpButtonRole +#define QAXPositionAttribute NSAccessibilityPositionAttribute +#define QAXPositionAttribute NSAccessibilityPositionAttribute +#define QAXPressAction NSAccessibilityPressAction +#define QAXPressAction NSAccessibilityPressAction +#define QAXPreviousContentsAttribute NSAccessibilityPreviousContentsAttribute +#define QAXPreviousContentsAttribute NSAccessibilityPreviousContentsAttribute +#define QAXPreviousContentsAttribute NSAccessibilityPreviousContentsAttribute +#define QAXProgressIndicatorRole NSAccessibilityProgressIndicatorRole +#define QAXRadioButtonRole NSAccessibilityRadioButtonRole +#define QAXRoleAttribute NSAccessibilityRoleAttribute +#define QAXRoleAttribute NSAccessibilityRoleAttribute +#define QAXRoleDescriptionAttribute NSAccessibilityRoleDescriptionAttribute +#define QAXRowRole NSAccessibilityRowRole +#define QAXRowsAttribute NSAccessibilityRowsAttribute +#define QAXRowsAttribute NSAccessibilityRowsAttribute +#define QAXScrollAreaRole NSAccessibilityScrollAreaRole +#define QAXScrollAreaRole NSAccessibilityScrollAreaRole +#define QAXScrollAreaRole NSAccessibilityScrollAreaRole +#define QAXScrollBarRole NSAccessibilityScrollBarRole +#define QAXSelectedAttribute NSAccessibilitySelectedAttribute +#define QAXSelectedChildrenAttribute NSAccessibilitySelectedChildrenAttribute +#define QAXSelectedRowsAttribute NSAccessibilitySelectedRowsAttribute +#define QAXSelectedRowsAttribute NSAccessibilitySelectedRowsAttribute +#define QAXSizeAttribute NSAccessibilitySizeAttribute +#define QAXSizeAttribute NSAccessibilitySizeAttribute +#define QAXSliderRole NSAccessibilitySliderRole +#define QAXSplitGroupRole NSAccessibilitySplitGroupRole +#define QAXSplitterRole NSAccessibilitySplitterRole +#define QAXSplitterRole NSAccessibilitySplitterRole +#define QAXSplitterRole NSAccessibilitySplitterRole +#define QAXSplittersAttribute NSAccessibilitySplittersAttribute +#define QAXSplittersAttribute NSAccessibilitySplittersAttribute +#define QAXStaticTextRole NSAccessibilityStaticTextRole +#define QAXStaticTextRole NSAccessibilityStaticTextRole +#define QAXSubroleAttribute NSAccessibilitySubroleAttribute +#define QAXSubroleAttribute NSAccessibilitySubroleAttribute +#define QAXSubroleAttribute NSAccessibilitySubroleAttribute +#define QAXTabGroupRole NSAccessibilityTabGroupRole +#define QAXTabGroupRole NSAccessibilityTabGroupRole +#define QAXTableRole NSAccessibilityTableRole +#define QAXTabsAttribute NSAccessibilityTabsAttribute +#define QAXTabsAttribute NSAccessibilityTabsAttribute +#define QAXTextFieldRole NSAccessibilityTextFieldRole +#define QAXTextFieldRole NSAccessibilityTextFieldRole +#define QAXTitleAttribute NSAccessibilityTitleAttribute +#define QAXTitleAttribute NSAccessibilityTitleAttribute +#define QAXTitleAttribute NSAccessibilityTitleAttribute +#define QAXTitleAttribute NSAccessibilityTitleAttribute +#define QAXTitleUIElementAttribute NSAccessibilityTitleUIElementAttribute +#define QAXTitleUIElementAttribute NSAccessibilityTitleUIElementAttribute +#define QAXToolbarButtonAttribute NSAccessibilityToolbarButtonAttribute +#define QAXToolbarButtonAttribute NSAccessibilityToolbarButtonAttribute +#define QAXToolbarRole NSAccessibilityToolbarRole +#define QAXTopLevelUIElementAttribute NSAccessibilityTopLevelUIElementAttribute +#define QAXTopLevelUIElementAttribute NSAccessibilityTopLevelUIElementAttribute +#define QAXTopLevelUIElementAttribute NSAccessibilityTopLevelUIElementAttribute +#define QAXUnknownRole NSAccessibilityUnknownRole +#define QAXUnknownRole NSAccessibilityUnknownRole +#define QAXValueAttribute NSAccessibilityValueAttribute +#define QAXValueAttribute NSAccessibilityValueAttribute +#define QAXValueAttribute NSAccessibilityValueAttribute +#define QAXValueAttribute NSAccessibilityValueAttribute +#define QAXValueChangedNotification NSAccessibilityValueChangedNotification +#define QAXValueIndicatorRole NSAccessibilityValueIndicatorRole +#define QAXVerticalOrientationValue NSAccessibilityVerticalOrientationValue +#define QAXVerticalScrollBarAttribute NSAccessibilityVerticalScrollBarAttribute +#define QAXVerticalScrollBarAttribute NSAccessibilityVerticalScrollBarAttribute +#define QAXVisibleRowsAttribute NSAccessibilityVisibleRowsAttribute +#define QAXVisibleRowsAttribute NSAccessibilityVisibleRowsAttribute +#define QAXWindowAttribute NSAccessibilityWindowAttribute +#define QAXWindowAttribute NSAccessibilityWindowAttribute +#define QAXWindowAttribute NSAccessibilityWindowAttribute +#define QAXWindowCreatedNotification NSAccessibilityWindowCreatedNotification +#define QAXWindowMovedNotification NSAccessibilityWindowMovedNotification +#define QAXWindowRole NSAccessibilityWindowRole +#define QAXZoomButtonAttribute NSAccessibilityZoomButtonAttribute +#define QAXZoomButtonAttribute NSAccessibilityZoomButtonAttribute +#else +typedef CFStringRef const QAXRoleType; +#define QAXApplicationRole kAXApplicationRole +#define QAXButtonRole kAXButtonRole +#define QAXCancelAction kAXCancelAction +#define QAXCancelAction kAXCancelAction +#define QAXCheckBoxRole kAXCheckBoxRole +#define QAXChildrenAttribute kAXChildrenAttribute +#define QAXChildrenAttribute kAXChildrenAttribute +#define QAXChildrenAttribute kAXChildrenAttribute +#define QAXCloseButtonAttribute kAXCloseButtonAttribute +#define QAXCloseButtonAttribute kAXCloseButtonAttribute +#define QAXColumnRole kAXColumnRole +#define QAXConfirmAction kAXConfirmAction +#define QAXConfirmAction kAXConfirmAction +#define QAXContentsAttribute kAXContentsAttribute +#define QAXContentsAttribute kAXContentsAttribute +#define QAXDecrementAction kAXDecrementAction +#define QAXDecrementAction kAXDecrementAction +#define QAXDecrementArrowSubrole kAXDecrementArrowSubrole +#define QAXDecrementPageSubrole kAXDecrementPageSubrole +#define QAXDescriptionAttribute kAXDescriptionAttribute +#define QAXDescriptionAttribute kAXDescriptionAttribute +#define QAXDescriptionAttribute kAXDescriptionAttribute +#define QAXDescriptionAttribute kAXDescriptionAttribute +#define QAXEnabledAttribute kAXEnabledAttribute +#define QAXEnabledAttribute kAXEnabledAttribute +#define QAXExpandedAttribute kAXExpandedAttribute +#define QAXFocusedAttribute kAXFocusedAttribute +#define QAXFocusedAttribute kAXFocusedAttribute +#define QAXFocusedAttribute kAXFocusedAttribute +#define QAXFocusedUIElementChangedNotification kAXFocusedUIElementChangedNotification +#define QAXFocusedWindowChangedNotification kAXFocusedWindowChangedNotification +#define QAXGroupRole kAXGroupRole +#define QAXGrowAreaAttribute kAXGrowAreaAttribute +#define QAXGrowAreaAttribute kAXGrowAreaAttribute +#define QAXGrowAreaRole kAXGrowAreaRole +#define QAXHelpAttribute kAXHelpAttribute +#define QAXHelpAttribute kAXHelpAttribute +#define QAXHelpAttribute kAXHelpAttribute +#define QAXHorizontalOrientationValue kAXHorizontalOrientationValue +#define QAXHorizontalScrollBarAttribute kAXHorizontalScrollBarAttribute +#define QAXHorizontalScrollBarAttribute kAXHorizontalScrollBarAttribute +#define QAXIncrementAction kAXIncrementAction +#define QAXIncrementAction kAXIncrementAction +#define QAXIncrementArrowSubrole kAXIncrementArrowSubrole +#define QAXIncrementPageSubrole kAXIncrementPageSubrole +#define QAXIncrementorRole kAXIncrementorRole +#define QAXLinkedUIElementsAttribute kAXLinkedUIElementsAttribute +#define QAXLinkedUIElementsAttribute kAXLinkedUIElementsAttribute +#define QAXListRole kAXListRole +#define QAXMainAttribute kAXMainAttribute +#define QAXMaxValueAttribute kAXMaxValueAttribute +#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 QAXMinValueAttribute kAXMinValueAttribute +#define QAXMinimizeButtonAttribute kAXMinimizeButtonAttribute +#define QAXMinimizeButtonAttribute kAXMinimizeButtonAttribute +#define QAXMinimizedAttribute kAXMinimizedAttribute +#define QAXMinimizedAttribute kAXMinimizedAttribute +#define QAXNextContentsAttribute kAXNextContentsAttribute +#define QAXNextContentsAttribute kAXNextContentsAttribute +#define QAXOrientationAttribute kAXOrientationAttribute +#define QAXOrientationAttribute kAXOrientationAttribute +#define QAXOrientationAttribute kAXOrientationAttribute +#define QAXParentAttribute kAXParentAttribute +#define QAXPickAction kAXPickAction +#define QAXPickAction kAXPickAction +#define QAXPopUpButtonRole kAXPopUpButtonRole +#define QAXPositionAttribute kAXPositionAttribute +#define QAXPositionAttribute kAXPositionAttribute +#define QAXPressAction kAXPressAction +#define QAXPressAction kAXPressAction +#define QAXPreviousContentsAttribute kAXPreviousContentsAttribute +#define QAXPreviousContentsAttribute kAXPreviousContentsAttribute +#define QAXPreviousContentsAttribute kAXPreviousContentsAttribute +#define QAXProgressIndicatorRole kAXProgressIndicatorRole +#define QAXRadioButtonRole kAXRadioButtonRole +#define QAXRoleAttribute kAXRoleAttribute +#define QAXRoleAttribute kAXRoleAttribute +#define QAXRoleDescriptionAttribute kAXRoleDescriptionAttribute +#define QAXRowRole kAXRowRole +#define QAXRowsAttribute kAXRowsAttribute +#define QAXRowsAttribute kAXRowsAttribute +#define QAXScrollAreaRole kAXScrollAreaRole +#define QAXScrollAreaRole kAXScrollAreaRole +#define QAXScrollAreaRole kAXScrollAreaRole +#define QAXScrollBarRole kAXScrollBarRole +#define QAXSelectedAttribute kAXSelectedAttribute +#define QAXSelectedChildrenAttribute kAXSelectedChildrenAttribute +#define QAXSelectedRowsAttribute kAXSelectedRowsAttribute +#define QAXSelectedRowsAttribute kAXSelectedRowsAttribute +#define QAXSizeAttribute kAXSizeAttribute +#define QAXSizeAttribute kAXSizeAttribute +#define QAXSliderRole kAXSliderRole +#define QAXSplitGroupRole kAXSplitGroupRole +#define QAXSplitterRole kAXSplitterRole +#define QAXSplitterRole kAXSplitterRole +#define QAXSplitterRole kAXSplitterRole +#define QAXSplittersAttribute kAXSplittersAttribute +#define QAXSplittersAttribute kAXSplittersAttribute +#define QAXStaticTextRole kAXStaticTextRole +#define QAXStaticTextRole kAXStaticTextRole +#define QAXSubroleAttribute kAXSubroleAttribute +#define QAXSubroleAttribute kAXSubroleAttribute +#define QAXSubroleAttribute kAXSubroleAttribute +#define QAXTabGroupRole kAXTabGroupRole +#define QAXTabGroupRole kAXTabGroupRole +#define QAXTableRole kAXTableRole +#define QAXTabsAttribute kAXTabsAttribute +#define QAXTabsAttribute kAXTabsAttribute +#define QAXTextFieldRole kAXTextFieldRole +#define QAXTextFieldRole kAXTextFieldRole +#define QAXTitleAttribute kAXTitleAttribute +#define QAXTitleAttribute kAXTitleAttribute +#define QAXTitleAttribute kAXTitleAttribute +#define QAXTitleAttribute kAXTitleAttribute +#define QAXTitleUIElementAttribute kAXTitleUIElementAttribute +#define QAXTitleUIElementAttribute kAXTitleUIElementAttribute +#define QAXToolbarButtonAttribute kAXToolbarButtonAttribute +#define QAXToolbarButtonAttribute kAXToolbarButtonAttribute +#define QAXToolbarRole kAXToolbarRole +#define QAXTopLevelUIElementAttribute kAXTopLevelUIElementAttribute +#define QAXTopLevelUIElementAttribute kAXTopLevelUIElementAttribute +#define QAXTopLevelUIElementAttribute kAXTopLevelUIElementAttribute +#define QAXUnknownRole kAXUnknownRole +#define QAXUnknownRole kAXUnknownRole +#define QAXValueAttribute kAXValueAttribute +#define QAXValueAttribute kAXValueAttribute +#define QAXValueAttribute kAXValueAttribute +#define QAXValueAttribute kAXValueAttribute +#define QAXValueChangedNotification kAXValueChangedNotification +#define QAXValueIndicatorRole kAXValueIndicatorRole +#define QAXVerticalOrientationValue kAXVerticalOrientationValue +#define QAXVerticalScrollBarAttribute kAXVerticalScrollBarAttribute +#define QAXVerticalScrollBarAttribute kAXVerticalScrollBarAttribute +#define QAXVisibleRowsAttribute kAXVisibleRowsAttribute +#define QAXVisibleRowsAttribute kAXVisibleRowsAttribute +#define QAXWindowAttribute kAXWindowAttribute +#define QAXWindowAttribute kAXWindowAttribute +#define QAXWindowAttribute kAXWindowAttribute +#define QAXWindowCreatedNotification kAXWindowCreatedNotification +#define QAXWindowMovedNotification kAXWindowMovedNotification +#define QAXWindowRole kAXWindowRole +#define QAXZoomButtonAttribute kAXZoomButtonAttribute +#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) + :elementRef( +#ifndef QT_MAC_USE_COCOA + AXUIElementCreateWithHIObjectAndIdentifier(object, child) +#endif +) +{ +#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; +#if (MAC_OS_X_VERSION_MAX_ALLOWED >= MAC_OS_X_VERSION_10_4) + else if (CFStringCompare(attribute, CFStringRef(QAXDescriptionAttribute), 0) == kCFCompareEqualTo) + return QAccessible::Description; +#endif + 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)); +#if (MAC_OS_X_VERSION_MAX_ALLOWED >= MAC_OS_X_VERSION_10_4) + qt_mac_append_cf_uniq(attrs, CFStringRef(QAXTopLevelUIElementAttribute)); +#endif + + // Append these names if the QInterafceItem returns any data for them. + appendIfSupported(attrs, CFStringRef(QAXTitleAttribute), interface); + appendIfSupported(attrs, CFStringRef(QAXValueAttribute), interface); +#if (MAC_OS_X_VERSION_MAX_ALLOWED >= MAC_OS_X_VERSION_10_4) + appendIfSupported(attrs, CFStringRef(QAXDescriptionAttribute), interface); + appendIfSupported(attrs, CFStringRef(QAXLinkedUIElementsAttribute), interface); +#endif + 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) +*/ +#if (MAC_OS_X_VERSION_MAX_ALLOWED >= MAC_OS_X_VERSION_10_4) +static OSStatus handleTopLevelUIElementAttribute(EventHandlerCallRef next_ref, EventRef event, const QAInterface &interface) +{ + return navigateAncestors<IsWindowTest>(next_ref, event, interface, CFStringRef(QAXTopLevelUIElementAttribute)); +} +#endif + +/* + 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); +#if (MAC_OS_X_VERSION_MAX_ALLOWED >= MAC_OS_X_VERSION_10_4) + } else if(CFStringCompare(var, CFStringRef(QAXTopLevelUIElementAttribute), 0) == kCFCompareEqualTo) { + return handleTopLevelUIElementAttribute(next_ref, event, interface); +#endif + } 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 (MAC_OS_X_VERSION_MAX_ALLOWED >= MAC_OS_X_VERSION_10_4) && !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); + } +#if (MAC_OS_X_VERSION_MAX_ALLOWED >= MAC_OS_X_VERSION_10_4) + } 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); +#endif + } 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/gui/accessible/qaccessible_mac_carbon.cpp b/src/gui/accessible/qaccessible_mac_carbon.cpp new file mode 100644 index 0000000..3b2ab68 --- /dev/null +++ b/src/gui/accessible/qaccessible_mac_carbon.cpp @@ -0,0 +1,119 @@ +/**************************************************************************** +** +** Copyright (C) 2009 Nokia Corporation and/or its subsidiary(-ies). +** Contact: Qt Software Information (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 either Technology Preview License Agreement or the +** Beta Release License Agreement. +** +** 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.0, included in the file LGPL_EXCEPTION.txt in this +** package. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU +** General Public License version 3.0 as published by the Free Software +** Foundation and appearing in the file LICENSE.GPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU General Public License version 3.0 requirements will be +** met: http://www.gnu.org/copyleft/gpl.html. +** +** If you are unsure which license is appropriate for your use, please +** contact the sales department at qt-sales@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/gui/accessible/qaccessible_mac_cocoa.mm b/src/gui/accessible/qaccessible_mac_cocoa.mm new file mode 100644 index 0000000..e69de29 --- /dev/null +++ b/src/gui/accessible/qaccessible_mac_cocoa.mm diff --git a/src/gui/accessible/qaccessible_mac_p.h b/src/gui/accessible/qaccessible_mac_p.h new file mode 100644 index 0000000..e271253 --- /dev/null +++ b/src/gui/accessible/qaccessible_mac_p.h @@ -0,0 +1,479 @@ +/**************************************************************************** +** +** Copyright (C) 2009 Nokia Corporation and/or its subsidiary(-ies). +** Contact: Qt Software Information (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 either Technology Preview License Agreement or the +** Beta Release License Agreement. +** +** 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.0, included in the file LGPL_EXCEPTION.txt in this +** package. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU +** General Public License version 3.0 as published by the Free Software +** Foundation and appearing in the file LICENSE.GPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU General Public License version 3.0 requirements will be +** met: http://www.gnu.org/copyleft/gpl.html. +** +** If you are unsure which license is appropriate for your use, please +** contact the sales department at qt-sales@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 funcitons. +*/ +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 ¶ms = 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 provies lookup funcitons + 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/gui/accessible/qaccessible_unix.cpp b/src/gui/accessible/qaccessible_unix.cpp new file mode 100644 index 0000000..ac51e4f --- /dev/null +++ b/src/gui/accessible/qaccessible_unix.cpp @@ -0,0 +1,134 @@ +/**************************************************************************** +** +** Copyright (C) 2009 Nokia Corporation and/or its subsidiary(-ies). +** Contact: Qt Software Information (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 either Technology Preview License Agreement or the +** Beta Release License Agreement. +** +** 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.0, included in the file LGPL_EXCEPTION.txt in this +** package. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU +** General Public License version 3.0 as published by the Free Software +** Foundation and appearing in the file LICENSE.GPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU General Public License version 3.0 requirements will be +** met: http://www.gnu.org/copyleft/gpl.html. +** +** If you are unsure which license is appropriate for your use, please +** contact the sales department at qt-sales@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/gui/accessible/qaccessible_win.cpp b/src/gui/accessible/qaccessible_win.cpp new file mode 100644 index 0000000..99cc272 --- /dev/null +++ b/src/gui/accessible/qaccessible_win.cpp @@ -0,0 +1,1219 @@ +/**************************************************************************** +** +** Copyright (C) 2009 Nokia Corporation and/or its subsidiary(-ies). +** Contact: Qt Software Information (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 either Technology Preview License Agreement or the +** Beta Release License Agreement. +** +** 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.0, included in the file LGPL_EXCEPTION.txt in this +** package. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU +** General Public License version 3.0 as published by the Free Software +** Foundation and appearing in the file LICENSE.GPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU General Public License version 3.0 requirements will be +** met: http://www.gnu.org/copyleft/gpl.html. +** +** If you are unsure which license is appropriate for your use, please +** contact the sales department at qt-sales@nokia.com. +** $QT_END_LICENSE$ +** +****************************************************************************/ +#include "qaccessible.h" +#ifndef QT_NO_ACCESSIBILITY + +#include "qapplication.h" +#include "qlibrary.h" +#include "qmessagebox.h" // ### dependency +#include "qt_windows.h" +#include "qwidget.h" +#include "qsettings.h" + +#include <winuser.h> +#if !defined(WINABLEAPI) +# if defined(Q_OS_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_OS_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)]; +} + +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 + +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; + } + + QByteArray soundName; + switch (reason) { + case PopupMenuStart: + soundName = "MenuPopup"; + break; + + case MenuCommand: + soundName = "MenuCommand"; + break; + + case Alert: + { +#ifndef QT_NO_MESSAGEBOX + QMessageBox *mb = qobject_cast<QMessageBox*>(o); + if (mb) { + switch (mb->icon()) { + case QMessageBox::Warning: + soundName = "SystemExclamation"; + break; + case QMessageBox::Critical: + soundName = "SystemHand"; + break; + case QMessageBox::Information: + soundName = "SystemAsterisk"; + break; + default: + break; + } + } else +#endif // QT_NO_MESSAGEBOX + { + soundName = "SystemAsterisk"; + } + + } + break; + default: + break; + } + + if (soundName.size()) { +#ifndef QT_NO_SETTINGS + QSettings settings(QLatin1String("HKEY_CURRENT_USER\\AppEvents\\Schemes\\Apps\\.Default\\") + + QString::fromLatin1(soundName.constData()), QSettings::NativeFormat); + QString file = settings.value(QLatin1String(".Current/.")).toString(); +#else + QString file; +#endif + if (!file.isEmpty()) { + QT_WA({ + PlaySoundW(reinterpret_cast<const wchar_t *> (QString::fromLatin1(soundName).utf16()), 0, SND_ALIAS | SND_ASYNC | SND_NODEFAULT | SND_NOWAIT ); + } , { + PlaySoundA(soundName.constData(), 0, SND_ALIAS | SND_ASYNC | SND_NODEFAULT | SND_NOWAIT ); + }); + } + } + + if (!isActive()) + return; + + typedef void (WINAPI *PtrNotifyWinEvent)(DWORD, HWND, LONG, LONG); + +#if defined(Q_OS_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)QLibrary::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; + if (o->isWidgetType()) { + w = (QWidget*)o; + } else { + QObject *p = o; + while ((p = p->parent()) != 0) { + if (p->isWidgetType()) { + w = (QWidget*)p; + break; + } + } + } + + if (!w) { + if (reason != QAccessible::ContextHelpStart && + reason != QAccessible::ContextHelpEnd) + w = qApp->focusWidget(); + if (!w) { + w = qApp->activeWindow(); + + if (!w) + return; + +// ### Fixme +// if (!w) { +// w = qApp->mainWidget(); +// if (!w) +// return; +// } + } + } + + if (reason != MenuCommand) { // MenuCommand is faked + ptrNotifyWinEvent(reason, w->winId(), OBJID_CLIENT, who); + } +#endif // Q_OS_WINCE +} + +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; + } + + HRESULT STDMETHODCALLTYPE QueryInterface(REFIID, LPVOID *); + ULONG STDMETHODCALLTYPE AddRef(); + ULONG STDMETHODCALLTYPE Release(); + + 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 *); + + 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); + + 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; + + QAccessibleInterface *acc = 0; + RelationFlag rel = varChildID.lVal ? Child : Self; + accessible->navigate(rel, varChildID.lVal, &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) { + (*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)->winId(); + return S_OK; +} + +HRESULT STDMETHODCALLTYPE QWindowsAccessible::ContextSensitiveHelp(BOOL) +{ + return S_OK; +} + +QT_END_NAMESPACE + +#endif // QT_NO_ACCESSIBILITY diff --git a/src/gui/accessible/qaccessiblebridge.cpp b/src/gui/accessible/qaccessiblebridge.cpp new file mode 100644 index 0000000..7c03e9c --- /dev/null +++ b/src/gui/accessible/qaccessiblebridge.cpp @@ -0,0 +1,158 @@ +/**************************************************************************** +** +** Copyright (C) 2009 Nokia Corporation and/or its subsidiary(-ies). +** Contact: Qt Software Information (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 either Technology Preview License Agreement or the +** Beta Release License Agreement. +** +** 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.0, included in the file LGPL_EXCEPTION.txt in this +** package. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU +** General Public License version 3.0 as published by the Free Software +** Foundation and appearing in the file LICENSE.GPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU General Public License version 3.0 requirements will be +** met: http://www.gnu.org/copyleft/gpl.html. +** +** If you are unsure which license is appropriate for your use, please +** contact the sales department at qt-sales@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/gui/accessible/qaccessiblebridge.h b/src/gui/accessible/qaccessiblebridge.h new file mode 100644 index 0000000..0725e19 --- /dev/null +++ b/src/gui/accessible/qaccessiblebridge.h @@ -0,0 +1,92 @@ +/**************************************************************************** +** +** Copyright (C) 2009 Nokia Corporation and/or its subsidiary(-ies). +** Contact: Qt Software Information (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 either Technology Preview License Agreement or the +** Beta Release License Agreement. +** +** 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.0, included in the file LGPL_EXCEPTION.txt in this +** package. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU +** General Public License version 3.0 as published by the Free Software +** Foundation and appearing in the file LICENSE.GPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU General Public License version 3.0 requirements will be +** met: http://www.gnu.org/copyleft/gpl.html. +** +** If you are unsure which license is appropriate for your use, please +** contact the sales department at qt-sales@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/gui/accessible/qaccessibleobject.cpp b/src/gui/accessible/qaccessibleobject.cpp new file mode 100644 index 0000000..7df097b --- /dev/null +++ b/src/gui/accessible/qaccessibleobject.cpp @@ -0,0 +1,410 @@ +/**************************************************************************** +** +** Copyright (C) 2009 Nokia Corporation and/or its subsidiary(-ies). +** Contact: Qt Software Information (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 either Technology Preview License Agreement or the +** Beta Release License Agreement. +** +** 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.0, included in the file LGPL_EXCEPTION.txt in this +** package. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU +** General Public License version 3.0 as published by the Free Software +** Foundation and appearing in the file LICENSE.GPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU General Public License version 3.0 requirements will be +** met: http://www.gnu.org/copyleft/gpl.html. +** +** If you are unsure which license is appropriate for your use, please +** contact the sales department at qt-sales@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(qApp->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 = qFindChildren<QObject *>(w, 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 = qApp->activeWindow(); + break; + default: + break; + } + *target = QAccessible::queryAccessibleInterface(targetObject); + return *target ? 0 : -1; +} + +/*! \reimp */ +QString QAccessibleApplication::text(Text t, int) const +{ + switch (t) { + case Name: + if (qApp->activeWindow()) + return qApp->activeWindow()->windowTitle(); + break; + case Description: + return qApp->applicationFilePath(); + default: + break; + } + return QString(); +} + +/*! \reimp */ +QAccessible::Role QAccessibleApplication::role(int) const +{ + return Application; +} + +/*! \reimp */ +QAccessible::State QAccessibleApplication::state(int) const +{ + return qApp->activeWindow() ? Focused : Normal; +} + +/*! \reimp */ +int QAccessibleApplication::userActionCount(int) const +{ + return 1; +} + +/*! \reimp */ +bool QAccessibleApplication::doAction(int action, int child, const QVariantList ¶m) +{ + if (action == 0 || action == 1) { + QWidget *w = 0; + w = qApp->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 ¶ms) +{ 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/gui/accessible/qaccessibleobject.h b/src/gui/accessible/qaccessibleobject.h new file mode 100644 index 0000000..aef7ce7 --- /dev/null +++ b/src/gui/accessible/qaccessibleobject.h @@ -0,0 +1,140 @@ +/**************************************************************************** +** +** Copyright (C) 2009 Nokia Corporation and/or its subsidiary(-ies). +** Contact: Qt Software Information (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 either Technology Preview License Agreement or the +** Beta Release License Agreement. +** +** 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.0, included in the file LGPL_EXCEPTION.txt in this +** package. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU +** General Public License version 3.0 as published by the Free Software +** Foundation and appearing in the file LICENSE.GPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU General Public License version 3.0 requirements will be +** met: http://www.gnu.org/copyleft/gpl.html. +** +** If you are unsure which license is appropriate for your use, please +** contact the sales department at qt-sales@nokia.com. +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#ifndef QACCESSIBLEOBJECT_H +#define QACCESSIBLEOBJECT_H + +#include <QtGui/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 ¶ms); + 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 ¶ms); + 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 ¶ms); + 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/gui/accessible/qaccessibleplugin.cpp b/src/gui/accessible/qaccessibleplugin.cpp new file mode 100644 index 0000000..00fe2b1 --- /dev/null +++ b/src/gui/accessible/qaccessibleplugin.cpp @@ -0,0 +1,107 @@ +/**************************************************************************** +** +** Copyright (C) 2009 Nokia Corporation and/or its subsidiary(-ies). +** Contact: Qt Software Information (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 either Technology Preview License Agreement or the +** Beta Release License Agreement. +** +** 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.0, included in the file LGPL_EXCEPTION.txt in this +** package. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU +** General Public License version 3.0 as published by the Free Software +** Foundation and appearing in the file LICENSE.GPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU General Public License version 3.0 requirements will be +** met: http://www.gnu.org/copyleft/gpl.html. +** +** If you are unsure which license is appropriate for your use, please +** contact the sales department at qt-sales@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/gui/accessible/qaccessibleplugin.h b/src/gui/accessible/qaccessibleplugin.h new file mode 100644 index 0000000..a566921 --- /dev/null +++ b/src/gui/accessible/qaccessibleplugin.h @@ -0,0 +1,87 @@ +/**************************************************************************** +** +** Copyright (C) 2009 Nokia Corporation and/or its subsidiary(-ies). +** Contact: Qt Software Information (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 either Technology Preview License Agreement or the +** Beta Release License Agreement. +** +** 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.0, included in the file LGPL_EXCEPTION.txt in this +** package. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU +** General Public License version 3.0 as published by the Free Software +** Foundation and appearing in the file LICENSE.GPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU General Public License version 3.0 requirements will be +** met: http://www.gnu.org/copyleft/gpl.html. +** +** If you are unsure which license is appropriate for your use, please +** contact the sales department at qt-sales@nokia.com. +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#ifndef QACCESSIBLEPLUGIN_H +#define QACCESSIBLEPLUGIN_H + +#include <QtGui/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/gui/accessible/qaccessiblewidget.cpp b/src/gui/accessible/qaccessiblewidget.cpp new file mode 100644 index 0000000..4b2b2ab --- /dev/null +++ b/src/gui/accessible/qaccessiblewidget.cpp @@ -0,0 +1,1041 @@ +/**************************************************************************** +** +** Copyright (C) 2009 Nokia Corporation and/or its subsidiary(-ies). +** Contact: Qt Software Information (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 either Technology Preview License Agreement or the +** Beta Release License Agreement. +** +** 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.0, included in the file LGPL_EXCEPTION.txt in this +** package. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU +** General Public License version 3.0 as published by the Free Software +** Foundation and appearing in the file LICENSE.GPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU General Public License version 3.0 requirements will be +** met: http://www.gnu.org/copyleft/gpl.html. +** +** If you are unsure which license is appropriate for your use, please +** contact the sales department at qt-sales@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 <QtGui/QFocusFrame> +#include <QtGui/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) +{ + if (text.isEmpty()) + return text; + + const QChar *ch = text.unicode(); + int length = text.length(); + QString str; + while (length > 0) { + if (*ch == QLatin1Char('&')) { + ++ch; + --length; + if (!ch) + --ch; + } + str += *ch; + ++ch; + --length; + } + return str; +} + +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) { + if (fa == text.length() - 1 || text.at(fa+1) != QLatin1Char('&')) { + ac = text.at(fa+1); + 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 ¶ms) +{ + 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 ¶ms) +{ 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 qVariantFromValue(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/gui/accessible/qaccessiblewidget.h b/src/gui/accessible/qaccessiblewidget.h new file mode 100644 index 0000000..e6423d9 --- /dev/null +++ b/src/gui/accessible/qaccessiblewidget.h @@ -0,0 +1,141 @@ +/**************************************************************************** +** +** Copyright (C) 2009 Nokia Corporation and/or its subsidiary(-ies). +** Contact: Qt Software Information (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 either Technology Preview License Agreement or the +** Beta Release License Agreement. +** +** 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.0, included in the file LGPL_EXCEPTION.txt in this +** package. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU +** General Public License version 3.0 as published by the Free Software +** Foundation and appearing in the file LICENSE.GPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU General Public License version 3.0 requirements will be +** met: http://www.gnu.org/copyleft/gpl.html. +** +** If you are unsure which license is appropriate for your use, please +** contact the sales department at qt-sales@nokia.com. +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#ifndef QACCESSIBLEWIDGET_H +#define QACCESSIBLEWIDGET_H + +#include <QtGui/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 ¶ms); +#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 ¶ms); + + QVariant invokeMethodEx(Method method, int child, const QVariantList ¶ms); + +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 |