Qt
Internal/Contributor docs for the Qt SDK. <b>Note:</b> These are NOT official API docs; those are found <a href='https://doc.qt.io/'>here</a>.
Loading...
Searching...
No Matches
qaccessiblewidget.cpp
Go to the documentation of this file.
1// Copyright (C) 2016 The Qt Company Ltd.
2// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only
3
4#include "qaccessiblewidget.h"
5
6#if QT_CONFIG(accessibility)
7
8#include "qapplication.h"
9#if QT_CONFIG(groupbox)
10#include "qgroupbox.h"
11#endif
12#if QT_CONFIG(label)
13#include "qlabel.h"
14#endif
15#if QT_CONFIG(tooltip)
16#include "qtooltip.h"
17#endif
18#if QT_CONFIG(whatsthis)
19#include "qwhatsthis.h"
20#endif
21#include "qwidget.h"
22#include "qdebug.h"
23#include <qmath.h>
24#if QT_CONFIG(rubberband)
25#include <QRubberBand>
26#endif
27#include <QFocusFrame>
28#if QT_CONFIG(menu)
29#include <QMenu>
30#endif
31#include <QtWidgets/private/qwidget_p.h>
32
34
35using namespace Qt::StringLiterals;
36
37QWidgetList _q_ac_childWidgets(const QWidget *widget);
38
39static QString buddyString(const QWidget *widget)
40{
41 if (!widget)
42 return QString();
43 QWidget *parent = widget->parentWidget();
44 if (!parent)
45 return QString();
46#if QT_CONFIG(shortcut) && QT_CONFIG(label)
47 for (QObject *o : parent->children()) {
48 QLabel *label = qobject_cast<QLabel*>(o);
49 if (label && label->buddy() == widget)
50 return label->text();
51 }
52#endif
53
54#if QT_CONFIG(groupbox)
55 QGroupBox *groupbox = qobject_cast<QGroupBox*>(parent);
56 if (groupbox)
57 return groupbox->title();
58#endif
59
60 return QString();
61}
62
63/* This function will return the offset of the '&' in the text that would be
64 preceding the accelerator character.
65 If this text does not have an accelerator, -1 will be returned. */
66static qsizetype qt_accAmpIndex(const QString &text)
67{
68#ifndef QT_NO_SHORTCUT
69 if (text.isEmpty())
70 return -1;
71
72 qsizetype fa = 0;
73 while ((fa = text.indexOf(u'&', fa)) != -1) {
74 ++fa;
75 if (fa < text.size()) {
76 // ignore "&&"
77 if (text.at(fa) == u'&') {
78
79 ++fa;
80 continue;
81 } else {
82 return fa - 1;
83 break;
84 }
85 }
86 }
87
88 return -1;
89#else
91 return -1;
92#endif
93}
94
95QString qt_accStripAmp(const QString &text)
96{
97 QString newText(text);
98 qsizetype ampIndex = qt_accAmpIndex(newText);
99 if (ampIndex != -1)
100 newText.remove(ampIndex, 1);
101
102 return newText.replace("&&"_L1, "&"_L1);
103}
104
105QString qt_accHotKey(const QString &text)
106{
107#ifndef QT_NO_SHORTCUT
108 qsizetype ampIndex = qt_accAmpIndex(text);
109 if (ampIndex != -1)
111#else
112 Q_UNUSED(text);
113#endif
114
115 return QString();
116}
117
118// ### inherit QAccessibleObjectPrivate
119class QAccessibleWidgetPrivate
120{
121public:
122 QAccessibleWidgetPrivate()
123 :role(QAccessible::Client)
124 {}
125
126 QAccessible::Role role;
128 QStringList primarySignals;
129};
130
159QAccessibleWidget::QAccessibleWidget(QWidget *w, QAccessible::Role role, const QString &name)
160: QAccessibleObject(w)
161{
162 Q_ASSERT(widget());
163 d = new QAccessibleWidgetPrivate();
164 d->role = role;
165 d->name = name;
166}
167
169bool QAccessibleWidget::isValid() const
170{
171 if (!object() || static_cast<QWidget *>(object())->d_func()->data.in_destructor)
172 return false;
173 return QAccessibleObject::isValid();
174}
175
177QWindow *QAccessibleWidget::window() const
178{
179 const QWidget *w = widget();
180 Q_ASSERT(w);
181 QWindow *result = w->windowHandle();
182 if (!result) {
183 if (const QWidget *nativeParent = w->nativeParentWidget())
184 result = nativeParent->windowHandle();
185 }
186 return result;
187}
188
192QAccessibleWidget::~QAccessibleWidget()
193{
194 delete d;
195}
196
200QWidget *QAccessibleWidget::widget() const
201{
202 return qobject_cast<QWidget*>(object());
203}
204
209QObject *QAccessibleWidget::parentObject() const
210{
211 QWidget *w = widget();
212 if (!w || w->isWindow() || !w->parentWidget())
213 return qApp;
214 return w->parent();
215}
216
218QRect QAccessibleWidget::rect() const
219{
220 QWidget *w = widget();
221 if (!w->isVisible())
222 return QRect();
223 QPoint wpos = w->mapToGlobal(QPoint(0, 0));
224
225 return QRect(wpos.x(), wpos.y(), w->width(), w->height());
226}
227
234void QAccessibleWidget::addControllingSignal(const QString &signal)
235{
237 if (Q_UNLIKELY(object()->metaObject()->indexOfSignal(s) < 0))
238 qWarning("Signal %s unknown in %s", s.constData(), object()->metaObject()->className());
239 d->primarySignals << QLatin1StringView(s);
240}
241
242static inline bool isAncestor(const QObject *obj, const QObject *child)
243{
244 while (child) {
245 if (child == obj)
246 return true;
247 child = child->parent();
248 }
249 return false;
250}
251
253QList<QPair<QAccessibleInterface *, QAccessible::Relation>>
254QAccessibleWidget::relations(QAccessible::Relation match /*= QAccessible::AllRelations*/) const
255{
256 QList<QPair<QAccessibleInterface *, QAccessible::Relation>> rels;
257 if (match & QAccessible::Label) {
258 const QAccessible::Relation rel = QAccessible::Label;
259 if (QWidget *parent = widget()->parentWidget()) {
260#if QT_CONFIG(shortcut) && QT_CONFIG(label)
261 // first check for all siblings that are labels to us
262 // ideally we would go through all objects and check, but that
263 // will be too expensive
264 const QList<QWidget*> kids = _q_ac_childWidgets(parent);
265 for (QWidget *kid : kids) {
266 if (QLabel *labelSibling = qobject_cast<QLabel*>(kid)) {
267 if (labelSibling->buddy() == widget()) {
268 QAccessibleInterface *iface = QAccessible::queryAccessibleInterface(labelSibling);
269 rels.append(qMakePair(iface, rel));
270 }
271 }
272 }
273#endif
274#if QT_CONFIG(groupbox)
275 QGroupBox *groupbox = qobject_cast<QGroupBox*>(parent);
276 if (groupbox && !groupbox->title().isEmpty()) {
277 QAccessibleInterface *iface = QAccessible::queryAccessibleInterface(groupbox);
278 rels.append(qMakePair(iface, rel));
279 }
280#endif
281 }
282 }
283
284 if (match & QAccessible::Controlled) {
285 QObjectList allReceivers;
286 QObject *connectionObject = object();
287 for (int sig = 0; sig < d->primarySignals.size(); ++sig) {
288 const QObjectList receivers = connectionObject->d_func()->receiverList(d->primarySignals.at(sig).toLatin1());
289 allReceivers += receivers;
290 }
291
292 allReceivers.removeAll(object()); //### The object might connect to itself internally
293
294 for (int i = 0; i < allReceivers.size(); ++i) {
295 const QAccessible::Relation rel = QAccessible::Controlled;
296 QAccessibleInterface *iface = QAccessible::queryAccessibleInterface(allReceivers.at(i));
297 if (iface)
298 rels.append(qMakePair(iface, rel));
299 }
300 }
301
302 return rels;
303}
304
306QAccessibleInterface *QAccessibleWidget::parent() const
307{
308 return QAccessible::queryAccessibleInterface(parentObject());
309}
310
312QAccessibleInterface *QAccessibleWidget::child(int index) const
313{
314 Q_ASSERT(widget());
315 QWidgetList childList = _q_ac_childWidgets(widget());
316 if (index >= 0 && index < childList.size())
317 return QAccessible::queryAccessibleInterface(childList.at(index));
318 return nullptr;
319}
320
322QAccessibleInterface *QAccessibleWidget::focusChild() const
323{
324 if (widget()->hasFocus())
325 return QAccessible::queryAccessibleInterface(object());
326
327 QWidget *fw = widget()->focusWidget();
328 if (!fw)
329 return nullptr;
330
331 if (isAncestor(widget(), fw)) {
332 QAccessibleInterface *iface = QAccessible::queryAccessibleInterface(fw);
333 if (!iface || iface == this || !iface->focusChild())
334 return iface;
335 return iface->focusChild();
336 }
337 return nullptr;
338}
339
341int QAccessibleWidget::childCount() const
342{
343 QWidgetList cl = _q_ac_childWidgets(widget());
344 return cl.size();
345}
346
348int QAccessibleWidget::indexOfChild(const QAccessibleInterface *child) const
349{
350 if (!child)
351 return -1;
352 QWidgetList cl = _q_ac_childWidgets(widget());
353 return cl.indexOf(qobject_cast<QWidget *>(child->object()));
354}
355
356// from qwidget.cpp
358
360QString QAccessibleWidget::text(QAccessible::Text t) const
361{
362 QString str;
363
364 switch (t) {
365 case QAccessible::Name:
366 if (!d->name.isEmpty()) {
367 str = d->name;
368 } else if (!widget()->accessibleName().isEmpty()) {
369 str = widget()->accessibleName();
370 } else if (widget()->isWindow()) {
371 if (widget()->isMinimized())
372 str = qt_setWindowTitle_helperHelper(widget()->windowIconText(), widget());
373 else
375 } else {
376 str = qt_accStripAmp(buddyString(widget()));
377 }
378 break;
379 case QAccessible::Description:
380 str = widget()->accessibleDescription();
381#if QT_CONFIG(tooltip)
382 if (str.isEmpty())
383 str = widget()->toolTip();
384#endif
385 break;
386 case QAccessible::Help:
387#if QT_CONFIG(whatsthis)
388 str = widget()->whatsThis();
389#endif
390 break;
391 case QAccessible::Accelerator:
392 str = qt_accHotKey(buddyString(widget()));
393 break;
394 case QAccessible::Value:
395 break;
396 default:
397 break;
398 }
399 return str;
400}
401
403QStringList QAccessibleWidget::actionNames() const
404{
406 if (widget()->isEnabled()) {
407 if (widget()->focusPolicy() != Qt::NoFocus)
408 names << setFocusAction();
409 }
410 return names;
411}
412
414void QAccessibleWidget::doAction(const QString &actionName)
415{
416 if (!widget()->isEnabled())
417 return;
418
419 if (actionName == setFocusAction()) {
420 if (widget()->isWindow())
422 widget()->setFocus();
423 }
424}
425
427QStringList QAccessibleWidget::keyBindingsForAction(const QString & /* actionName */) const
428{
429 return QStringList();
430}
431
433QAccessible::Role QAccessibleWidget::role() const
434{
435 return d->role;
436}
437
439QAccessible::State QAccessibleWidget::state() const
440{
442
443 QWidget *w = widget();
444 if (w->testAttribute(Qt::WA_WState_Visible) == false)
445 state.invisible = true;
446 if (w->focusPolicy() != Qt::NoFocus)
447 state.focusable = true;
448 if (w->hasFocus())
449 state.focused = true;
450 if (!w->isEnabled())
451 state.disabled = true;
452 if (w->isWindow()) {
453 if (w->windowFlags() & Qt::WindowSystemMenuHint)
454 state.movable = true;
455 if (w->minimumSize() != w->maximumSize())
456 state.sizeable = true;
457 if (w->isActiveWindow())
458 state.active = true;
459 }
460
461 return state;
462}
463
465QColor QAccessibleWidget::foregroundColor() const
466{
467 return widget()->palette().color(widget()->foregroundRole());
468}
469
471QColor QAccessibleWidget::backgroundColor() const
472{
473 return widget()->palette().color(widget()->backgroundRole());
474}
475
477void *QAccessibleWidget::interface_cast(QAccessible::InterfaceType t)
478{
479 if (t == QAccessible::ActionInterface)
480 return static_cast<QAccessibleActionInterface*>(this);
481 return nullptr;
482}
483
485
486#endif // QT_CONFIG(accessibility)
\inmodule QtGui
The QAccessible class provides enums and static functions related to accessibility.
\inmodule QtCore
Definition qbytearray.h:57
The QColor class provides colors based on RGB, HSV or CMYK values.
Definition qcolor.h:31
The QGroupBox widget provides a group box frame with a title.
Definition qgroupbox.h:17
The QKeySequence class encapsulates a key sequence as used by shortcuts.
QString toString(SequenceFormat format=PortableText) const
The QLabel widget provides a text or image display.
Definition qlabel.h:20
qsizetype removeAll(const AT &t)
Definition qlist.h:592
\inmodule QtCore
Definition qobject.h:103
const QColor & color(ColorGroup cg, ColorRole cr) const
Returns the color in the specified color group, used for the given color role.
Definition qpalette.h:67
\inmodule QtCore\reentrant
Definition qpoint.h:25
\inmodule QtCore\reentrant
Definition qrect.h:30
\inmodule QtCore
\macro QT_RESTRICTED_CAST_FROM_ASCII
Definition qstring.h:129
qsizetype indexOf(QLatin1StringView s, qsizetype from=0, Qt::CaseSensitivity cs=Qt::CaseSensitive) const
Definition qstring.cpp:4517
bool isEmpty() const noexcept
Returns true if the string has no characters; otherwise returns false.
Definition qstring.h:192
qsizetype size() const noexcept
Returns the number of characters in this string.
Definition qstring.h:186
const QChar at(qsizetype i) const
Returns the character at the given index position in the string.
Definition qstring.h:1226
The QWidget class is the base class of all user interface objects.
Definition qwidget.h:99
QWidget * nativeParentWidget() const
Definition qwidget.cpp:4333
QPalette palette
the widget's palette
Definition qwidget.h:132
QWidget * focusWidget() const
Returns the last child of this widget that setFocus had been called on.
Definition qwidget.cpp:6828
void setFocus()
This is an overloaded member function, provided for convenience. It differs from the above function o...
Definition qwidget.h:423
QWidget * parentWidget() const
Returns the parent of this widget, or \nullptr if it does not have any parent widget.
Definition qwidget.h:904
void activateWindow()
Sets the top-level widget containing this widget to be the active window.
\inmodule QtGui
Definition qwindow.h:63
QOpenGLWidget * widget
[1]
QString str
[2]
QString text
auto signal
else opt state
[0]
Combined button and popup list for selecting options.
bool isEnabled()
constexpr QBindableInterface iface
Definition qproperty.h:666
@ ALT
@ WA_WState_Visible
Definition qnamespace.h:296
@ NoFocus
Definition qnamespace.h:107
@ WindowSystemMenuHint
Definition qnamespace.h:227
#define Q_UNLIKELY(x)
QList< QString > QStringList
Constructs a string list that contains the given string, str.
#define qApp
#define qWarning
Definition qlogging.h:166
GLfloat GLfloat GLfloat w
[0]
GLuint index
[2]
GLuint object
[3]
GLint GLsizei GLsizei GLenum GLenum GLsizei void * data
GLuint GLsizei const GLchar * label
[43]
GLuint name
GLhandleARB obj
[2]
GLdouble s
[6]
Definition qopenglext.h:235
GLuint GLuint * names
GLdouble GLdouble t
Definition qopenglext.h:243
GLuint64EXT * result
[6]
QT_BEGIN_NAMESPACE constexpr decltype(auto) qMakePair(T1 &&value1, T2 &&value2) noexcept(noexcept(std::make_pair(std::forward< T1 >(value1), std::forward< T2 >(value2))))
Definition qpair.h:19
static bool isWindow(QObject *object)
#define Q_ASSERT(cond)
Definition qrandom.cpp:47
#define Q_UNUSED(x)
static bool match(const uchar *found, uint foundLen, const char *target, uint targetLen)
ptrdiff_t qsizetype
Definition qtypes.h:165
QString qt_setWindowTitle_helperHelper(const QString &title, const QWidget *widget)
Returns a modified window title with the [*] place holder replaced according to the rules described i...
Definition qwidget.cpp:5992
QWidget * qobject_cast< QWidget * >(QObject *o)
Definition qwidget.h:786
static QString windowTitle(HWND hwnd)
obj metaObject() -> className()
QLayoutItem * child
[0]
static QByteArray normalizedSignature(const char *method)
Normalizes the signature of the given method.