Use events for accessibility updates.
The problem with the old updates is that it was impossible to send details about the update. For the Linux implementation to work properly with AT-SPI I need to know which state changed (currently I only get a generic "state changed" event) or which part of the text was changed for long texts (imagine a word processor sending updates). This also gives us more options when updating with events generated from not QObject based objects. Change-Id: If0b6c83c523092565eb48e79f3f6de5a1b905ea8 Reviewed-by: Jan-Arve Sæther <jan-arve.saether@nokia.com>
This commit is contained in:
parent
cf52c268b0
commit
bf9bdf5328
@ -654,13 +654,29 @@ void QAccessible::setRootObject(QObject *object)
|
||||
}
|
||||
|
||||
/*!
|
||||
Notifies accessibility clients about a change in \a object's
|
||||
accessibility information.
|
||||
\deprecated
|
||||
|
||||
\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.
|
||||
Use the version with a single \l QAccessibleEvent paremeter instead.
|
||||
*/
|
||||
void QAccessible::updateAccessibility(QObject *object, int child, Event reason)
|
||||
{
|
||||
Q_ASSERT(object);
|
||||
|
||||
qWarning("QAccessible::updateAccessibility is deprecated.");
|
||||
|
||||
QAccessibleEvent event = QAccessibleEvent(reason, object, child);
|
||||
updateAccessibility(event);
|
||||
}
|
||||
|
||||
/*!
|
||||
Notifies about a change that might be relevant for accessibility clients.
|
||||
|
||||
\a event gives the details about the change.
|
||||
This includes the source of the change and what the actual change is.
|
||||
There should be sufficient details delivered with this event to give meaningful notifications.
|
||||
|
||||
For example, the type \c ValueChange indicates that the position of
|
||||
a slider has been changed.
|
||||
|
||||
Call this function whenever the state of your accessible object or
|
||||
one of its sub-elements has been changed either programmatically
|
||||
@ -671,12 +687,10 @@ void QAccessible::setRootObject(QObject *object)
|
||||
the parameters of the call is expensive you can test isActive() to
|
||||
avoid unnecessary computations.
|
||||
*/
|
||||
void QAccessible::updateAccessibility(QObject *object, int child, Event reason)
|
||||
void QAccessible::updateAccessibility(const QAccessibleEvent &event)
|
||||
{
|
||||
Q_ASSERT(object);
|
||||
|
||||
if (updateHandler) {
|
||||
updateHandler(object, child, reason);
|
||||
updateHandler(event);
|
||||
return;
|
||||
}
|
||||
|
||||
@ -684,9 +698,43 @@ void QAccessible::updateAccessibility(QObject *object, int child, Event reason)
|
||||
return;
|
||||
|
||||
if (QPlatformAccessibility *pfAccessibility = platformAccessibility())
|
||||
pfAccessibility->notifyAccessibilityUpdate(object, child, reason);
|
||||
pfAccessibility->notifyAccessibilityUpdate(event);
|
||||
}
|
||||
|
||||
/*!
|
||||
\class QAccessibleEvent
|
||||
\brief The QAccessibleEvent is use to notify about changes that are
|
||||
relevant for accessibility in the application.
|
||||
|
||||
\ingroup accessibility
|
||||
\inmodule QtGui
|
||||
|
||||
This class should be created on the stack and used as parameter for
|
||||
\l QAccessible::updateAccessibility().
|
||||
*/
|
||||
|
||||
/*!
|
||||
Returns the QAccessibleInterface associated with the event.
|
||||
|
||||
The caller of this function takes ownership of the returned interface.
|
||||
*/
|
||||
QAccessibleInterface *QAccessibleEvent::accessibleInterface() const
|
||||
{
|
||||
QAccessibleInterface *iface = QAccessible::queryAccessibleInterface(m_object);
|
||||
if (!iface)
|
||||
return 0;
|
||||
|
||||
if (m_child >= 0) {
|
||||
QAccessibleInterface *child = iface->child(m_child);
|
||||
if (child) {
|
||||
delete iface;
|
||||
iface = child;
|
||||
} else {
|
||||
qWarning() << "Cannot creat accessible child interface for object: " << m_object << " index: " << m_child;
|
||||
}
|
||||
}
|
||||
return iface;
|
||||
}
|
||||
|
||||
/*!
|
||||
\class QAccessibleInterface
|
||||
|
@ -59,6 +59,7 @@ QT_BEGIN_NAMESPACE
|
||||
#ifndef QT_NO_ACCESSIBILITY
|
||||
|
||||
class QAccessibleInterface;
|
||||
class QAccessibleEvent;
|
||||
class QWindow;
|
||||
|
||||
// We need to inherit QObject to expose the enums to QML.
|
||||
@ -326,7 +327,7 @@ public:
|
||||
};
|
||||
|
||||
typedef QAccessibleInterface*(*InterfaceFactory)(const QString &key, QObject*);
|
||||
typedef void(*UpdateHandler)(QObject*, int who, Event reason);
|
||||
typedef void(*UpdateHandler)(const QAccessibleEvent &event);
|
||||
typedef void(*RootObjectHandler)(QObject*);
|
||||
|
||||
static void installFactory(InterfaceFactory);
|
||||
@ -335,7 +336,10 @@ public:
|
||||
static RootObjectHandler installRootObjectHandler(RootObjectHandler);
|
||||
|
||||
static QAccessibleInterface *queryAccessibleInterface(QObject *);
|
||||
|
||||
static void updateAccessibility(QObject *object, int child, Event reason);
|
||||
static void updateAccessibility(const QAccessibleEvent &event);
|
||||
|
||||
static bool isActive();
|
||||
static void setRootObject(QObject *object);
|
||||
|
||||
@ -425,6 +429,28 @@ public:
|
||||
private:
|
||||
};
|
||||
|
||||
class Q_GUI_EXPORT QAccessibleEvent
|
||||
{
|
||||
public:
|
||||
inline QAccessibleEvent(QAccessible::Event type, QObject *object, int child = -1)
|
||||
: m_type(type), m_object(object), m_child(child)
|
||||
{
|
||||
Q_ASSERT(object);
|
||||
}
|
||||
|
||||
QAccessible::Event type() const { return m_type; }
|
||||
QObject *object() const { return m_object; }
|
||||
int child() const { return m_child; }
|
||||
|
||||
QAccessibleInterface *accessibleInterface() const;
|
||||
|
||||
private:
|
||||
QAccessible::Event m_type;
|
||||
QObject *m_object;
|
||||
int m_child;
|
||||
};
|
||||
|
||||
|
||||
#define QAccessibleInterface_iid "org.qt-project.Qt.QAccessibleInterface"
|
||||
Q_DECLARE_INTERFACE(QAccessibleInterface, QAccessibleInterface_iid)
|
||||
|
||||
|
@ -53,13 +53,14 @@ QT_BEGIN_NAMESPACE
|
||||
#ifndef QT_NO_ACCESSIBILITY
|
||||
|
||||
class QAccessibleInterface;
|
||||
class QAccessibleEvent;
|
||||
|
||||
class QAccessibleBridge
|
||||
{
|
||||
public:
|
||||
virtual ~QAccessibleBridge() {}
|
||||
virtual void setRootObject(QAccessibleInterface *) = 0;
|
||||
virtual void notifyAccessibilityUpdate(int, QAccessibleInterface*, int) = 0;
|
||||
virtual void notifyAccessibilityUpdate(const QAccessibleEvent &event) = 0;
|
||||
};
|
||||
|
||||
struct Q_GUI_EXPORT QAccessibleBridgeFactoryInterface : public QFactoryInterface
|
||||
|
@ -45,6 +45,8 @@
|
||||
#include "qaccessiblebridge.h"
|
||||
#include <QtGui/QGuiApplication>
|
||||
|
||||
#include <QDebug>
|
||||
|
||||
QT_BEGIN_NAMESPACE
|
||||
|
||||
/* accessiblebridge plugin discovery stuff */
|
||||
@ -73,33 +75,15 @@ QPlatformAccessibility::~QPlatformAccessibility()
|
||||
{
|
||||
}
|
||||
|
||||
void QPlatformAccessibility::notifyAccessibilityUpdate(QObject *o,
|
||||
int who,
|
||||
QAccessible::Event reason)
|
||||
void QPlatformAccessibility::notifyAccessibilityUpdate(const QAccessibleEvent &event)
|
||||
{
|
||||
initialize();
|
||||
|
||||
if (!bridges() || bridges()->isEmpty())
|
||||
return;
|
||||
|
||||
QAccessibleInterface *iface = QAccessible::queryAccessibleInterface(o);
|
||||
if (!iface)
|
||||
return;
|
||||
|
||||
// updates for List/Table/Tree should send child
|
||||
if (who) {
|
||||
QAccessibleInterface *child = iface->child(who - 1);
|
||||
if (child) {
|
||||
delete iface;
|
||||
iface = child;
|
||||
who = 0;
|
||||
}
|
||||
}
|
||||
|
||||
for (int i = 0; i < bridges()->count(); ++i)
|
||||
bridges()->at(i)->notifyAccessibilityUpdate(reason, iface, who);
|
||||
delete iface;
|
||||
|
||||
bridges()->at(i)->notifyAccessibilityUpdate(event);
|
||||
}
|
||||
|
||||
void QPlatformAccessibility::setRootObject(QObject *o)
|
||||
|
@ -57,7 +57,7 @@ public:
|
||||
QPlatformAccessibility();
|
||||
|
||||
virtual ~QPlatformAccessibility();
|
||||
virtual void notifyAccessibilityUpdate(QObject *o, int who, QAccessible::Event reason);
|
||||
virtual void notifyAccessibilityUpdate(const QAccessibleEvent &event);
|
||||
virtual void setRootObject(QObject *o);
|
||||
virtual void initialize();
|
||||
virtual void cleanup();
|
||||
|
@ -1296,10 +1296,10 @@ QWindowsAccessibility::QWindowsAccessibility()
|
||||
}
|
||||
|
||||
|
||||
void QWindowsAccessibility::notifyAccessibilityUpdate(QObject *o, int who, QAccessible::Event reason)
|
||||
void QWindowsAccessibility::notifyAccessibilityUpdate(const QAccessibleEvent &event)
|
||||
{
|
||||
QString soundName;
|
||||
switch (reason) {
|
||||
switch (event.type()) {
|
||||
case QAccessible::PopupMenuStart:
|
||||
soundName = QLatin1String("MenuPopup");
|
||||
break;
|
||||
@ -1370,8 +1370,9 @@ void QWindowsAccessibility::notifyAccessibilityUpdate(QObject *o, int who, QAcce
|
||||
|
||||
// An event has to be associated with a window,
|
||||
// so find the first parent that is a widget and that has a WId
|
||||
QAccessibleInterface *iface = QAccessible::queryAccessibleInterface(o);
|
||||
QAccessibleInterface *iface = event.accessibleInterface();
|
||||
QWindow *window = iface ? window_helper(iface) : 0;
|
||||
delete iface;
|
||||
|
||||
if (!window) {
|
||||
window = QGuiApplication::activeWindow();
|
||||
@ -1382,18 +1383,17 @@ void QWindowsAccessibility::notifyAccessibilityUpdate(QObject *o, int who, QAcce
|
||||
QPlatformNativeInterface *platform = QGuiApplication::platformNativeInterface();
|
||||
HWND hWnd = (HWND)platform->nativeResourceForWindow("handle", window);
|
||||
|
||||
if (reason != QAccessible::MenuCommand) { // MenuCommand is faked
|
||||
if (event.type() != QAccessible::MenuCommand) { // MenuCommand is faked
|
||||
// See comment "SENDING EVENTS TO OBJECTS WITH NO WINDOW HANDLE"
|
||||
eventNum %= 50; //[0..49]
|
||||
int eventId = - eventNum - 1;
|
||||
|
||||
qAccessibleRecentSentEvents()->insert(eventId, qMakePair(o, who));
|
||||
ptrNotifyWinEvent(reason, hWnd, OBJID_CLIENT, eventId );
|
||||
qAccessibleRecentSentEvents()->insert(eventId, qMakePair(event.object(), event.child()));
|
||||
ptrNotifyWinEvent(event.type(), hWnd, OBJID_CLIENT, eventId );
|
||||
|
||||
++eventNum;
|
||||
}
|
||||
#endif // Q_WS_WINCE
|
||||
|
||||
}
|
||||
|
||||
/*
|
||||
|
@ -50,12 +50,12 @@ class QWindowsAccessibility : public QPlatformAccessibility
|
||||
public:
|
||||
QWindowsAccessibility();
|
||||
static bool handleAccessibleObjectFromWindowRequest(HWND hwnd, WPARAM wParam, LPARAM lParam, LRESULT *lResult);
|
||||
virtual void notifyAccessibilityUpdate(QObject *o, int who, QAccessible::Event reason);
|
||||
virtual void notifyAccessibilityUpdate(const QAccessibleEvent &event);
|
||||
/*
|
||||
virtual void setRootObject(QObject *o);
|
||||
virtual void initialize();
|
||||
virtual void cleanup();
|
||||
*/
|
||||
*/
|
||||
};
|
||||
|
||||
#endif // QWINDOWSACCESSIBILITY_H
|
||||
|
@ -134,10 +134,10 @@ private:
|
||||
}
|
||||
}
|
||||
|
||||
static void updateHandler(QObject *o, int c, QAccessible::Event e)
|
||||
static void updateHandler(const QAccessibleEvent &event)
|
||||
{
|
||||
// qDebug("updateHandler called: %p %d %d", o, c, (int)e);
|
||||
eventList().append(QTestAccessibilityEvent(o, c, (int)e));
|
||||
eventList().append(QTestAccessibilityEvent(event.object(), event.child(), (int)event.type()));
|
||||
}
|
||||
|
||||
static EventList &eventList()
|
||||
|
Loading…
Reference in New Issue
Block a user