1/****************************************************************************
2**
3** Copyright (C) 2014 Digia Plc and/or its subsidiary(-ies).
4** Contact: http://www.qt-project.org/legal
5**
6** This file is part of the QtGui module of the Qt Toolkit.
7**
8** $QT_BEGIN_LICENSE:LGPL$
9** Commercial License Usage
10** Licensees holding valid commercial Qt licenses may use this file in
11** accordance with the commercial license agreement provided with the
12** Software or, alternatively, in accordance with the terms contained in
13** a written agreement between you and Digia. For licensing terms and
14** conditions see http://qt.digia.com/licensing. For further information
15** use the contact form at http://qt.digia.com/contact-us.
16**
17** GNU Lesser General Public License Usage
18** Alternatively, this file may be used under the terms of the GNU Lesser
19** General Public License version 2.1 as published by the Free Software
20** Foundation and appearing in the file LICENSE.LGPL included in the
21** packaging of this file. Please review the following information to
22** ensure the GNU Lesser General Public License version 2.1 requirements
23** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
24**
25** In addition, as a special exception, Digia gives you certain additional
26** rights. These rights are described in the Digia Qt LGPL Exception
27** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
28**
29** GNU General Public License Usage
30** Alternatively, this file may be used under the terms of the GNU
31** General Public License version 3.0 as published by the Free Software
32** Foundation and appearing in the file LICENSE.GPL included in the
33** packaging of this file. Please review the following information to
34** ensure the GNU General Public License version 3.0 requirements will be
35** met: http://www.gnu.org/copyleft/gpl.html.
36**
37**
38** $QT_END_LICENSE$
39**
40****************************************************************************/
41
42#include "qaccessiblewidget.h"
43
44#ifndef QT_NO_ACCESSIBILITY
45
46#include "qaction.h"
47#include "qapplication.h"
48#include "qgroupbox.h"
49#include "qlabel.h"
50#include "qtooltip.h"
51#include "qwhatsthis.h"
52#include "qwidget.h"
53#include "qdebug.h"
54#include <qmath.h>
55#include <QRubberBand>
56#include <QtGui/QFocusFrame>
57#include <QtGui/QMenu>
58
59QT_BEGIN_NAMESPACE
60
61static QList<QWidget*> childWidgets(const QWidget *widget)
62{
63 QList<QObject*> list = widget->children();
64 QList<QWidget*> widgets;
65 for (int i = 0; i < list.size(); ++i) {
66 QWidget *w = qobject_cast<QWidget *>(list.at(i));
67 if (w && !w->isWindow()
68 && !qobject_cast<QFocusFrame*>(w)
69#if !defined(QT_NO_MENU)
70 && !qobject_cast<QMenu*>(w)
71#endif
72 && w->objectName() != QLatin1String("qt_rubberband"))
73 widgets.append(w);
74 }
75 return widgets;
76}
77
78static QString buddyString(const QWidget *widget)
79{
80 if (!widget)
81 return QString();
82 QWidget *parent = widget->parentWidget();
83 if (!parent)
84 return QString();
85#ifndef QT_NO_SHORTCUT
86 QObjectList ol = parent->children();
87 for (int i = 0; i < ol.size(); ++i) {
88 QLabel *label = qobject_cast<QLabel*>(ol.at(i));
89 if (label && label->buddy() == widget)
90 return label->text();
91 }
92#endif
93
94#ifndef QT_NO_GROUPBOX
95 QGroupBox *groupbox = qobject_cast<QGroupBox*>(parent);
96 if (groupbox)
97 return groupbox->title();
98#endif
99
100 return QString();
101}
102
103/* This function will return the offset of the '&' in the text that would be
104 preceding the accelerator character.
105 If this text does not have an accelerator, -1 will be returned. */
106static int qt_accAmpIndex(const QString &text)
107{
108#ifndef QT_NO_SHORTCUT
109 if (text.isEmpty())
110 return -1;
111
112 int fa = 0;
113 QChar ac;
114 while ((fa = text.indexOf(QLatin1Char('&'), fa)) != -1) {
115 ++fa;
116 if (fa < text.length()) {
117 // ignore "&&"
118 if (text.at(fa) == QLatin1Char('&')) {
119 ++fa;
120 continue;
121 } else {
122 return fa - 1;
123 break;
124 }
125 }
126 }
127
128 return -1;
129#else
130 Q_UNUSED(text);
131 return -1;
132#endif
133}
134
135QString Q_GUI_EXPORT qt_accStripAmp(const QString &text)
136{
137 QString newText(text);
138 int ampIndex = qt_accAmpIndex(newText);
139 if (ampIndex != -1)
140 newText.remove(ampIndex, 1);
141
142 return newText.replace(QLatin1String("&&"), QLatin1String("&"));
143}
144
145QString Q_GUI_EXPORT qt_accHotKey(const QString &text)
146{
147 int ampIndex = qt_accAmpIndex(text);
148 if (ampIndex != -1)
149 return (QString)QKeySequence(Qt::ALT) + text.at(ampIndex + 1);
150
151 return QString();
152}
153
154class QAccessibleWidgetPrivate : public QAccessible
155{
156public:
157 QAccessibleWidgetPrivate()
158 :role(Client)
159 {}
160
161 Role role;
162 QString name;
163 QString description;
164 QString value;
165 QString help;
166 QString accelerator;
167 QStringList primarySignals;
168 const QAccessibleInterface *asking;
169};
170
171/*!
172 \class QAccessibleWidget
173 \brief The QAccessibleWidget class implements the QAccessibleInterface for QWidgets.
174
175 \ingroup accessibility
176
177 This class is convenient to use as a base class for custom
178 implementations of QAccessibleInterfaces that provide information
179 about widget objects.
180
181 The class provides functions to retrieve the parentObject() (the
182 widget's parent widget), and the associated widget(). Controlling
183 signals can be added with addControllingSignal(), and setters are
184 provided for various aspects of the interface implementation, for
185 example setValue(), setDescription(), setAccelerator(), and
186 setHelp().
187
188 \sa QAccessible, QAccessibleObject
189*/
190
191/*!
192 Creates a QAccessibleWidget object for widget \a w.
193 \a role and \a name are optional parameters that set the object's
194 role and name properties.
195*/
196QAccessibleWidget::QAccessibleWidget(QWidget *w, Role role, const QString &name)
197: QAccessibleObject(w)
198{
199 Q_ASSERT(widget());
200 d = new QAccessibleWidgetPrivate();
201 d->role = role;
202 d->name = name;
203 d->asking = 0;
204}
205
206/*!
207 Destroys this object.
208*/
209QAccessibleWidget::~QAccessibleWidget()
210{
211 delete d;
212}
213
214/*!
215 Returns the associated widget.
216*/
217QWidget *QAccessibleWidget::widget() const
218{
219 return qobject_cast<QWidget*>(object());
220}
221
222/*!
223 Returns the associated widget's parent object, which is either the
224 parent widget, or qApp for top-level widgets.
225*/
226QObject *QAccessibleWidget::parentObject() const
227{
228 QObject *parent = object()->parent();
229 if (!parent)
230 parent = qApp;
231 return parent;
232}
233
234/*! \reimp */
235int QAccessibleWidget::childAt(int x, int y) const
236{
237 QWidget *w = widget();
238 if (!w->isVisible())
239 return -1;
240 QPoint gp = w->mapToGlobal(QPoint(0, 0));
241 if (!QRect(gp.x(), gp.y(), w->width(), w->height()).contains(x, y))
242 return -1;
243
244 QWidgetList list = childWidgets(w);
245 int ccount = childCount();
246
247 // a complex child
248 if (list.size() < ccount) {
249 for (int i = 1; i <= ccount; ++i) {
250 if (rect(i).contains(x, y))
251 return i;
252 }
253 return 0;
254 }
255
256 QPoint rp = w->mapFromGlobal(QPoint(x, y));
257 for (int i = 0; i<list.size(); ++i) {
258 QWidget *child = list.at(i);
259 if (!child->isWindow() && !child->isHidden() && child->geometry().contains(rp)) {
260 return i + 1;
261 }
262 }
263 return 0;
264}
265
266/*! \reimp */
267QRect QAccessibleWidget::rect(int child) const
268{
269 if (child) {
270 qWarning("QAccessibleWidget::rect: This implementation does not support subelements! "
271 "(ID %d unknown for %s)", child, widget()->metaObject()->className());
272 }
273
274 QWidget *w = widget();
275 if (!w->isVisible())
276 return QRect();
277 QPoint wpos = w->mapToGlobal(QPoint(0, 0));
278
279 return QRect(wpos.x(), wpos.y(), w->width(), w->height());
280}
281
282QT_BEGIN_INCLUDE_NAMESPACE
283#include <private/qobject_p.h>
284QT_END_INCLUDE_NAMESPACE
285
286class QACConnectionObject : public QObject
287{
288 Q_DECLARE_PRIVATE(QObject)
289public:
290 inline bool isSender(const QObject *receiver, const char *signal) const
291 { return d_func()->isSender(receiver, signal); }
292 inline QObjectList receiverList(const char *signal) const
293 { return d_func()->receiverList(signal); }
294 inline QObjectList senderList() const
295 { return d_func()->senderList(); }
296};
297
298/*!
299 Registers \a signal as a controlling signal.
300
301 An object is a Controller to any other object connected to a
302 controlling signal.
303*/
304void QAccessibleWidget::addControllingSignal(const QString &signal)
305{
306 QByteArray s = QMetaObject::normalizedSignature(signal.toAscii());
307 if (object()->metaObject()->indexOfSignal(s) < 0)
308 qWarning("Signal %s unknown in %s", s.constData(), object()->metaObject()->className());
309 d->primarySignals << QLatin1String(s);
310}
311
312/*!
313 Sets the value of this interface implementation to \a value.
314
315 The default implementation of text() returns the set value for
316 the Value text.
317
318 Note that the object wrapped by this interface is not modified.
319*/
320void QAccessibleWidget::setValue(const QString &value)
321{
322 d->value = value;
323}
324
325/*!
326 Sets the description of this interface implementation to \a desc.
327
328 The default implementation of text() returns the set value for
329 the Description text.
330
331 Note that the object wrapped by this interface is not modified.
332*/
333void QAccessibleWidget::setDescription(const QString &desc)
334{
335 d->description = desc;
336}
337
338/*!
339 Sets the help of this interface implementation to \a help.
340
341 The default implementation of text() returns the set value for
342 the Help text.
343
344 Note that the object wrapped by this interface is not modified.
345*/
346void QAccessibleWidget::setHelp(const QString &help)
347{
348 d->help = help;
349}
350
351/*!
352 Sets the accelerator of this interface implementation to \a accel.
353
354 The default implementation of text() returns the set value for
355 the Accelerator text.
356
357 Note that the object wrapped by this interface is not modified.
358*/
359void QAccessibleWidget::setAccelerator(const QString &accel)
360{
361 d->accelerator = accel;
362}
363
364static inline bool isAncestor(const QObject *obj, const QObject *child)
365{
366 while (child) {
367 if (child == obj)
368 return true;
369 child = child->parent();
370 }
371 return false;
372}
373
374
375/*! \reimp */
376QAccessible::Relation QAccessibleWidget::relationTo(int child,
377 const QAccessibleInterface *other, int otherChild) const
378{
379 Relation relation = Unrelated;
380 if (d->asking == this) // recursive call
381 return relation;
382
383 QObject *o = other ? other->object() : 0;
384 if (!o)
385 return relation;
386
387 QWidget *focus = widget()->focusWidget();
388 if (object() == focus && isAncestor(o, focus))
389 relation |= FocusChild;
390
391 QACConnectionObject *connectionObject = (QACConnectionObject*)object();
392 for (int sig = 0; sig < d->primarySignals.count(); ++sig) {
393 if (connectionObject->isSender(o, d->primarySignals.at(sig).toAscii())) {
394 relation |= Controller;
395 break;
396 }
397 }
398 // test for passive relationships.
399 // d->asking protects from endless recursion.
400 d->asking = this;
401 int inverse = other->relationTo(otherChild, this, child);
402 d->asking = 0;
403
404 if (inverse & Controller)
405 relation |= Controlled;
406 if (inverse & Label)
407 relation |= Labelled;
408
409 if(o == object()) {
410 if (child && !otherChild)
411 return relation | Child;
412 if (!child && otherChild)
413 return relation | Ancestor;
414 if (!child && !otherChild)
415 return relation | Self;
416 }
417
418 QObject *parent = object()->parent();
419 if (o == parent)
420 return relation | Child;
421
422 if (o->parent() == parent) {
423 relation |= Sibling;
424 QAccessibleInterface *sibIface = QAccessible::queryAccessibleInterface(o);
425 Q_ASSERT(sibIface);
426 QRect wg = rect(0);
427 QRect sg = sibIface->rect(0);
428 if (wg.intersects(sg)) {
429 QAccessibleInterface *pIface = 0;
430 sibIface->navigate(Ancestor, 1, &pIface);
431 if (pIface && !((sibIface->state(0) | state(0)) & Invisible)) {
432 int wi = pIface->indexOfChild(this);
433 int si = pIface->indexOfChild(sibIface);
434
435 if (wi > si)
436 relation |= QAccessible::Covers;
437 else
438 relation |= QAccessible::Covered;
439 }
440 delete pIface;
441 } else {
442 QPoint wc = wg.center();
443 QPoint sc = sg.center();
444 if (wc.x() < sc.x())
445 relation |= QAccessible::Left;
446 else if(wc.x() > sc.x())
447 relation |= QAccessible::Right;
448 if (wc.y() < sc.y())
449 relation |= QAccessible::Up;
450 else if (wc.y() > sc.y())
451 relation |= QAccessible::Down;
452 }
453 delete sibIface;
454
455 return relation;
456 }
457
458 if (isAncestor(o, object()))
459 return relation | Descendent;
460 if (isAncestor(object(), o))
461 return relation | Ancestor;
462
463 return relation;
464}
465
466/*! \reimp */
467int QAccessibleWidget::navigate(RelationFlag relation, int entry,
468 QAccessibleInterface **target) const
469{
470 if (!target)
471 return -1;
472
473 *target = 0;
474 QObject *targetObject = 0;
475
476 QWidgetList childList = childWidgets(widget());
477 bool complexWidget = childList.size() < childCount();
478
479 switch (relation) {
480 // Hierarchical
481 case Self:
482 targetObject = object();
483 break;
484 case Child:
485 if (complexWidget) {
486 if (entry > 0 && entry <= childCount())
487 return entry;
488 return -1;
489 }else {
490 if (entry > 0 && childList.size() >= entry)
491 targetObject = childList.at(entry - 1);
492 }
493 break;
494 case Ancestor:
495 {
496 if (entry <= 0)
497 return -1;
498 targetObject = widget()->parentWidget();
499 int i;
500 for (i = entry; i > 1 && targetObject; --i)
501 targetObject = targetObject->parent();
502 if (!targetObject && i == 1)
503 targetObject = qApp;
504 }
505 break;
506 case Sibling:
507 {
508 QAccessibleInterface *iface = QAccessible::queryAccessibleInterface(parentObject());
509 if (!iface)
510 return -1;
511
512 iface->navigate(Child, entry, target);
513 delete iface;
514 if (*target)
515 return 0;
516 }
517 break;
518
519 // Geometrical
520 case QAccessible::Left:
521 if (complexWidget && entry) {
522 if (entry < 2 || widget()->height() > widget()->width() + 20) // looks vertical
523 return -1;
524 return entry - 1;
525 }
526 // fall through
527 case QAccessible::Right:
528 if (complexWidget && entry) {
529 if (entry >= childCount() || widget()->height() > widget()->width() + 20) // looks vertical
530 return -1;
531 return entry + 1;
532 }
533 // fall through
534 case QAccessible::Up:
535 if (complexWidget && entry) {
536 if (entry < 2 || widget()->width() > widget()->height() + 20) // looks horizontal
537 return - 1;
538 return entry - 1;
539 }
540 // fall through
541 case QAccessible::Down:
542 if (complexWidget && entry) {
543 if (entry >= childCount() || widget()->width() > widget()->height() + 20) // looks horizontal
544 return - 1;
545 return entry + 1;
546 } else {
547 QAccessibleInterface *pIface = QAccessible::queryAccessibleInterface(parentObject());
548 if (!pIface)
549 return -1;
550
551 QRect startg = rect(0);
552 QPoint startc = startg.center();
553 QAccessibleInterface *candidate = 0;
554 int mindist = 100000;
555 int sibCount = pIface->childCount();
556 for (int i = 0; i < sibCount; ++i) {
557 QAccessibleInterface *sibling = 0;
558 pIface->navigate(Child, i+1, &sibling);
559 Q_ASSERT(sibling);
560 if ((relationTo(0, sibling, 0) & Self) || (sibling->state(0) & QAccessible::Invisible)) {
561 //ignore ourself and invisible siblings
562 delete sibling;
563 continue;
564 }
565
566 QRect sibg = sibling->rect(0);
567 QPoint sibc = sibg.center();
568 QPoint sibp;
569 QPoint startp;
570 QPoint distp;
571 switch (relation) {
572 case QAccessible::Left:
573 startp = QPoint(startg.left(), startg.top() + startg.height() / 2);
574 sibp = QPoint(sibg.right(), sibg.top() + sibg.height() / 2);
575 if (QPoint(sibc - startc).x() >= 0) {
576 delete sibling;
577 continue;
578 }
579 distp = sibp - startp;
580 break;
581 case QAccessible::Right:
582 startp = QPoint(startg.right(), startg.top() + startg.height() / 2);
583 sibp = QPoint(sibg.left(), sibg.top() + sibg.height() / 2);
584 if (QPoint(sibc - startc).x() <= 0) {
585 delete sibling;
586 continue;
587 }
588 distp = sibp - startp;
589 break;
590 case QAccessible::Up:
591 startp = QPoint(startg.left() + startg.width() / 2, startg.top());
592 sibp = QPoint(sibg.left() + sibg.width() / 2, sibg.bottom());
593 if (QPoint(sibc - startc).y() >= 0) {
594 delete sibling;
595 continue;
596 }
597 distp = sibp - startp;
598 break;
599 case QAccessible::Down:
600 startp = QPoint(startg.left() + startg.width() / 2, startg.bottom());
601 sibp = QPoint(sibg.left() + sibg.width() / 2, sibg.top());
602 if (QPoint(sibc - startc).y() <= 0) {
603 delete sibling;
604 continue;
605 }
606 distp = sibp - startp;
607 break;
608 default:
609 break;
610 }
611
612 int dist = (int)qSqrt((qreal)distp.x() * distp.x() + distp.y() * distp.y());
613 if (dist < mindist) {
614 delete candidate;
615 candidate = sibling;
616 mindist = dist;
617 } else {
618 delete sibling;
619 }
620 }
621 delete pIface;
622 *target = candidate;
623 if (*target)
624 return 0;
625 }
626 break;
627 case Covers:
628 if (entry > 0) {
629 QAccessibleInterface *pIface = QAccessible::queryAccessibleInterface(parentObject());
630 if (!pIface)
631 return -1;
632
633 QRect r = rect(0);
634 int sibCount = pIface->childCount();
635 QAccessibleInterface *sibling = 0;
636 for (int i = pIface->indexOfChild(this) + 1; i <= sibCount && entry; ++i) {
637 pIface->navigate(Child, i, &sibling);
638 if (!sibling || (sibling->state(0) & Invisible)) {
639 delete sibling;
640 sibling = 0;
641 continue;
642 }
643 if (sibling->rect(0).intersects(r))
644 --entry;
645 if (!entry)
646 break;
647 delete sibling;
648 sibling = 0;
649 }
650 delete pIface;
651 *target = sibling;
652 if (*target)
653 return 0;
654 }
655 break;
656 case Covered:
657 if (entry > 0) {
658 QAccessibleInterface *pIface = QAccessible::queryAccessibleInterface(parentObject());
659 if (!pIface)
660 return -1;
661
662 QRect r = rect(0);
663 int index = pIface->indexOfChild(this);
664 QAccessibleInterface *sibling = 0;
665 for (int i = 1; i < index && entry; ++i) {
666 pIface->navigate(Child, i, &sibling);
667 Q_ASSERT(sibling);
668 if (!sibling || (sibling->state(0) & Invisible)) {
669 delete sibling;
670 sibling = 0;
671 continue;
672 }
673 if (sibling->rect(0).intersects(r))
674 --entry;
675 if (!entry)
676 break;
677 delete sibling;
678 sibling = 0;
679 }
680 delete pIface;
681 *target = sibling;
682 if (*target)
683 return 0;
684 }
685 break;
686
687 // Logical
688 case FocusChild:
689 {
690 if (widget()->hasFocus()) {
691 targetObject = object();
692 break;
693 }
694
695 QWidget *fw = widget()->focusWidget();
696 if (!fw)
697 return -1;
698
699 if (isAncestor(widget(), fw) || fw == widget())
700 targetObject = fw;
701 /* ###
702 QWidget *parent = fw;
703 while (parent && !targetObject) {
704 parent = parent->parentWidget();
705 if (parent == widget())
706 targetObject = fw;
707 }
708 */
709 }
710 break;
711 case Label:
712 if (entry > 0) {
713 QAccessibleInterface *pIface = QAccessible::queryAccessibleInterface(parentObject());
714 if (!pIface)
715 return -1;
716
717 // first check for all siblings that are labels to us
718 // ideally we would go through all objects and check, but that
719 // will be too expensive
720 int sibCount = pIface->childCount();
721 QAccessibleInterface *candidate = 0;
722 for (int i = 0; i < sibCount && entry; ++i) {
723 const int childId = pIface->navigate(Child, i+1, &candidate);
724 Q_ASSERT(childId >= 0);
725 if (childId > 0)
726 candidate = pIface;
727 if (candidate->relationTo(childId, this, 0) & Label)
728 --entry;
729 if (!entry)
730 break;
731 if (candidate != pIface)
732 delete candidate;
733 candidate = 0;
734 }
735 if (!candidate) {
736 if (pIface->relationTo(0, this, 0) & Label)
737 --entry;
738 if (!entry)
739 candidate = pIface;
740 }
741 if (pIface != candidate)
742 delete pIface;
743
744 *target = candidate;
745 if (*target)
746 return 0;
747 }
748 break;
749 case Labelled: // only implemented in subclasses
750 break;
751 case Controller:
752 if (entry > 0) {
753 // check all senders we are connected to,
754 // and figure out which one are controllers to us
755 QACConnectionObject *connectionObject = (QACConnectionObject*)object();
756 QObjectList allSenders = connectionObject->senderList();
757 QObjectList senders;
758 for (int s = 0; s < allSenders.size(); ++s) {
759 QObject *sender = allSenders.at(s);
760 QAccessibleInterface *candidate = QAccessible::queryAccessibleInterface(sender);
761 if (!candidate)
762 continue;
763 if (candidate->relationTo(0, this, 0)&Controller)
764 senders << sender;
765 delete candidate;
766 }
767 if (entry <= senders.size())
768 targetObject = senders.at(entry-1);
769 }
770 break;
771 case Controlled:
772 if (entry > 0) {
773 QObjectList allReceivers;
774 QACConnectionObject *connectionObject = (QACConnectionObject*)object();
775 for (int sig = 0; sig < d->primarySignals.count(); ++sig) {
776 QObjectList receivers = connectionObject->receiverList(d->primarySignals.at(sig).toAscii());
777 allReceivers += receivers;
778 }
779 if (entry <= allReceivers.size())
780 targetObject = allReceivers.at(entry-1);
781 }
782 break;
783 default:
784 break;
785 }
786
787 *target = QAccessible::queryAccessibleInterface(targetObject);
788 return *target ? 0 : -1;
789}
790
791/*! \reimp */
792int QAccessibleWidget::childCount() const
793{
794 QWidgetList cl = childWidgets(widget());
795 return cl.size();
796}
797
798/*! \reimp */
799int QAccessibleWidget::indexOfChild(const QAccessibleInterface *child) const
800{
801 QWidgetList cl = childWidgets(widget());
802 int index = cl.indexOf(qobject_cast<QWidget *>(child->object()));
803 if (index != -1)
804 ++index;
805 return index;
806}
807
808// from qwidget.cpp
809extern QString qt_setWindowTitle_helperHelper(const QString &, const QWidget*);
810
811/*! \reimp */
812QString QAccessibleWidget::text(Text t, int child) const
813{
814 QString str;
815
816 switch (t) {
817 case Name:
818 if (!d->name.isEmpty()) {
819 str = d->name;
820 } else if (!widget()->accessibleName().isEmpty()) {
821 str = widget()->accessibleName();
822 } else if (!child && widget()->isWindow()) {
823 if (widget()->isMinimized())
824 str = qt_setWindowTitle_helperHelper(widget()->windowIconText(), widget());
825 else
826 str = qt_setWindowTitle_helperHelper(widget()->windowTitle(), widget());
827 } else {
828 str = qt_accStripAmp(buddyString(widget()));
829 }
830 break;
831 case Description:
832 if (!d->description.isEmpty())
833 str = d->description;
834 else if (!widget()->accessibleDescription().isEmpty())
835 str = widget()->accessibleDescription();
836#ifndef QT_NO_TOOLTIP
837 else
838 str = widget()->toolTip();
839#endif
840 break;
841 case Help:
842 if (!d->help.isEmpty())
843 str = d->help;
844#ifndef QT_NO_WHATSTHIS
845 else
846 str = widget()->whatsThis();
847#endif
848 break;
849 case Accelerator:
850 if (!d->accelerator.isEmpty())
851 str = d->accelerator;
852 else
853 str = qt_accHotKey(buddyString(widget()));
854 break;
855 case Value:
856 str = d->value;
857 break;
858 default:
859 break;
860 }
861 return str;
862}
863
864#ifndef QT_NO_ACTION
865
866/*! \reimp */
867int QAccessibleWidget::userActionCount(int child) const
868{
869 if (child)
870 return 0;
871 return widget()->actions().count();
872}
873
874/*! \reimp */
875QString QAccessibleWidget::actionText(int action, Text t, int child) const
876{
877 if (action == DefaultAction)
878 action = SetFocus;
879
880 if (action > 0 && !child) {
881 QAction *act = widget()->actions().value(action - 1);
882 if (act) {
883 switch (t) {
884 case Name:
885 return act->text();
886 case Description:
887 return act->toolTip();
888#ifndef QT_NO_SHORTCUT
889 case Accelerator:
890 return act->shortcut().toString();
891#endif
892 default:
893 break;
894 }
895 }
896 }
897
898 return QAccessibleObject::actionText(action, t, child);
899}
900
901/*! \reimp */
902bool QAccessibleWidget::doAction(int action, int child, const QVariantList &params)
903{
904 if (action == SetFocus || action == DefaultAction) {
905 if (child || !widget()->isEnabled())
906 return false;
907
908 if ((widget()->focusPolicy() == Qt::NoFocus) && (!widget()->isWindow()))
909 return false;
910
911 if (!widget()->isWindow())
912 widget()->setFocus();
913
914 widget()->activateWindow();
915
916 return true;
917 } else if (action > 0) {
918 if (QAction *act = widget()->actions().value(action - 1)) {
919 act->trigger();
920 return true;
921 }
922 }
923 return QAccessibleObject::doAction(action, child, params);
924}
925
926#endif // QT_NO_ACTION
927
928/*! \reimp */
929QAccessible::Role QAccessibleWidget::role(int child) const
930{
931 if (!child)
932 return d->role;
933
934 QWidgetList childList = childWidgets(widget());
935 if (childList.count() > 0 && child <= childList.count()) {
936 QWidget *targetWidget = childList.at(child - 1);
937 QAccessibleInterface *iface = QAccessible::queryAccessibleInterface(targetWidget);
938 if (iface) {
939 QAccessible::Role role = iface->role(0);
940 delete iface;
941 return role;
942 }
943 }
944
945 return NoRole;
946}
947
948/*! \reimp */
949QAccessible::State QAccessibleWidget::state(int child) const
950{
951 if (child)
952 return Normal;
953
954 QAccessible::State state = Normal;
955
956 QWidget *w = widget();
957 if (w->testAttribute(Qt::WA_WState_Visible) == false)
958 state |= Invisible;
959 if (w->focusPolicy() != Qt::NoFocus)
960 state |= Focusable;
961 if (w->hasFocus())
962 state |= Focused;
963 if (!w->isEnabled())
964 state |= Unavailable;
965 if (w->isWindow()) {
966 if (w->windowFlags() & Qt::WindowSystemMenuHint)
967 state |= Movable;
968 if (w->minimumSize() != w->maximumSize())
969 state |= Sizeable;
970 }
971
972 return state;
973}
974
975// ### Qt 5: remove me - binary compatibility hack
976QAccessibleWidgetEx::QAccessibleWidgetEx(QWidget *o, Role role, const QString& name)
977 : QAccessibleObjectEx(o)
978{
979 Q_ASSERT(widget());
980 d = new QAccessibleWidgetPrivate();
981 d->role = role;
982 d->name = name;
983 d->asking = 0;
984}
985
986int QAccessibleWidgetEx::childCount() const
987{ return reinterpret_cast<const QAccessibleWidget *>(this)->QAccessibleWidget::childCount(); }
988int QAccessibleWidgetEx::indexOfChild(const QAccessibleInterface *child) const
989{ return reinterpret_cast<const QAccessibleWidget *>(this)->QAccessibleWidget::indexOfChild(child); }
990QAccessible::Relation QAccessibleWidgetEx::relationTo(int child, const QAccessibleInterface *other, int otherChild) const
991{ return reinterpret_cast<const QAccessibleWidget *>(this)->QAccessibleWidget::relationTo(child, other, otherChild); }
992
993int QAccessibleWidgetEx::childAt(int x, int y) const
994{ return reinterpret_cast<const QAccessibleWidget *>(this)->QAccessibleWidget::childAt(x, y); }
995QRect QAccessibleWidgetEx::rect(int child) const
996{ return reinterpret_cast<const QAccessibleWidget *>(this)->QAccessibleWidget::rect(child); }
997int QAccessibleWidgetEx::navigate(RelationFlag rel, int entry, QAccessibleInterface **target) const
998{ return reinterpret_cast<const QAccessibleWidget *>(this)->QAccessibleWidget::navigate(rel, entry, target); }
999
1000QString QAccessibleWidgetEx::text(Text t, int child) const
1001{ return reinterpret_cast<const QAccessibleWidget *>(this)->QAccessibleWidget::text(t, child); }
1002QAccessible::Role QAccessibleWidgetEx::role(int child) const
1003{ return reinterpret_cast<const QAccessibleWidget *>(this)->QAccessibleWidget::role(child); }
1004QAccessible::State QAccessibleWidgetEx::state(int child) const
1005{ return (reinterpret_cast<const QAccessibleWidget *>(this)->QAccessibleWidget::state(child))
1006 | HasInvokeExtension; }
1007
1008QString QAccessibleWidgetEx::actionText(int action, Text t, int child) const
1009{ return reinterpret_cast<const QAccessibleWidget *>(this)->QAccessibleWidget::actionText(action, t, child); }
1010bool QAccessibleWidgetEx::doAction(int action, int child, const QVariantList &params)
1011{ return reinterpret_cast<QAccessibleWidget *>(this)->QAccessibleWidget::doAction(action, child, params); }
1012
1013QAccessibleWidgetEx::~QAccessibleWidgetEx()
1014{ delete d; }
1015QWidget *QAccessibleWidgetEx::widget() const
1016{ return reinterpret_cast<const QAccessibleWidget *>(this)->QAccessibleWidget::widget(); }
1017QObject *QAccessibleWidgetEx::parentObject() const
1018{ return reinterpret_cast<const QAccessibleWidget *>(this)->QAccessibleWidget::parentObject(); }
1019
1020void QAccessibleWidgetEx::addControllingSignal(const QString &signal)
1021{ reinterpret_cast<QAccessibleWidget *>(this)->QAccessibleWidget::addControllingSignal(signal); }
1022void QAccessibleWidgetEx::setValue(const QString &value)
1023{ reinterpret_cast<QAccessibleWidget *>(this)->QAccessibleWidget::setValue(value); }
1024void QAccessibleWidgetEx::setDescription(const QString &desc)
1025{ reinterpret_cast<QAccessibleWidget *>(this)->QAccessibleWidget::setDescription(desc); }
1026void QAccessibleWidgetEx::setHelp(const QString &help)
1027{ reinterpret_cast<QAccessibleWidget *>(this)->QAccessibleWidget::setHelp(help); }
1028void QAccessibleWidgetEx::setAccelerator(const QString &accel)
1029{ reinterpret_cast<QAccessibleWidget *>(this)->QAccessibleWidget::setAccelerator(accel); }
1030
1031QVariant QAccessibleWidgetEx::invokeMethodEx(Method method, int child, const QVariantList & /*params*/)
1032{
1033 if (child)
1034 return QVariant();
1035
1036 switch (method) {
1037 case ListSupportedMethods: {
1038 QSet<QAccessible::Method> set;
1039 set << ListSupportedMethods << ForegroundColor << BackgroundColor;
1040 return QVariant::fromValue(set);
1041 }
1042 case ForegroundColor:
1043 return widget()->palette().color(widget()->foregroundRole());
1044 case BackgroundColor:
1045 return widget()->palette().color(widget()->backgroundRole());
1046 default:
1047 return QVariant();
1048 }
1049}
1050
1051QT_END_NAMESPACE
1052
1053#endif //QT_NO_ACCESSIBILITY
1054