1
/****************************************************************************
3
** Copyright (C) 1992-2005 Trolltech AS. All rights reserved.
5
** This file is part of the accessibility module of the Qt Toolkit.
7
** This file may be distributed under the terms of the Q Public License
8
** as defined by Trolltech AS of Norway and appearing in the file
9
** LICENSE.QPL included in the packaging of this file.
11
** This file may be distributed and/or modified under the terms of the
12
** GNU General Public License version 2 as published by the Free Software
13
** Foundation and appearing in the file LICENSE.GPL included in the
14
** packaging of this file.
16
** See http://www.trolltech.com/pricing.html or email sales@trolltech.com for
17
** information about Qt Commercial License Agreements.
18
** See http://www.trolltech.com/qpl/ for QPL licensing information.
19
** See http://www.trolltech.com/gpl/ for GPL licensing information.
21
** Contact info@trolltech.com if any conditions of this licensing are
24
** This file is provided AS IS with NO WARRANTY OF ANY KIND, INCLUDING THE
25
** WARRANTY OF DESIGN, MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE.
27
****************************************************************************/
29
#include "qaccessiblewidget.h"
31
#ifndef QT_NO_ACCESSIBILITY
33
#include "qapplication.h"
34
#include "qgroupbox.h"
37
#include "qwhatsthis.h"
42
static QWidgetList childWidgets(const QWidget *widget)
44
QObjectList list = widget->children();
46
for (int i = 0; i < list.size(); ++i) {
47
QWidget *w = qobject_cast<QWidget *>(list.at(i));
54
static QString buddyString(const QWidget *widget)
58
QWidget *parent = widget->parentWidget();
61
QObjectList ol = parent->children();
62
for (int i = 0; i < ol.size(); ++i) {
63
QLabel *label = qobject_cast<QLabel*>(ol.at(i));
64
if (label && label->buddy() == widget)
68
QGroupBox *groupbox = qobject_cast<QGroupBox*>(parent);
70
return groupbox->title();
75
QString Q_GUI_EXPORT qt_accStripAmp(const QString &text)
80
const QChar *ch = text.unicode();
81
int length = text.length();
97
QString Q_GUI_EXPORT qt_accHotKey(const QString &text)
104
while ((fa = text.indexOf('&', fa)) != -1) {
105
if (fa == text.length() - 1 || text.at(fa+1) != '&') {
112
return (QString)QKeySequence(Qt::ALT) + ac.toUpper();
115
class QAccessibleWidgetPrivate : public QAccessible
118
QAccessibleWidgetPrivate()
128
QStringList primarySignals;
129
const QAccessibleInterface *asking;
133
\class QAccessibleWidget
134
\brief The QAccessibleWidget class implements the QAccessibleInterface for QWidgets.
136
\ingroup accessibility
138
This class is convenient to use as a base class for custom
139
implementations of QAccessibleInterfaces that provide information
140
about widget objects.
142
The class provides functions to retrieve the parentObject() (the
143
widget's parent widget), and the associated widget(). Controlling
144
signals can be added with addControllingSignal(), and setters are
145
provided for various aspects of the interface implementation, for
146
example setValue(), setDescription(), setAccelerator(), and
149
\sa QAccessible, QAccessibleObject
153
Creates a QAccessibleWidget object for widget \a w.
154
\a role and \a name are optional parameters that set the object's
155
role and name properties.
157
QAccessibleWidget::QAccessibleWidget(QWidget *w, Role role, const QString &name)
158
: QAccessibleObject(w)
161
d = new QAccessibleWidgetPrivate();
168
Destroys this object.
170
QAccessibleWidget::~QAccessibleWidget()
176
Returns the associated widget.
178
QWidget *QAccessibleWidget::widget() const
180
return qobject_cast<QWidget*>(object());
184
Returns the associated widget's parent object, which is either the
185
parent widget, or qApp for top-level widgets.
187
QObject *QAccessibleWidget::parentObject() const
189
QObject *parent = object()->parent();
196
int QAccessibleWidget::childAt(int x, int y) const
198
QWidget *w = widget();
199
QPoint gp = w->mapToGlobal(QPoint(0, 0));
200
if (!QRect(gp.x(), gp.y(), w->width(), w->height()).contains(x, y))
203
QWidgetList list = childWidgets(w);
204
int ccount = childCount();
207
if (list.size() < ccount) {
208
for (int i = 1; i <= ccount; ++i) {
209
if (rect(i).contains(x, y))
215
QPoint rp = w->mapFromGlobal(QPoint(x, y));
216
for (int i = 0; i<list.size(); ++i) {
217
QWidget *child = list.at(i);
218
if (!child->isWindow() && !child->isHidden() && child->geometry().contains(rp)) {
226
QRect QAccessibleWidget::rect(int child) const
229
qWarning("QAccessibleWidget::rect: This implementation does not support subelements! (ID %d unknown for %s)", child, widget()->metaObject()->className());
231
QWidget *w = widget();
232
QPoint wpos = w->mapToGlobal(QPoint(0, 0));
234
return QRect(wpos.x(), wpos.y(), w->width(), w->height());
237
#include <private/qobject_p.h>
239
class ConnectionObject : public QObject
241
Q_DECLARE_PRIVATE(QObject)
243
inline bool isSender(const QObject *receiver, const char *signal) const
244
{ return d_func()->isSender(receiver, signal); }
245
inline QObjectList receiverList(const char *signal) const
246
{ return d_func()->receiverList(signal); }
247
inline QObjectList senderList() const
248
{ return d_func()->senderList(); }
252
Registers \a signal as a controlling signal.
254
An object is a Controller to any other object connected to a
257
void QAccessibleWidget::addControllingSignal(const QString &signal)
259
QByteArray s = QMetaObject::normalizedSignature(signal.toAscii());
260
if (object()->metaObject()->indexOfSignal(s) < 0)
261
qWarning("Signal %s unknown in %s", (const char*)s, object()->metaObject()->className());
262
d->primarySignals << s;
266
Sets the value of this interface implementation to \a value.
268
The default implementation of text() returns the set value for
271
Note that the object wrapped by this interface is not modified.
273
void QAccessibleWidget::setValue(const QString &value)
279
Sets the description of this interface implementation to \a desc.
281
The default implementation of text() returns the set value for
282
the Description text.
284
Note that the object wrapped by this interface is not modified.
286
void QAccessibleWidget::setDescription(const QString &desc)
288
d->description = desc;
292
Sets the help of this interface implementation to \a help.
294
The default implementation of text() returns the set value for
297
Note that the object wrapped by this interface is not modified.
299
void QAccessibleWidget::setHelp(const QString &help)
305
Sets the accelerator of this interface implementation to \a accel.
307
The default implementation of text() returns the set value for
308
the Accelerator text.
310
Note that the object wrapped by this interface is not modified.
312
void QAccessibleWidget::setAccelerator(const QString &accel)
314
d->accelerator = accel;
317
static inline bool isAncestor(const QObject *obj, const QObject *child)
322
child = child->parent();
329
QAccessible::Relation QAccessibleWidget::relationTo(int child,
330
const QAccessibleInterface *other, int otherChild) const
332
Relation relation = Unrelated;
333
if (d->asking == this) // recursive call
336
QObject *o = other ? other->object() : 0;
340
QWidget *focus = widget()->focusWidget();
341
if (object() == focus && isAncestor(o, focus))
342
relation |= FocusChild;
344
ConnectionObject *connectionObject = (ConnectionObject*)object();
345
for (int sig = 0; sig < d->primarySignals.count(); ++sig) {
346
if (connectionObject->isSender(o, d->primarySignals.at(sig).toAscii())) {
347
relation |= Controller;
351
// test for passive relationships.
352
// d->asking protects from endless recursion.
354
int inverse = other->relationTo(otherChild, this, child);
357
if (inverse & Controller)
358
relation |= Controlled;
360
relation |= Labelled;
363
if (child && !otherChild)
364
return relation | Child;
365
if (!child && otherChild)
366
return relation | Ancestor;
367
if (!child && !otherChild)
368
return relation | Self;
371
QObject *parent = object()->parent();
373
return relation | Child;
375
if (o->parent() == parent) {
377
QAccessibleInterface *sibIface = QAccessible::queryAccessibleInterface(o);
380
QRect sg = sibIface->rect(0);
381
if (wg.intersects(sg)) {
382
QAccessibleInterface *pIface = 0;
383
sibIface->navigate(Ancestor, 1, &pIface);
384
if (pIface && !((sibIface->state(0) | state(0)) & Invisible)) {
385
int wi = pIface->indexOfChild(this);
386
int si = pIface->indexOfChild(sibIface);
389
relation |= QAccessible::Covers;
391
relation |= QAccessible::Covered;
395
QPoint wc = wg.center();
396
QPoint sc = sg.center();
398
relation |= QAccessible::Left;
399
else if(wc.x() > sc.x())
400
relation |= QAccessible::Right;
402
relation |= QAccessible::Up;
403
else if (wc.y() > sc.y())
404
relation |= QAccessible::Down;
411
if (isAncestor(o, object()))
412
return relation | Descendent;
413
if (isAncestor(object(), o))
414
return relation | Ancestor;
420
int QAccessibleWidget::navigate(RelationFlag relation, int entry,
421
QAccessibleInterface **target) const
427
QObject *targetObject = 0;
429
QWidgetList childList = childWidgets(widget());
430
bool complexWidget = childList.size() < childCount();
435
targetObject = object();
439
if (entry > 0 && entry <= childCount())
443
if (entry > 0 && childList.size() >= entry)
444
targetObject = childList.at(entry - 1);
451
targetObject = widget()->parentWidget();
453
for (i = entry; i > 1 && targetObject; --i)
454
targetObject = targetObject->parent();
455
if (!targetObject && i == 1)
461
QAccessibleInterface *iface = QAccessible::queryAccessibleInterface(parentObject());
465
iface->navigate(Child, entry, target);
473
case QAccessible::Left:
474
if (complexWidget && entry) {
475
if (entry < 2 || widget()->height() > widget()->width() + 20) // looks vertical
480
case QAccessible::Right:
481
if (complexWidget && entry) {
482
if (entry >= childCount() || widget()->height() > widget()->width() + 20) // looks vertical
487
case QAccessible::Up:
488
if (complexWidget && entry) {
489
if (entry < 2 || widget()->width() > widget()->height() + 20) // looks horizontal
494
case QAccessible::Down:
495
if (complexWidget && entry) {
496
if (entry >= childCount() || widget()->width() > widget()->height() + 20) // looks horizontal
500
QAccessibleInterface *pIface = QAccessible::queryAccessibleInterface(parentObject());
504
QRect startg = rect(0);
505
QPoint startc = startg.center();
506
QAccessibleInterface *candidate = 0;
507
int mindist = 100000;
508
int sibCount = pIface->childCount();
509
for (int i = 0; i < sibCount; ++i) {
510
QAccessibleInterface *sibling = 0;
511
pIface->navigate(Child, i+1, &sibling);
513
if ((relationTo(0, sibling, 0) & Self) || (sibling->state(0) & QAccessible::Invisible)) {
514
//ignore ourself and invisible siblings
519
QRect sibg = sibling->rect(0);
520
QPoint sibc = sibg.center();
525
case QAccessible::Left:
526
startp = QPoint(startg.left(), startg.top() + startg.height() / 2);
527
sibp = QPoint(sibg.right(), sibg.top() + sibg.height() / 2);
528
if (QPoint(sibc - startc).x() >= 0) {
532
distp = sibp - startp;
534
case QAccessible::Right:
535
startp = QPoint(startg.right(), startg.top() + startg.height() / 2);
536
sibp = QPoint(sibg.left(), sibg.top() + sibg.height() / 2);
537
if (QPoint(sibc - startc).x() <= 0) {
541
distp = sibp - startp;
543
case QAccessible::Up:
544
startp = QPoint(startg.left() + startg.width() / 2, startg.top());
545
sibp = QPoint(sibg.left() + sibg.width() / 2, sibg.bottom());
546
if (QPoint(sibc - startc).y() >= 0) {
550
distp = sibp - startp;
552
case QAccessible::Down:
553
startp = QPoint(startg.left() + startg.width() / 2, startg.bottom());
554
sibp = QPoint(sibg.left() + sibg.width() / 2, sibg.top());
555
if (QPoint(sibc - startc).y() <= 0) {
559
distp = sibp - startp;
565
int dist = (int)sqrt((double)distp.x() * distp.x() + distp.y() * distp.y());
566
if (dist < mindist) {
582
QAccessibleInterface *pIface = QAccessible::queryAccessibleInterface(parentObject());
587
int sibCount = pIface->childCount();
588
QAccessibleInterface *sibling = 0;
589
for (int i = pIface->indexOfChild(this) + 1; i <= sibCount && entry; ++i) {
590
pIface->navigate(Child, i, &sibling);
592
if (!sibling || (sibling->state(0) & Invisible)) {
597
if (sibling->rect(0).intersects(r))
612
QAccessibleInterface *pIface = QAccessible::queryAccessibleInterface(parentObject());
617
int index = pIface->indexOfChild(this);
618
QAccessibleInterface *sibling = 0;
619
for (int i = 1; i < index && entry; ++i) {
620
pIface->navigate(Child, i, &sibling);
622
if (!sibling || (sibling->state(0) & Invisible)) {
627
if (sibling->rect(0).intersects(r))
644
if (widget()->hasFocus())
647
QWidget *fw = widget()->focusWidget();
651
if (isAncestor(widget(), fw))
654
QWidget *parent = fw;
655
while (parent && !targetObject) {
656
parent = parent->parentWidget();
657
if (parent == widget())
665
QAccessibleInterface *pIface = QAccessible::queryAccessibleInterface(parentObject());
669
// first check for all siblings that are labels to us
670
// ideally we would go through all objects and check, but that
671
// will be too expensive
672
int sibCount = pIface->childCount();
673
QAccessibleInterface *candidate = 0;
674
for (int i = 0; i < sibCount && entry; ++i) {
675
pIface->navigate(Child, i+1, &candidate);
677
if (candidate->relationTo(0, this, 0) & Label)
685
if (pIface->relationTo(0, this, 0) & Label)
690
if (pIface != candidate)
698
case Labelled: // only implemented in subclasses
702
// check all senders we are connected to,
703
// and figure out which one are controllers to us
704
ConnectionObject *connectionObject = (ConnectionObject*)object();
705
QObjectList allSenders = connectionObject->senderList();
707
for (int s = 0; s < allSenders.size(); ++s) {
708
QObject *sender = allSenders.at(s);
709
QAccessibleInterface *candidate = QAccessible::queryAccessibleInterface(sender);
712
if (candidate->relationTo(0, this, 0)&Controller)
716
if (entry <= senders.size())
717
targetObject = senders.at(entry-1);
722
QObjectList allReceivers;
723
ConnectionObject *connectionObject = (ConnectionObject*)object();
724
for (int sig = 0; sig < d->primarySignals.count(); ++sig) {
725
QObjectList receivers = connectionObject->receiverList(d->primarySignals.at(sig).toAscii());
726
allReceivers += receivers;
728
if (entry <= allReceivers.size())
729
targetObject = allReceivers.at(entry-1);
735
*target = QAccessible::queryAccessibleInterface(targetObject);
736
return *target ? 0 : -1;
740
int QAccessibleWidget::childCount() const
742
QWidgetList cl = childWidgets(widget());
747
int QAccessibleWidget::indexOfChild(const QAccessibleInterface *child) const
749
QWidgetList cl = childWidgets(widget());
750
int index = cl.indexOf(qobject_cast<QWidget *>(child->object()));
757
QString QAccessibleWidget::text(Text t, int child) const
763
if (!d->name.isEmpty())
765
else if (!widget()->accessibleName().isEmpty())
766
str = widget()->accessibleName();
767
else if (!child && widget()->isWindow())
768
str = widget()->windowTitle();
770
str = qt_accStripAmp(buddyString(widget()));
773
if (!d->description.isEmpty())
774
str = d->description;
775
else if (!widget()->accessibleDescription().isEmpty())
776
str = widget()->accessibleDescription();
778
str = widget()->toolTip();
781
if (!d->help.isEmpty())
784
str = widget()->whatsThis();
787
if (!d->accelerator.isEmpty())
788
str = d->accelerator;
790
str = qt_accHotKey(buddyString(widget()));
802
QString QAccessibleWidget::actionText(int action, Text t, int child) const
804
if (action == DefaultAction)
807
return QAccessibleObject::actionText(action, t, child);
811
bool QAccessibleWidget::doAction(int action, int child, const QVariantList ¶ms)
813
if (action == SetFocus || action == DefaultAction) {
814
if (child || !widget()->isEnabled())
816
if (widget()->focusPolicy() != Qt::NoFocus)
817
widget()->setFocus();
818
else if (widget()->isWindow())
819
widget()->activateWindow();
824
return QAccessibleObject::doAction(action, child, params);
828
QAccessible::Role QAccessibleWidget::role(int child) const
836
QAccessible::State QAccessibleWidget::state(int child) const
843
QWidget *w = widget();
844
if (w->testAttribute(Qt::WA_WState_Hidden))
846
if (w->focusPolicy() != Qt::NoFocus && w->isActiveWindow())
851
state |= Unavailable;
853
if (w->windowFlags() & Qt::WindowSystemMenuHint)
855
if (w->minimumSize() != w->maximumSize())
862
#endif //QT_NO_ACCESSIBILITY